Custom checkers


Một số bài tập có thể có nhiều output đúng, vì vậy đôi lúc ta cần phải viết checker để kiểm tra xem output có đúng hay chưa.

1. Checker mặc định

VNOJ có hỗ trợ các checker mặc định của DMOJ, các bạn có thể xem ở đây

2. Custom Checker (Python)

Một checker được viết bằng Python cần cài đặt một hàm như sau:

def check(process_output, judge_output, **kwargs):
    # your code

Trong đó:

  • process_output: output của bài nộp
  • judge_output: đáp án

**kwargs có thể chứa các biến sau:

  • submission_source: source code của bài nộp
  • judge_input: input của đề bài
  • point_value: điểm của test đang chấm
  • case_position: thứ tự của test
  • batch: batch của test case (với các bài chấm theo subtask), đại đa số các bài ta không cần quan tâm tới biến này.
  • submission_language: ngôn ngữ của bài nộp
  • execution_time: thời gian chạy, tính bằng giây

Return

Hàm check có 2 cách return:

  1. Return bằng True hoặc False, nếu đáp án đúng thì return True, ngược lại return False
  2. Return bằng CheckerResult, return bằng cách này thì có thể trả về được feedback cho người nộp. Cách dùng như sau: CheckerResult(passed, points_awarded). Trong đó:
    • passed là có giá trị True/False tùy vào kết quả có đúng hay không.
    • points_awarded: là số điểm nhận được với test đó.
    • feedback: thông tin đưa tới người nộp.

Ví dụ

Dưới đây là checker mẫu cho bài toán POST - A cộng B.

from dmoj.result import CheckerResult

def check(process_output, judge_output, judge_input, point_value, **kwargs):
    # convert from bytes to texts
    process_output = process_output.decode("ascii")
    judge_output = judge_output.decode("ascii")
    judge_input = judge_input.decode("ascii")

    # read data as normal
    a, b = judge_input.split(' ')
    output_sum = int(process_output)
    if a + b != output_sum:
        return CheckerResult(False, 0, f"{a} + {b} != {output_sum}")
    return CheckerResult(True, point_value, "Ok answer is correct")

3. Custom Checker (C++)

Để viết được C++ checker, ta cần viết một chương trình C++ nhận vào 3 tham số dòng lệnh theo thứ tự là input_file, output_file, answer_file, tươn ứng với đường dẫn tới các file input, output, đáp án.

Return

Chương trình (hàm main) trả về các giá trị sau:

  • 0 nếu AC (100% số điểm)
  • 1 nếu WA (0 điểm)
  • 7 nếu nhận được đ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 tỷ lệ điểm. Lưu ý rằng điểm phải được in ra ở dòng đầu tiên của stderr
  • Nếu chương trình trả về giá trị khác (exit code khác 0, hay run time error) thì bài nộp sẽ được 0 điểm (xem như WA).

Những thông tin được viết ra stdout sẽ được in ra màn hình cho người nộp bài (feedback), nhưng thông tin này chỉ hiển thị được khoản 20 ký tự. Nếu muốn người dùng xem được nhiều feedback hơn, thì in feedback vào stderr (lưu ý in sau khi in điểm ở dòng đầu tiên).

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 \ge 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 <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) {
            cerr << "This line will be show to the contestants as a extended feedback";
            return 0; // AC
        }
        else {
            cerr << 0.5 << '\n'; // in ra điểm ở dòng đầu tiên
            cerr << "Thís line will be show to the contestants as a extended feedback";
            return 7; // PARTIAL
        }
    }     
    else {
        cout << "a + b = " << a + b << " != " << n << endl;
        return 1; // WA
    }
}

VNOJ cũng hộ trợ các checker được viết bằng testlib.h, tuy nhiên hiện tại chỉ có thể chấm các bài không phải interactive.

Đây là checker được viết bằng testlib.h cho bài toán trên:

#include "testlib.h"

using namespace std;

int main(int argc, char* argv[]) {
    registerTestlibCmd(argc, argv);

    int n = inf.readInt();
    int a = ouf.readInt();
    int b = ouf.readInt();
    ensuref(a + b == n, "%d + %d != %d", a, b, n);
    if (a < 0) {
        quitf(_points, "0.5 \n a = %d < 0", a);
    }
    if (b < 0) {
        quitf(_points, "0.5 \n b = %d < 0", a);
    }
    quitf(_ok, "%d + %d = %d", a, b, n);
}