スペシャルジャッジの実装例

Latest Author 👑 H20H20 /Date 2021-11-12 23:36:12 / Views 3001
5 (Favした一覧ページはユーザーページから)

仕様についてはこちらを参照

実装例

例えば、以下の問題のスペシャルジャッジを作る場合を考えます。

整数 $N$ が与えられる。次の条件を満たす 2 つの整数 $A$, $B$ を半角スペース区切りで出力せよ。
$N = A + B$
#include <bits/stdc++.h>

int main(int argc, char** argv) {
  
  // テストケースの入力ファイルの input stream
  std::ifstream input_ifs(argv[1]);
  // テストケースの出力ファイルの input stream
  std::ifstream output_ifs(argv[2]);
  // 提出されたコードのファイルの input stream
  std::ifstream code_ifs(argv[3]);
  // スコアファイル(スコア問題のみ利用)の output stream
  std::ofstream score_ofs(argv[4]);
  
  // 標準入力(std::cin)に提出コードでの標準出力が渡される
  
  // ------
  
  
  // 「提出コードでの標準出力」から2つの整数を読み込む
  // 半角スペース区切り・改行区切りのどちらでも可
  int a, b;
  std::cin >> a >> b;
  
  // int型なので、32bit整数で表現出来ない数値は読み込めない
  // 脆弱性を突かれないためにも、制約を決めて、問題文に記載するべき。
  // 例えば、-100以上100以下の整数しか受け付けない場合、以下のように記述すれば良い。
  // abortは、メッセージを標準エラーに出力して異常終了(コード1)する関数。
  if (-100 > a || a > 100) abort("invalid a");
  if (-100 > b || b > 100) abort("invalid b");
  
  // 「テストケースの入力ファイル」から1つの整数を読み込む
  int n;
  input_ifs >> n;
  
  // a + b == n でないならば
  if (a - n != -b) {
    // Wrong Answer として、ジャッジプログラムを終了する。
    // メッセージを記載しておくと、デバッグしやすい。
    std::cerr << "a=" << a << ", b=" << b << ", n=" << n << std::endl;
    abort("Wrong Answer: a + b = n");
  }
  // assertを使って以下のように記載しても良い。
  // ただしassertは、コンパイル時のマクロ定義によっては無効化されることがある。
  // assert(a - n == -b);
  
  // 正解なので、正常終了する。
  return 0;
}

また、スペシャルジャッジ問題の場合、入力制約のみならず、出力制約にも気を配りましょう。

文字列を受け取る場合 std::setw を使い、入力数を制限することも検討してください。
https://cpprefjp.github.io/reference/iomanip/setw.html
特にユーザーコードがバグにより異常に多い出力になってしまった場合でTLEにならないまま ジャッジ側に渡された場合J_TLE と言われる場合があります。
通常の問題の場合J_TLEと出るのは好ましくないです。
文字数も問題の判定の要素の場合はN+1文字で制限するなどで検討してください。
ランダムにJ_TLEが出る場合は、ジャッジサーバーの増強を考えますのでご連絡ください。
※空ファイルで十分ですのでテスト出力ファイルをおいてください。テスト出力ファイルが存在しない場合はジャッジされません。

その他の言語の実装例

Python3

きっと誰かが書いてくれます(書きました)

import sys

#テストケースの入力ファイル
input_file = open(sys.argv[1],mode='r',encoding='utf-8')

#テストケースの出力ファイル
output_file = open(sys.argv[2],mode='r',encoding='utf-8')

#提出されたコードのファイル
code_file = open(sys.argv[3],mode='r',encoding='utf-8')

#スコアファイル
score_file = open(sys.argv[4],mode='w',encoding='utf-8')

###########################################################

#標準出力はopen(0)で開いて、多く出力されていないかも見たほうが良い。
std_input = open(0).read().split()

if len(std_input)!=2:
  #標準エラー出力をしておくと便利である。
  sys.stderr.write("too many output!\n")
  #必ず例外を発生させる。
  raise Exception

#実は、std_inputの各要素には改行がついていることがあるので文字列として扱う場合は注意
a,b=map(int,std_input)

N=int(input_file.read().split()[0])

if a+b!=N:
  sys.stderr.write(f"a={a},b={b},N={N}\n")
  #Exceptionのあとにメッセージを入れることも可能
  raise Exception("a+b!=N")

#エラーがなくてもエラー出力しておくとデバックしやすい
sys.stderr.write(f"success,a={a},b={b},N={N}\n")


#ファイルは必ず閉じる(閉じなくてもエラーが起きたりはしない)
#with を使うと閉じなくてよいので便利
input_file.close()

output_file.close()

code_file.close()

score_file.close()

Ruby

あとで書きます


Go

こちら