---
# System prepended metadata

title: 'Domjudge: 如何出互動題'
tags: [Note]

---

---
tags: Note
---

# Domjudge: 如何出互動題

\* 請將下文的problem置換成題目名稱

## 一、互動題是什麼

互動題是一種較特殊的題目類型，裁判程式與答題程式以標準輸入/輸出互動，通常由答題程式根據互動提供的線索來推測出正確輸出。

## 二、需求檔案

1. **problem_run.zip**
    - **build**: 編譯**runjury_problem.c**的script
    - **run**: 裁判機執行**runjury**(**runjury_problem.c**編譯後的執行檔)的script
    - **runjury_problem.c**: 裁判用程式的程式碼
2. **problem_cmp.zip**
    - **build**: 編譯**check_problem.c**的script
    - **run**: 裁判機執行**check_problem**(**check_problem.c**編譯後的執行檔)的script
    - **check_problem.c**: 比較用程式的程式碼
3. 測資(以下為建議內容，依題目需求而定)
    - **輸入檔案**: 與答題程式互動所需的提示資料
    - **解答檔案**: 對照答案(判定結果)所需資料

以上都可以在 ```DOMjudge Jury interface/Executables/``` 找到範例題目的範本```boolfind_run, boolfind_cmp```，這篇說明的程式碼也是用此範本改的

<br><br><br><br><br><br><br><br><br><br><br><br>
## 三、評判流程

![](https://i.imgur.com/eb0q0RF.png)
<br>

1. 編譯並執行答題程式
    - 編譯失敗: <span style="color: Red">**COMPILER-ERROR**</span> 
3. **runjury**讀取測資輸入檔並且與答題程式互動，產生**progout**檔案
    - 讀取**測資輸入檔案**(`argv[1]`)
    - `talk()`函式: 互動
        - 從 `stdout` 輸出提示給答題程式
        - 從 `stdin` 讀取答題程式的回應
        - 將欲比對的資訊或答案的錯誤訊息(格式錯誤等等)輸出至**progout**(`argv[2]`)
        - 若途中有程式執行上的錯誤(開檔失敗等等) $\rightarrow$ `exit(1)` $\rightarrow$ <span style="Color: Red">Internal Error</span>
    - 此階段執行過久: <span style="color: Red">**TIMELIMIT**</span> \*故回應越快越好
4. **check_problem**讀取測資輸入、測資解答、**runjury**產生的**progout**檔案，並比對解答
    - 讀取**測資輸入檔案**(`argv[1]`)、**測資解答檔案**(`argv[2]`)
    - 從 `stdin` 讀取**progout**內容
    - 比對解答
        - 若為錯誤訊息或解答有誤: 輸出訊息至 `stdout`
        - 比對正確則讓程式正常結束
        - 無論結果是WA或AC都要`return 0`
    - 途中有程式執行上的錯誤(開檔失敗等等) $\rightarrow$ `return 1` $\rightarrow$ <span style="Color: Red">Internal Error</span>
5. 根據**judgemessage.txt**有無內容來決定評判結果
    - 有內容(**check_problem**有從`stdout`輸出過東西): <span style="color:Red">**WRONG-ANSWER**</span>
    - 沒內容: <span style="color: Green">**CORRECT**</span> 
    - **judgemessage.txt**的內容會寫在Jury的`Diff output`欄位，也會用來跟測資解答比較

## 四、 上傳至DOMjudge
\*待補: 如何打包上傳
1. 更新及測試
    - 將**problem_run**的**build**中，Source file的部分改成`runjury_problem.c`
    - 試著在同一層目錄下使用 `$ ./build` 並確定能正確編譯
    - 將**problem_cmp**的**build**中，Source file的部分改成`check_problem.c`、命名改為`check_problem`
    - 將**problem_cmp**的**run**中，環境變數`CHECK_PROGRAM`的部分改成`"${SCRIPTPATH}/check_problem"`
    - 試著在同一層目錄下使用 `$ ./build` 並確定能正確編譯
    - \*待補: 編譯沒成功會怎樣
3. 上傳執行檔
    - \*壓縮要用Linux指令(Windows會有檔案權限問題) 
    - **problem_run.zip**
        - `$ zip -r problem_run.zip run build runjury_problem.c`
    - **problem_cmp.zip**
        - `$ zip -r problem_cmp.zip run build check_problem.c`
    - 在 `DOMjudge Jury interface/Executables` 上傳兩個zip檔
        - **problem_run.zip**: Type run
        - **problem_cmp.zip**: Type compare
4. 新增問題
    - 在 `DOMjudge Jury interface/Problems` 新增問題
        - 設定Time limit, 上傳測資, etc
        - `run script`: **problem_run**
        - `compare script`: **problem_cmp**
5. 測試題目
<br>

## 五、範例: Boolean Switch Search(bool_find)
\*括號內為以此檔案為範本修改時的建議
- 題目概述:
    - 目標: 給定一個$01$數列，解答目標是輸出後面接有$0$的$1$的位置
    - 互動
        - 裁判程式給定測試數
        - 每筆測試先提供數列長度 $n$，再根據使用者的輸出回答該位置是 $true(1)$ 或是 $false(0)$ ，或是接受答案
        - 答題程式收到測試數後，在每筆測試拿到數列長度
        - 輸出 `READ x` ，從裁判程式拿到位置 $x$ 是 $true(1)$ 或是 $false(0)$
        - 輸出 `OUTPUT x` ，裁判程式接受答案後開始下一個測試
    - 測資內容
        - **輸入檔案**: 依序為測試數、各筆測試內容(依序包含數列長度及各個位置的 $0/1$ 值)
        - **解答檔案**(本題未使用): `OUTPUT 1` 

- **runjury_boolfind.c**

![](https://i.imgur.com/bhKuBle.png)
事前檢查(基本上這裡可以不用改)

---
![](https://i.imgur.com/EbxmXen.png)
從測資讀取及開始互動
這裡是先讀取測試數後，分次讀取數列內容及互動
(根據題目調整，讀入輸入檔案後呼叫`talk()`函式)

---
![](https://i.imgur.com/ZEap4dj.png)
互動函式: 輸出數列長度給答題程式後進入無窮迴圈，比對答題程式給出的回答後做適當回應，內容有錯誤就輸出訊息到**progout**後跳出迴圈，繼續下一筆
(根據題目調整，先將事前要給答題程式的輸出完，用無窮迴圈讀取回答，內容有錯誤就輸出訊息到**progout**後跳出迴圈)
(圖中48行只是模擬用的，基本上函式內可以整個重寫)
(建議此處做格式上的檢查，內容交給**problem_cmp**比對)

---
![](https://i.imgur.com/X6HiwpO.png)
後續處理: 關閉檔案、將答題程式多餘的輸出
(這裡基本上不用改)<br>

- **check_boolfind.c**

![](https://i.imgur.com/SUUSjSK.png)
事前檢查(基本上這裡可以不用改)

---
![](https://i.imgur.com/5dPfPDB.png)
檢查答案部分
(根據題目調整，內容有錯誤將訊息輸出到`stdout`)
(若答案有錯也可以輸出錯誤答案到`stdout`，Jury那會有比對結果)