Add IOI signature to UI
This commit is contained in:
parent
220a7e7237
commit
64495be799
9 changed files with 469 additions and 272 deletions
48
judge/migrations/0156_auto_20230801_0107.py
Normal file
48
judge/migrations/0156_auto_20230801_0107.py
Normal file
|
@ -0,0 +1,48 @@
|
|||
# Generated by Django 3.2.18 on 2023-07-31 18:07
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import judge.models.problem_data
|
||||
import judge.utils.problem_data
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("judge", "0155_output_only"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="problemdata",
|
||||
name="signature_handler",
|
||||
field=models.FileField(
|
||||
blank=True,
|
||||
null=True,
|
||||
storage=judge.utils.problem_data.ProblemDataStorage(),
|
||||
upload_to=judge.models.problem_data.problem_directory_file,
|
||||
validators=[
|
||||
django.core.validators.FileExtensionValidator(
|
||||
allowed_extensions=["cpp"]
|
||||
)
|
||||
],
|
||||
verbose_name="signature handler",
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="problemdata",
|
||||
name="signature_header",
|
||||
field=models.FileField(
|
||||
blank=True,
|
||||
null=True,
|
||||
storage=judge.utils.problem_data.ProblemDataStorage(),
|
||||
upload_to=judge.models.problem_data.problem_directory_file,
|
||||
validators=[
|
||||
django.core.validators.FileExtensionValidator(
|
||||
allowed_extensions=["h"]
|
||||
)
|
||||
],
|
||||
verbose_name="signature header",
|
||||
),
|
||||
),
|
||||
]
|
22
judge/migrations/0157_auto_20230801_1145.py
Normal file
22
judge/migrations/0157_auto_20230801_1145.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 3.2.18 on 2023-08-01 04:45
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("judge", "0156_auto_20230801_0107"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="problemdata",
|
||||
name="use_ioi_signature",
|
||||
field=models.BooleanField(
|
||||
help_text="Use IOI Signature",
|
||||
null=True,
|
||||
verbose_name="is IOI signature",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -123,6 +123,27 @@ class ProblemData(models.Model):
|
|||
help_text=_("Support output-only problem"),
|
||||
null=True,
|
||||
)
|
||||
use_ioi_signature = models.BooleanField(
|
||||
verbose_name=_("is IOI signature"),
|
||||
help_text=_("Use IOI Signature"),
|
||||
null=True,
|
||||
)
|
||||
signature_handler = models.FileField(
|
||||
verbose_name=_("signature handler"),
|
||||
storage=problem_data_storage,
|
||||
null=True,
|
||||
blank=True,
|
||||
upload_to=problem_directory_file,
|
||||
validators=[FileExtensionValidator(allowed_extensions=["cpp"])],
|
||||
)
|
||||
signature_header = models.FileField(
|
||||
verbose_name=_("signature header"),
|
||||
storage=problem_data_storage,
|
||||
null=True,
|
||||
blank=True,
|
||||
upload_to=problem_directory_file,
|
||||
validators=[FileExtensionValidator(allowed_extensions=["h"])],
|
||||
)
|
||||
|
||||
__original_zipfile = None
|
||||
|
||||
|
@ -169,6 +190,18 @@ class ProblemData(models.Model):
|
|||
self.custom_validator.name = problem_directory_file_helper(
|
||||
new, self.custom_validator.name
|
||||
)
|
||||
if self.interactive_judge:
|
||||
self.interactive_judge.name = problem_directory_file_helper(
|
||||
new, self.interactive_judge.name
|
||||
)
|
||||
if self.signature_header:
|
||||
self.signature_header.name = problem_directory_file_helper(
|
||||
new, self.signature_header.name
|
||||
)
|
||||
if self.signature_handler:
|
||||
self.signature_handler.name = problem_directory_file_helper(
|
||||
new, self.signature_handler.name
|
||||
)
|
||||
self.save()
|
||||
|
||||
_update_code.alters_data = True
|
||||
|
|
|
@ -233,9 +233,7 @@ class ProblemDataCompiler(object):
|
|||
if self.data.checker == "interact":
|
||||
interactor_path = split_path_first(self.data.interactive_judge.name)
|
||||
if len(interactor_path) != 2:
|
||||
raise ProblemDataError(
|
||||
_("How did you corrupt the interactor path?")
|
||||
)
|
||||
raise ProblemDataError(_("Invalid interactor judge"))
|
||||
init["interactive"] = {
|
||||
"files": interactor_path[1],
|
||||
"feedback": True,
|
||||
|
@ -256,7 +254,18 @@ class ProblemDataCompiler(object):
|
|||
init["file_io"]["output"] = self.data.fileio_output
|
||||
if self.data.output_only:
|
||||
init["output_only"] = True
|
||||
if self.data.use_ioi_signature:
|
||||
handler_path = split_path_first(self.data.signature_handler.name)
|
||||
if len(handler_path) != 2:
|
||||
raise ProblemDataError(_("Invalid signature handler"))
|
||||
header_path = split_path_first(self.data.signature_header.name)
|
||||
if len(header_path) != 2:
|
||||
raise ProblemDataError(_("Invalid signature header"))
|
||||
|
||||
init["signature_grader"] = {
|
||||
"entry": handler_path[1],
|
||||
"header": header_path[1],
|
||||
}
|
||||
return init
|
||||
|
||||
def compile(self):
|
||||
|
|
|
@ -13,10 +13,242 @@ def about(request):
|
|||
|
||||
|
||||
def custom_checker_sample(request):
|
||||
content = """
|
||||
1. Trình chấm tự viết (PY)
|
||||
2. Trình chấm tự viết (CPP)
|
||||
3. Interactive (CPP)
|
||||
4. Dùng hàm như IOI (CPP)
|
||||
|
||||
---
|
||||
|
||||
##1. Trình chấm tự viết (PY)
|
||||
Đây là checker mặc định của website, cho phép người dùng cập nhật được nhiều thông tin nhất (chi tiết xem ở bên dưới). Chúng ta cần hoàn thành hàm `check` dưới đây:
|
||||
```py
|
||||
def check(process_output, judge_output, **kwargs):
|
||||
# return True/False
|
||||
```
|
||||
|
||||
Trong đó, `**kwargs` có thể chứa các biến sau:
|
||||
|
||||
- `process_output`: output
|
||||
- `judge_output`: đáp án
|
||||
- `submission_source`: Code bài nộp
|
||||
- `judge_input`: input
|
||||
- `point_value`: điểm của test đang chấm
|
||||
- `case_position`: thứ tự của test
|
||||
- `submission_language`: ngôn ngữ của bài nộp
|
||||
- `execution_time`: thời gian chạy
|
||||
|
||||
**Return**:
|
||||
|
||||
- Cách 1: Trả về True/False
|
||||
- Cách 2: Trả về một object `CheckerResult` có thể được gọi như sau `CheckerResult(case_passed_bool, points_awarded, feedback='')`
|
||||
|
||||
**Ví dụ:**
|
||||
Dưới đây là ví dụ cho bài toán: Input gồm 1 số nguyên n. In ra 2 số nguyên a, b sao cho a + b = n.
|
||||
|
||||
```py
|
||||
from dmoj.result import CheckerResult
|
||||
|
||||
def wa(feedback):
|
||||
return CheckerResult(False, 0, feedback)
|
||||
|
||||
def check(process_output, judge_output, judge_input, **kwargs):
|
||||
# process the input
|
||||
input_arr = judge_input.split()
|
||||
assert(len(input_arr) == 1)
|
||||
n = int(input_arr[0])
|
||||
|
||||
# process the contestant's output
|
||||
output_arr = process_output.split()
|
||||
|
||||
if (len(output_arr) != 2):
|
||||
return wa('Wrong output format')
|
||||
|
||||
try:
|
||||
a, b = int(output_arr[0]), int(output_arr[1])
|
||||
except:
|
||||
return wa('Wrong output format')
|
||||
|
||||
if (n == a + b):
|
||||
return True
|
||||
return wa('a + b != n')
|
||||
```
|
||||
|
||||
## 2. Trình chấm tự viết (CPP)
|
||||
|
||||
Để sử dụng chức năng này, cần viết một chương trình C++ pass vào 3 arguments theo thứ tự `input_file`, `output_file`, `ans_file` tương ứng với các file input, output, đáp án.
|
||||
|
||||
Để test chương trình trên máy tính, có thể dùng lệnh như sau (Windows):
|
||||
|
||||
```bash
|
||||
main.exe [input_file] [output_file] [ans_file]
|
||||
```
|
||||
|
||||
hoặc thay bằng `./main` trên Linux/MacOS.
|
||||
|
||||
**Return:**
|
||||
Chương trình trả về giá trị:
|
||||
|
||||
- 0 nếu AC (100% điểm)
|
||||
- 1 nếu WA (0 điểm)
|
||||
- 2 nếu điểm thành phần. Khi đó cần in ra stderr một số thực trong đoạn [0, 1] thể hiện cho tỷ lệ điểm. Nếu điểm < 1 thì hiển thị WA, điểm = 1 thì hiển thị AC.
|
||||
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)
|
||||
|
||||
**Ví dụ:**
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
```cpp
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ifstream inp(argv[1]);
|
||||
ifstream out(argv[2]);
|
||||
ifstream ans(argv[3]);
|
||||
|
||||
int n, a, b, c, d;
|
||||
|
||||
inp >> n;
|
||||
out >> a >> b;
|
||||
ans >> c >> d;
|
||||
|
||||
if (a + b == c + d) {
|
||||
cout << a << " + " << b << " = " << c << " + " << d << endl;
|
||||
|
||||
if (a >= 0 && b >= 0) {
|
||||
return 0; // AC
|
||||
}
|
||||
else {
|
||||
cerr << 0.5;
|
||||
return 2; // PARTIAL
|
||||
}
|
||||
}
|
||||
else {
|
||||
cout << "a + b = " << a + b << " != " << n << endl;
|
||||
return 1; // WA
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Interactive (CPP)
|
||||
Để sử dụng chức năng này, cần viết một chương trình C++ pass vào 2 arguments `input_file` `answer_file` tương ứng file input và đáp án (nếu cần thiết).
|
||||
|
||||
Để test chương trình trên máy tính với tư cách thí sinh, có thể dùng lệnh như sau (Windows):
|
||||
|
||||
```bash
|
||||
main.exe [input_file] [answer_file]
|
||||
```
|
||||
|
||||
hoặc thay bằng `./main` trên Linux/MacOS.
|
||||
|
||||
**Return:**
|
||||
Chương trình trả về giá trị:
|
||||
|
||||
- 0 nếu AC (100% điểm)
|
||||
- 1 nếu WA (0 điểm)
|
||||
- 2 nếu điểm thành phần. Khi đó cần in ra stderr một số thực trong đoạn [0, 1] thể hiện cho tỷ lệ điểm. Nếu điểm < 1 thì hiển thị WA, điểm = 1 thì hiển thị AC.
|
||||
Thông tin được in ra trong stderr (bằng cerr) sẽ là feedback hiển thị cho người dùng.
|
||||
|
||||
**Ví dụ:**
|
||||
Chương trình sau dùng để chấm bài toán guessgame: Người chơi phải tìm 1 số bí mật n (n chứa trong file input). Mỗi lần họ được hỏi một số x, và chương trình sẽ trả về "SMALLER", "BIGGER" hoặc "HOLA" dựa trên giá trị của n và x. Cần tìm ra n sau không quá 31 câu hỏi.
|
||||
|
||||
```cpp
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
|
||||
void quit(string reason) {
|
||||
cerr << reason << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void read(long long& guess) {
|
||||
if (!(cin >> guess)) exit(1); // Nếu không có dòng này, chương trình sẽ chờ vô hạn
|
||||
if (guess < 1 || guess > 2e9) exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
ifstream inp(argv[1]);
|
||||
int N, guesses = 0;
|
||||
long long guess;
|
||||
inp >> N;
|
||||
|
||||
while (guess != N && guesses <= 31) {
|
||||
read(guess);
|
||||
if (guess == N) {
|
||||
cout << "HOLA" << endl;
|
||||
} else if (guess > N) {
|
||||
cout << "SMALLER" << endl;
|
||||
} else {
|
||||
cout << "BIGGER" << endl;
|
||||
}
|
||||
guesses++;
|
||||
}
|
||||
|
||||
cerr << "Number of used guesses: " << guesses << endl;
|
||||
|
||||
if (guesses <= 31)
|
||||
return 0; // AC
|
||||
else {
|
||||
cerr << "Used too many guesses" << endl;
|
||||
return 1; // WA
|
||||
}
|
||||
}
|
||||
```
|
||||
## 4. IOI Signature (CPP)
|
||||
Đây là chức năng để sử dụng hàm như trong IOI. Thí sinh được cho một định nghĩa hàm và cần cài đặt hàm đó trả về giá trị đúng.
|
||||
Để sử dụng chức năng này, cần viết 2 chương trình:
|
||||
- Header: Đây là file định nghĩa hàm (đuôi phải là `.h`)
|
||||
- Handler: Đây là chương trình xử lý input và xuất ra output dựa trên hàm (đuôi phải là `.cpp`)
|
||||
|
||||
**Ví dụ:**
|
||||
Cho bài toán: nhập vào số n. Viết hàm `solve(int n)` trả về `n * 2`. Giả sử input là multitest có dạng:
|
||||
- Dòng đầu chứa `t` là số test
|
||||
- Mỗi dòng chứa một số nguyên `n`
|
||||
|
||||
**Header (header.h):**
|
||||
```cpp
|
||||
#ifndef _HEADER_INCLUDED
|
||||
#define _HEADER_INCLUDED
|
||||
long long solve(long long n);
|
||||
#endif
|
||||
```
|
||||
|
||||
**Handler (handler.cpp):**
|
||||
```cpp
|
||||
#include <bits/stdc++.h>
|
||||
#include "header.h"
|
||||
using namespace std;
|
||||
|
||||
|
||||
int main() {
|
||||
int t;
|
||||
cin >> t;
|
||||
for (int z = 1; z <= t; z++) {
|
||||
long long n;
|
||||
cin >> n;
|
||||
cout << solve(n) << "\\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**Bài nộp thí sinh:**
|
||||
```cpp
|
||||
int solve(int n) {
|
||||
return n * 2;
|
||||
}
|
||||
```
|
||||
|
||||
"""
|
||||
return render(
|
||||
request,
|
||||
"about/custom-checker-sample.html",
|
||||
{
|
||||
"title": _("Custom Checker Sample"),
|
||||
"content": content,
|
||||
},
|
||||
)
|
||||
|
|
|
@ -93,6 +93,9 @@ class ProblemDataForm(ModelForm):
|
|||
"fileio_input",
|
||||
"fileio_output",
|
||||
"output_only",
|
||||
"use_ioi_signature",
|
||||
"signature_handler",
|
||||
"signature_header",
|
||||
]
|
||||
widgets = {
|
||||
"zipfile": FineUploadFileInput,
|
||||
|
@ -103,6 +106,7 @@ class ProblemDataForm(ModelForm):
|
|||
"fileio_input": TextInput,
|
||||
"fileio_output": TextInput,
|
||||
"output_only": CheckboxInput,
|
||||
"use_ioi_signature": CheckboxInput,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: lqdoj2\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-07-26 22:55+0700\n"
|
||||
"POT-Creation-Date: 2023-08-01 12:22+0700\n"
|
||||
"PO-Revision-Date: 2021-07-20 03:44\n"
|
||||
"Last-Translator: Icyene\n"
|
||||
"Language-Team: Vietnamese\n"
|
||||
|
@ -210,7 +210,7 @@ msgid "Taxonomy"
|
|||
msgstr ""
|
||||
|
||||
#: judge/admin/problem.py:215 judge/admin/problem.py:438
|
||||
#: templates/contest/contest.html:101 templates/problem/data.html:517
|
||||
#: templates/contest/contest.html:101 templates/problem/data.html:533
|
||||
#: templates/problem/list.html:22 templates/problem/list.html:48
|
||||
#: templates/user/base-users-table.html:10 templates/user/user-about.html:36
|
||||
#: templates/user/user-about.html:52 templates/user/user-problems.html:58
|
||||
|
@ -1783,11 +1783,11 @@ msgstr "file zip chứa test"
|
|||
msgid "generator file"
|
||||
msgstr "file tạo test"
|
||||
|
||||
#: judge/models/problem_data.py:69 judge/models/problem_data.py:205
|
||||
#: judge/models/problem_data.py:69 judge/models/problem_data.py:238
|
||||
msgid "output prefix length"
|
||||
msgstr "độ dài hiển thị output"
|
||||
|
||||
#: judge/models/problem_data.py:72 judge/models/problem_data.py:208
|
||||
#: judge/models/problem_data.py:72 judge/models/problem_data.py:241
|
||||
msgid "output limit length"
|
||||
msgstr "giới hạn hiển thị output"
|
||||
|
||||
|
@ -1795,15 +1795,15 @@ msgstr "giới hạn hiển thị output"
|
|||
msgid "init.yml generation feedback"
|
||||
msgstr "phản hồi của quá trình tạo file init.yml"
|
||||
|
||||
#: judge/models/problem_data.py:78 judge/models/problem_data.py:211
|
||||
#: judge/models/problem_data.py:78 judge/models/problem_data.py:244
|
||||
msgid "checker"
|
||||
msgstr "trình chấm"
|
||||
|
||||
#: judge/models/problem_data.py:81 judge/models/problem_data.py:214
|
||||
#: judge/models/problem_data.py:81 judge/models/problem_data.py:247
|
||||
msgid "checker arguments"
|
||||
msgstr "các biến trong trình chấm"
|
||||
|
||||
#: judge/models/problem_data.py:83 judge/models/problem_data.py:216
|
||||
#: judge/models/problem_data.py:83 judge/models/problem_data.py:249
|
||||
msgid "checker arguments as a JSON object"
|
||||
msgstr "các biến trong trình chấm theo dạng JSON"
|
||||
|
||||
|
@ -1819,7 +1819,7 @@ msgstr "file trình chấm"
|
|||
msgid "interactive judge"
|
||||
msgstr ""
|
||||
|
||||
#: judge/models/problem_data.py:110 judge/models/problem_data.py:196
|
||||
#: judge/models/problem_data.py:110 judge/models/problem_data.py:229
|
||||
msgid "input file name"
|
||||
msgstr "tên file input"
|
||||
|
||||
|
@ -1827,7 +1827,7 @@ msgstr "tên file input"
|
|||
msgid "Leave empty for stdin"
|
||||
msgstr "Để trống nếu nhập từ bàn phím"
|
||||
|
||||
#: judge/models/problem_data.py:116 judge/models/problem_data.py:199
|
||||
#: judge/models/problem_data.py:116 judge/models/problem_data.py:232
|
||||
msgid "output file name"
|
||||
msgstr "tên file output"
|
||||
|
||||
|
@ -1843,39 +1843,55 @@ msgstr "Output-only?"
|
|||
msgid "Support output-only problem"
|
||||
msgstr "Dùng cho các bài output-only (nộp bằng file zip)"
|
||||
|
||||
#: judge/models/problem_data.py:180
|
||||
#: judge/models/problem_data.py:127
|
||||
msgid "is IOI signature"
|
||||
msgstr "Nộp bài bằng hàm?"
|
||||
|
||||
#: judge/models/problem_data.py:128
|
||||
msgid "Use IOI Signature"
|
||||
msgstr "Nộp bài bằng hàm như IOI"
|
||||
|
||||
#: judge/models/problem_data.py:132
|
||||
msgid "signature handler"
|
||||
msgstr "File xử lý hàm"
|
||||
|
||||
#: judge/models/problem_data.py:140
|
||||
msgid "signature header"
|
||||
msgstr "File định nghĩa hàm"
|
||||
|
||||
#: judge/models/problem_data.py:213
|
||||
msgid "problem data set"
|
||||
msgstr "tập hợp dữ liệu bài"
|
||||
|
||||
#: judge/models/problem_data.py:184
|
||||
#: judge/models/problem_data.py:217
|
||||
msgid "case position"
|
||||
msgstr "vị trí test"
|
||||
|
||||
#: judge/models/problem_data.py:187
|
||||
#: judge/models/problem_data.py:220
|
||||
msgid "case type"
|
||||
msgstr "loại test"
|
||||
|
||||
#: judge/models/problem_data.py:189
|
||||
#: judge/models/problem_data.py:222
|
||||
msgid "Normal case"
|
||||
msgstr "Test bình thường"
|
||||
|
||||
#: judge/models/problem_data.py:190
|
||||
#: judge/models/problem_data.py:223
|
||||
msgid "Batch start"
|
||||
msgstr "Bắt đầu nhóm"
|
||||
|
||||
#: judge/models/problem_data.py:191
|
||||
#: judge/models/problem_data.py:224
|
||||
msgid "Batch end"
|
||||
msgstr "Kết thúc nhóm"
|
||||
|
||||
#: judge/models/problem_data.py:201
|
||||
#: judge/models/problem_data.py:234
|
||||
msgid "generator arguments"
|
||||
msgstr "biến trong file sinh test"
|
||||
|
||||
#: judge/models/problem_data.py:202
|
||||
#: judge/models/problem_data.py:235
|
||||
msgid "point value"
|
||||
msgstr "điểm"
|
||||
|
||||
#: judge/models/problem_data.py:203
|
||||
#: judge/models/problem_data.py:236
|
||||
msgid "case is pretest?"
|
||||
msgstr "test là pretest?"
|
||||
|
||||
|
@ -2565,10 +2581,18 @@ msgid "How did you corrupt the generator path?"
|
|||
msgstr ""
|
||||
|
||||
#: judge/utils/problem_data.py:237
|
||||
msgid "Invalid interactor judge"
|
||||
msgstr ""
|
||||
|
||||
#: judge/utils/problem_data.py:249
|
||||
#, fuzzy
|
||||
#| msgid "How did you corrupt the custom checker path?"
|
||||
msgid "How did you corrupt the interactor path?"
|
||||
msgstr "How did you corrupt the custom checker path?"
|
||||
#| msgid "Invalid Return"
|
||||
msgid "Invalid signature handler"
|
||||
msgstr "Invalid Return"
|
||||
|
||||
#: judge/utils/problem_data.py:254
|
||||
msgid "Invalid signature header"
|
||||
msgstr ""
|
||||
|
||||
#: judge/utils/problems.py:115
|
||||
msgid "Wrong"
|
||||
|
@ -2629,7 +2653,7 @@ msgstr "%h:%m"
|
|||
msgid "About"
|
||||
msgstr "Giới thiệu"
|
||||
|
||||
#: judge/views/about.py:20
|
||||
#: judge/views/about.py:251
|
||||
msgid "Custom Checker Sample"
|
||||
msgstr "Hướng dẫn viết trình chấm"
|
||||
|
||||
|
@ -3104,27 +3128,27 @@ msgstr ""
|
|||
msgid "Your zip file is invalid!"
|
||||
msgstr "File Zip không hợp lệ!"
|
||||
|
||||
#: judge/views/problem_data.py:165
|
||||
#: judge/views/problem_data.py:169
|
||||
#, python-brace-format
|
||||
msgid "Comparing submissions for {0}"
|
||||
msgstr "So sánh các bài nộp cho {0}"
|
||||
|
||||
#: judge/views/problem_data.py:169
|
||||
#: judge/views/problem_data.py:173
|
||||
#, python-brace-format
|
||||
msgid "Comparing submissions for <a href=\"{1}\">{0}</a>"
|
||||
msgstr "So sánh các bài nộp cho <a href=\"{1}\">{0}</a>"
|
||||
|
||||
#: judge/views/problem_data.py:206
|
||||
#: judge/views/problem_data.py:210
|
||||
#, python-brace-format
|
||||
msgid "Editing data for {0}"
|
||||
msgstr "Chỉnh sửa dữ liệu cho {0}"
|
||||
|
||||
#: judge/views/problem_data.py:210
|
||||
#: judge/views/problem_data.py:214
|
||||
#, python-format
|
||||
msgid "Editing data for %s"
|
||||
msgstr "Chỉnh sửa dữ liệu cho %s"
|
||||
|
||||
#: judge/views/problem_data.py:340 judge/views/problem_data.py:342
|
||||
#: judge/views/problem_data.py:344 judge/views/problem_data.py:346
|
||||
#, python-format
|
||||
msgid "Generated init.yml for %s"
|
||||
msgstr "File init.yml cho %s"
|
||||
|
@ -3242,50 +3266,50 @@ msgstr "Bài nộp của %(user)s cho bài %(problem)s"
|
|||
msgid "All submissions"
|
||||
msgstr "Tất cả bài nộp"
|
||||
|
||||
#: judge/views/submission.py:590 judge/views/submission.py:595
|
||||
#: judge/views/submission.py:595 judge/views/submission.py:600
|
||||
msgid "All my submissions"
|
||||
msgstr "Tất cả bài nộp của tôi"
|
||||
|
||||
#: judge/views/submission.py:591
|
||||
#: judge/views/submission.py:596
|
||||
#, python-format
|
||||
msgid "All submissions by %s"
|
||||
msgstr "Tất cả bài nộp của %s"
|
||||
|
||||
#: judge/views/submission.py:597
|
||||
#: judge/views/submission.py:602
|
||||
#, python-brace-format
|
||||
msgid "All submissions by <a href=\"{1}\">{0}</a>"
|
||||
msgstr "Tất cả bài nộp của <a href=\"{1}\">{0}</a>"
|
||||
|
||||
#: judge/views/submission.py:618
|
||||
#: judge/views/submission.py:623
|
||||
#, fuzzy
|
||||
#| msgid "All submissions"
|
||||
msgid "All friend submissions"
|
||||
msgstr "Tất cả bài nộp"
|
||||
|
||||
#: judge/views/submission.py:647
|
||||
#: judge/views/submission.py:652
|
||||
#, python-format
|
||||
msgid "All submissions for %s"
|
||||
msgstr "Tất cả bài nộp cho %s"
|
||||
|
||||
#: judge/views/submission.py:675
|
||||
#: judge/views/submission.py:680
|
||||
msgid "Must pass a problem"
|
||||
msgstr "Phải làm được một bài"
|
||||
|
||||
#: judge/views/submission.py:733
|
||||
#: judge/views/submission.py:738
|
||||
#, python-format
|
||||
msgid "My submissions for %(problem)s"
|
||||
msgstr "Bài nộp của tôi cho %(problem)s"
|
||||
|
||||
#: judge/views/submission.py:734
|
||||
#: judge/views/submission.py:739
|
||||
#, python-format
|
||||
msgid "%(user)s's submissions for %(problem)s"
|
||||
msgstr "Các bài nộp của %(user)s cho %(problem)s"
|
||||
|
||||
#: judge/views/submission.py:879
|
||||
#: judge/views/submission.py:884
|
||||
msgid "Must pass a contest"
|
||||
msgstr "Phải qua một kỳ thi"
|
||||
|
||||
#: judge/views/submission.py:909
|
||||
#: judge/views/submission.py:914
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"<a href=\"{1}\">{0}</a>'s submissions for <a href=\"{3}\">{2}</a> in <a href="
|
||||
|
@ -3294,7 +3318,7 @@ msgstr ""
|
|||
"Các bài nộp của <a href=\"{1}\">{0}</a> cho <a href=\"{3}\">{2}</a> trong <a "
|
||||
"href=\"{5}\">{4}</a>"
|
||||
|
||||
#: judge/views/submission.py:921
|
||||
#: judge/views/submission.py:926
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"<a href=\"{1}\">{0}</a>'s submissions for problem {2} in <a href=\"{4}\">{3}"
|
||||
|
@ -3303,7 +3327,7 @@ msgstr ""
|
|||
"Các bài nộp của <a href=\"{1}\">{0}</a> cho bài {2} trong <a href=\"{4}\">{3}"
|
||||
"</a>"
|
||||
|
||||
#: judge/views/submission.py:1058
|
||||
#: judge/views/submission.py:1063
|
||||
#, fuzzy
|
||||
#| msgid "You do not have the permission to rejudge submissions."
|
||||
msgid "You don't have permission to access."
|
||||
|
@ -3711,7 +3735,7 @@ msgstr "Đăng nhập để vote"
|
|||
msgid "edit %(edits)s"
|
||||
msgstr "chỉnh sửa %(edits)s"
|
||||
|
||||
#: templates/comments/content-list.html:46 templates/comments/media-js.html:96
|
||||
#: templates/comments/content-list.html:46 templates/comments/media-js.html:97
|
||||
msgid "edited"
|
||||
msgstr "đã chỉnh sửa"
|
||||
|
||||
|
@ -3735,8 +3759,8 @@ msgstr "Ẩn"
|
|||
#| "\"javascript:comment_show_content(%(id)s)\">here</a> to view it."
|
||||
msgid ""
|
||||
"This comment is hidden due to too much negative feedback. Click <a\n"
|
||||
" href=\"javascript:comment_show_content(%(id)s)\">here</a> to "
|
||||
"view it."
|
||||
" href=\"javascript:comment_show_content(%(id)s)\">here</a> "
|
||||
"to view it."
|
||||
msgstr ""
|
||||
"Bình luận bị ẩn vì nhiều phản hồi tiêu cực. Nhấp vào <a href=\"javascript:"
|
||||
"comment_show_content(%(id)s)\">đây</a> để mở."
|
||||
|
@ -3775,16 +3799,16 @@ msgstr "Không có bình luận nào."
|
|||
msgid "Comments are disabled on this page."
|
||||
msgstr "Bình luận bị tắt trong trang này."
|
||||
|
||||
#: templates/comments/media-js.html:39
|
||||
#: templates/comments/media-js.html:40
|
||||
msgid "Replying to comment"
|
||||
msgstr "Trả lời bình luận"
|
||||
|
||||
#: templates/comments/media-js.html:91
|
||||
#: templates/comments/media-js.html:92
|
||||
#, python-brace-format
|
||||
msgid "edit {edits}"
|
||||
msgstr "chỉnh sửa {edits}"
|
||||
|
||||
#: templates/comments/media-js.html:94
|
||||
#: templates/comments/media-js.html:95
|
||||
msgid "original"
|
||||
msgstr "original"
|
||||
|
||||
|
@ -4424,7 +4448,7 @@ msgid "There are no requests to approve."
|
|||
msgstr "Không có đơn đăng ký."
|
||||
|
||||
#: templates/organization/requests/pending.html:24
|
||||
#: templates/problem/data.html:520
|
||||
#: templates/problem/data.html:536
|
||||
msgid "Delete?"
|
||||
msgstr "Xóa?"
|
||||
|
||||
|
@ -4465,32 +4489,32 @@ msgstr "Đuổi"
|
|||
msgid "Enter a new code for the cloned problem:"
|
||||
msgstr "Nhập mã bài mới cho bài tập được nhân bản:"
|
||||
|
||||
#: templates/problem/data.html:149
|
||||
#: templates/problem/data.html:154 templates/problem/data.html:161
|
||||
msgid "Instruction"
|
||||
msgstr "Hướng dẫn"
|
||||
|
||||
#: templates/problem/data.html:469
|
||||
#: templates/problem/data.html:485
|
||||
msgid "View YAML"
|
||||
msgstr "Xem YAML"
|
||||
|
||||
#: templates/problem/data.html:486
|
||||
#: templates/problem/data.html:502
|
||||
msgid "Autofill testcases"
|
||||
msgstr "Tự động điền test"
|
||||
|
||||
#: templates/problem/data.html:490 templates/problem/problem.html:276
|
||||
#: templates/problem/data.html:506 templates/problem/problem.html:276
|
||||
msgid "Problem type"
|
||||
msgid_plural "Problem types"
|
||||
msgstr[0] "Dạng bài"
|
||||
|
||||
#: templates/problem/data.html:497
|
||||
#: templates/problem/data.html:513
|
||||
msgid "Fill testcases"
|
||||
msgstr "Điền test"
|
||||
|
||||
#: templates/problem/data.html:501
|
||||
#: templates/problem/data.html:517
|
||||
msgid "Batch start positions"
|
||||
msgstr "Vị trí bắt đầu nhóm"
|
||||
|
||||
#: templates/problem/data.html:505
|
||||
#: templates/problem/data.html:521
|
||||
msgid ""
|
||||
"Leave empty if not use batch. If you want to divide to three batches [1, 4], "
|
||||
"[5, 8], [9, 10], enter: 1, 5, 9"
|
||||
|
@ -4498,27 +4522,27 @@ msgstr ""
|
|||
"Để trống nếu không dùng nhóm. Nếu muốn chia test thành các nhóm [1, 4], [5, "
|
||||
"8], [9, 10], nhập: 1, 5, 9"
|
||||
|
||||
#: templates/problem/data.html:509 templates/problem/data.html:560
|
||||
#: templates/problem/data.html:525 templates/problem/data.html:576
|
||||
msgid "Apply!"
|
||||
msgstr "Lưu!"
|
||||
|
||||
#: templates/problem/data.html:514
|
||||
#: templates/problem/data.html:530
|
||||
msgid "Type"
|
||||
msgstr "Kiểu"
|
||||
|
||||
#: templates/problem/data.html:515
|
||||
#: templates/problem/data.html:531
|
||||
msgid "Input file"
|
||||
msgstr "File Input"
|
||||
|
||||
#: templates/problem/data.html:516
|
||||
#: templates/problem/data.html:532
|
||||
msgid "Output file"
|
||||
msgstr "File Output"
|
||||
|
||||
#: templates/problem/data.html:518
|
||||
#: templates/problem/data.html:534
|
||||
msgid "Pretest?"
|
||||
msgstr "Pretest?"
|
||||
|
||||
#: templates/problem/data.html:561
|
||||
#: templates/problem/data.html:577
|
||||
msgid "Add new case"
|
||||
msgstr "Thêm test mới"
|
||||
|
||||
|
@ -5733,6 +5757,11 @@ msgstr "Thông tin"
|
|||
msgid "Check all"
|
||||
msgstr "Chọn tất cả"
|
||||
|
||||
#, fuzzy
|
||||
#~| msgid "How did you corrupt the custom checker path?"
|
||||
#~ msgid "How did you corrupt the interactor path?"
|
||||
#~ msgstr "How did you corrupt the custom checker path?"
|
||||
|
||||
#~ msgid "replies"
|
||||
#~ msgstr "phản hồi"
|
||||
|
||||
|
|
|
@ -1,208 +1,12 @@
|
|||
{% extends "common-content.html" %}
|
||||
{% block description %}
|
||||
{% block content_media %}
|
||||
<style>
|
||||
article {
|
||||
padding: 2.5em 3.5em;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
li {
|
||||
padding: 0.2em;
|
||||
}
|
||||
#content-right {
|
||||
display: none;
|
||||
#content-left {
|
||||
margin-left: 10%;
|
||||
width: 80%;
|
||||
}
|
||||
</style>
|
||||
<article id="py">
|
||||
<h2>1. Custom checker (PY)</h2>
|
||||
<hr>
|
||||
<p>
|
||||
Đây là checker mặc định của website, cho phép người dùng cập nhật được nhiều thông tin nhất (chi tiết xem ở bên dưới). Chúng ta cần hoàn thành hàm check dưới đây:
|
||||
</p>
|
||||
|
||||
{{
|
||||
"""
|
||||
def check(process_output, judge_output, **kwargs):
|
||||
# return True/False
|
||||
"""|highlight('py')}}
|
||||
|
||||
<p>
|
||||
Trong đó, <code>**kwargs</code> có thể chứa các biến sau:
|
||||
</p>
|
||||
<ul>
|
||||
<li><code>process_output:</code> output</li>
|
||||
<li><code>judge_output:</code> đáp án</li>
|
||||
<li><code>submission_source</code>: Code bài nộp</li>
|
||||
<li><code>judge_input</code>: input</li>
|
||||
<li><code>point_value:</code> điểm của test đang chấm</li>
|
||||
<li><code>case_position:</code> thứ tự của test</li>
|
||||
<li><code>submission_language:</code> ngôn ngữ của bài nộp</li>
|
||||
<li><code>execution_time:</code> thời gian chạy</li>
|
||||
</ul>
|
||||
<h2>Return: </h2>
|
||||
<ul>
|
||||
<li>Cách 1: Trả về True/False</li>
|
||||
<li>Cách 2: Trả về một object <code>CheckerResult</code> có thể được gọi như sau <pre class="code2">CheckerResult(case_passed_bool, points_awarded, feedback='')</pre></li>
|
||||
</ul>
|
||||
|
||||
<h2>Ví dụ: </h2>
|
||||
<p>Dưới đây là ví dụ cho bài toán: Input gồm 1 số nguyên n. In ra 2 số nguyên a, b sao cho a + b = n.
|
||||
</p>
|
||||
{{
|
||||
"""
|
||||
from dmoj.result import CheckerResult
|
||||
|
||||
|
||||
def wa(feedback):
|
||||
return CheckerResult(False, 0, feedback)
|
||||
|
||||
|
||||
def check(process_output, judge_output, judge_input, **kwargs):
|
||||
# process the input
|
||||
input_arr = judge_input.split()
|
||||
assert(len(input_arr) == 1)
|
||||
n = int(input_arr[0])
|
||||
|
||||
# process the contestant's output
|
||||
output_arr = process_output.split()
|
||||
|
||||
if (len(output_arr) != 2):
|
||||
return wa('Wrong output format')
|
||||
|
||||
try:
|
||||
a, b = int(output_arr[0]), int(output_arr[1])
|
||||
except:
|
||||
return wa('Wrong output format')
|
||||
|
||||
if (n == a + b):
|
||||
return True
|
||||
return wa('a + b != n')
|
||||
"""| highlight('py')}}
|
||||
</article>
|
||||
<article id="cpp">
|
||||
<h2>2. Custom validator (CPP)</h2>
|
||||
<hr>
|
||||
<p>
|
||||
Để sử dụng chức năng này, cần viết một chương trình C++ pass vào 3 arguments theo thứ tự <code>input_file</code>, <code>output_file</code>, <code>ans_file</code> tương ứng với các file input, output, đáp án.
|
||||
</p>
|
||||
<p>
|
||||
Để test chương trình trên máy tính, có thể dùng lệnh như sau (Windows):
|
||||
<pre class="code2">
|
||||
main.exe [input_file] [output_file] [ans_file]</pre>
|
||||
hoặc thay bằng <code>./main</code> trên Linux/MacOS.
|
||||
</p>
|
||||
<h2>Return: </h2>
|
||||
<p>
|
||||
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. Khi đó cần in ra stderr một số thực trong đoạn [0, 1] thể hiện cho tỷ lệ điểm. Nếu điểm < 1 thì hiển thị WA, điểm = 1 thì hiển thị AC. </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>
|
||||
|
||||
<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>
|
||||
{{
|
||||
"""
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ifstream inp(argv[1]);
|
||||
ifstream out(argv[2]);
|
||||
ifstream ans(argv[3]);
|
||||
|
||||
int n, a, b, c, d;
|
||||
|
||||
inp >> n;
|
||||
out >> a >> b;
|
||||
ans >> c >> d;
|
||||
|
||||
if (a + b == c + d) {
|
||||
cout << a << \" + \" << b << \" = \" << c << \" + \" << d << endl;
|
||||
|
||||
if (a >= 0 && b >= 0) {
|
||||
return 0; // AC
|
||||
}
|
||||
else {
|
||||
cerr << 0.5;
|
||||
return 2; // PARTIAL
|
||||
}
|
||||
}
|
||||
else {
|
||||
cout << \"a + b = \" << a + b << \" != \" << n << endl;
|
||||
return 1; // WA
|
||||
}
|
||||
}
|
||||
""" | highlight('cpp')}}
|
||||
</article>
|
||||
<article id="interactive">
|
||||
<h2>3. Interactive (CPP)</h2>
|
||||
<hr>
|
||||
<p>
|
||||
Để sử dụng chức năng này, cần viết một chương trình C++ pass vào 2 arguments <code>input_file</code> <code>answer_file</code> tương ứng file input và đáp án (nếu cần thiết).
|
||||
</p>
|
||||
<p>
|
||||
Để test chương trình trên máy tính với tư cách thí sinh, có thể dùng lệnh như sau (Windows):
|
||||
<pre class="code2">
|
||||
main.exe [input_file] [answer_file]</pre>
|
||||
hoặc thay bằng <code>./main</code> trên Linux/MacOS.
|
||||
</p>
|
||||
<h2>Return: </h2>
|
||||
<p>
|
||||
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. Khi đó cần in ra stderr một số thực trong đoạn [0, 1] thể hiện cho tỷ lệ điểm. Nếu điểm < 1 thì hiển thị WA, điểm = 1 thì hiển thị AC. </li>
|
||||
</ul>
|
||||
Thông tin được in ra trong stderr (bằng cerr) sẽ là feedback hiển thị cho người dùng.
|
||||
</p>
|
||||
|
||||
<h2>Ví dụ: </h2>
|
||||
<p>Chương trình sau dùng để chấm bài toán guessgame: Người chơi phải tìm 1 số bí mật n (n chứa trong file input). Mỗi lần họ được hỏi một số x, và chương trình sẽ trả về "SMALLER", "BIGGER" hoặc "HOLA" dựa trên giá trị của n và x. Cần tìm ra n sau không quá 31 câu hỏi. </p>
|
||||
{{
|
||||
"""
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
|
||||
void quit(string reason) {
|
||||
cerr << reason << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void read(long long& guess) {
|
||||
if (!(cin >> guess)) exit(1); // Nếu không có dòng này, chương trình sẽ chờ vô hạn
|
||||
if (guess < 1 || guess > 2e9) exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
ifstream inp(argv[1]);
|
||||
int N, guesses = 0;
|
||||
long long guess;
|
||||
inp >> N;
|
||||
|
||||
while (guess != N && guesses <= 31) {
|
||||
read(guess);
|
||||
if (guess == N) {
|
||||
cout << \"HOLA\" << endl;
|
||||
} else if (guess > N) {
|
||||
cout << \"SMALLER\" << endl;
|
||||
} else {
|
||||
cout << \"BIGGER\" << endl;
|
||||
}
|
||||
guesses++;
|
||||
}
|
||||
cerr << \"Number of used guesses: \" << guesses << endl;
|
||||
if (guesses <= 31)
|
||||
return 0; // AC
|
||||
else {
|
||||
cerr << \"Used too many guesses\" << endl;
|
||||
return 1; // WA
|
||||
}
|
||||
}
|
||||
""" | highlight('cpp')}}
|
||||
</article>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
{% block description %}
|
||||
{{ content|markdown|str|safe}}
|
||||
{% endblock %}
|
||||
|
|
|
@ -136,13 +136,18 @@
|
|||
(function toggle_custom() {
|
||||
let $checker = $('#id_problem-data-checker')
|
||||
|
||||
let $custom_checker = $('#id_problem-data-custom_checker')
|
||||
let $validator = $('#id_problem-data-custom_validator')
|
||||
let $interactive = $('#id_problem-data-interactive_judge')
|
||||
let $custom_checker = $('#id_problem-data-custom_checker');
|
||||
let $validator = $('#id_problem-data-custom_validator');
|
||||
let $interactive = $('#id_problem-data-interactive_judge');
|
||||
let $sig_handler = $('#id_problem-data-signature_handler');
|
||||
let $sig_header = $('#id_problem-data-signature_header');
|
||||
let $ioi_signature = $("#id_problem-data-use_ioi_signature");
|
||||
|
||||
$tr_checker = $custom_checker.parent().parent();
|
||||
$tr_validator = $validator.parent().parent()
|
||||
$tr_interactive = $interactive.parent().parent()
|
||||
$tr_validator = $validator.parent().parent();
|
||||
$tr_interactive = $interactive.parent().parent();
|
||||
$tr_sig_handler = $sig_handler.parent().parent();
|
||||
$tr_sig_header = $sig_header.parent().parent();
|
||||
|
||||
$td = $checker.parent();
|
||||
var $sample = $("<a/>",{
|
||||
|
@ -152,13 +157,24 @@
|
|||
href: "{{url('custom_checker_sample')}}"
|
||||
}).appendTo($td);
|
||||
|
||||
$("<a/>",{
|
||||
text: " ({{_('Instruction')}})",
|
||||
target: "_blank",
|
||||
href: "{{url('custom_checker_sample')}}"
|
||||
}).appendTo($ioi_signature.parent());
|
||||
|
||||
$checker.change(function () {
|
||||
$tr_checker.toggle($checker.val() == 'custom').change();
|
||||
$tr_validator.toggle($checker.val() == 'customval' || $checker.val() == 'testlib').change();
|
||||
$tr_interactive.toggle($checker.val() == 'interact').change();
|
||||
|
||||
$sample.toggle(['custom', 'customval', 'interact'].includes($checker.val())).change();
|
||||
}).change();
|
||||
|
||||
$ioi_signature.change(function() {
|
||||
$tr_interactive.toggle($ioi_signature.is(':checked')).change();
|
||||
$tr_sig_header.toggle($ioi_signature.is(':checked')).change();
|
||||
$tr_sig_handler.toggle($ioi_signature.is(':checked')).change();
|
||||
}).change();
|
||||
})();
|
||||
|
||||
checker_precision($('#id_problem-data-checker'));
|
||||
|
|
Loading…
Reference in a new issue