自己制作一个小小的OJ by darkfish
这个OJ做完之后,并没有做严格的测试,只当自己练练shell编程。On-line Judge用shell script来写实在算不上什么难的事情,毕竟shell script就集合了Linux系统的所有工具,一个小小的OJ又算得了什么,只是过程繁琐了点而已。
下面的OJ只实现了超时处理,并没有处理超内存的情况。因为超时和超内存都是由ulimit这个命令来控制的,需要直接加上就可以了。
下面的OJ还用了gcc-3.3中的检查溢出功能,学校内有fbounds-checking的就只找到了gcc-3.3。
先来规划一下OJ要实现的功能。
给定一个目录,之下有new, run和finished,三个子目录
"oj-dir"
\__new 是测试数据存放目录。存放测试数据格式为input.1、input.2,output.1、output.2……。如果有timelimit.1...则程序运行时间按照timelimit里面的数据来限制,否则是1S。
\__run 编译之后的程序以及结果的存放目录,编译错误放在compile.stderr下面,stderr存放运行的错误信息,比如溢出。运行结果存放在result里面。
\__finished 系统判定结果完毕之后,新建一个同名文件夹,把new里面的所有东西移到文件夹下。
我们的程序如下规划:
1.execute
\__check_process #第一次编译得到compile.stderr以判断CE 和 stderr以判断RE
\__sub_process #第二次编译编译执行得到output time
2.judge #判断AC WA TLE RE
3.ojdaemon #守护进程
execute脚本:
#!/bin/bash
# name : execute
NOWDIR=`pwd`
cd "$1"
DATA=`pwd`
cd "$2"
RUN=`pwd`
TotalInput=`find $DATA -name "input.*" | wc -l`
#---get the timelimit-----------------
if [ -e $DATA/timelimit.$count ]
then
TIMELIMIT=`cat $DATA/timelimit.$count`
else
TIMELIMIT=1
fi
#--end-----
# in this part check the --------------------------------------CE
$NOWDIR/check_process $DATA $RUN $TIMELIMIT $TotalInput
if [ $? -eq 1 ]
then
echo "CE" >> $RUN/result.txt
exit 1
fi
#--end----
#--complie main.c to main in the directory of RUN.--
gcc $DATA/main.c -lm -o $RUN/main 2>/dev/null
for i in `seq 1 $TotalInput`
do
/usr/bin/time -o $RUN/time.$i -f "%e" $NOWDIR/sub_process $DATA $RUN $i $TIMELIMIT
echo "$?" > $RUN/"exitcode.$i"
done
check_process脚本:
#!/bin/bash
DATA=$1
RUN=$2
TIMELIMIT=`expr $3 + 1`
TotalInput=$4
gcc-3.3 -fbounds-checking $DATA/main.c -o $RUN/main_check -Wall 2>$RUN/compile.stderr
grep 'error' $RUN/compile.stderr > /dev/null 2>&1
if [ $? -eq 0 ] #--------CE-----------------
then
exit 1
fi
for i in `seq 1 $TotalInput`
do
ulimit -t $TIMELIMIT
exec $RUN/main_check < $DATA/input.$i >$RUN/output.$i 2>$RUN/stderr.$i
done
exit 0
sub_process脚本:
#!/bin/bash
DATA=$1
RUN=$2
NUM=$3
TIMELIMIT=`expr $4 + 1 `
ulimit -t $TIMELIMIT
exec $RUN/main < $DATA/input.$NUM > $RUN/stdout.$NUM 2>/dev/null
judge脚本:
#!/bin/bash
# name : judge
cd "$1"
DATA=`pwd`
cd "$2"
RUN=`pwd`
TotalInput=`find $DATA -name "input.*" | wc -l`
#The working directory is $RUN
count=1
while [ $count -le $TotalInput ]
do
#------------------------------------------------test RE
grep 'error' $RUN/stderr.$count >/dev/null 2>&1
if [ $? -eq 0 ]
then
echo "$count RE" >> result.txt
let count=$count+1
continue
fi
#------end to test RE
#test time -------------------------------------------TLE
if [ -e $DATA/timelimit.$count ]
then
TIMELIMIT=`cat $DATA/timelimit.$count`
else
TIMELIMIT=1
fi
TIME=`tail -1 $RUN/time.$count | cut -c1`
if [ $TIME -gt $TIMELIMIT ]
then
TIME=`tail -1 $RUN/time.$count`
echo "$count TLE $TIME" >> $RUN/result.txt
let count=$count+1
continue
fi
#----- test time end
#test correction------------------------------------WA/AC
TIME=`tail -1 $RUN/time.$count`
diff $DATA/output.$count $RUN/stdout.$count >/dev/null 2>&1
if [ $? -eq 0 ]
then
echo "$count AC $TIME" >> "$RUN"/"result.txt"
else
echo "$count WA $TIME" >> "$RUN"/"result.txt"
fi
let count=$count+1
done
ojdaemon脚本:
#!/bin/bash
# name : ojdaemon
OJDIR=$1
while :
do
if [ `ls $OJDIR/new | wc -l` != 0 ]
then
FILE=`ls $OJDIR/new`
for i in $FILE
do
echo "start file: $i"
mkdir $OJDIR/run/$i
./execute $OJDIR/new/$i $OJDIR/run/$i
if [ $? != 1 ]
then
./judge $OJDIR/new/$i $OJDIR/run/$i
fi
mv $OJDIR/new/$i $OJDIR/finished/$i
echo "finish file: $i"
done
fi
sleep 1
done
阅读(1152) | 评论(1) | 转发(0) |