Add partial grading to checker
This commit is contained in:
parent
b6232fd4e6
commit
f838f20d00
4 changed files with 59 additions and 21 deletions
|
@ -34,7 +34,7 @@ msgstr "bình luận"
|
||||||
|
|
||||||
#: chat_box/views.py:41
|
#: chat_box/views.py:41
|
||||||
msgid "Chat Box"
|
msgid "Chat Box"
|
||||||
msgstr "Khu Tâm Sự"
|
msgstr "Khu Trò Chuyện"
|
||||||
|
|
||||||
#: dmoj/settings.py:349
|
#: dmoj/settings.py:349
|
||||||
msgid "German"
|
msgid "German"
|
||||||
|
|
|
@ -98,10 +98,18 @@ main.exe [input_file] [output_file] [ans_file]</pre>
|
||||||
</p>
|
</p>
|
||||||
<h2>Return: </h2>
|
<h2>Return: </h2>
|
||||||
<p>
|
<p>
|
||||||
Chương trình trả về giá trị 0 nếu AC, 1 nếu WA. Những thông tin được viết ra stdout (bằng cout) sẽ được in ra màn hình cho người nộp bài(feedback)
|
Chương trình trả về giá trị:
|
||||||
|
<ul>
|
||||||
|
<li> 0 nếu AC (100% điểm)</li>
|
||||||
|
<li> 1 nếu WA (0 điểm)</li>
|
||||||
|
<li> 2 nếu điểm thành phần (sẽ hiển thị là WA). Khi đó cần in ra stderr một số thực trong đoạn [0, 1) thể hiện cho tỷ lệ điểm. </li>
|
||||||
|
</ul>
|
||||||
|
Những thông tin được viết ra stdout (bằng cout) sẽ được in ra màn hình cho người nộp bài(feedback)
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Ví dụ: </h2>
|
<h2>Ví dụ: </h2>
|
||||||
|
<p>Chương trình sau dùng để chấm bài toán: Cho n là một số nguyên dương. In ra hai số tự nhiên a, b sao cho a + b = n. </p>
|
||||||
|
<p>Nếu in ra a + b = n và a, b >= 0 thì được 100% số điểm, nếu a + b = n nhưng một trong 2 số a, b âm thì được 50% số điểm. </p>
|
||||||
<pre class="code2">
|
<pre class="code2">
|
||||||
#include <bits/stdc++.h>
|
#include <bits/stdc++.h>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -119,8 +127,15 @@ int main(int argc, char** argv) {
|
||||||
|
|
||||||
if (a + b == c + d) {
|
if (a + b == c + d) {
|
||||||
cout << a << " + " << b << " = " << c << " + " << d << endl;
|
cout << a << " + " << b << " = " << c << " + " << d << endl;
|
||||||
|
|
||||||
|
if (a >= 0 && b >= 0) {
|
||||||
return 0; // AC
|
return 0; // AC
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
cerr << 0.5;
|
||||||
|
return 2; // PARTIAL
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
cout << "a + b = " << a + b << " != " << n << endl;
|
cout << "a + b = " << a + b << " != " << n << endl;
|
||||||
return 1; // WA
|
return 1; // WA
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
<td><span class="case-{{submission.result}}">{{submission.long_status}}</span></td>
|
<td><span class="case-{{submission.result}}">{{submission.long_status}}</span></td>
|
||||||
|
|
||||||
<td><span class="col-title">{{_('Point: ')}}</span>
|
<td><span class="col-title">{{_('Point: ')}}</span>
|
||||||
{{ submission.case_points|floatformat(0) }}/{{ submission.case_total|floatformat(0) }}
|
{{ submission.case_points|floatformat(1) }}/{{ submission.case_total|floatformat(0) }}
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
{% if not batch.id %}
|
{% if not batch.id %}
|
||||||
<td><span class="col-title">{{_('Point')}}: </span> {{ case.points|floatformat(0) }}/{{ case.total|floatformat(0) }}</td>
|
<td><span class="col-title">{{_('Point')}}: </span> {{ case.points|floatformat }}/{{ case.total|floatformat(0) }}</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import os
|
import os, re
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from dmoj.contrib import contrib_modules
|
|
||||||
from dmoj.error import InternalError
|
from dmoj.error import InternalError
|
||||||
from dmoj.judgeenv import env, get_problem_root
|
from dmoj.judgeenv import env, get_problem_root
|
||||||
from dmoj.result import CheckerResult
|
from dmoj.result import CheckerResult
|
||||||
from dmoj.utils.helper_files import compile_with_auxiliary_files, mktemp
|
from dmoj.utils.helper_files import compile_with_auxiliary_files, mktemp, parse_helper_file_error
|
||||||
from dmoj.utils.unicode import utf8text
|
from dmoj.utils.unicode import utf8text
|
||||||
|
|
||||||
executor = None
|
executor = None
|
||||||
|
@ -23,28 +22,52 @@ def get_executor(files, lang, compiler_time_limit, problem_id):
|
||||||
|
|
||||||
return executor
|
return executor
|
||||||
|
|
||||||
|
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))
|
||||||
|
if not 0 <= points < 1:
|
||||||
|
raise InternalError('Invalid partial points: %d' % points)
|
||||||
|
return CheckerResult(False, points * point_value, feedback=feedback)
|
||||||
|
elif proc.returncode == cls.WA:
|
||||||
|
return CheckerResult(False, 0, feedback=feedback)
|
||||||
|
else:
|
||||||
|
parse_helper_file_error(proc, executor, name, stderr, time_limit, memory_limit)
|
||||||
|
|
||||||
|
|
||||||
def check(process_output, judge_output, judge_input,
|
def check(process_output, judge_output, judge_input,
|
||||||
problem_id={{problemid}},
|
problem_id={{problemid}},
|
||||||
files={{filecpp}},
|
files={{filecpp}},
|
||||||
lang='CPP14',
|
lang='CPP14',
|
||||||
time_limit=10,
|
time_limit=10,
|
||||||
memory_limit=1024**2,
|
memory_limit=1024 * 512,
|
||||||
compiler_time_limit=30,
|
compiler_time_limit=30,
|
||||||
feedback=True, type='default',
|
feedback=True,
|
||||||
point_value=None, **kwargs) -> CheckerResult:
|
point_value=None, **kwargs) -> CheckerResult:
|
||||||
executor = get_executor(files, lang, compiler_time_limit, problem_id)
|
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:
|
with mktemp(judge_input) as input_file, mktemp(process_output) as output_file, mktemp(judge_output) as judge_file:
|
||||||
|
try:
|
||||||
process = executor.launch(input_file.name, output_file.name, judge_file.name, stdout=subprocess.PIPE,
|
process = executor.launch(input_file.name, output_file.name, judge_file.name, stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE, memory=memory_limit, time=time_limit)
|
stderr=subprocess.PIPE, memory=memory_limit, time=time_limit)
|
||||||
|
|
||||||
proc_output, error = map(utf8text, process.communicate())
|
proc_output, error = map(utf8text, process.communicate())
|
||||||
|
except Exception as err:
|
||||||
|
raise InternalError('Error while running checker: %r', err)
|
||||||
|
|
||||||
return contrib_modules[type].ContribModule.parse_return_code(process, executor, point_value, time_limit,
|
return Module.parse_return_code(process, executor, point_value, time_limit,
|
||||||
memory_limit,
|
memory_limit,
|
||||||
feedback=utf8text(proc_output)
|
feedback=utf8text(proc_output)
|
||||||
if feedback else None, name='checker',
|
if feedback else None, name='checker',
|
||||||
|
|
Loading…
Reference in a new issue