online judge(以下简称OJ)是用于acm的在线评判系统,有名的OJ包括有
puk:http://poj.org/
zju:http://acm.zju.edu.cn
等等,还有许多我就不一一列举了....
先来说说OJ的用途,通常,在ACM的比赛中,参赛选手需要根据比赛的题目,提交该题目的编程代码,然后评判端对提交的代码进行评判并给出结论(这个结论可能包括正确,答案错误,超时,编译错误,内存超出等等)。
这里有个需要说明下,在acm的比赛中,数据的输出输入平台是控制台(命令行).....
例如一道最简单经典例子:
题目: A+B Problem
描述
计算 a+b
输入
两个整数 a,b (0<=a,b<=10)
输出
输出a+b的和
输入样例
1 2
输出样例
3
然后选手需要给出实现a+b功能的代码,并正确的输出到控制台。
如:
#include<stdio.h>
int main()
{
int a,b;
while(scanf("%d%d",&a,&b)!=EOF)
{
printf("%d/n",a+b);
}
return 0;
}
然后,我们可以手工对其正确性进行验证,先编译这段代码,然后运行,在屏幕上输入5 6,然后屏幕显示11(这时可以再输入多组数据进行验证)
而对于自动化的评判程序来说,显然,OJ的内核就是评判端的设计。 接下来让我们分析下一个简易的评判端工作流程:
接收提交的代码
||
编译代码 = _编译错误 = 返回编程错误结果
||
运行编译后的程序
||
对输出的结果进行判断
上面这个工作流程我省略了大部分的细节,只是让大家都先对整个流程有个整体的把握。
接着我们再开始说说一个通用的oj一步一步是如何设计实现的。
一.接收代码
这部分可以通过很多途径,也并非本文的要点,在此忽略,抱歉抱歉。。。
二.编译代码
也许习惯在windows下用IDE的童鞋们很少接触命令行编译这东西吧?
没错,我们需要用到的就是命令行编译,在命令行下调用编译器的命令行编译程序,让它来完成编译工作。
举个windows下的例子:我们用微软的vc++的命令行编译工具cl
首先安装好vc++6.0,注意,在安装完成最后的时候,他会提示你是否要更改环境变量,记得把钩钩选上,不然,你得自己手动修改
然后,你可以试试运行cmd打开控制台
准备好一个c/c++程序,在控制台输入“cl c:/test.c”
这时你就会发现目录里多了test.obj和test.exe这两个文件.
test.exe就是编译好的文件,如果你的代码出现问题,cl会把错误提示在控制台上显示出来
你也可以编写代码来编译这个test.c文件
如:
//命令行下编译程序
//system函数已经被收录在标准c库中,可以直接调用
system("cl c:/test.c");
三.运行程序
这是一个简易的OJ系统中的关键部分。
首先,我们需要对这个运行的程序进行计时,若程序超出时间,必须能自动kill它。否则,评判机将可能因为运行程序死循环而停止工作下一步的工作或者同时运行过多死循环的程序而崩溃。。
第二,我们需要把这个程序的输出和输入重定向到文本。
输入流:自动评判机是不会从键盘输入数据到控制台的,所以从键盘的输入需要重定向到文本(我们可以事先写好这个文本的内容),这样,就可以模拟手动从键盘向程序输入数据了。
输出流:在自动评判的时候没有人为介入,所以输出到屏幕显示并无意义,我们需要把原本输出到屏幕的内容重定向输出到文本。而且这样可以对用户的程序输出流进行保存,也方便接下来的答案评判处理
鉴于这部分比较沉长~决定拿出来作为一个单独的篇章来写,有兴趣的童鞋可以等一下下,我会很用力的写好它。。
四.对输出的结果进行判断
这里需要用到第三步骤的输出流重定向的文件。。
我们回头看下第三步骤,重定向输入输出流到文件,也就是说,我们的输入文件是事先根据题目准备好的。
例如前面的 A+B Problem 题目
我们可以事先准备几组测试数据,如
1 2
5 6
8 9
保存在一个文件中(例如:in.text)
然后由in.text得到一个标准答案:
3
11
17
保存在另一个文件中(例如:out.text)
现在,我们在第三步的时候,把in.text重定向到用户提交代码程序的输入流,把输出流重定向到useout.text文件
接下来,我们只需要比较useout.text和out.text的差别,就可判断出用户提交的代码是否正确的了。。^.^
随手写了一个简单的评判比较函数,可以参考下
int f_compare(char *usout,char *stout)
/*===========================================
文件比较
参数:传人两个文件的地址,usout和stout。
功能:判断两个文件是否匹配,正确放回1 错误返回EOF
=============================================*/
{
int ch1,ch2;
FILE *p1,*p2;
p1=fopen(usout,"r");
p2=fopen(stout,"r");
do
{
ch2=fgetc(p2);
ch1=fgetc(p1);
if(ch1 != ch2) return EOF;
}
while(ch2!=EOF||ch1!=EOF);
fclose(p1);
fclose(p2);
return 1;
}
这样,我们一个简易的oj系统就可以完成了。。
接下来,我会把之前完成的windows版本的oj和linux版本的oj陆续发布出来,并做尽可能详细的解释说明,与大家交流探讨