「BUAA OO Unit 1 HW1」面向測試小白的簡易評測機
「BUAA OO Unit 1 HW1」面向測試小白的簡易評測機
宣告:本評測機所使用資料生成來自郭鴻宇同學,這對本評測機非常重要
目錄Part 0 前言
筆者的配置與環境
- Windows10家庭版
- Pycharm 2021.3.2
- Anaconda1.9.7,其中用於python專案的python版本為3.6,但是應該是python3就可以
- IDEA 2021.3.2
面向人群
所有人,無論是否有python基礎或者評測機搭建經驗。
定位
基於本篇部落格,您可以從零迅速搭建一個適合您的評測機,並且對您的專案路徑沒有要求。得益於資料輸入輸出和資料生成模組的解耦合,您可以快速遷移本評測機的輸入輸出,並更換您需要的資料生成模組,提高了泛用性。
Part 1 準備工作
- 若沒有,則安裝Anaconda,並安裝一個python3的環境,這將在Part5附錄部分介紹
- 若沒有,則安裝IDEA和Pycharm
Part 2 獲取java jar包
目的
為了避免不同同學的Java專案結構目錄、依賴包等的不同導致的無謂的麻煩,將Java專案打包為jar包,方法可移植性強。
過程
-
在IDEA中建立專案,並將程式碼置於其中,測試可以執行即可。如果有依賴包,則需要匯入依賴包。
-
File
->Project Structure
->Artifacts
->+
->JAR
->From modules with dependencies...
-
Main Class
中選中程式入口類->OK
->Cancel
-
修改
Name
Apply
->OK
-
Build
->Build Artifacts
,然後在其中選擇剛才Name
的項,然後Build
- 在專案目錄/out/artifacts/
Name
下可以找到生成的jar包
須知
對於本次作業,課程組提供的官方輸入輸出包需要被註釋掉,同時需要自行將原MainClass
中的Scanner
切換回標準的Scanner SCANNER = new Scanner(System.in)
。同時,本評測機暫不支援預解析模式輸入。
Part 2 修改評測機引數
pipline.py
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
"""
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 有待改進的地方
- 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。