2020年了,为了 blog 不咕,还是要写点什么。
这是一个补档,记录了 2019 CUSTACM 校队选拔赛前为了校史上首次推出的滚榜活动做的准备。
不过说到为什么要做这个,其实都是一时兴起罢了。
该方案可以被广泛应用于各种 OJ 而不限于 DOMJudge 或 PC^2。我校的 CustOJ 就是基于 OnlineJudge 的。
什么是 ICPC Resolver
ICPC Resolver 是 ICPC Tools 中的一员,最初都是用于 ICPC World Finals 的。
如同它一万年不更新的文档所说:
The ICPC Resolver is a tool for graphical animation of contest results. It shows the final runs submitted
during a contest in an interesting way, and leads up to display of the award winners.
ICPC Resolver 可以在比赛结束后,用于展示封榜时期内的比赛结果变化,也就是俗称的滚榜。
长期以来,在 *cpc 现场赛,滚榜都是一项传统艺能。不过也有的赛区因为各种原因不滚榜/滚不了榜,令人发指(指省赛)。
如果身为选手,观看滚榜是非常激动人心的,尤其是在铜铁/银铜/金银交界的区域,看到自己队名的时候。当然,作为万年铜首(Cust),我已经麻木了。所以才有勇气直视 Resolver(雾)
如何部署 ICPC Resolver
No~ No~ No~
下载解压后你会发现,他连个能跑的 demo 都不给,这怎么整?
至于文档,乍一看运行方法倒是有很多,什么 Event Feed 啦,CDP/CDS 之类的,仔细阅读就会陷入递归读文档的深渊中。更过分的是,向前挖了几个版本,文档居然长得都几乎一毛一样。至少从文档上,并看不出历代 Resolver 的具体数据要求的区别。
而真实的 Resovler 文档,大概散落在 PC^2 文档里的某个角落。当然,PC^2 给的文档,只介绍了怎么把 PC^2 的数据喂给 Resolver。DOMJudge 大概也同理。
于是求助搜索引擎。根据我们的实际需求,排除了 CDP 的运行方式,最后参考了这篇博文里提供的数据。此处要感谢东北大学。
题外话: 这个数据来自16沈阳站热身,记录了我的第一口大锅: 帮学长把一个最短路 sb 题读成了一个不可做题
如何正确运行 ICPC Resolver
数据格式
虽然有了数据,一开始也是跑不起来。根据 Exception 和凌乱的文档瞎猜了一些改法(比如把 run 改成 submission,跑是能跑起来了,不过跑起来是一个完全没有数据,只有队名的情况。中间略去许多的坑,得到的结论是: 使用了过高版本的 Resolver (干!)
枚举了数个过往的 dev 版本,最后确定了使用 1.1.0dev.1057。这个版本可以正确兼容目前手里的数据。
之后做的事情,其实是对网上下载来的数据做一个瘦身。不负责任的猜测,那份数据是 PC^2 自动生成的。再略去来回反复枚举参数的操作,最后得到了如下的结构
1 | <contest> |
首先是比赛的信息,标题、总时长、封榜时间、罚时信息是必要的。
之后是题目,每个题目给个id
就行。
再之后是队伍信息,每个队伍有个id
,而队伍名称用university
代替,可能是因为那个版本的 Resolver 只滚学校名称(毕竟 World Finals)。
用run
代表提交信息(这部分新版本已经完全不一样了),每次提交有个id
(使用整数类型,而不是 hash string)。problem
和team
代表该次提交哪支队伍了哪题,里面填的是对应的id
,很好理解。time
是从 0 开始以秒为单位的时间戳。judged=true
是必要的,否则会抛异常。solved
和penalty
是两个属性,合在一起可以代表提交的结果。只有 Accepted 中的solved=true
且penalty=false
,其他都是提交不通过,solved=false
。其中 Compilation Error 不计罚时,所以penalty=false
,否则penalty=true
。最后可能有first-to-solve=true
的属性,代表该次提交是该题的一血提交。但是不需要first-to-solve=false
,切记。
award
代表奖项,这里需要人工颁下奖。team
代表获奖队伍的id
,type
有winner
、medal
、first_to_solve
三种,citation
是获奖的详细介绍。一支队伍允许获三个type
不同的奖。
中文字体
老外开发的软件,对中文支持不是很好(等于没有)。Resolver 默认使用的是 Helvetica,一个古老而经典的拉丁字母无衬线字体。
根据搜索引擎,据说支持通过设置环境变量ICPC_FONT
来调整使用的字体,但实测没有效果。估计是高版本 Resolver 的 feature。
不过,通过解压resolver.jar
包发现,字体是打包在里面的。只要将里面的字体替换成有中文的,就有办法支持中文。没有编码问题真是太感动了
原本的字体文件名叫HELV.PFB
。pfb
是一个古老的字体格式。将我们已有的字体(基本上都是ttf
格式)通过在线工具转成pfb
,并命名成HELV.PFB
放在font
文件夹下,之后通过以下命令即可将我们想要的字体注入进 jar 包。
1 | jar -uvf resolver.jar font |
略过一番折腾和反复重试(不是所有中文字体都很好地适配 Resolver,非常容易出现文字重叠/截断或其他奇奇怪怪的事情),使用了自己的 Mac 里不知道哪里掏出来的STHEITI.ttf
。这个字体看起来效果还 OK。
不过还是有问题。有一些特殊的字符,显示效果不好,比如提交信息中间的-(两边貌似有空格)。于是尝试组合字体。
随手找了一个合并字体文件的在线工具,将原本的HELV.PFB
里的字体(需要先转成ttf
)和STHEITI.ttf
合并。
由于 Helvetica 有点古老,为了显示效果,使用 Right Join,即以STHEITI.ttf
为主,没有的字符从HELV.PFB
获取,得到的mixed.ttf
转成pfb
注入resolver.jar
经过这样一番折腾,终于得到了可用的 Resolver。这里提供已经折腾完的版本 - Github
运行
首先我们假设文档说的是真的。所以通过命令启动 Resolver。
1 | ./resolver.sh sample.xml |
我只验证了 fast 参数,是好用的,例如这样加速 10 倍滚榜
1 | ./resolver.sh sample.xml --fast 0.1 |
其他参数可能也是真的。以上命令适用于 Linux/MacOS,Windows 使用resolver.bat
同理,毕竟是跨平台的 Java 项目。
另外,滚榜中的一些键盘操作,也可能是真的。反正按空格真的可以让它一直滚。
如何在 CustOJ 上实装
其实有了 Resolver 所需的数据格式,剩下的只是大模拟而已。把 OJ 的题目和提交记录,通过字符串处理成所需的格式,然后再手动填一下谁获了奖,滚榜就算 ready 了。
No~ No~ No~
不知道怎么就从大模拟变成了一坨 SQL (大草
大概是有点懒得加接口专门搞这玩意,并且也不想写个爬虫(自己爬自己是怎么回事)再把数据 format 起来,所以最简单粗暴的方法当然是~操库!
有一说一,PostgreSQL 还是挺好操的。首先它原生支持查询结果以xml
格式返回,这就方便了许多。对应的命令是xmlforest
。其他 RDBMS 也同理,感觉基本都有。
之后就是写查询了。偶尔把逻辑写在 SQL,感觉也不错,反正上面也没有其他语言对接,直接就出结果了。
这里需要两条查询,一条查询所有的参赛队伍,还有一条查询所有的提交。当然比较流氓的写法就是两条查询UNION ALL
起来,那搞一次就行了。
整句SQL写了不到20行,可以接受。为避免透露人尽皆知的 CustOJ 表结构,这里就不放了。不过 Github Repo 里有这段 SQL。
查询的逻辑,按实际需求做就行,要注意的点大概有这几条
- 筛选有提交的参赛队伍,以防滚榜从一堆鸽子开始
- 提交记录过滤掉验题的(如果有的话)
- 查一血的时候,不如多 join 一次,而不是嵌套查询
对于 PostgreSQL 来说,查询结果保存在文件挺方便的,利用\o
指令即可。
如果 DB 端口不对外开的话,这些查询可以在服务器上做,之后scp
下来(什么? 没有scp
?? OJ 平时都靠人肉运维吗???)
之后把结果贴进要 resolve 的xml
文件就行。注意上面说的,不需要first-to-solve=false
。如果查询里避免不掉,可以批量替换成空串。
后记
虽然是后记,也是后得很后的后记了。
由于比赛举办时不在学校,所以滚榜由学弟代为操作了。我远程操作了比赛结果整理了滚榜数据。
感觉效果还行,让许多本校的、NENU/CCUT 没参加过现场赛的同学体会了滚榜这项 *cpc 传统艺能。据说整场比赛的办赛效果惊动了隔壁 NENU,引来无数大佬砸钱赞助他们的 ACM(?)。
另外,这套单独的滚榜方案显然没有 JLU - yanger 的全套 DOMJudge + ICPC Tools 来得完善。今年我校要办赛,首先是希望有滚榜吧,其次不要像去年 EC Final 一样因为技术原因把滚榜锅了。像这样的一套备用方案,也算有个底。
对了,首先的首先的首先,希望今年省赛有 Ubuntu!