owned this note
owned this note
Published
Linked with GitHub
# 問題(problem)打包
*可向下相容ver6版本的domjudge*
問題打包功能使用
===
在domjudge系統中,一個問題所需要包含
* <font color="#f00">```domjudge-problem.ini```</font> (可選): 問題的基本資料設定
* <font color="#f00">``problem.{pdf,html,txt}``</font>(可選): 問題的描述文件
* <font color="#f00">``problem.yaml``</font>: 問題的配置文件
* <font color="#f00">``data``</font>: 測試資料存放處
* <font color="#f00">``secret``</font> :隱藏的測資,一般隊伍無法看見測資內容
* <font color="#f00">``sample``</font> :公開的測資,一般隊伍可看見的測資內容
admin可從""DOMjudge Jury interface >> Problem""中找到此頁面

點擊右方存儲符號的icon,即可將該問題打包下載至你的電腦中,會以問題的別名以壓縮包```.zip```的格式下載
壓縮包```.zip```的內容如上述,會有以下幾個檔案:

除了按照domjudge "Problem"頁面來新增problem之外,也可以透過"Problem"下方來新增問題

選擇相對應的contest >> 選擇要新增的problem的 .zip 壓縮包 >> Upload 上傳檔案
問題打包格式參照
===
DOMjudge 支援以 .zip 格式匯入及匯出 problem
基本格式參照 [ICPC problem format](https://clics.ecs.baylor.edu/index.php?title=Problem_format) (為 [problemformat.org](https://www.problemarchive.org/wiki/index.php/Problem_Format) 的子集)
<br>
DOMjudge 定義了一些擴展模式:
* <font color="#f00">```domjudge-problem.ini```</font> (可選):metadata文件,定義題目的限制名稱等條件,參考下方
* <font color="#f00">``problem.{pdf,html,txt}``</font>(可選):分配給參加選手的問題陳述。文件得副檔名可以是其中選一。如果有多個符合的文件,則使用其中之一。
(檔名可能為 promblem.pdf/problem.html/problem.txt)
<br>
<font color="#f00">```domjudge-problem.ini```</font> 文件包含 key = value 鍵值配對。
<font color="#f00">```=```</font> 兩端的空白可有可無,值(value)可以用引號<font color="#f00">```"" or ''```</font>,以便換行。允許的關鍵字如下(這些關鍵字會對應到jury後台的設置,一般來說官方原始給的關鍵字如下說明,但是透過改動原始碼可以自行增添選項):
* <font color="#f00">```name```</font> - 題目所顯示的名字
* <font color="#f00">```allow_submit```</font> - 允許提交這個題目,若不允許題目會對 team 及 public 做隱藏
* <font color="#f00">```allow_judge```</font> - 允許評判這個題目
* <font color="#f00">```timelimit```</font> - 每筆測資的時間限制(以秒為單位)
* <font color="#f00">```special_run```</font> - 特殊的script可執行id(executable id)
* <font color="#f00">```special_compare```</font> - 特殊的的比較script的可執行id(executable id)
* <font color="#f00">```points```</font> - 題目的分數(預設值為1)
* <font color="#f00">```color```</font> - 題目的 CSS 顏色規格
以上為官方原始關鍵字,下方為新增之關鍵字:
* <font color="#f00">```restriction_languages```</font> - 限制題目的繳交語言,其中限制的語言必須是管理者設定可以繳交的語言,填入名稱以 language 中的 name 為基準且以 json 方式儲存。
:::info
範例:```restriction_languages = '["C","C++"]'```
:::
* <font color="#f00">```subtask```</font> - 將測資拆分(拆分組數不得大於測資筆數),作為子任務來評分,輸入格式為整數,會搭配<font color="#f00">```task_point```</font>做使用
:假設一個 problem 有10筆測資,輸入3就可以將10筆拆分成3組再根據<font color="#f00">```task_point```</font>做分數分配(最多拆成10個 subtask)
:::info
範例:```subtask = '3'```
:::
* <font color="#f00">```task_point```</font> - 將<font color="#f00">```subtask```</font>拆分出的組別,分別給上分數,以json方式儲存,輸入格式為整數
:如上述,10筆測資拆分成3組,根據以上格式,第一組的分數為1,第二組為2,第三組為3(給的分數至多等於拆分組數,subtask 拆成3組 task_point 最多給3筆)
:::info
範例:```task_point='"1,2,1"'```
:::
---
zip壓縮包內會含有以下檔案
* <font color="#f00">```domjudge-problem.ini```</font> (可選)
* <font color="#f00">``problem.{pdf,html,txt}``</font>(可選)
* <font color="#f00">``problem.yaml``</font>
* <font color="#f00">``data``</font>
* <font color="#f00">``secret``</font> :隱藏的測資,一般隊伍無法看見測資內容
* <font color="#f00">``sample``</font> :公開的測資,一般隊伍可看見的測資內容
每筆測資檔案規格如下:
* 同一筆測資的檔名需一樣
* <font color="#0048BA">```檔名1.in```</font>: input 內容,需以 .in 作為檔案名稱結尾
* <font color="#0048BA">```檔名1.ans```</font>: output 內容,需以 .ans 作為檔案名稱結尾
* <font color="#0048BA">```檔名1.task```</font>: 此筆測資分類到的 subtask 之組別內容為**整數**,需以 .task 作為檔案名稱結尾
:::info
範例: 有5筆測資,subtask='3',意及把這5筆測資分成三組,皆放在 secret 資料夾中
<br>
| 測資1 | test1.in | test1.ans | test1.task ||
| -------- | -------- | -------- |--------|---------|
|測資1的檔案內容|1 2 3|Hello World !|1(分到第1組)|程式讀入1 2 3分別會輸出 Hello World !|
|測資2| test2.in | test2.ans | test2.task |
||||1(分到第1組)|
|測資3| test3.in | test3.ans | test3.task |
||||2(分到第2組)|
|測資4| test4.in | test4.ans | test4.task |
||||3(分到第3組)|
|測資5| test5.in | test5.ans | test5.task |
||||2(分到第2組)|
:::
程式碼部分
===
有了上方的打包概念後,除了基礎官方原定的打包項目外,也可以加入自己設定的打包項目,可以透過修改下方的 code 做添加:
### import 將 .zip 檔案匯入
可以在專案的```domjudge/domserver/webapp/src/Service/ImportProblemService.php```路徑中找到此檔案以及函式
修改此檔案後可以在
```ProblemController.php >> indexAction() >> importProblemService >> importZippedProblem()```
此Controller的呼叫中被應用到專案中
以下為```importZippedProblem()```新增的修改內容:
```php=
//除了預設的選項外,可在此擴增需求
//新增restriction_languages, subtask ,task_point
+ $iniKeysProblem = ['name', 'timelimit', 'special_run', 'special_compare','subtask','restriction_languages','task_point'];
//新增 restriction_languages 等需要 import 到 problem 等內容,基本從 zip 裡頭的 domjudge-problem-ini,需透過正則表達式將符號統一,以便儲存到資料庫
+ if (isset($problemProperties['restriction_languages'])) {
+ $problemProperties['restriction_languages'] = preg_replace('/x5C|\[|\]|\"/' , '' , $problemProperties['restriction_languages']);
+ $problemProperties['restriction_languages'] = explode(',', $problemProperties['restriction_languages']);
+ }
//新增 task_point
+ if (isset($problemProperties['task_point'])) {
+ $problemProperties['task_point'] = preg_replace('/\"/' , '' , $problemProperties['task_point']);
+ }
```
因為預設的```domjudge-problem.ini```會缺少我們新增的項目,所以必須在```addTestcaseToZip```的函式中新增內容
```php=
/**
* @param Testcase[] $testcases
* @param ZipArchive $zip
*/
/*----CCU-----*/
// 在prototype 新增傳入 array $iniData
public function addTestcasesToZip(array $testcases, ZipArchive $zip, bool $isSample, array $iniData)
{
$formatString = sprintf('data/%%s/%%0%dd', ceil(log10(count($testcases) + 1)));
$rankInGroup = 0;
foreach ($testcases as $testcase) {
$rankInGroup++;
$filename = sprintf($formatString, $isSample ? 'sample' : 'secret', $rankInGroup);
$zip->addFromString($filename . '.in', $testcase->getContent()->getInput());
$zip->addFromString($filename . '.ans', $testcase->getContent()->getOutput());
if (!empty($testcase->getDescription(true))) {
$description = $testcase->getDescription(true);
if (strstr($description, "\n") === false) {
$description .= "\n";
}
$zip->addFromString($filename . '.desc', $description);
}
if (!empty($testcase->getImageType())) {
$zip->addFromString($filename . '.' . $testcase->getImageType(),
$testcase->getContent()->getImage());
}
if($iniData['subtask'] != 0){
//新增 若task有分類,將task的分類下載
if (!empty($testcase->getTask(true))) {
$task = $testcase->getTask(true);
$zip->addFromString($filename . '.task', strval($task));
}
}
}
}
```
### export 將 .zip 檔案匯出
可以在專案的```domjudge/domserver/webapp/src/Controller```路徑下找到:
```ProblemController.php -> exportAction()```修改其中的
```php=
$iniData = [
'timelimit' => $problem->getTimelimit(),
'special_run' => $problem->getSpecialRun(),
'special_compare' => $problem->getSpecialCompare(),
'color' => $contestProblem ? $contestProblem->getColor() : null,
+ //新增壓縮資訊
+ //去相對應的table(Entity)去抓取相對應的資料,轉成預期的type
+ 'restriction_languages' => json_encode($problem->getRestrictionLanguages()),
+ 'subtask' => $problem->getSubtask(),
+ 'task_point' => json_encode($problem->getTaskPoint()),
];
```
因為prototype被改變,所以傳入的內容也需要增加
所以需要到同一個```ProblemController.php -> exportAction()```其中的
```php=
foreach ([true, false] as $isSample) {
/** @var Testcase[] $testcases */
$testcases = $this->em->createQueryBuilder()
->from(Testcase::class, 't')
->join('t.content', 'c')
->select('t', 'c')
->andWhere('t.problem = :problem')
->andWhere('t.sample = :sample')
->setParameter(':problem', $problem)
->setParameter(':sample', $isSample)
->orderBy('t.rank')
->getQuery()
->getResult();
/*----CCU-----*/
//新增 傳入$iniData,以獲取我們新增的資訊
$this->addTestcasesToZip($testcases, $zip, $isSample, $iniData);
}
```