「BUAA OO Unit 1 HW1」面向测试小白的简易评测机

Posted by saltyfishyjk on 2022-03-07
Words 1.4k and Reading Time 6 Minutes
Viewed Times

「BUAA OO Unit 1 HW1」面向测试小白的简易评测机

声明:本评测机所使用数据生成来自郭鸿宇同学,这对本评测机非常重要

[TOC]

Part 0 前言

笔者的配置与环境

  1. Windows10家庭版
  2. Pycharm 2021.3.2
  3. Anaconda1.9.7,其中用于python项目的python版本为3.6,但是应该是python3就可以
  4. IDEA 2021.3.2

面向人群

所有人,无论是否有python基础或者评测机搭建经验。

定位

基于本篇博客,您可以从零迅速搭建一个适合您的评测机,并且对您的项目路径没有要求。得益于数据输入输出和数据生成模块的解耦合,您可以快速迁移本评测机的输入输出,并更换您需要的数据生成模块,提高了泛用性。

Part 1 准备工作

  1. 若没有,则安装Anaconda,并安装一个python3的环境,这将在Part5附录部分介绍
  2. 若没有,则安装IDEA和Pycharm

Part 2 获取java jar包

目的

为了避免不同同学的Java项目结构目录、依赖包等的不同导致的无谓的麻烦,将Java项目打包为jar包,方法可移植性强

过程

  1. 在IDEA中创建项目,并将代码置于其中,测试可以运行即可。如果有依赖包,则需要导入依赖包。

  2. File ->Project Structure->Artifacts->+->JAR->From modules with dependencies...

  3. Main Class中选中程序入口类->OK->Cancel

  4. 修改Name(也可以不改)->Apply->OK

  5. Build->Build Artifacts,然后在其中选择刚才Name的项,然后Build

  6. 在项目目录/out/artifacts/Name下可以找到生成的jar包

须知

对于本次作业,课程组提供的官方输入输出包需要被注释掉,同时需要自行将原MainClass中的Scanner切换回标准的Scanner SCANNER = new Scanner(System.in)。同时,本评测机暂不支持预解析模式输入。

Part 2 修改评测机参数

pipline.py

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
import sympy # 如果报错显示没有这个包,就需要导入
from xeger import Xeger
import random
import subprocess
from subprocess import STDOUT, PIPE
from gendata import genData


def execute_java(stdin):
cmd = ['java', '-jar', 'archer.jar']# 更改为自己的.jar包名
proc = subprocess.Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
stdout, stderr = proc.communicate(stdin.encode())
return stdout.decode().strip()


x = sympy.Symbol('x')
X = Xeger(limit=10)
cnt = 1

while True:
cnt = cnt + 1
if cnt % 1000 == 0:
print(cnt)
poly, ans = genData()
#print(poly)
f = sympy.parse_expr(poly)
strr = execute_java(poly)
#print(strr)
g = sympy.parse_expr(strr)
if sympy.simplify(f).equals(g) :
print("AC : " + str(cnt))
else:
print("!!WA!! with " + "poly : " + poly + " YOURS: " + strr)

上述代码中需要改jar包为自己的包名

其他不修改即可正常使用,也可根据需求自行修改。

gendata.py

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
"""
Auther: GHY
Date: 20222022/3/5
"""

import random
import sympy

intPool = [0,1,2,3,4] # 常量池
hasWhiteSpace = False # 是否加入空白字符
hasLeadZeros = False # 数字是否有前导零,如果传入sympy的表达式中数字有前导零,sympy将无法识别
maxTerm = 10 # 表达式中的最大项数
maxFactor = 3 # 项中最大因子个数
specialData = ["1","x-x","-1"] # 可以放一些特殊数据
globalPointer = 0

def rd(a,b) :
return random.randint(a,b)

def getWhiteSpace():
if hasWhiteSpace==False:
return ""
str = ""
cnt = rd(0,2)
for i in range(cnt):
type = rd(0,1)
if type==0:
str = str + " "
else:
str = str + "\t"
return str


def getSymbol():
if rd(0,1)==1:
return "+"
else:
return "-"

def getNum(positive):
result = ""
integer = intPool[rd(0,len(intPool)-1)]
iszero = rd(0,2)
for i in range(iszero):
result = result + "0"
if hasLeadZeros==False:
result = ""
result = result + str(integer)
if rd(0,1)==1:
if positive==True:
result = "+" + result
else:
result = getSymbol() + result
# print("num:"+result)
return result


def getExponent():
result = "**"
result = result + getWhiteSpace()
case = rd(0,2)
if rd(0,1)==1:
result = result + "+"
if case==0:
result = result + "0"
elif case==1:
result = result + "1"
else:
result = result + "2"
# result = result + getNum(True)
# print("exponent:"+result)
return result


def getPower():
result = "x"
if rd(0,1)==1:
result = result + getWhiteSpace() + getExponent()
# print("Power:"+result)
return result


def getTerm(genExpr):
factorNum = rd(1,maxFactor)
result = ""
if rd(0,1)==1:
result = getSymbol()+getWhiteSpace()
for i in range(factorNum):
factor = rd(0,2)
if factor==0:
result = result + getNum(False)
elif factor==1:
result = result + getPower()
elif factor==2 and genExpr==True:
result = result + getExpr(True)
else:
result = result + "0"
if i < factorNum-1:
result = result + getWhiteSpace() + "*" + getWhiteSpace()
# print("term:"+result)
return result


def getExpr(isFactor):
termNum = rd(1,maxTerm)
result = getWhiteSpace()
genExpr = True
if isFactor==True:
genExpr = False
for i in range(termNum):
result = result + getSymbol() + getWhiteSpace() + getTerm(genExpr) + getWhiteSpace()
if isFactor==True:
result = "(" + result + ")"
if rd(0,1)==1:
result = result + getWhiteSpace() + getExponent()
# print("Expr:"+result)
return result


def genData():
global globalPointer
if globalPointer<len(specialData):
expr = specialData[globalPointer]
globalPointer = globalPointer + 1
else:
expr = getExpr(False)
x = sympy.Symbol('x')
simplifed = sympy.expand(eval(expr))
return str(expr),str(simplifed)


x = sympy.Symbol('x')
fx = "+x**+0*x**0++3++x**+1*+1"
y = sympy.expand(eval(fx))
print(y)

上述代码不修改即可正常使用,也可根据需求修改数据生成方式。

Part 3 评测机架构

本评测机需要将jar包、pipline.py和gendata.py放在同一目录下即可,无其他要求。

对于多个jar包,允许在多个文件夹中分别存放评测机,同时测试运行。

Part 4 有待改进的地方

  1. Part2中要求注释掉官方包及切换回Scanner的原因是,目前笔者没有办法在获取输出时跳过第一行,但这应该可以做到。

Part 5 附录:如何从0配置本评测机可运行的 python+Anaconda 环境

一、下载pycharm:

此步仅执行连接中步骤1.2.3,即不进行后续python安装即环境变量的配置。仅安装pycharm。
https://www.runoob.com/w3cnote/pycharm-windows-install.html

二、Anaconda安装教程

如果没有特定版本需求,可选择文中版本安装,此版本默认安装python3.7
https://zhuanlan.zhihu.com/p/75717350

三、创建python项目时关联Anaconda的python.exe

仅参考步骤五即可
https://www.cnblogs.com/yuxuefeng/articles/9235431.html

四、安装 xeger库:见链接方法一

https://www.cnblogs.com/ShineLeBlog/p/10893419.html

五、更新sympy库

同上,在此界面取消Anaconda模式后,找到sympy库双击。

勾选 Spectify version ,选择1.9版本,点击 Install Package。


This is copyright.