2020-07-29 21:20:09 +00:00
|
|
|
import os, re
|
2020-03-18 02:41:09 +00:00
|
|
|
import subprocess
|
|
|
|
|
|
|
|
from dmoj.error import InternalError
|
|
|
|
from dmoj.judgeenv import env, get_problem_root
|
|
|
|
from dmoj.result import CheckerResult
|
2020-07-29 21:20:09 +00:00
|
|
|
from dmoj.utils.helper_files import compile_with_auxiliary_files, mktemp, parse_helper_file_error
|
2020-03-18 02:41:09 +00:00
|
|
|
from dmoj.utils.unicode import utf8text
|
|
|
|
|
|
|
|
executor = None
|
|
|
|
|
|
|
|
|
|
|
|
def get_executor(files, lang, compiler_time_limit, problem_id):
|
|
|
|
global executor
|
|
|
|
|
|
|
|
if executor is None:
|
|
|
|
if not isinstance(files, list):
|
|
|
|
files = [files]
|
|
|
|
filenames = [os.path.join(get_problem_root(problem_id), f) for f in files]
|
2020-07-02 16:49:39 +00:00
|
|
|
executor = compile_with_auxiliary_files(filenames,
|
|
|
|
compiler_time_limit=compiler_time_limit)
|
2020-03-18 02:41:09 +00:00
|
|
|
|
|
|
|
return executor
|
|
|
|
|
2020-07-29 21:20:09 +00:00
|
|
|
class Module:
|
|
|
|
AC = 0
|
|
|
|
WA = 1
|
|
|
|
PARTIAL = 2
|
|
|
|
|
|
|
|
# a float from 0 to 1
|
|
|
|
repartial = re.compile(r'^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$', re.M)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def parse_return_code(cls, proc, executor, point_value, time_limit, memory_limit, feedback, name, stderr):
|
|
|
|
if proc.returncode == cls.AC:
|
|
|
|
return CheckerResult(True, point_value, feedback=feedback)
|
|
|
|
elif proc.returncode == cls.PARTIAL:
|
|
|
|
match = cls.repartial.search(stderr)
|
|
|
|
if not match:
|
|
|
|
raise InternalError('Invalid stderr for partial points: %r' % stderr)
|
|
|
|
points = float(match.group(0))
|
2020-07-29 21:36:54 +00:00
|
|
|
if not 0 <= points <= 1:
|
2020-07-29 21:20:09 +00:00
|
|
|
raise InternalError('Invalid partial points: %d' % points)
|
2020-07-29 21:36:54 +00:00
|
|
|
|
|
|
|
ac = (points == 1)
|
|
|
|
return CheckerResult(ac, points * point_value, feedback=feedback)
|
2020-07-29 21:20:09 +00:00
|
|
|
elif proc.returncode == cls.WA:
|
|
|
|
return CheckerResult(False, 0, feedback=feedback)
|
|
|
|
else:
|
|
|
|
parse_helper_file_error(proc, executor, name, stderr, time_limit, memory_limit)
|
|
|
|
|
2020-03-18 02:41:09 +00:00
|
|
|
|
|
|
|
def check(process_output, judge_output, judge_input,
|
|
|
|
problem_id={{problemid}},
|
|
|
|
files={{filecpp}},
|
|
|
|
lang='CPP14',
|
|
|
|
time_limit=10,
|
2020-07-29 21:20:09 +00:00
|
|
|
memory_limit=1024 * 512,
|
2020-07-22 21:13:41 +00:00
|
|
|
compiler_time_limit=30,
|
2020-07-29 21:20:09 +00:00
|
|
|
feedback=True,
|
2020-03-18 02:41:09 +00:00
|
|
|
point_value=None, **kwargs) -> CheckerResult:
|
|
|
|
executor = get_executor(files, lang, compiler_time_limit, problem_id)
|
|
|
|
|
|
|
|
with mktemp(judge_input) as input_file, mktemp(process_output) as output_file, mktemp(judge_output) as judge_file:
|
2020-07-29 21:20:09 +00:00
|
|
|
try:
|
|
|
|
process = executor.launch(input_file.name, output_file.name, judge_file.name, stdout=subprocess.PIPE,
|
2020-03-18 02:41:09 +00:00
|
|
|
stderr=subprocess.PIPE, memory=memory_limit, time=time_limit)
|
2020-07-29 21:20:09 +00:00
|
|
|
proc_output, error = map(utf8text, process.communicate())
|
|
|
|
except Exception as err:
|
|
|
|
raise InternalError('Error while running checker: %r', err)
|
2020-03-18 02:41:09 +00:00
|
|
|
|
2020-07-29 21:20:09 +00:00
|
|
|
return Module.parse_return_code(process, executor, point_value, time_limit,
|
|
|
|
memory_limit,
|
|
|
|
feedback=utf8text(proc_output)
|
|
|
|
if feedback else None, name='checker',
|
|
|
|
stderr=error)
|