From 64495be79934a9f746ee6801ae8158d74cfa6ee8 Mon Sep 17 00:00:00 2001 From: cuom1999 Date: Tue, 1 Aug 2023 12:26:15 +0700 Subject: [PATCH] Add IOI signature to UI --- judge/migrations/0156_auto_20230801_0107.py | 48 ++++ judge/migrations/0157_auto_20230801_1145.py | 22 ++ judge/models/problem_data.py | 33 +++ judge/utils/problem_data.py | 15 +- judge/views/about.py | 232 ++++++++++++++++++++ judge/views/problem_data.py | 4 + locale/vi/LC_MESSAGES/django.po | 147 ++++++++----- templates/about/custom-checker-sample.html | 212 +----------------- templates/problem/data.html | 28 ++- 9 files changed, 469 insertions(+), 272 deletions(-) create mode 100644 judge/migrations/0156_auto_20230801_0107.py create mode 100644 judge/migrations/0157_auto_20230801_1145.py diff --git a/judge/migrations/0156_auto_20230801_0107.py b/judge/migrations/0156_auto_20230801_0107.py new file mode 100644 index 0000000..a5f2b9a --- /dev/null +++ b/judge/migrations/0156_auto_20230801_0107.py @@ -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", + ), + ), + ] diff --git a/judge/migrations/0157_auto_20230801_1145.py b/judge/migrations/0157_auto_20230801_1145.py new file mode 100644 index 0000000..802c56c --- /dev/null +++ b/judge/migrations/0157_auto_20230801_1145.py @@ -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", + ), + ), + ] diff --git a/judge/models/problem_data.py b/judge/models/problem_data.py index 38a214b..d61b528 100644 --- a/judge/models/problem_data.py +++ b/judge/models/problem_data.py @@ -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 diff --git a/judge/utils/problem_data.py b/judge/utils/problem_data.py index 8be05ae..eb56229 100644 --- a/judge/utils/problem_data.py +++ b/judge/utils/problem_data.py @@ -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): diff --git a/judge/views/about.py b/judge/views/about.py index e503724..3f6d266 100644 --- a/judge/views/about.py +++ b/judge/views/about.py @@ -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 +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 +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 +#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, }, ) diff --git a/judge/views/problem_data.py b/judge/views/problem_data.py index 587d10a..121d570 100644 --- a/judge/views/problem_data.py +++ b/judge/views/problem_data.py @@ -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, } diff --git a/locale/vi/LC_MESSAGES/django.po b/locale/vi/LC_MESSAGES/django.po index 9fa8966..0ab0dd6 100644 --- a/locale/vi/LC_MESSAGES/django.po +++ b/locale/vi/LC_MESSAGES/django.po @@ -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 {0}" msgstr "So sánh các bài nộp cho {0}" -#: 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 {0}" msgstr "Tất cả bài nộp của {0}" -#: 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 "" "{0}'s submissions for {2} in {0} cho {2} trong {4}" -#: judge/views/submission.py:921 +#: judge/views/submission.py:926 #, python-brace-format msgid "" "{0}'s submissions for problem {2} in {3}" @@ -3303,7 +3327,7 @@ msgstr "" "Các bài nộp của {0} cho bài {2} trong {3}" "" -#: 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 to view it." msgid "" "This comment is hidden due to too much negative feedback. Click here to " -"view it." +" href=\"javascript:comment_show_content(%(id)s)\">here " +"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 đây để 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" diff --git a/templates/about/custom-checker-sample.html b/templates/about/custom-checker-sample.html index b6497df..26aae70 100644 --- a/templates/about/custom-checker-sample.html +++ b/templates/about/custom-checker-sample.html @@ -1,208 +1,12 @@ {% extends "common-content.html" %} -{% block description %} +{% block content_media %} -
-

1. Custom checker (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: -

- - {{ - """ - def check(process_output, judge_output, **kwargs): - # return True/False - """|highlight('py')}} - -

- 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. -

- {{ - """ - 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')}} -
-
-

2. Custom validator (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): -

-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.

- {{ - """ - #include - 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')}} -
-
-

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): -

-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.

- {{ - """ - #include - 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')}} -
-{% endblock %} \ No newline at end of file +{% endblock %} +{% block description %} + {{ content|markdown|str|safe}} +{% endblock %} diff --git a/templates/problem/data.html b/templates/problem/data.html index 696cab8..0bc8f4c 100644 --- a/templates/problem/data.html +++ b/templates/problem/data.html @@ -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 = $("",{ @@ -152,13 +157,24 @@ href: "{{url('custom_checker_sample')}}" }).appendTo($td); + $("",{ + 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'));