Ejemplo n.º 1
0
        private double GradeOneSubmission(string problemName, string userName, out JudgeUpdateScoreType status)
        {
            status = JudgeUpdateScoreType.OK;
            int total = problemModel[problemName].Testcases.Count;

            //Remove old submission
            judgeModel.RemoveSubmission(problemName, userName);
            OnUpdateScore?.Invoke(this, new JudgeUpdateScoreSubmissionEvent()
            {
                ProblemName = problemName,
                UserName    = userName,
                Status      = JudgeUpdateScoreType.RemoveSubmission,
                Points      = 0,
            });

            OnGradeStatusChanged?.Invoke(this, new JudgeGradingEvent()
            {
                Event       = JudgeGradingEventType.BeginGradingSubmission,
                ProblemName = problemName,
                UserName    = userName
            });
            //--------------- check submission existed & get user, problem object
            User    user    = userModel[userName];
            Problem problem = problemModel[problemName];
            List <UserSubmission> submissions = user.GetSubmission(problemName);

            if (submissions.Count == 0)
            {
                //Submission not found
                OnGradeStatusChanged?.Invoke(this, new JudgeGradingEvent()
                {
                    Event       = JudgeGradingEventType.SubmissionNotFound,
                    UserName    = userName,
                    ProblemName = problemName
                });
                TestcasesGraded += total;
                judgeModel.CreateNewSubmission(problemName, userName, "Not found submission!", "MS", "(null)");
                status = JudgeUpdateScoreType.SubmissionNotFound;
                return(0);
            }

            //--------------- make directory
            string currentDir        = FS.Combine(workSpace, DateTime.Now.Ticks.ToString());
            string currentUserDir    = FS.Combine(currentDir, user.UserName);
            string currentProblemDir = FS.Combine(currentDir, problem.ProblemName);
            string inputRun          = FS.Combine(currentProblemDir, "input.txt");

            FS.CreateDirectory(currentDir);
            FS.CreateDirectory(currentUserDir);
            FS.CreateDirectory(currentProblemDir);
            FS.CreateEmptyFile(inputRun);

            Compiler       compiler      = null;
            UserSubmission submission    = null;
            CompileStatus  compileResult = null;

            //--------------- compile
            foreach (UserSubmission sub in submissions)
            {
                submission = sub;
                string userSourceCode = FS.Combine(userModel.UserDirectory, userName, sub.ToString());

                string newSource = FS.Combine(currentUserDir, sub.ToString());
                FS.CopyFile(userSourceCode, newSource);

                if (!compilerManager.Contains(sub.Extension))
                {
                    continue;
                }
                List <Compiler> compilers = compilerManager[sub.Extension];
                bool            found     = false;
                foreach (Compiler com in compilers)
                {
                    compiler = com;

                    OnGradeStatusChanged.Invoke(this, new JudgeGradingEvent()
                    {
                        Event       = JudgeGradingEventType.Compiling,
                        Status      = com.Name,
                        UserName    = userName,
                        ProblemName = problemName
                    });

                    compileResult = com.Compile(sandbox, sub.ToString(), currentUserDir);

                    if (!IsGrading) //cancel
                    {
                        FS.DeleteDirectory(currentDir);
                        TestcasesGraded += total;
                        return(0);
                    }

                    if (compileResult.Success)
                    {
                        found = true;
                        break;
                    }
                }
                if (found)
                {
                    break;
                }
            }
            if (compiler == null)
            {
                //Submission not found
                OnGradeStatusChanged?.Invoke(this, new JudgeGradingEvent()
                {
                    Event       = JudgeGradingEventType.CompilerNotFound,
                    UserName    = userName,
                    ProblemName = problemName
                });
                TestcasesGraded += total;
                judgeModel.CreateNewSubmission(problemName, userName, "Not found submission!", "MS", "(null)");
                status = JudgeUpdateScoreType.CompilerNotFound;
                return(0);
            }

            if (!compileResult.Success)
            {
                //Compile error
                OnGradeStatusChanged?.Invoke(this, new JudgeGradingEvent()
                {
                    Status      = compileResult.Message,
                    UserName    = userName,
                    ProblemName = problemName,
                    Event       = JudgeGradingEventType.CompileError
                });
                TestcasesGraded += total;
                FS.DeleteDirectory(currentDir);
                judgeModel.CreateNewSubmission(problemName, userName, compileResult.Message, "CE", compiler.Name);
                status = JudgeUpdateScoreType.CompileError;
                return(0);
            }

            //OK
            OnGradeStatusChanged.Invoke(this, new JudgeGradingEvent()
            {
                Event       = JudgeGradingEventType.CompileSuccessfully,
                UserName    = userName,
                ProblemName = problemName,
                Status      = compiler.Name
            });

            //Check execute exist
            if (!FS.FileExist(FS.Combine(currentUserDir, compileResult.OutputFileName)))
            {
                OnGradeStatusChanged?.Invoke(this, new JudgeGradingEvent()
                {
                    ProblemName = problemName,
                    UserName    = userName,
                    Event       = JudgeGradingEventType.SubmissionNotFound
                });
                OnGradeStatusChanged?.Invoke(this, new JudgeGradingEvent()
                {
                    ProblemName = problemName,
                    UserName    = userName,
                    Event       = JudgeGradingEventType.NotFoundExecute
                });
                judgeModel.CreateNewSubmission(problemName, userName, "Not found execute", "NFE", compiler.Name);
                status = JudgeUpdateScoreType.ExecuteNotFound;
                return(0);
            }

            //3. Run testcase
            List <SubmissionTestcaseResult> gradingTestcaseResult = new List <SubmissionTestcaseResult>();

            foreach (Testcase test in problem.Testcases)
            {
                OnGradeStatusChanged?.Invoke(this, new JudgeGradingEvent()
                {
                    Event = JudgeGradingEventType.BeginRunTest
                });
                string currentTestDir = FS.Combine(currentProblemDir, test.TestcaseName);
                string sourceInput    = FS.Combine(problem.ParentDirectory, problem.ProblemName, test.TestcaseName, problem.Input);
                string sourceOutput   = FS.Combine(problem.ParentDirectory, problem.ProblemName, test.TestcaseName, problem.Output);
                string destOutput     = FS.Combine(currentTestDir, problem.Output);

                //create testcase directory
                FS.CreateDirectory(currentTestDir);

                //copy execute
                FS.CopyFile(FS.Combine(currentUserDir, compileResult.OutputFileName),
                            FS.Combine(currentTestDir, compileResult.OutputFileName));

                //copy input
                if (!problem.UseStdin)
                {
                    string destInput = FS.Combine(currentTestDir, problem.Input);
                    FS.CopyFile(sourceInput, destInput);
                }

                //run
                var running_status = sandbox.StartRun(-1,
                                                      ('"' + compiler.RunProgram + '"' + " " + compiler.RunArgs).Replace("$NAME$", submission.Name),
                                                      currentTestDir,
                                                      problem.Timelimit,
                                                      problem.Memorylimit * 1024,
                                                      problem.UseStdin ? sourceInput : inputRun,
                                                      problem.UseStdout ? destOutput : null,
                                                      TreatExitCodeNonZeroAsRTE
                                                      );

                if (!IsGrading) //cancel
                {
                    TestcasesGraded += total;
                    FS.DeleteDirectory(currentDir);
                    return(0);
                }
                TestcasesGraded++;
                total--;

                string grading_status = running_status.Status.ToString();
                double points         = 0.0;
                int    timeExecute    = running_status.TimeExecuted;
                int    memUsed        = running_status.MemoryUsed;

                //check
                if (running_status.ExitCode != 0)
                {
                    if (running_status.Status == SandBoxStatusType.TLE)
                    {
                        OnGradeStatusChanged?.Invoke(this, new JudgeGradingEvent()
                        {
                            Event        = JudgeGradingEventType.EndRunTest,
                            ProblemName  = problemName,
                            UserName     = userName,
                            TestCaseName = test.TestcaseName,
                            TimeExecuted = timeExecute,
                            Status       = "TLE"
                        });
                    }
                    else if (running_status.Status == SandBoxStatusType.MLE)
                    {
                        OnGradeStatusChanged?.Invoke(this, new JudgeGradingEvent()
                        {
                            Event        = JudgeGradingEventType.EndRunTest,
                            ProblemName  = problemName,
                            UserName     = userName,
                            TestCaseName = test.TestcaseName,
                            Status       = "MLE"
                        });
                    }
                    else if (running_status.Status == SandBoxStatusType.RTE)
                    {
                        OnGradeStatusChanged?.Invoke(this, new JudgeGradingEvent()
                        {
                            Event        = JudgeGradingEventType.EndRunTest,
                            ProblemName  = problemName,
                            UserName     = userName,
                            TestCaseName = test.TestcaseName,
                            Status       = "RTE"
                        });
                    }
                    else if (running_status.Status == SandBoxStatusType.UnknownError)
                    {
                        OnGradeStatusChanged?.Invoke(this, new JudgeGradingEvent()
                        {
                            Event        = JudgeGradingEventType.EndRunTest,
                            ProblemName  = problemName,
                            UserName     = userName,
                            TestCaseName = test.TestcaseName,
                            Status       = "Unknown"
                        });
                    }
                    else
                    {
                        throw new Exception("JUDGER ERROR");
                    }
                }
                else
                {
                    //if run ok -> copy output & rename
                    FS.CopyFile(sourceOutput, destOutput + "$");

                    //check result
                    bool checker_result = checker.Compare(problem.Checker, problem.Output, problem.Output + "$", currentTestDir);

                    if (checker_result)
                    {
                        grading_status = "AC";
                        points         = test.Point;
                    }
                    else
                    {
                        grading_status = "WA";
                    }
                    OnGradeStatusChanged?.Invoke(this, new JudgeGradingEvent()
                    {
                        Event        = JudgeGradingEventType.EndRunTest,
                        MemoryUsed   = memUsed,
                        TimeExecuted = timeExecute,
                        Status       = grading_status,
                        Points       = points,
                        TestCaseName = test.TestcaseName,
                        ProblemName  = problemName,
                        UserName     = userName,
                    });
                }

                gradingTestcaseResult.Add(new SubmissionTestcaseResult()
                {
                    ProblemName  = problemName,
                    UserName     = userName,
                    TestcaseName = test.TestcaseName,
                    Points       = points,
                    MemoryUsed   = memUsed,
                    TimeExecuted = timeExecute,
                    Status       = grading_status
                });
            }

            //update status to database & calc score
            double totalScore    = 0;
            int    submission_id = judgeModel.CreateNewSubmission(problemName, userName, compileResult.Message, "OK", compiler.Name);

            foreach (SubmissionTestcaseResult r in gradingTestcaseResult)
            {
                if (r.Status == "AC")
                {
                    judgeModel.UpdateLanguageTimeGrading(compiler.Name, r.TimeExecuted);
                }
                judgeModel.UpdateStatus(submission_id, r.TestcaseName,
                                        r.Points, r.Status, r.TimeExecuted, r.MemoryUsed);
                totalScore += r.Points;
            }

            //4. Clean
            FS.DeleteDirectory(currentDir);
            OnGradeStatusChanged?.Invoke(this, new JudgeGradingEvent()
            {
                Event = JudgeGradingEventType.EndGradingSubmission
            });
            status = JudgeUpdateScoreType.OK;
            return(totalScore);
        }