Skip to content

Commit

Permalink
Merge pull request #90 from tossy310/domjudgeValidator
Browse files Browse the repository at this point in the history
Add DOMJudge custom output validator support
  • Loading branch information
tossy310 authored Aug 15, 2023
2 parents ea3a3a2 + 140abb4 commit a61dbfb
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 9 deletions.
20 changes: 14 additions & 6 deletions rime/basic/codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@ def Compile(self):

@taskgraph.task_method
def Run(self, args, cwd, input, output, timeout, precise,
redirect_error=False):
redirect_error=False, ok_returncode=0, ng_returncode=None):
"""Run the code and return RunResult."""
try:
result = yield self._ExecForRun(
args=tuple(list(self.run_args) + list(args)), cwd=cwd,
input=input, output=output, timeout=timeout, precise=precise,
redirect_error=redirect_error)
redirect_error=redirect_error,
ok_returncode=ok_returncode, ng_returncode=ng_returncode)
except Exception as e:
result = codes.RunResult('On execution: %s' % e, None)
yield result
Expand Down Expand Up @@ -72,7 +73,7 @@ def _ExecForCompile(self, args):

@taskgraph.task_method
def _ExecForRun(self, args, cwd, input, output, timeout, precise,
redirect_error=False):
redirect_error=False, ok_returncode=0, ng_returncode=None):
with open(input, 'r') as infile:
with open(output, 'w') as outfile:
if redirect_error:
Expand All @@ -82,11 +83,13 @@ def _ExecForRun(self, args, cwd, input, output, timeout, precise,
yield (yield self._ExecInternal(
args=args, cwd=cwd,
stdin=infile, stdout=outfile, stderr=errfile,
timeout=timeout, precise=precise))
timeout=timeout, precise=precise,
ok_returncode=ok_returncode, ng_returncode=ng_returncode))

@taskgraph.task_method
def _ExecInternal(self, args, cwd, stdin, stdout, stderr,
timeout=None, precise=False):
timeout=None, precise=False, ok_returncode=0,
ng_returncode=None):
task = taskgraph.ExternalProcessTask(
args, cwd=cwd, stdin=stdin, stdout=stdout, stderr=stderr,
timeout=timeout, exclusive=precise)
Expand All @@ -100,12 +103,17 @@ def _ExecInternal(self, args, cwd, stdin, stdout, stderr,
timeout=timeout, exclusive=True)
proc = yield task
code = proc.returncode
if code == 0:
if code == ok_returncode:
status = codes.RunResult.OK
elif code == -(signal.SIGXCPU):
status = codes.RunResult.TLE
elif code < 0:
status = codes.RunResult.RE
elif ng_returncode is not None:
if code == ng_returncode:
status = codes.RunResult.NG
else:
status = codes.RunResult.RE
else:
status = codes.RunResult.NG
yield codes.RunResult(status, task.time)
Expand Down
57 changes: 56 additions & 1 deletion rime/plugins/judge_system/domjudge.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from rime.core import targets
from rime.core import taskgraph
from rime.plugins.plus import commands as plus_commands
from rime.plugins.plus import flexible_judge
from rime.util import files


Expand Down Expand Up @@ -45,6 +46,22 @@ def __init__(self, *args, **kwargs):
self.domjudge_pack_dir = os.path.join(self.problem.out_dir, 'domjudge')


class DOMJudgeJudgeRunner(flexible_judge.JudgeRunner):
PREFIX = 'domjudge'

def Run(self, judge, infile, difffile, outfile, cwd, judgefile):
domjudge_workdir = infile + '.domjudge'
files.MakeDir(domjudge_workdir)
return judge.Run(
args=(infile, difffile, domjudge_workdir),
cwd=cwd,
input=outfile,
output=judgefile,
timeout=None, precise=False,
redirect_error=True,
ok_returncode=42, ng_returncode=43)


class DOMJudgePacker(plus_commands.PackerBase):
@taskgraph.task_method
def Pack(self, ui, testset):
Expand Down Expand Up @@ -100,6 +117,42 @@ def Pack(self, ui, testset):
ui.errors.Exception(testset)
yield False

if len(testset.judges) > 1:
ui.errors.Error(
testset, 'Multiple varidators is not supported in DOMJudge.')
yield False
elif len(testset.judges) == 1:
judge = testset.judges[0]

if not isinstance(judge.variant, DOMJudgeJudgeRunner):
ui.errors.Error(
testset,
'Only domjudge_judge_runner is supported.')
yield False

validator_dir = os.path.join(
pack_files_dir, 'output_validators',
os.path.splitext(judge.src_name)[0])
files.MakeDir(validator_dir)
ui.console.PrintAction(
'PACK',
testset,
'output validator files',
progress=True)
files.CopyFile(
os.path.join(testset.src_dir, judge.src_name),
validator_dir)
for f in judge.dependency:
files.CopyFile(
os.path.join(testset.project.library_dir, f),
validator_dir)

# Generate problem.yaml
# TODO: add more data to problem.yaml?
yaml_file = os.path.join(pack_files_dir, 'problem.yaml')
with open(yaml_file, 'w') as f:
f.write('validation: custom\n')

if (testset.problem.domjudge_config_defined and
testset.problem.domjudge_problem_file):
dest_filename = 'problem.pdf'
Expand Down Expand Up @@ -274,7 +327,7 @@ def Submit(self, ui, solution):
if solution.IsCorrect() is not (verdict == 'AC'):
ui.errors.Warning(
solution, 'Expected %s, but got %s' %
('pass' if solution.IsCorrect() else 'fail' , verdict))
('pass' if solution.IsCorrect() else 'fail', verdict))

yield True

Expand All @@ -283,6 +336,8 @@ def Submit(self, ui, solution):
targets.registry.Override('Problem', Problem)
targets.registry.Override('Testset', Testset)

flexible_judge.judge_runner_registry.Add(DOMJudgeJudgeRunner)

plus_commands.packer_registry.Add(DOMJudgePacker)
plus_commands.uploader_registry.Add(DOMJudgeUploader)
plus_commands.submitter_registry.Add(DOMJudgeSubmitter)
11 changes: 9 additions & 2 deletions rime/plugins/plus/basic_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,8 @@ def _RunValidatorForInvalidCasesOne(self, validator, testcase, ui):
# fast_test
@taskgraph.task_method
def _ExecInternal(self, args, cwd, stdin, stdout, stderr,
timeout=None, precise=False):
timeout=None, precise=False, ok_returncode=0,
ng_returncode=None):
task = taskgraph.ExternalProcessTask(
args, cwd=cwd, stdin=stdin, stdout=stdout, stderr=stderr,
timeout=timeout, exclusive=precise)
Expand All @@ -412,12 +413,18 @@ def _ExecInternal(self, args, cwd, stdin, stdout, stderr,
timeout=timeout, exclusive=precise)
proc = yield task
code = proc.returncode
if code == 0:

if code == ok_returncode:
status = codes.RunResult.OK
elif code == -(signal.SIGXCPU):
status = codes.RunResult.TLE
elif code < 0:
status = codes.RunResult.RE
elif ng_returncode is not None:
if code == ng_returncode:
status = codes.RunResult.NG
else:
status = codes.RunResult.RE
else:
status = codes.RunResult.NG
yield codes.RunResult(status, task.time)
Expand Down

0 comments on commit a61dbfb

Please sign in to comment.