学校oj的判题系统再一次崩溃了,在测试某些程序时一直显示判题状态。从github上更新了判题程序,实现测试点下载功能的程序也就需要重新修改了。
现将需要注意的点记录如下,用作备忘。
在数据库的solution表中添加两个保存字符串的关键字:
rec:各个测试点的状态
file_path:没有ac的测试点路径,在这里我用逗号分隔各个数据的路径,网页解析的时候拆分就行了。
在源代码中不同的数值代感受测试点不同的返回结果,直接保存数字不好操作,我们可以把字符'A'加返回值的字母保存到数据库中。字符串记录各个测试点的测试情况,字符'A'表示当前测试点WT0,字符E'表示当前测试点AC。例字符串"EHHEEE"就表示为第2、第3个测试点超时,其它测试点AC。
#define OJ_WT0 0
#define OJ_WT1 1
#define OJ_CI 2
#define OJ_RI 3
#define OJ_AC 4
#define OJ_PE 5
#define OJ_WA 6
#define OJ_TL 7
#define OJ_ML 8
#define OJ_OL 9
#define OJ_RE 10
#define OJ_CE 11
#define OJ_CO 12
#define OJ_TR 13
judged_client.cc程序的功能就是不断是从数据库中读取待评测的记录,然后调用judged程序测试,然后将judged返回的结果再写入到数据库中。
char rec[100]; //最多只能存100个测试点的状态
char file_path[5000];
judged_client.cc可能是多线程并发的(judged程序是多线程运行的,但是不清楚judged_client.cc是不是多线程的),定义成全局变量可能会出错,不过我们学校的oj对并发容量的要求并不高,目前来说还没有问题。
先定以到以下的代码片段:
if (oi_mode) {
if (ACflg == OJ_AC) {
++pass_rate;
}
if (finalACflg < ACflg) {
finalACflg = ACflg;
}
ACflg = OJ_AC;
}
很明显,上述代码片段是用来统计分数,pass_rate变量统计通过的数量,ACflg为测试点状态。
将程序改为如下所示:
if (oi_mode) {
rec[num_of_test-1]='A'+ACflg;//edit by zhc
if (ACflg == OJ_AC) {
++pass_rate;
}
else{ //edit by zhc
strcat(file_path,",");
strcat(file_path,infile);
}
if (finalACflg < ACflg) {
finalACflg = ACflg;
}
ACflg = OJ_AC;
}
定位到 _update_solution_mysql 函数之后,修改写入的sql语句。
未修改的代码:
if (oi_mode) {
sprintf(sql,
"UPDATE %s SET result=%d,time=%d,memory=%d,pass_rate=%f,judger='%s',judgetime=now() WHERE solution_id=%d",
tbname,result,time,memory,pass_rate,judger,solution_id);
}
修改以后的代码:
if (oi_mode) {
sprintf(sql,
"UPDATE %s SET result=%d,time=%d,memory=%d,pass_rate=%f,judger='%s',rec='%s',file_path='%s',judgetime=now() WHERE solution_id=%d",
tbname,result,time,memory,pass_rate,judger,rec,file_path,solution_id);
}
最后就是读取数据库中的数据显示到网页中去了,其实在我实现测试数据下载功能中,最折腾时间的反而是将数据显示到网页上,个人建议在showsource.php的基础上显示测试数据详情。
网页显示效果如下:
judge_client.cc源码中是有记录每个测试点的完成时间的,优化的时候你们可以在solution表中添加一个字段记录每个测试点的使用时间。
修改oj是一个痛并快乐着的过程,这个过程会迫使你去触及以前从未到达的领域,不断地去学习。
上述的功能虽然不是十全十美,但勉强能用,也算是摆脱了总要给学生发题目数据的困扰了。