add cpp checker
This commit is contained in:
parent
f74f8b6e05
commit
e820697e60
6 changed files with 2859 additions and 8 deletions
File diff suppressed because it is too large
Load diff
|
@ -29,8 +29,8 @@ CHECKERS = (
|
||||||
('sorted', _('Unordered')),
|
('sorted', _('Unordered')),
|
||||||
('identical', _('Byte identical')),
|
('identical', _('Byte identical')),
|
||||||
('linecount', _('Line-by-line')),
|
('linecount', _('Line-by-line')),
|
||||||
('custom', _('Custom checker')),
|
('custom', _('Custom checker (PY)')),
|
||||||
('customval', _('Custom Validator')),
|
('customval', _('Custom validator (CPP)')),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import shutil
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -9,6 +10,10 @@ from django.core.files.storage import FileSystemStorage
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
|
|
||||||
|
VALIDATOR_TEMPLATE_PATH = 'validator_template/template.py'
|
||||||
|
|
||||||
|
|
||||||
if os.altsep:
|
if os.altsep:
|
||||||
def split_path_first(path, repath=re.compile('[%s]' % re.escape(os.sep + os.altsep))):
|
def split_path_first(path, repath=re.compile('[%s]' % re.escape(os.sep + os.altsep))):
|
||||||
return repath.split(path, 1)
|
return repath.split(path, 1)
|
||||||
|
@ -63,17 +68,38 @@ class ProblemDataCompiler(object):
|
||||||
raise ProblemDataError(_('Empty batches not allowed.'))
|
raise ProblemDataError(_('Empty batches not allowed.'))
|
||||||
cases.append(batch)
|
cases.append(batch)
|
||||||
|
|
||||||
|
def make_checker_for_validator(case):
|
||||||
|
checker_name = "cppvalidator.py"
|
||||||
|
validator_path = split_path_first(case.custom_validator.name)
|
||||||
|
|
||||||
|
if len(validator_path) != 2:
|
||||||
|
raise ProblemDataError(_('How did you corrupt the custom checker path?'))
|
||||||
|
|
||||||
|
checker = os.path.join(settings.DMOJ_PROBLEM_DATA_ROOT,
|
||||||
|
validator_path[0],
|
||||||
|
checker_name)
|
||||||
|
|
||||||
|
validator_name = validator_path[1]
|
||||||
|
shutil.copy(VALIDATOR_TEMPLATE_PATH, checker)
|
||||||
|
|
||||||
|
# replace {{filecpp}} and {{problemid}} in checker file
|
||||||
|
filedata = open(checker, 'r').read()
|
||||||
|
filedata = filedata.replace('{{filecpp}}', "\'%s\'" % validator_name)
|
||||||
|
filedata = filedata.replace('{{problemid}}', "\'%s\'" % validator_path[0])
|
||||||
|
open(checker, 'w').write(filedata)
|
||||||
|
|
||||||
|
return checker_name
|
||||||
|
|
||||||
def make_checker(case):
|
def make_checker(case):
|
||||||
if (case.checker == 'custom'):
|
if (case.checker == 'custom'):
|
||||||
custom_checker_path = split_path_first(case.custom_checker.name)
|
custom_checker_path = split_path_first(case.custom_checker.name)
|
||||||
if len(custom_checker_path) != 2:
|
if len(custom_checker_path) != 2:
|
||||||
raise ProblemDataError(_('How did you corrupt the custom checker path?'))
|
raise ProblemDataError(_('How did you corrupt the custom checker path?'))
|
||||||
return(custom_checker_path[1])
|
return(custom_checker_path[1])
|
||||||
|
|
||||||
if (case.checker == 'customval'):
|
if (case.checker == 'customval'):
|
||||||
validator_path = split_path_first(case.custom_validator.name)
|
return make_checker_for_validator(case)
|
||||||
if len(validator_path) != 2:
|
|
||||||
raise ProblemDataError(_('How did you corrupt the custom checker path?'))
|
|
||||||
return(validator_path[1])
|
|
||||||
if case.checker_args:
|
if case.checker_args:
|
||||||
return {
|
return {
|
||||||
'name': case.checker,
|
'name': case.checker,
|
||||||
|
|
|
@ -218,8 +218,8 @@ header {
|
||||||
}
|
}
|
||||||
|
|
||||||
#nav-shadow {
|
#nav-shadow {
|
||||||
height: 1px;
|
height: 2px;
|
||||||
background: linear-gradient(rgba(0, 0, 0, 0.5), transparent);
|
background: linear-gradient($widget_black, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
#nav-container {
|
#nav-container {
|
||||||
|
|
|
@ -117,12 +117,18 @@
|
||||||
<td colspan="5">
|
<td colspan="5">
|
||||||
<div class="case-info">
|
<div class="case-info">
|
||||||
{% set curr_data = cases_data[case.case] %}
|
{% set curr_data = cases_data[case.case] %}
|
||||||
|
{% if curr_data != null %}
|
||||||
<strong>{{ _('Input:') }}</strong>
|
<strong>{{ _('Input:') }}</strong>
|
||||||
<pre class="case-output">{{ curr_data['input']|linebreaksbr }}</pre>
|
<pre class="case-output">{{ curr_data['input']|linebreaksbr }}</pre>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<strong>{{ _('Output:') }}</strong>
|
<strong>{{ _('Output:') }}</strong>
|
||||||
<pre class="case-output">{{ case.output|linebreaksbr }}</pre>
|
<pre class="case-output">{{ case.output|linebreaksbr }}</pre>
|
||||||
|
|
||||||
|
{% if curr_data != null %}
|
||||||
<strong>{{ _('Answer:') }}</strong>
|
<strong>{{ _('Answer:') }}</strong>
|
||||||
<pre class="case-output">{{ curr_data['answer']|linebreaksbr }}</pre>
|
<pre class="case-output">{{ curr_data['answer']|linebreaksbr }}</pre>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if case.extended_feedback or case.feedback %}
|
{% if case.extended_feedback or case.feedback %}
|
||||||
<strong>{{ _('Judge feedback:') }}</strong>
|
<strong>{{ _('Judge feedback:') }}</strong>
|
||||||
|
|
50
validator_template/template.py
Normal file
50
validator_template/template.py
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from dmoj.contrib import contrib_modules
|
||||||
|
from dmoj.error import InternalError
|
||||||
|
from dmoj.judgeenv import env, get_problem_root
|
||||||
|
from dmoj.result import CheckerResult
|
||||||
|
from dmoj.utils.helper_files import compile_with_auxiliary_files, mktemp
|
||||||
|
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]
|
||||||
|
executor = compile_with_auxiliary_files(filenames, lang, compiler_time_limit)
|
||||||
|
|
||||||
|
return executor
|
||||||
|
|
||||||
|
|
||||||
|
def check(process_output, judge_output, judge_input,
|
||||||
|
problem_id={{problemid}},
|
||||||
|
files={{filecpp}},
|
||||||
|
lang='CPP14',
|
||||||
|
time_limit=10,
|
||||||
|
memory_limit=1024**2,
|
||||||
|
compiler_time_limit=10,
|
||||||
|
feedback=True, type='default',
|
||||||
|
point_value=None, **kwargs) -> CheckerResult:
|
||||||
|
executor = get_executor(files, lang, compiler_time_limit, problem_id)
|
||||||
|
|
||||||
|
if type not in contrib_modules:
|
||||||
|
raise InternalError('%s is not a valid return code parser' % type)
|
||||||
|
|
||||||
|
with mktemp(judge_input) as input_file, mktemp(process_output) as output_file, mktemp(judge_output) as judge_file:
|
||||||
|
process = executor.launch(input_file.name, output_file.name, judge_file.name, stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE, memory=memory_limit, time=time_limit)
|
||||||
|
|
||||||
|
proc_output, error = map(utf8text, process.communicate())
|
||||||
|
|
||||||
|
return contrib_modules[type].ContribModule.parse_return_code(process, executor, point_value, time_limit,
|
||||||
|
memory_limit,
|
||||||
|
feedback=utf8text(proc_output)
|
||||||
|
if feedback else None, name='checker',
|
||||||
|
stderr=error)
|
Loading…
Reference in a new issue