前言

时光飞逝,笔者的大学生涯已经来到大三的尾声,即将面临读研还是就业的艰难选择,也不再有太多精力组织校内的 XCPC 比赛。我希望在这里记下一些关于配置选手机器、搭建评测系统的相关经验,谈谈一场 XCPC 校赛的技术工作是如何完成的。

本篇文章将按照时间顺序,介绍如何开展赛前到赛后的技术工作,内容将尽可能详细。

校赛技术环境

笔者所在学校的基本技术环境如下:

  • 选手机器为 Windows 系统,自动还原,不让装镜像
  • 不同机房的选手机系统存在很多软件差异
  • 难以通过外部手段限制选手机器能访问的网络地址
  • 校内有一台专用的比赛服务器

我不太清楚其他学校的情况如何,不过这也许和多数学校的条件相近。

本篇内容的本地/服务器环境

  • 个人 Windows 电脑
  • Ubuntu Server 22.04 LTS 服务器
  • DOMjudge 8.3
  • icpctools 2.5.936

阅读需要的知识/能力

举办一场简单的校赛,技术方面的要求不高,但是至少需要以下方面的知识/能力:

  • 网络方面的基本知识
  • Windows/Linux 基本命令行操作
  • 在 Linux 下编辑文件
  • Docker 的基本使用
  • 阅读软件文档的能力

比赛前

比赛前首要的就是搭建比赛的评测系统,导入队伍信息,其次是完成选手机操作系统的配置。

搭建比赛评测系统

比赛评测系统采用 DOMjudge,如无特殊需求(如搭建负载均衡集群等),直接 Docker Compose 的方式进行部署,开箱即用。
DOMjudge 需要部署两个部分:

  • domserver: DOMjudge 的 Web App,选手和工作人员使用的网页面板
  • judgehost: DOMjudge 的评测主机,用于评测题目
    部署 DOMjudge 之前还需要部署一个 MariaDB 数据库,用于存储 DOMjudge 的系统数据;一个 CDS (Contest Data Server) 用于比赛数据收集和后续滚榜。

选择机器

选择的机器必须保证选手机器可以访问,如学校内网的服务器,或者购买的公网服务器。

如果选用公网服务器,建议选购带宽较大的国内服务器,避免比赛时因访问流量过大带来 IP 封禁的风险。

建议使用性能较好的机器作为 mariadb/domserver 的部署机器,否则可能导致选手访问评测系统速度较慢。

另外,如果 domserver与mariadb 或者 domserver与judgehost 没有部署在同一台机器上,则必须保证他们之间的网络通信有足够的带宽,否则可能导致网站访问缓慢,或者下发测试点花费较长时间。

为保证比赛公平性,如果需要在多个机器上部署 judgehost, 请确保这些机器的软硬件配置相同。

配置机器环境

操作系统环境

操作系统一般会选用 Ubuntu。不建议使用过新的系统,尤其是需要在机器上部署 judgehost 时。
之前配置的时候遇到一个坑点,使用 Ubuntu 24.04 的时候无论如何 judgehost 都无法启动,原因是 cgroup v1 在这个系统版本里已经被移除了,即使配置系统使用 cgroup v1,系统仍会使用 cgroup v2,导致 judgehost 无法启动。

个人建议使用久经考验的 Ubuntu 22.04. 下面的论述都将以 Ubuntu 22.04 为操作系统。

连接到服务器

如果您无法直接连接到服务器(比如服务器放在机房,或者使用云服务器),请通过 SSH 的方式连接到您的服务器执行后续的命令。

关于文件传输:如果您正在使用 Windows 操作系统,可以使用 WinSCP 软件进行文件传输。如果您正在使用 Linux 的某一发行版,则可以直接通过 SCP 命令进行文件传输。

配置 cgroup

如果这台机器需要运行 judgehost,则首先应当为这台机器配置 cgroup,否则这一步可以跳过。

以 root 权限编辑 /etc/default/grub 文件,找到 GRUB_CMDLINE_LINUX_DEFAULT=开头的行,例如:

1
GRUB_CMDLINE_LINUX_DEFAULT="quiet"

在引号内部最后添加 cgroup_enable=memory swapaccount=1:

1
GRUB_CMDLINE_LINUX_DEFAULT="quiet cgroup_enable=memory swapaccount=1"

在较新的系统,还需要添加 systemd.unified_cgroup_hierarchy=0 (Ubuntu 22.04需要添加):

1
GRUB_CMDLINE_LINUX_DEFAULT="quiet cgroup_enable=memory swapaccount=1 systemd.unified_cgroup_hierarchy=0"

保存文件,执行以下命令:

1
sudo update-grub

更改完成后,需要重启系统:

1
sudo reboot

安装 Docker & Docker Compose

如果没有安装 Docker,则需要先安装 Docker,除非你希望直接在系统中进行繁琐的部署

请参考官方的安装文档或者直接执行下面的指令:

1
2
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh ./get-docker.sh

这会安装 Docker 和 Docker Compose.

由于学校管理要求或者神秘力量限制,您可能遇到无法连接外网或者下载缓慢的问题。此时请参考上述官方文档,配合文件传输工具进行离线安装。

配置和启动 Docker 容器

编写评测系统容器配置文件

我们使用 Docker Compose 的方式来部署数据库和 Domjudge.
建议 mariadb, domserver, cds 部署在同一个机器上。如果 judgehost 也运行在同一个机器上,那么可以参考下面的配置:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
networks:
domjudge:
name: domjudge

services:
mariadb:
container_name: mariadb
image: mariadb:latest
networks:
- domjudge
ports:
- 13306:3306
environment:
- CONTAINER_TIMEZONE=Asia/Shanghai
- MYSQL_ROOT_PASSWORD=$db_root_passwd
- MYSQL_USER=$db_user
- MYSQL_PASSWORD=$db_passwd
- MYSQL_DATABASE=$db_database
command: --max-connections=1000 --innodb-log-file-size=1024M --max-allowed-packet=1024M

domserver:
container_name: domserver
image: domjudge/domserver:latest
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup
- /var/local/print:/var/local/print
networks:
- domjudge
ports:
- 80:80
depends_on:
- mariadb
environment:
- CONTAINER_TIMEZONE=Asia/Shanghai
- MYSQL_HOST=mariadb
- MYSQL_ROOT_PASSWORD=$db_root_passwd
- MYSQL_USER=$db_user
- MYSQL_PASSWORD=$db_passwd
- MYSQL_DATABASE=$db_database

judgehost-1:
container_name: judgehost-1
image: domjudge/judgehost:latest
privileged: true
hostname: judgedaemon-1
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup
networks:
- domjudge
depends_on:
- domserver
environment:
- CONTAINER_TIMEZONE=Asia/Shanghai
- DOMSERVER_BASEURL=http://domserver/
- DAEMON_ID=1
- JUDGEDAEMON_PASSWORD=$restapi_key

将上面的内容保存到 docker-compose.yml,并替换 $db_root_passwd$db_user$db_passwd$db_database 为您想要的值。注意同一个变量的值必须是一样的。
max-allowed-packet 建议设置为题目最大测试点大小的 2 倍,innodb-log-file-size 建议设置为题目最大测试点大小的 10 倍,请根据实际情况调整。

此外,您还需要根据您的比赛需要配置 judgehost 的数量,将配置最后的 judgehost-1 部分的内容复制粘贴,并修改名称(judgehost-X)、主机名(judgedaemon-X)、DAEMON_ID(X),X 为您评测机的序号,从 1 开始。

judgehost 的数量不能超过 CPU 的总核心数,因为它需要绑定一个 CPU 核心执行任务。不建议设置 DAEMON_ID 为 0,因为 Linux 系统会在 CPU 0 上派遣任务(除非特殊指定其他核心)。

不建议使用过多的 judgehost,除非您使用多机承担前端请求。 因为 judgehost 也需要通过 API 访问 domserver 轮询提交进行评测,会给服务器带来压力。

启动 domserver

编辑完成后,我们暂时先启动 mariadb 和 domserver,不要启动其他容器

1
sudo docker compose up -d mariadb domserver

如果因为网络问题无法拉取镜像,请在其他可以正常拉取镜像的机器上拉取并导出相应的镜像,再导入到您的机器上。此过程可以参考网上关于 Docker 镜像导出导入的文章,此处不再赘述。

启动完成后,我们需要获取预设的 admin 密码和 API 密码:

1
2
docker exec -it domserver cat /opt/domjudge/domserver/etc/initial_admin_password.secret
docker exec -it domserver cat /opt/domjudge/domserver/etc/restapi.secret

第一条指令将获得 DOMjudge 网页中 admin 账户的密码,第二条指令将获得 Domjudge RestAPI 的访问密码,用于配置评测机。

现在你可以通过 http://服务器IP/ 访问 domserver,并使用 admin 账号登陆,查看系统是否正常运行。

启动 judgehost

现在,将 docker-compose.yml 中的 $restapi_key 替换为从 restapi.secret 文件获取的密码。然后,将配置文件中的所有容器启动:

1
sudo docker compose up -d

如果各个 judgehost 正常启动,现在可以在网页中的 “judgehosts” 页面看到您配置的评测机已经出现,旁边有一个绿色的勾表示状态正常。
那么,恭喜你,现在 DOMjudge 评测系统本身已经完成了部署!

为 CDS 创建 DOMjudge 账号

在 Jury Interface 中选择 “Users”,然后选择 “Add new user”,填写用户名为 “cds”,并自定一个安全的密码。

下方 Roles 需要勾选: API reader, API writer, Source code reader

创建用户,记录好密码备用。

编写CDS容器配置文件

CDS (Contest Data Server) 不是 DOMjudge 的一部分,而是后面信息展示、滚榜、颁奖要用到的 icpctools 的一部分。

将工作目录更改到一个不同于上面您保存 docker-compose.yml 的目录,然后创建一个新的 docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
services:
cds:
container_name: cds
image: ghcr.io/icpctools/cds:2.5.936
volumes:
- ./accounts.yaml:/opt/wlp/usr/servers/cds/config/accounts.yaml
ports:
- 8080:8080
- 8443:8443
environment:
- CCS_URL=http://$your_ip/api/contests/$cid
- CCS_USER=$ccs_user
- CCS_PASSWORD=$ccs_passwd

$your_ip 更改为您 domserver 运行主机的 IP 地址。并更改 $ccs_user$ccs_passwd,分别为前面前面创建的 cds 账户的账号和密码。

$cid 需要更改为 DOMjudge 中正赛的 Contest ID,由于我们尚未建立比赛,后面临近比赛开始再更改此变量并启动 CDS。另外 CDS 只能服务一场比赛,因此服务完一场比赛后,需要删除该容器(sudo docker compose down)。

不建议使用过新的 icpctools 版本,因为可能存在潜在的问题。
请咨询其他有办赛经验的人了解相对稳定的 icpctools 版本号。

如果您网络不佳,建议提前拉取镜像。

在同目录下创建 accounts.yaml,填入以下内容,并编辑各个账户的密码(__XXX_PASSWORD__)。后面配置信息展示屏、滚榜、设置奖项等需要用到。

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
- username: admin
password: __ADMIN_PASSWORD__
type: admin
- username: presAdmin
password: __PRES_ADMIN_PASSWORD__
type: presAdmin
- username: blue
password: __BLUE_PASSWORD__
type: staff
- username: balloon
password: __BALLOON_PASSWORD__
type: balloon
- username: presentation
password: __PRESENTATION_PASSWORD__
type: public
- username: myicpc
password: __MYICPC_PASSWORD__
type: analyst
- username: live
password: __LIVE_PASSWORD__
type: analyst
- username: team1
password: __TEAM1_PASSWORD__
type: team
team_id: '1'

至此,比赛的评测相关软件已经基本安装完毕。

配置评测系统

首先我们需要进行数个 JSON 生成与导入工作。请确保您已拥有选手的报名信息,并分配好选手的座位表。

如何导入各类 JSON 数据

从 DOMjudge Jury Interface 进入 Import / export 页面。
Jury Interface
找到 Import JSON / YAML 部分。选择对应的 Type 和文件,点击 “Import” 进行导入。Type 一般只会选 organizations, teams, accounts 几个选项,分别对应组织信息、队伍信息、账号信息。
Import JSON
具体的 JSON 的内容格式,请参照以下信息和官方文档

请注意,您生成的 JSON 文件应该使用 UTF-8 编码,否则中文可能导入后显示异常。

导入学校信息

根据报名的选手信息,生成一个 organizations.json,用于导入队伍的学校信息。内容结构如下:

1
2
3
4
5
6
7
8
[
{
"name": "学校简称,例如:PKU",
"formal_name": "学校详名,例如:Peking University",
"country": "国家代码,例如:CHN",
"id": "生成一个唯一的组织ID,例如:INST-1"
}
]

如果您希望达到更好的显示效果,可以手动或者编写脚本使用 API 上传各个学校的校徽。

您可以访问 http://服务器IP/api/doc 来获取您的 DOMjudge 支持的 API.

导入队伍信息

您需要根据报名信息,生成一个 teams.json 用于导入队伍信息。内容结构如下:

1
2
3
4
5
6
7
8
9
10
11
[
{
"id": "生成一个队伍的唯一ID",
"group_ids": [
"队伍类型ID"
],
"name": "队伍名称",
"organization_id": "organizations.json中设置的对应ID",
"room": "队伍座位"
}
]

队伍类型ID可以在 “Team Categories” 页面查看。如果没有修改过,3 是正式队伍,4 是打星队伍。

roomorganization_id 是可选的,如果不需要,可以不写这两个字段。

推荐设置 room,方面后面发放气球和打印。

如果您希望达到更好的显示效果,可以手动或者编写脚本使用 API 上传各个队伍的滚榜照片。

导入队伍账号

您需要根据报名信息,生成一个 accounts.json 用于导入队伍账号。您需要为每支队伍生成一个账号。内容结构如下:

1
2
3
4
5
6
7
8
9
10
[
{
"type": "team", // 表示为team类型的账户
"id": "账户的唯一ID,建议与用户名一致",
"username": "用户名,例如:team-001",
"password": "生成一个队伍的随机密码",
"name": "账户显示名称,和队伍名保持一致就可以",
"team_id": "对应上面队伍设置的唯一ID"
}
]

建议为热身赛和正式赛生成不同的密码。即热身赛结束后,重新随机生成所有账户的 password 一项,然后重新导入 accounts.json。需要特别注意,不要修改 username 字段,否则可能导致生成新的账户,而旧的账户仍然可用。

如果您能够为选手机位分配固定的 IP,则您可以不设置 password 字段,而选择设置 ip 字段指定选手机器的 IP。这样选手的机器可以在打开 DOMjudge 网页时自动登陆而无需输入密码.

导入题目

如果您使用 Polygon 出题,则您可以通过 Polygon2Domjudge 工具将 Polygon 中导出的题目包转换为 DOMjudge 支持的格式。请参阅 Polygon2Domjudge 的项目页获取详细用法。

关于如何在 Polygon 上筹备比赛题目,可参考 OI-Wiki 上的说明

在获取了 DOMjudge 支持的格式的各题题目包后,您可以从 “Import / export” 页最上方选择压缩包进行题目的逐个导入。
Problem Import

PHP 上传大小超限/爆内存的处理

当题目数据非常大时,可能遇到超过 PHP 上传文件大小限制(256MB),或者超出 PHP 内存限制(512MB)的问题,此时有两种解决方案:

  1. 调整题目压缩包,先上传部分数据,剩余的数据手动逐个上传
  2. 调整 domserver 的 PHP 配置,重启该容器

这里详细介绍第二种。该配置位于容器的 /opt/domjudge/domserver/etc/domjudge-fpm.conf 文件内。由于容器内并没有 vim 等文本编辑器,编辑起来较为困难,故将文件复制出来再编辑,再回拷。

1
sudo docker compose cp domserver:/opt/domjudge/domserver/etc/domjudge-fpm.conf ./domjudge-fpm.conf

编辑文件:

1
sudo vim ./domjudge-fpm.conf

可以看到比较下面的地方有几行配置:

1
2
3
4
5
; Set these three to be at least the size of your largest testcase and
; largest expected program output.
php_admin_value[memory_limit] = 512M
php_admin_value[upload_max_filesize] = 256M
php_admin_value[post_max_size] = 256M

将上面几个值调整为您需要的值,保存,再回拷文件,重启 domserver 容器。

1
2
sudo docker compose cp ./domjudge-fpm.conf domserver:/opt/domjudge/domserver/etc/domjudge-fpm.conf
sudo docker compose restart domserver

调整评测设置

从 Jury Interface 进入 Contests 页 Configuration settings 页,切换到 Judging 标签,注意以下设置:

  • Output limit: 确保 Output limit 大小不小于各个测试点标准答案的输出大小
  • Timelimit overshoot: 一般设为 1s|10%
  • Enable parallel judging: 并行评测,不建议开启,如果赛前题目测试中遇到奇怪的超时问题,可以尝试关闭此选项重测

创建比赛

从 Jury Interface 进入 Contests 页,选择 “Add new contest” 新建一场比赛。以下是各个参数的配置说明:

参数 说明
Shortname 比赛的短名称,例如:2025_TUPC_WARMUP
Name 比赛的全名,例如: 2025 Test University Programming Contest Warmup
Activate time 比赛激活时间,队伍在激活时间后才能看到此比赛,例如:2025-06-09 00:09:00 Asia/Shanghai
Start time 比赛开始时间,在开始时间后才能看题、答题,例如:2025-06-09 00:10:00 Asia/Shanghai
Scoreboard freeze time 封榜时间,一般设置为比赛开始后的 4 小时: +04:00:00
End time 比赛结束时间,一般设置为比赛开始后的 5 小时: +05:00:00
Scoreboard unfreeze time 解除封榜的时间,一般不设置,后面手动解封
Deactivate time 比赛取消激活的时间,一般不设置,后面手动 deactivate
Allow submit 允许提交,一般设置为 Yes
Record balloons 处理气球,一般设置为 Yes
Medal enabled 一般设置为 Yes, 并补充能获得奖项的参赛类别,以及各种牌子发几个
Enable public scoreboard 开放外榜,允许未登陆用户查看榜单,根据实际需要设置
Open contest to all teams 选择 No, 并在随即出现的 Team categories 中选择参赛的队伍类别
Banner 放置在比赛页上方的图片,根据需要设置
Scoreboard warning message 显示在榜单上的文本警告信息,必要时可以设置

页面最下方是题目列表,按序选择要添加的题目,配置题号(Short name)、气球颜色(Colour)。Points 在 XCPC 赛制中固定为 1. 其他设置一般不动。

创建比赛后仍可以对比赛和赛题列表进行编辑。

配置打印

前面的 docker-compose.yml 文件中已经配置了一个文件夹映射,如果需要配置打印脚本,请直接在 domserver 的宿主机的 /var/local/print/ 目录下创建打印脚本,并编写脚本的内容。

我们曾经采用的方案是在 Linux 系统下使用 cups, ps2pdf 等工具,配合 Python 编写的 HTTP Server 在技术人员的电脑上远程打印。如果恰好符合您的需求,可以使用此方案。

我现在更推荐使用 Hydroxcpc-tools 做打印工作,支持多平台系统。它不但可以为 DOMjudge 提供打印功能,也可以连接小票机打印气球单,方便发气球。仓库里也包含一个为 DOMjudge 设计的打印脚本,参照仓库内的文档配置 xcpc-tools (包括 fetch server 和 client) 和 DOMjudge 即可使用。

在 DOMjudge 中设置打印指令时,脚本命令需要使用完整路径,例如您在该目录下创建了名为 printcode 的脚本,则示例配置为 /var/local/print/printcode [teamname] [location] [original] [file] (后面的参数需根据打印脚本实际进行配置)

测试赛题

在题目导入到评测系统后,强烈建议创建一场包含所有赛题的非公开测试赛,以内部账号进行提交,测试各个赛题正解在本地部署的评测机上的运行时间、内存占用,并根据实测情况,调整各个题目的时空限制。

这么做可以避免出题平台与本地评测软硬件条件不一致导致选手被卡常或者不小心放过错解。

测试完成后,可以 finalize 并 deactivate 测试比赛。

配置选手机环境

这里主要介绍我校在选手机使用 Windows 系统、不让安装自定义镜像、硬盘自动还原等条件下的环境配置。如果您所在学校有条件自行安装系统镜像等,可以跳过本节。

我们主要使用 bat 脚本对 Windows 系统进行配置。由于系统自动还原,所以每场赛事开始前回由略懂电脑操作的志愿者携带U盘,进行环境配置。

环境/软件配置

各个软件均采用免安装版本,包括:

  • OpenJDK 17.0.0.1
  • Python 3.11.2 (Embed)
  • MinGW64 (GCC 12.2.0)
  • Google Chrome Portable
  • DevCpp
  • VSCode (安装 C/C++, Java, Python, CPH 和中文语言包插件)

这些程序和需要放在桌面的文件直接拷贝到 C:\Applications

1
2
3
echo Copying Files
C:\windows\system32\xcopy.exe /B /E /Y /Q .\Applications C:\Applications\
C:\windows\system32\xcopy.exe /B /E /Y /Q .\DesktopFiles C:\Users\Public\Desktop\

并配置环境变量:

1
2
3
echo Configuring Environment Paths
C:\windows\system32\setx PATH "C:\Windows;C:\Windows\System32;C:\Applications\mingw64\bin;C:\Applications\jdk-17.0.0.1\bin;C:\Applications\python3112;" /M
C:\windows\system32\setx JAVA_HOME "C:\Applications\jdk-17.0.0.1" /M

由于各个机房环境变量的设置千奇百怪,有的把 C:\Windows 等系统路径都删除了,因此脚本中全部使用命令的绝对路径,并设置必要的系统环境变量路径(否则 VSCode 在调用 CMD 时会因找不到路径而出错)。

在摸点机房,实测脚本时,发现如果使用需要安装版本的 Python 进行命令行静默安装,在一个机房中总是会失败。原因似乎是机房的系统本来自带的Python无法通过命令行正确卸载,导致脚本里试图安装的另一个版本也装不上。因此最后决定使用 Python 的 Embed 版本,只需要复制文件并配置环境变量即可。

关于如何配置 VSCode 便携版,请参考 VSCode 的官方文档

关于如何装配 Python Embed 版,可以参考这篇知乎文章

创建快捷方式

我们需要为编写应用创建快捷方式。
创建一个 shortcut.bat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@echo off & setlocal
set arg1=%~1
set arg2=%~2
set arg3=%~3
if not defined arg1 goto usage
if "%arg2%"=="" set arg2=Desktop
if "%arg3%"=="" set arg3=shortcut
C:\windows\system32\mshta VBScript:Execute("Set a=CreateObject(""WScript.Shell""):Set b=a.CreateShortcut(a.SpecialFolders(""%arg2%"") & ""\%arg3%.lnk""):b.TargetPath=""%arg1%"":b.WorkingDirectory=""%~dp0"":b.Save:close")
goto :eof

:usage
echo %~n0 targetpath [shortcutfolder] [shortcutname]

goto :eof

然后在环境配置脚本中调用:

1
2
3
4
5
6
7
echo Creating Shortcuts
call shortcut.bat C:\Applications\VSCode\Code.exe "" "VSCode"
call shortcut.bat C:\Applications\DevCpp\devcpp.exe "" "DevCpp"
call shortcut.bat C:\Applications\GoogleChromePortable\GoogleChromePortable.exe "" "Chrome"
copy "%USERPROFILE%\Desktop\VSCode.lnk" C:\Users\Public\Desktop
copy "%USERPROFILE%\Desktop\DevCpp.lnk" C:\Users\Public\Desktop
copy "%USERPROFILE%\Desktop\Chrome.lnk" C:\Users\Public\Desktop

阻止选手访问外网

使用 Windows 防火墙完成,请根据您服务器的实际 IP 地址调整过滤网段:

1
2
3
echo Setting up Firewall
C:\windows\system32\netsh advfirewall set allprofiles state on
C:\windows\system32\netsh advfirewall firewall add rule name="oj" dir=out protocol=any action=block remoteip=0.0.0.0-1.1.1.0,1.1.1.2-172.0.0.0,173.0.0.1-192.168.0.0,192.169.0.0-255.255.255.255

阻止选手更改 USB 设备

看情况设置。有的时候会带来一些麻烦,比如 USB 鼠标键盘线松了再插回去就不识别了。

1
2
echo Disabling USB Stor
C:\windows\system32\reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\UsbStor /v Start /t REG_DWORD /d 4 /f

创建选手用户

创建一个名为 Contestent 的普通用户,为其他账户设置密码:

1
2
3
4
5
6
echo Configuring Users
C:\windows\system32\net user administrator /active:yes
C:\windows\system32\net user Administrator a_strong_password
C:\windows\system32\net user %USERNAME% a_strong_password
C:\windows\system32\net user Guest /active:yes
C:\windows\system32\net user Contestent /add

由于有的电脑默认登陆的是 Administrator,还有部分机房是 Lenovo 之类的用户名,因此两个账户都设置密码。

配置完成后,手工切换到参赛选手账户。

赛中的故障处理

一般故障处置

比赛中难免因为拉扯鼠标、键盘导致 USB 线松动,这个时候我们的解决方案是工作人员暂时切回管理员账户,启用 USB 识别键鼠后再封禁切回比赛选手账户。

启用 USB 的指令:

1
C:\windows\system32\reg add HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\UsbStor /v Start /t REG_DWORD /d 3 /f

禁用防火墙的指令:

1
C:\windows\system32\netsh advfirewall set allprofiles state off

准备冗余机位

有时,可能出现选手机中场无法使用的情况,可以提前准备几台额外的选手机作为冗余。当遇到无法及时解决的电脑故障时,切换到备用的机位。

准备比赛

一般来说,校赛一般会分为热身赛和正式赛两场。每场比赛开始前,您需要做一些准备工作。

下发测试数据

这个环结主要是将比赛题目的测试数据提前发送到各个 judgehost,需要占用较高的网络带宽。这可以加速比赛开始后各个题目的评测。

您可以从对应的比赛页面,选择 “Heat up judgehosts with contest data” 进行评测预热。

此时需要通过网络传输大量数据,可能会有 judgehost 出现掉线的现象,但这无需担心:在拉取完评测数据后,judgehost 会恢复正常的上线状态。

激活比赛

比赛开始前,请确保在 DOMjudge 网页中激活(activate)相应的比赛。

检查打印

打印是外部系统,并且一般由技术人员的电脑负责从网络接受打印请求。请务必记得在此时启动您的打印服务器/xcpc-tools.

此外,连接校园网的电脑的 IP 一般不是固定的,也许会在重新连接网络后发生地址变动。如有这种情况,请及时更改打印脚本中配置的网络地址。

您可以从 DOMjudge Jury Interface / Print 页面中选择一个文件尝试打印,以测试系统打印是否正常工作。

配置 icpctools

icpctools 包括多个部分,本文只会用到 CDS (Contest Data Server), Presentation Admin, Presentation Client 以及 Resolver 几个部分。

在比赛开始前的准备阶段,我们需要先启动 CDS, 并在所需的显示屏上使用正确的配置打开 Presentation Client. 这样,我们稍后可以使用 Presentation Admin 工具设置各个显示屏的展示内容,例如倒计时、榜单、评测队列等。

请先从 icpctools 的 GitHub Releases下载符合您 CDS 版本的各种工具备用。

点击对应版本的 Assets 可以看到各种工具的下载列表。一般来说,您只需下载对应工具的 .zip 后缀的压缩包即可。

启动 CDS

前面我们已经创建了一个用于 CDS 的 docker-compose.yml,现在请将 DOMjudge 中对应比赛的 ID 替换文件中的 $cid 变量。然后,在存放该文件的路径下执行指令将其启动。

1
sudo docker compose up -d

如果您之前已经让它为其他比赛服务过(例如正式赛时,已在热身赛启动过 CDS),建议您首先应停止并销毁先前的 CDS 实例:

1
sudo docker compose down

如果 CDS 配置无误,则稍后您可以通过 https://服务器IP:8443 访问 CDS 的管理页面。您可以使用您先前在 accounts.yaml 中配置的 admin 账号进行登录。

启动 Presentation

这一步需要在各个需要展示的电脑上运行 Presentation Client, 以启动显示板。您必须确保这些电脑可以通过网络连接到 CDS.

编写脚本启动

Presentation Client 本身已带一个 client.bat,但是我们需要做一些额外工作将其启动。

BAT 文件首先设置 ICPC_FONT 环境变量,否则默认的内置字体无法正常显示中文。

1
set ICPC_FONT="Microsoft Yahei"

然后使用 client.bat 启动 Presentation Client,命令格式为:

1
.\client.bat <CDS地址> <账号> <密码> [其他选项]

账号密码请使用 accounts.yaml 中配置的 presentation 账户的账号密码。不要使用其他账户,以免排行榜展示出现问题。

例如,您的 CDS 运行在 192.168.1.233 的 8443 端口上,比赛的 ID 为 3,则您可以使用以下脚本启动:

1
2
set ICPC_FONT="Microsoft Yahei"
.\client.bat https://192.168.1.233:8443/api/contests/3/ presentation your_password

如果您使用 PowerShell (.ps1 脚本),则您应使用 $env:ICPC_FONT="Microsoft Yahei" 语句设置 ICPC_FONT 环境变量。

有时,用于展示的电脑连接了多个屏幕,这时您可以使用 --display 选项指定目标显示屏的序号,例如:

1
.\client.bat https://cds presentation your_password --display 2

还有其他的选项,请参考 Presentation Client 文档

检查 Java 环境

Presentation Client 运行需要 Java 环境,请先测试目标机器上的 java 指令是否存在。

如果不存在,您可以下载一个 OpenJDK 并解压,然后配置系统的 PathJAVA_HOME 等环境变量。

icpctools 目前使用 JDK 17 构建。OpenJDK 17 已经标记为 Archived, 但您仍可以在 Archived Releases 下载它。

运行脚本

将您上面编写的脚本保存为 start.bat,和 client.bat 放在同一目录下。

这样您在将 Presentation Client 拷贝到电脑上后可以直接双击 start.bat 文件启动。您可以根据需要在每台电脑上调整脚本的内容,例如有时您需要使用选项指定 Client 的名称,以便在控制时区分不同的显示屏,否则他们在管理端将显示自己的 IP 地址。

启动 Presentation Client 需要一定时间,会在运行 bat 后卡一会儿,请耐心等待。
如果长时间未出现展示工具,或者一段时间后工具自行退出,请检查 logs 文件夹下的日志,查看是否发生了错误。

启动 Presentation Admin

Presentation Admin 工具一般启动在技术/管理人员的电脑上,请确保您的电脑可以访问 CDS.

在 presentationAdmin 的目录下,使用以下指令启动:

1
.\presAdmin.bat <CDS地址> <账号> <密码>

此处的账号密码使用前面 accounts.yaml 中配置的 presAdmin 账号。CDS 地址和前面 Presentation Client 启动时的一致。

启动 Presentation Admin 后,界面左侧会显示已连接的 Presentation Client 的转播画面。界面右侧是可以选择的展示内容,您可以将展示内容拖动到左侧的显示屏中以更改指定显示屏的展示内容。

您可以在比赛中随时调整显示屏的内容,便于在场选手了解比赛开始时间、当前榜单状态等信息。

比赛中

比赛中除了解决故障以外,一般不会有太多的技术工作。

监控系统状况

  • 检测评测压力,如果评测队列一直过长,请考虑添加评测机(但比赛签到阶段队列稍微长一些是正常的)
  • 留意评测机是否有异常,评测结果是否有异常,及时重启故障评测机
  • 关注打印机、小票机的纸张情况,及时添纸和更换纸卷

处理 Clarifications

这个一般交给各个题目的出题人回复。可以创建一个专用的 Jury 权限账户,分发给各个裁判进行 Clarifications 的回复。

处理题目变更

一般题目的评测数据在开赛前就已经确定了,但是不免会有题目数据/标答出锅的情况,这时需要修正题目数据并重测先前被判定为未通过的提交。

修正题目

从 Jury Interface / Problems 进去找到需要修改的题目,点击 Edit, 拉到最下面重新导入新的题目包,记得选择题目对应的比赛。
Update Problem

进行重测

在 rejudgings 页面点击 Add new rejuding,选择重测范围,然后点击 Save 进行范围重测。
Rejudgings
重测后,结果不会立即生效,而是需要在对应重测页面确认应用重测的结果,才会生效。

调整展示内容

比赛中可以使用 Presentation Admin 调整各个显示器的展示内容。临近比赛结束时,可以将展示内容更改为比赛的剩余时间。

附件的发放

有时在开赛后需要发送额外的电子附件,但是又没有配置其他的服务器,可以选择一道赛题,添加附件供参赛选手下载。不建议发送很大的附件。

比赛后

关闭代码提交

比赛结束后,可以选择关闭提交功能。关闭后,选手将不能继续提交(默认情况下,选手可以继续提交,但不计入排行,也无法看到评测结果)。
Disable Submit

finalize 比赛

确认比赛结果不会再产生变更后,在 DOMjudge 的对应比赛页面点击 finalize,表示比赛不再更新。

配置奖项

下载 icpctools 中的 resolver 工具,双击 awards.bat 启动奖项配置工具,出现下图界面:
Awards Connect
URL 输入和前面 Presentation 一样的网址,输入 accounts.yaml 中配置的 admin 账号密码进行连接。连接后可以对队伍的奖项进行可视化配置。配置完成后,请点击 Upload 上传奖项设置。

有时,Awards 工具会提示 “Contest not done updating”,此时可以尝试进入网页 CDS,选择 “End update” 后再配置奖项。

如果在线配置不成功,或者有离线滚榜需求也可以参考 cn-xcpc-tools的说明 导出 Event Feed, 进行离线奖项配置。

滚榜

滚榜用的电脑需要 Java 环境,并且也需要提前设置字体,请在 resolver 的目录打开终端,先设置字体。

如果终端是命令提示符,请执行:

1
set ICPC_FONT="Microsoft Yahei"

如果终端是 PowerShell,请执行:

1
$env:ICPC_FONT="Microsoft Yahei"

然后启动 resolver, 账密使用 admin 账户:

1
.\resolver.bat <CDS地址> <账号> <密码>

等待 resolver 启动完成,即可开始滚榜。

请务必提前在用于滚榜的电脑上测试是否可以正常走完滚榜的全流程。
如果队伍数较多,请更改 resolver.bat 中的 JVM 内存大小设置,确保 Java 虚拟机有充足的内存!默认配置为 -Xmx1024m 即 1024MB.

解冻榜单(可选)

在结果公布完毕之后,您可以从 DOMjudge 在 Contest 页面中点击 unfreeze 解冻榜单,这样公共榜单上将会显示最终的结果。