一个简单的本地判题脚本

在做程序设计作业的时候,题目经常是要输入 10 个数字,但用不起 Matrix 的我只能手动输入,不但麻烦,而且也很难模拟随机过程,想过做一个 OJ (在线判题平台),但又苦于不会用 Docker ,思来想去,就用 Python 写了个本地判题脚本,虽然还不能防恶意代码,也无法实现内存检查,但基本的输入输出还是能够做到,供君一乐。


源码

Windows下

鉴于本人是追求实用(能跑就行),同理猜测读者也不关心这到底怎么实现,或者说不着急关心,于是直接附上 Windows 环境下的 Python 源码,开盒即用,只需要你有一点 Python 的基础,会装 subprocess 和 tqdm 库就行,然后在脚本所在的目录新建一个名为标准代码的文件夹,并在里面放入一个std.c作为测试输出的基准参照,同理新建一个测试代码的文件夹并放入test.c作为被测试的代码,同时安装好gcc,运行脚本,就能大功告成了。

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
import subprocess
import random
import sys
from tqdm import tqdm

def random_int_list(start, stop, length):
start, stop = (int(start), int(stop)) if start <= stop else (
int(stop), int(start))
length = int(abs(length)) if length else 0
random_list = []
for i in range(length):
random_list.append(random.randint(start, stop))
return random_list

def iotest(filename, path, data):
obj = subprocess.Popen([filename], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=path, encoding="utf-8",shell=True)
obj.stdin.write(data)
out_info, out_error = obj.communicate() # 简单写法,out_info:标准输出
# print(out_info,out_error)
return out_info

if __name__ == '__main__':
stdpath = "%s\\标准代码\\" % sys.path[0] # 标准代码所在路径
testpath = "%s\\测试代码\\" % sys.path[0] # 测试代码所有路径
#编译标准及测试代码
result = subprocess.check_output("gcc -std=c99 -o std std.c", shell=True, cwd=stdpath)
result = subprocess.check_output("gcc -std=c99 -o test test.c", shell=True, cwd=testpath)

f = open('%s\测试结果.txt' % sys.path[0], 'w+', encoding='utf-8', newline="")
print('随机测试中...')
pas=0 # 通过次数
freq=10 # 测试次数
for index in tqdm(range(freq)):
# 生成测试数据
rtest = random_int_list(0, 99, 10)
s = ''
for i in rtest:
s = "%s%s " % (s, i)
s = "%s\n" % s
# 进行测试
output = iotest(".\\test.exe", testpath, s)
stdoutput = iotest(".\\std.exe", stdpath, s)
f.write("随机测试 - r,%d数据点\n"%index)
f.write("标准输入\n%s" % s)
f.write("实际输出\n%s\n" % output)
f.write("期望输出\n%s\n\n" % stdoutput)
if output==stdoutput:
f.write('通过「随机测试 - r,%d数据点」测试点\n\n'%index)
pas=pas+1
else:
f.write('未通过「随机测试 - r,%d数据点」测试点\n\n'%index)
f.close()
print('随机测试 %d/%d'%(pas,freq))
print('测试完成')

同时附上样例标准代码:

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
57
58
59
#include <stdio.h>
#define N 10
void inputarray(int *arr);
void handlearray(int *arr);
void outputarray(int *arr);
void swap(int *p,int *q);
int main()
{
int array[N]= {0};
inputarray(array);
handlearray(array);
outputarray(array);
return 0;
}
void swap(int *p,int *q)
{
int temp=*p;
*p=*q;
*q=temp;
}
void handlearray(int *arr)
{
int *p=arr;
int max_index=0;
int min_index=0;
int max=arr[0];
int min=arr[0];
for(int i=1;i<N;i++)
{
if(*(p+i)>max)
{
max=*(p+i);
max_index=i;
}
if(*(p+i)<min)
{
min=*(p+i);
min_index=i;
}
}
swap((p+max_index),(p+9));
swap((p+min_index),(p+0));
}
void inputarray(int *arr)
{
int *p=arr;
for(int i=0; i<N; i++)
{
scanf("%d",(p+i));
}
}
void outputarray(int *arr)
{
int *p=arr;
for(int i=0; i<N; i++)
{
printf("%d ",*(p+i));
}
}

以及样例测试代码:

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
#include <stdio.h>
int main()
{
void inv(int *x, int n);
int i, a[10];
for (i = 0; i < 10; i++)
scanf("%d", &a[i]);
//printf("\n");
inv(a, 10);
//printf("The array has been inverted:\n");
for (i = 0; i < 10; i++)
printf("%d ", a[i]);
//printf("\n");
return 0;
}

void inv(int *x, int n)
{
int *i, max, min, p, q, *c, *d;
max = *x;
min = *(x + 1);
c = x + 0;
d = x + 1;
for (i = x; i < x + 10; i++)
if (*i > max)
{
max = *i;
c = i;
}
for (i = x; i < x + 10; i++)
if (*i < min)
{
min = *i;
d = i;
}
p = *x;
*x = *d;
*d = p;
q = *(x + 9);
*(x + 9) = *c;
*c = q;
}

Linux 下的 Python 源码

一个现象就是, Linux 下进行测试的速度明显比 Windows 下快,我测试的时候两者甚至相差 100 余倍,其中原因可留给读者细究。

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
import subprocess
import random
import sys
from tqdm import tqdm

def random_int_list(start, stop, length):
start, stop = (int(start), int(stop)) if start <= stop else (
int(stop), int(start))
length = int(abs(length)) if length else 0
random_list = []
for i in range(length):
random_list.append(random.randint(start, stop))
return random_list

def iotest(filename, path, data):
obj = subprocess.Popen([filename], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=path, encoding="utf-8")
obj.stdin.write(data)
out_info, out_error = obj.communicate() # 简单写法,out_info:标准输出
# print(out_info,out_error)
return out_info

if __name__ == '__main__':
stdpath = "%s/标准代码/" % sys.path[0] # 标准代码所在路径
testpath = "%s/测试代码/" % sys.path[0] # 测试代码所有路径
#编译标准及测试代码
result = subprocess.check_output("gcc -std=c99 -o std std.c", shell=True, cwd=stdpath)
result = subprocess.check_output("gcc -std=c99 -o test test.c", shell=True, cwd=testpath)

f = open('%s/测试结果.txt' % sys.path[0], 'w+', encoding='utf-8', newline="")
print('随机测试中...')
pas=0 # 通过次数
freq=100 # 测试次数
for index in tqdm(range(freq)):
# 生成测试数据
rtest = random_int_list(0, 99, 10)
s = ''
for i in rtest:
s = "%s%s " % (s, i)
s = "%s\n" % s
# 进行测试
output = iotest("./test", testpath, s)
stdoutput = iotest("./std", stdpath, s)
f.write("随机测试 - r,%d数据点\n"%index)
f.write("标准输入\n%s" % s)
f.write("实际输出\n%s\n" % output)
f.write("期望输出\n%s\n\n" % stdoutput)
if output==stdoutput:
f.write('通过「随机测试 - r,%d数据点」测试点\n\n'%index)
pas=pas+1
else:
f.write('未通过「随机测试 - r,%d数据点」测试点\n\n'%index)
f.close()
print('随机测试 %d/%d'%(pas,freq))
print('测试完成')
作者

未央

发布于

2021-12-28

更新于

2024-03-26

许可协议

评论