「TPS」:修訂間差異

出自TFcisWiki
跳至導覽 跳至搜尋
行 180: 行 180:
{{Memo|'''小提示:'''驗測資程式僅檢查與解法無關的輸入資料限制,檢查是否 TLE、得部分分數屬於[[#標程]]的範圍。|}}
{{Memo|'''小提示:'''驗測資程式僅檢查與解法無關的輸入資料限制,檢查是否 TLE、得部分分數屬於[[#標程]]的範圍。|}}


=== 子任務配分 ===
=== 子任務 ===
子任務設定於 [https://github.com/TNFSH-Programming-Contest/cms-environment-testing-problem/blob/main/pB/subtasks.json subtasks.json],包含各子任務的配分、文字描述、[[#驗測資程式]]。

<syntaxhighlight lang="text" line>
{
"global_validators": [
"validator.cpp"
],
"subtasks": {
"samples": {
"index": 0,
"score": 0,
"text": "範例輸入輸出",
"validators": []
}
}
}
</syntaxhighlight>
;設定說明
* global_validators:在所有測資使用的[[#驗測資程式|驗測資程式]]。
* Line 5:子任務代號,參見[[#產測資指令]]。
* index:流水號,出現在題本內的順序,從 0 開始;samples 必為 0。
* score:子任務分數;samples 必為 0。
* text:子任務描述,使用在題目描述內。
* validators:僅在該子任務使用的[[#驗測資程式|驗測資程式]]。


=== 題目敘述 ===
=== 題目敘述 ===

於 2022年8月15日 (一) 22:10 的修訂

TPS(Task Preparation System)是一套可以方便產生題目測試資料以及題本的工具,關於 TPS 可以參考以下的 Github Repo:

使用方式

Icon tools.svg 以下有此標誌的說明需要 CMS 系統管理員操作,出題者可忽略此說明。

建立Github Repo

  1. 進入tps-starter
  2. 填寫Repo資訊
    • Repository name 填入競賽英文名,例如「2024NHSPC-TNFSH-Preliminary」。
    • Description 填入競賽中文名,例如「113學年度資訊學科能力競賽臺南一中校內初選」。
    • OOjs UI icon alert-destructive.svg 注意:可見度必須選擇 Private
    • 點擊 Create repository from template。

建立新題目

  1. 進入由 tps-starter 建立的 Github repo。
  2. 點擊 Actions。
  3. 在 Workflows 段落,點擊 New problem。
  4. 點擊 Run workflow,在 Folder name to create 輸入要建立的資料夾名稱。
  5. 點擊藍色 Run workflow 按鈕。
  6. 等待約 1 分鐘。

競賽名稱

競賽名稱使用於:

  1. CMS 參賽介面左上角。
  2. 題本封面第一行。
  3. 題本內文各頁的左上角。

需寫入於:

  1. cover.tex
  2. 各題目 problem.json 的 contest_name 欄位。
  3. Icon tools.svg CMS 管理系統的 Description 欄位。

題目名稱

題目名稱使用於:

  1. CMS 題目敘述頁面。
  2. 題目標題(第一頁第一行)。
  3. 該題目各頁右上角。

需寫入於 problem.json 的 title 欄位。

題目英文名稱

題目英文名稱應足以讓所有命題人員識別個別題目即可,通常取自於中文題目名稱,並盡量僅使用一個英文詞,首字大寫,若需要兩個英文詞以上,則使用PascalCase。使用於:

  1. CMS 參賽介面題目列表。
  2. CMS 題目敘述。
  3. CMS 系統內部用來識別題目的 Primary key
    • Icon tools.svg 由於同一 CMS 系統上的名稱無法重複,若與其他競賽題目衝突[1],建議加上競賽名稱的英文縮寫作為前綴(例如「2022P-」)。
  4. 可能作為 Github repo 內的題目資料夾名稱。

需寫入於 problem.json 的 name 欄位。

題目編號

題目編號為 A, B, C... 的流水號,在決定題目順序後才會確定,使用於:

  1. 題目標題(第一頁第一行)。
  2. 該題目各頁右上角。
  3. 該題目各頁頁碼處。

記憶體限制

需寫入於 problem.json 的 memory_limit 欄位,單位為MB。

時間限制

需寫入於 problem.json 的 time_limit 欄位,單位為秒。

標程

AC code(官方解法、標程等)需放置在 solution 資料夾內,檔名無限制。同時將該檔名寫入 solutions.json ,格式請參照範本,verdict 必須標記為 model_solution。

其他 AC code 亦按照前述方式操作,verdict 必須標記為 correct。

其他類型的錯誤解法亦按照前述方式操作,verdict 標記方式請參考官方說明tps script

產測資

TPS 產測資方式與 Codeforces polygon 相同。測資可以使用手產測資檔案,亦可由程式亂數產生,亦可混合兩者。

手產測資檔

最佳實踐:僅在範例測資和 edge case 使用手產測資檔,其他使用產測程式。

手產測資檔應放置在 gen/manual 資料夾內,檔名無限制,但建議副檔名為 .in。

產測資程式

重要:產測資程式必須
  1. 使用命令列參數讀入測資組及測資點,參見 cppreferencestackoverflow
  2. 使用標準輸出(stdout),不可直接寫入檔案。
  3. 執行一次僅輸出一筆測資。
  4. 使用 testlib.h 等設定亂數種子的方式,使得每次產生的測資都是相同的。

產測資程式應放置在 gen 資料夾內,檔名無限制。‎

假設以下程式碼編譯成檔名為 gen 的執行檔(在 Windows 上的 gen.exe),那麼可以在命令列使用:

  • gen pos 10 隨機產生一個 1 ~ 10 之間的數字
  • gen pos 20 隨機產生一個 1 ~ 20 之間的數字
  • gen neg 10 隨機產生一個 -10 ~ -1 之間的數字
  • gen neg 20 隨機產生一個 -20 ~ -1 之間的數字
#include <bits/stdc++.h>
#include "testlib.h"
using namespace std;
int main(int argc, char* argv[]) {
	registerGen(argc, argv, 1);
	string task = argv[1];
	int range = atoi(argv[2]);
	if (task == "pos") {
		cout << rnd.next(1, range) << endl;
	} else {
		cout << rnd.next(-range, -1) << endl;
	}
	return 0;
}
程式碼說明
  • Line 5:將整個命名列參數註冊為亂數種子,照抄即可。
  • Line 6:可以將 argv 儲存在 string 變數,之後可用來判斷。
  • Line 7:如果有需要轉成整數或其他型態,可以使用 atoi 等函數轉型。
  • Line 8:判斷測資點。
  • Line 9:隨機產生 1 ~ range 之間的數字。
  • Line 11:隨機產生 -range ~ -1 之間的數字。

產測資指令

產測資指令應放置在 gen/data。‎

每一個測資點以 @subtask 接測資點代號為開頭,這個測資點代號亦會使用在#子任務配分

接下來每個測資點可以有多筆測資,每筆測資可以使用手產測資檔,也可使用產測資程式。

  • 使用手產測資檔則為 manual 接續放在 gen/manual 資料夾內的測資檔名。
  • 使用產測資程式則為呼叫在命令列中的指令。
@subtask samples
manual example-1.in

@subtask positive
gen	pos 20 test1-1
gen	pos 20 test1-2

@subtask negative
gen	neg 30 test2-1
gen	neg 30 test2-2

如果呼叫產測程式,但在指令中輸入了兩行一模一樣的內容,那麼這兩個測資就會相同(在設定亂數種子的情況下),因此通常會在後面放上隨機文字作為亂數種子的一部分,亦可透過更換亂數種子來重新產生測資,隨機文字可使用 Random String Generator 產生。

小技巧:
  1. 透過命令列參數直接控制測資範圍,就不需要在產測資程式碼內判斷測資點。
  2. 發現不良的測資時,透過修改命令列參數的隨機文字來得到一筆新的隨機測資。
  3. 若需要 edge case,使用手產測資檔。

驗測資程式

如果你寫了一個程式解題的問題,並準備好了測試資料,那麼你將可能會遇到一個恐怖的經驗:測試資料是無效的!(即測試資料並未符合題目所規定的限制),例如超過了範圍上限、你的圖實際上沒有連通、或是你的圖不是一棵樹……你很可能會有這種經驗,就算是有經驗的出題者也可能有時會出錯(知名案例像是 ACM ICPC World final 2007)。

最佳實踐:撰寫驗測資程式來自動檢查測資範圍及其他條件是否有符合題目的規定,避免測資範圍錯誤。

驗測資程式應該放置在 validator 資料夾內,檔名無限制,並將檔名寫入 subtasks.json 的 global_validators 或 subtasks 的 validators。

以下程式碼範例配合#產測資程式的範例。

#include "testlib.h"
using namespace std;
const int MAXN = 1000;
int main() {
	registerValidation();
	inf.readInt(-MAXN, MAXN, "n");
	inf.readEoln();
	inf.readEof();
	return 0;
}
程式碼說明
  • Line 5:初始化 testlib,照抄即可。
  • Line 6:預期讀入一個範圍在 -1000 ~ 1000 之間的整數。
  • Line 7:預期讀入一個換行。
  • Line 8:預期已經讀到檔案結尾。

除了檢查範圍以外,readInt 等函數會回傳其數值,可以保存到變數上作進一步檢查,例如檢查陣列數值皆相異,檢查是否是圖、樹或其他資料結構。

更多的說明請參見 Codeforces

小提示:驗測資程式僅檢查與解法無關的輸入資料限制,檢查是否 TLE、得部分分數屬於#標程的範圍。

子任務

子任務設定於 subtasks.json,包含各子任務的配分、文字描述、#驗測資程式

{
    "global_validators": [
        "validator.cpp"
    ],
    "subtasks": {
        "samples": {
            "index": 0,
            "score": 0,
            "text": "範例輸入輸出",
            "validators": []
        }
    }
}
設定說明
  • global_validators:在所有測資使用的驗測資程式
  • Line 5:子任務代號,參見#產測資指令
  • index:流水號,出現在題本內的順序,從 0 開始;samples 必為 0。
  • score:子任務分數;samples 必為 0。
  • text:子任務描述,使用在題目描述內。
  • validators:僅在該子任務使用的驗測資程式

題目敘述

註解