跳转至

Arbiter

Arbiter

Arbiter 為北京航空航天大學為 NOI Linux 開發的評測工具,現已用於各大 NOI 系列程序設計競賽的評測。據呂凱風在 2016 年冬令營上的講稿《下一代測評系統》,Arbiter 是由北京航空航天大學的團隊(GAIT)在尹寶林老師的帶領下開發完成的。

在 NOI Linux 更新到 2.0 版本後,Arbiter 也用 Qt 5.12.8 重新編譯,併發布為 Arbiter 2.0。因為之後的測評環境均使用 NOI Linux 2.0,因此以下介紹使用的 Arbiter 版本均為 NOI Linux 2.0 中自帶的 Arbiter 2.0。

此測評軟件僅能在 NOI Linux 下找到。二進制文件位置為 /usr/local/arbiter/local/arbiter_local

使用方法

配置程序

配置選手源程序文件夾和選手名單。選手文件夾如 NOIP 格式創建:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
players/
| -- day1
|    | -- <contestant_1's ID>
|    |     | -- <problem_1>
|    |     |   `-- <problem_1>.c/cpp/pas
|    |     | -- <problem_2>
|    |     |   `-- <problem_2>.c/cpp/pas
|    |     | ...
|    |     | -- <problem_x>
|    |        `-- <problem_x>.c/cpp/pas
|    | -- <contestant_2's ID>
|    |     | -- <problem_1>
|    |     ...
|    ...
| -- day2
|    | -- <contestant_1's ID>
|    |     | -- <problem_1>
|    |     |   `-- <problem_1>.c/cpp/pas
|    |     | -- <problem_2>
|    |     |   `-- <problem_2>.c/cpp/pas
|    |     | ...
|    |     | -- <problem_x>
|    |        `-- <problem_x>.c/cpp/pas
|    | -- <contestant_2's ID>
|    |     | -- <problem_1>
|    |     ...
|    ...
...

其中,day<x> 中的 <x> 是場次編號,<contestant_x's ID> 指的是選手編號,形如 <省份>-<編號>,例如 HL-001,JL-125 等等;<problem_x> 指的是題目名稱。在自測時可以使用字母、短線(即 -)和數字的組合作為選手編號。

選手名單格式如下:

1
2
3
<contestant_1's ID>,<contestant_1's name>
<contestant_2's ID>,<contestant_2's name>
...

其中,<contestant_x's name> 表示選手姓名。保存這個文件為純文本文件或 csv 文件,可以使用 UTF-8 編碼。

選手名單也可以在啓動 Arbiter 後手動添加。

接下來配置測試數據。每組數據的命名格式如下:

1
<problem_x><y>.in <problem_x><y>.ans

其中,<y> 是數據編號,編號從 1 開始。默認測試數據後綴名是 .ans,選手輸出的後綴名是 .out,不能混淆。

如果需要將之前生成的 out 格式修改為 ans 格式,在 NOI Linux 2.0 中可以使用 rename 命令批量修改,而在 Windows 中可以使用 ren 命令批量修改。我們將在後面介紹這些命令的用法。

不用將每題的測試數據放置在各題的文件夾裏,只需要放在一起即可。

然後開始測評文件夾的配置。

左下角「顯示應用程序」-「全部」-「Arbiter_local」,啓動 Arbiter。

Arbiter_Home

點擊 OPEN 可以打開已經建立的比賽,之後需選擇對應比賽文件夾下的 setup.cfg 文件;點擊 NEW 可以新建一個競賽,並設置名稱和比賽目錄。注意,需要在用户 主目錄下 新建一個文件夾,然後選擇其為比賽目錄,如果在桌面上建立比賽目錄的話無法測評。出現這種問題很有可能是因為比賽文件夾路徑中不能包含中文。

add_problem

在左邊試題概要裏「右鍵」-「添加考試」,再在考試標籤上「右鍵」-「添加試題」,新建出試題即可。

單擊考試左邊的向下箭頭即可全部顯示,單擊試題標籤對試題名稱進行修改,改為題目的英文名稱,同時修改題目時間與空間限制和比較方式。比較方式十分不推薦用「全文完全直接比較」,對於 Windows 下製作的數據十分不友好。可以根據題目自主選擇比較器,但是需要注意必須選擇一個比較器,否則測評結果將是 No Score.

problem_list

點擊「文件」-「保存」。該操作不可省略,否則程序將不會生成題目配置文件。注意每一次對題目配置的修改都要保存。

此時,打開考試文件夾,會發現有如下內容。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<name>/
| -- data
| -- evaldata
| -- filter
| -- final
| -- players
| -- result
| -- tmp
`-- day1.info
`-- player.info
`-- setup.cfg
`-- task1_1.info
`-- task1_2.info
`-- team.info

filter 文件夾放置了一些比較器;result 文件夾存放選手的測評結果;tmp 文件夾是測評時的緩存文件夾。其中 day<x>.info 為場次配置文件,<x> 為場次編號;task<x>_<y>.info 文件為題目配置文件,<x> 為場次編號,<y> 為題目序號。

把已經建好的選手程序文件夾放在 players/ 目錄下,注意最外層應按照考試日建立相應的 day<x> 文件夾。將所有測試數據(不放在文件夾裏)放在 evaldata 中。如果使用了自定義校驗器,則需要將自定義校驗器放在 filter 中。

正式測評

點開「試題評測」標籤,會出現如下頁面:

Pretest

如果選手名單已經建立了,直接選擇右邊的「導入名單」進行導入。如果人數較少,可以選擇右邊的「添加選手」進行導入。

導入後的頁面如圖。

Test

示例中的編號是 HL-001,程序會自動識別出「所屬」一欄。如果不是 NOIP 規範的編號是識別不出來的。

把測評第 0 場變為測評第 1 場(或者其他場次)。然後選擇右邊的全選(或選擇指定的選手),再選擇下面的評測選定選手,選擇要測評的題目(或全部試題),最後等待測評結束即可。

測試點詳細信息需要在 result 文件夾下查看,文件夾下會有選手的結果文件夾,結果文件的後綴名為 .result,用純文本方式查看即可。如果出現 No score file. 的錯誤,可以檢查測評時是否生成了 /tmp/_eval.score 文件。

自定義校驗器的編寫

反編譯其他校驗器,可以知道運行自定義校驗器的命令是 <problem>_e <in> <out> <ans>。後三個參數分別代表輸入,選手輸出和答案文件。最終的評分結果需寫入 /tmp/_eval.score 文件中,第一行是測評信息,第二行是分數,10 分為滿分。

編譯後自定義校驗器的名稱必須為 <problem>_e,其中 <problem> 為題目名稱。在配置題目時選擇自定義校驗器,然後選擇需要的自定義校驗器即可。

在試題管理中題目配置的地方將提交方式由源代碼改為答案文件,然後選擇自定義校驗器,可以測試提交答案題。

注意事項

已確認需要注意的內容:

  • 需要注意及時保存比賽,否則操作時可能閃退。為了確保不會閃退可以嘗試多次保存比賽,或進行一次修改時就保存比賽。
  • 沒有進行過評測時不要點擊上面的成績統計,否則將會導致 Arbiter 直接閃退。
  • 由於 Linux 運行時棧限制,如果要開無限棧,應在終端先輸入 ulimit -s unlimited 後執行 arbiter_local 打開測評器,否則可能出現 Exceeding memory limit 的問題。
  • 對於正式測評,在題目準備時需要讓所有題目空間限制一致。測評時將命令中的 unlimited 換為題目空間限制的千字節數(KiB),如:題目空間限制為 512 MiB,則命令為 ulimit -s $((512 * 1024))。導致這一問題的主要原因是直接啓動 Arbiter,其父進程為 GNOME,子進程繼承了父進程的棧空間限制。
  • 軟件的工作目錄不建議包含空格,若包含空格的話很可能會導致創建比賽時所有的默認校驗器都無法拷貝進 filter 目錄中(即 filter 目錄為空)。此時進行評測會出現全部爆 0 的情況,同時生成的 result 文件中可以看到 Compile Failed. 的提示。
  • 查看代碼時提示「未找到答案文件」指的是沒有找到選手的源代碼。

存疑的內容:

  • 很容易死機,如大量測評時移動鼠標會導致死機。
  • 不定時閃退(一部分原因是沒有及時保存比賽)。
  • 修改比較方式後有概率會出現修改失敗的情況,即比較方式修改後未被應用。
  • 配置時需要注意權限問題,但確保使用同一用户建立比賽,拷貝數據和進行測評的情況下不會出現權限問題。

漏洞

由於長期缺乏維護,系統存在一些漏洞,如可以使用 #pragma G++ optimize("O2")__attribute__((__optimize__("-O2"))) 等。可以使用 gcc-plugins-for-oi 在編譯期實現對這些命令的檢測。

評價

Arbiter 1.0.2 在開發完成後就一直沒有實質性更新,導致測評體驗極差,UI 脱離現代審美。在 NOI Linux 1.4.1 中,它和 NOI Linux 自帶的 GUIDE 一樣淪為選手與教練瘋狂吐槽的對象。在 NOI Linux 2.0 中,除了比較器移除了源代碼和軟件整體使用 Qt 5 重新編譯外,並沒有很大的變化,一些穩定性問題仍未得到解決。

附:ren 和 rename 命令的使用方法

在 Windows 操作系統中自帶了一個修改文件名稱的命令:ren

命令語法如下:

1
ren [<drive>:][<path>]<filename1> <filename2>

如果我們需要對當前工作目錄下的所有的文件進行修改,比如將所有的 out 文件修改為 ans 文件,可以執行如下命令:

1
ren *.out *.ans

如果是在 NOI Linux 2.0 環境中進行此類修改,似乎目前比較好用的是 rename 命令,但它不是 NOI Linux 2.0 環境內自帶的命令,所以你要先進行安裝:

1
sudo apt install rename

注:如果執行後提示 E: Unable to locate package package_name,你需要先執行這個命令:sudo apt-get update

安裝完成後,就可以正常使用 rename 命令了。rename 命令的使用類似於直接的文本替換,其在 NOI Linux 2.0 環境下的命令語法如下:

1
rename 's/<修改前的文本>/<修改後的文本>/' <filename>

其中 <filename> 可以使用通配符 *,也可以指定其中一類文件(比如 *.out)。

請注意在引號內末尾還有一個 /,如果少寫了一個 /rename 命令將會報錯:Substitution replacement not terminated at (user-supplied code)

此時如果我們需要對當前工作目錄下的所有的文件進行修改,比如將所有的 out 文件修改為 ans 文件,可以這麼寫:

1
rename 's/\.out/\.ans/' *

其中 \. 表示對 . 進行轉義。

(温馨提示:如果少寫了 \.,假如你的文件裏有個 outtest.out,這條命令執行過後文件將會被修改成 anstest.out)

類似的,如果你需要對所有名為 atmost<x>.ans 的文件進行統一修改(其中 <x> 代表測試點編號),將它們都修改為 test<x>.ans,不妨這麼寫:

1
rename 's/atmost/test/' *.ans