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,
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue