コード例 #1
0
        public async Task <JudgeResult> JudgeAsync(BuildOption buildOption, JudgeOption judgeOption)
        {
            _workingdir = Path.Combine(Path.GetTempPath(), "hjudgeTest", judgeOption.GuidStr);

            Directory.CreateDirectory(_workingdir);
            var result = new JudgeResult
            {
                JudgePoints = new List <JudgePoint>()
            };

            try
            {
                if (judgeOption.AnswerPoint != null)
                {
                    return(await AnswerJudgeAsync(buildOption, judgeOption));
                }

                var fileName = Path.Combine(_workingdir, $"{buildOption.SubmitFileName}{buildOption.ExtensionName}");
                File.WriteAllText(fileName, buildOption.Source, Encoding.UTF8);

                if (buildOption.StaticCheckOption != null)
                {
                    var logs = await StaticCheck(buildOption.StaticCheckOption);

                    result.StaticCheckLog = logs;
                }

                if (buildOption.CompilerOption != null)
                {
                    var(isSucceeded, logs) = await Compile(buildOption.CompilerOption, judgeOption.ExtraFiles);

                    result.CompileLog = logs;
                    if (!isSucceeded)
                    {
                        result.JudgePoints = Enumerable.Repeat(
                            new JudgePoint
                        {
                            ResultType = ResultCode.Compile_Error
                        }, judgeOption.DataPoints.Count)
                                             .ToList();
                        return(result);
                    }
                }

                for (var i = 0; i < judgeOption.DataPoints.Count; i++)
                {
                    var point = new JudgePoint();
                    if (!File.Exists(judgeOption.RunOption?.Exec))
                    {
                        point.ResultType = ResultCode.Compile_Error;
                        point.ExtraInfo  = "Cannot find compiled executable file";
                        result.JudgePoints.Add(point);
                        continue;
                    }
                    try
                    {
                        try
                        {
                            File.Copy(judgeOption.DataPoints[i].StdInFile.Replace("${index}", (i + 1).ToString()).Replace("${index0}", i.ToString()), Path.Combine(_workingdir, judgeOption.InputFileName), true);
                        }
                        catch
                        {
                            throw new InvalidOperationException("Unable to find standard input file");
                        }
                        var strErrFile = Path.Combine(_workingdir, $"stderr_{judgeOption.GuidStr}.dat");
                        var inputFile  = Path.Combine(_workingdir, judgeOption.InputFileName);
                        var outputFile = Path.Combine(_workingdir, judgeOption.OutputFileName);
                        var param      = new
                        {
                            judgeOption.RunOption.Exec,
                            judgeOption.RunOption.Args,
                            WorkingDir         = _workingdir,
                            StdErrRedirectFile = strErrFile,
                            InputFile          = inputFile,
                            OutputFile         = outputFile,
                            judgeOption.DataPoints[i].TimeLimit,
                            judgeOption.DataPoints[i].MemoryLimit,
                            IsStdIO = judgeOption.UseStdIO,
                            judgeOption.ActiveProcessLimit
                        };
                        var ret = new StringBuilder(256);
                        if (Execute(JsonConvert.SerializeObject(param), ret))
                        {
                            point = JsonConvert.DeserializeObject <JudgePoint>(ret.ToString()?.Trim() ?? "{}");
                        }
                        else
                        {
                            throw new Exception("Unable to execute target program");
                        }
                        try
                        {
                            File.Copy(judgeOption.DataPoints[i].StdOutFile.Replace("${index}", (i + 1).ToString()).Replace("${index0}", i.ToString()), Path.Combine(_workingdir, $"answer_{judgeOption.GuidStr}.dat"), true);
                        }
                        catch
                        {
                            throw new InvalidOperationException("Unable to find standard output file");
                        }

                        if (point.ResultType == ResultCode.Runtime_Error)
                        {
                            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
                                Enum.IsDefined(typeof(WindowsExceptionCode), (uint)point.ExitCode))
                            {
                                point.ExtraInfo = Enum.GetName(typeof(WindowsExceptionCode), (uint)point.ExitCode);
                            }
                            else if (Enum.IsDefined(typeof(LinuxExceptionCode), point.ExitCode - 128))
                            {
                                point.ExtraInfo = Enum.GetName(typeof(LinuxExceptionCode), point.ExitCode - 128);
                            }
                            else
                            {
                                point.ExtraInfo = "UNKNOWN_EXCEPTION";
                            }
                            point.Score = 0;
                        }
                        else
                        {
                            if (judgeOption.StandardErrorBehavior != StdErrBehavior.Ignore)
                            {
                                try
                                {
                                    var stderr = File.ReadAllText(strErrFile).Trim()
                                                 .Replace(_workingdir, "...")
                                                 .Replace(_workingdir.Replace("/", "\\"), "...");;

                                    if (!string.IsNullOrWhiteSpace(stderr.Replace("\n", string.Empty).Replace("\r", string.Empty).Replace("\t", string.Empty).Trim()))
                                    {
                                        switch (judgeOption.StandardErrorBehavior)
                                        {
                                        case StdErrBehavior.TreatAsCompileError:
                                            point.ResultType = ResultCode.Compile_Error;
                                            point.ExtraInfo  = stderr;
                                            break;

                                        case StdErrBehavior.TreatAsRuntimeError:
                                            point.ResultType = ResultCode.Runtime_Error;
                                            point.ExtraInfo  = stderr;
                                            break;
                                        }
                                        point.Score = 0;
                                    }
                                }
                                catch
                                {
                                    //ignored
                                }
                            }

                            if (point.ResultType == ResultCode.Accepted)
                            {
                                var(resultType, percentage, extraInfo) = point.ResultType == ResultCode.Accepted ?
                                                                         await CompareAsync(fileName, inputFile, Path.Combine(_workingdir, $"answer_{judgeOption.GuidStr}.dat"), outputFile, judgeOption)
                                    : (point.ResultType, 0, point.ExtraInfo);

                                point.ExtraInfo  = extraInfo;
                                point.ResultType = resultType;
                                point.Score      = percentage * judgeOption.DataPoints[i].Score;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        point.ExtraInfo = ex.Message;
                        if (ex is InvalidOperationException)
                        {
                            point.ResultType = ResultCode.Problem_Config_Error;
                        }
                        else
                        {
                            point.ResultType = ResultCode.Unknown_Error;
                        }
                    }

                    result.JudgePoints.Add(point);
                }
            }
            finally
            {
                try
                {
                    Directory.Delete(_workingdir, true);
                }
                catch { /* ignored */ }
            }
            return(result);
        }
コード例 #2
0
        private async Task <(ResultCode Result, float Percentage, string ExtraInfo)> CompareAsync(string sourceFile, string stdInputFile, string stdOutputFile, string outputFile, JudgeOption judgeOption, bool isAnswerJudge = false)
        {
            if (!File.Exists(outputFile))
            {
                return(ResultCode.Output_File_Error, 0, string.Empty);
            }

            if (judgeOption.SpecialJudgeOption != null)
            {
                var argsBuilder = new StringBuilder();
                if (judgeOption.SpecialJudgeOption.UseSourceFile)
                {
                    argsBuilder.Append($" \"{sourceFile}\"");
                }
                if (judgeOption.SpecialJudgeOption.UseOutputFile)
                {
                    argsBuilder.Append($" \"{outputFile}\"");
                }
                if (judgeOption.SpecialJudgeOption.UseStdInputFile)
                {
                    argsBuilder.Append($" \"{stdInputFile}\"");
                }
                if (judgeOption.SpecialJudgeOption.UseStdOutputFile)
                {
                    argsBuilder.Append($" \"{stdOutputFile}\"");
                }

                using (var judge = new Process
                {
                    StartInfo = new ProcessStartInfo
                    {
                        FileName = judgeOption.SpecialJudgeOption.Exec,
                        Arguments = argsBuilder.ToString(),
                        ErrorDialog = false,
                        RedirectStandardOutput = true,
                        RedirectStandardError = true,
                        UseShellExecute = false,
                        StandardOutputEncoding = Encoding.UTF8
                    }
                })
                {
                    await Task.Delay(100);

                    try
                    {
                        judge.Start();
                    }
                    catch (Exception ex)
                    {
                        return(ResultCode.Special_Judge_Error, 0, ex.Message);
                    }

                    if (judge.WaitForExit(60 * 1000))
                    {
                        try
                        {
                            judge.Kill();
                        }
                        catch
                        {
                            /* ignored */
                        }
                    }

                    var(error, output) = (await judge.StandardError.ReadToEndAsync(), await judge.StandardOutput.ReadToEndAsync());

                    if (judge.ExitCode != 0)
                    {
                        return(ResultCode.Special_Judge_Error, 0, null);
                    }

                    try
                    {
                        var percentage = Convert.ToSingle(output.Trim());
                        return(
                            Math.Abs(percentage - 1f) < 0.001 ?
                            ResultCode.Accepted : ResultCode.Wrong_Answer,
                            percentage,
                            error);
                    }
                    catch
                    {
                        return(ResultCode.Special_Judge_Error, 0, null);
                    }
                }
            }

            StreamReader std = null, act = null;
            var          retryTimes = 0;

            do
            {
                try
                {
                    std = new StreamReader(new FileStream(stdOutputFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), Encoding.UTF8);
                }
                catch (Exception ex)
                {
                    std?.Dispose();
                    std = null;
                    retryTimes++;
                    if (retryTimes > 100)
                    {
                        return(ResultCode.Unknown_Error, 0, ex.Message);
                    }
                    await Task.Delay(100);
                }
            } while (std == null);

            retryTimes = 0;
            do
            {
                try
                {
                    act = new StreamReader(new FileStream(outputFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), Encoding.UTF8, true);
                }
                catch (Exception ex)
                {
                    act?.Dispose();
                    act = null;
                    retryTimes++;
                    if (retryTimes > 100)
                    {
                        std?.Dispose();
                        return(ResultCode.Unknown_Error, 0, ex.Message);
                    }
                    await Task.Delay(100);
                }
            } while (act == null);

            var line   = 0;
            var result = new JudgePoint
            {
                ResultType = ResultCode.Accepted
            };

            while (!act.EndOfStream || !std.EndOfStream)
            {
                string actline = null, stdline = null;
                if (!std.EndOfStream)
                {
                    stdline = std.ReadLine();
                }

                if (!act.EndOfStream)
                {
                    actline = act.ReadLine();
                }

                line++;
                if (judgeOption.ComparingOption?.IgnoreLineTailWhiteSpaces ?? true)
                {
                    if (!string.IsNullOrEmpty(stdline))
                    {
                        stdline = stdline.TrimEnd();
                    }

                    if (!string.IsNullOrEmpty(actline))
                    {
                        actline = actline.TrimEnd();
                    }
                }

                if (judgeOption.ComparingOption?.IgnoreTextTailLineFeeds ?? true)
                {
                    if (stdline == null)
                    {
                        stdline = string.Empty;
                    }

                    if (actline == null)
                    {
                        actline = string.Empty;
                    }
                }

                if (stdline != actline)
                {
                    if (!isAnswerJudge)
                    {
                        result.ExtraInfo =
                            $"Line {line}: \nexpect: {stdline?.Substring(0, 64 < (stdline?.Length ?? 0) ? 64 : stdline?.Length ?? 0) ?? "<nothing>"}{((stdline?.Length ?? 0) > 64 ? "..." : string.Empty)} \noutput: {actline?.Substring(0, 64 < (actline?.Length ?? 0) ? 64 : actline?.Length ?? 0) ?? "<nothing>"}{((actline?.Length ?? 0) > 64 ? "..." : string.Empty)}";
                    }

                    if ((stdline?.Replace(" ", string.Empty) ?? string.Empty) ==
                        (actline?.Replace(" ", string.Empty) ?? string.Empty))
                    {
                        result.ResultType = ResultCode.Presentation_Error;
                    }
                    else
                    {
                        result.ResultType = ResultCode.Wrong_Answer;
                        break;
                    }
                }
            }

            std.Dispose();
            act.Dispose();
            return(result.ResultType, result.ResultType == ResultCode.Accepted ? 1 : 0, result.ExtraInfo);
        }