- 分享
python turtle配置
- @ 2024-5-21 16:43:02
可以看这个题目
快速配置一个turtle题目
打开右侧文件链接
下载全部文件
checker.py.py3turtle
compile.sh
config.yaml
controller.py
execute.sh
turtlecompare.py
上传到想要配置的题目中
修改checker.py.py3turtle中间部分代码,改为画出正确图形的代码
import turtle as t
import turtlecompare
t.speed(0)
# 这里开始是根据题目获取
# 如果为其他题目写checker,只需要改这一部分
# TODO 在这里开始写画出正确图形的turtle代码
## 注意, 由于是图片比较, 需要根据题面决定是否hideturtle
## 也要明确告知学生没有根据要求hideturtle就是WA
t.hideturtle()
# 需要修改的到这里结束
# 正确图案的画法已经转备好了
# 调用turtlecompare去判断是否一致
turtlecompare.compare()
这时候应该ok了,可以写一个AC的代码和一个错误的代码测试一下(注意是评测而不是自测)
技术方案详解
具体的做法就是用testlib自己些checker,去写代码进行测试用例的正确性判断
testlib checker
Codeforces上的说明,几个状态主要在这里
codeforces来的产物,judge系统会将[用户输入(出题人配置的输入数据)、用户输出(用户提交的数据)、答案数据(出题人配置的答案数据)] 三个流调用运行checker程序,HydroJudge根据stderr的结果来判定本次测试的结果(看代码)
如果stderr读到 "ok \n" 表示AC,其他则为WA,并将stderr的内容作为WA的信息进行输出(所以如果需要给出错误的提示,可以写在这个地方,比如 return: 999 expected: -1,表示正确答案是-1,但程序返回了999 )
设置checker类型的评测机制
评测文件中的config.yaml可以对评测进行配置,这个文件的文档
time: 5000ms
checker_type: testlib
checker: checker.py.py3turtle
user_extra_files:
- execute.sh
- compile.sh
- controller.py
judge_extra_files:
- turtlecompare.py # 评测需要用到这个文件里面的比较程序
cases:
- input: /dev/null # 本题无输入,当然你也可以设计成 input 一个数字,绘制对应边长的图形,等等
output: /dev/null
langs:
- py.py3turtle
注意:大部份的题目里面,只需要对checker.py.py3turtle进行修改即可
程序运行的配置
我们如何评测用户写好的代码能否画出对应的图形呢?当前的思路是
利用execute.sh去无头运行xvfb-run
由于turtle、tkinter需要有显示,judge其实是个后台跑的程序,需要用xvfb-run来运行
将用户写好的turtle程序转成输出
传统的judge系统就是根据用户程序的stdout和正确答案进行比对来判断程序正确性,沿用这个思路,我们将turtle的画布转成一个postscript串,再print()到stdout上,就可以将用户程序的结果流到checker中。
比较正确答案和用户输出
上一步让我们能在checker中拿到画好图像的postscript串。接下来我们只需要基于这个串生成pillow Image (user_out_image) ,在生成一个正确答案的pillow Image(answer_image)。将两者的尺寸与逐个像素进行比较,相差的像素数量小于0.5%(千分之五),就认为用户的程序结果是正确的。
以下是turtlecompare的实现
import turtle
import io
import sys
from PIL import Image, ImageChops
def get_size(img):
return img.size
def compare_by_pixel(img1, img2, w, h):
cnt = 0
diff_cnt = 0
for i in range(w):
for j in range(h):
p1 = img1.getpixel((i, j))
p2 = img2.getpixel((i, j))
if p1 == (255,255,255) and p2 == (255,255,255) :
continue
cnt += 1;
if p1 != p2:
diff_cnt += 1
return diff_cnt / cnt
def compare():
## 将checker里面当前的canvas str拿出来
answer_ps = turtle.getcanvas().postscript(colormode='color')
answer_canvas_image = Image.open(io.BytesIO(answer_ps.encode('utf-8')))
answer_im = answer_canvas_image
## 将foo里面用户画好的当前canvas str拿出来
#sys.stderr.write(open("user_out").read())
user_im = Image.open("user_out")
answer_img_size = get_size(answer_im)
user_img_size = get_size(user_im)
if answer_img_size != user_img_size:
sys.stderr.write("size is different: " + str(answer_img_size[0]) + ", " + str(answer_img_size[1]) + ", "
+ str(user_img_size[0]) + ", "+ str(user_img_size[1]))
else:
diff = compare_by_pixel(answer_im, user_im, answer_img_size[0], answer_img_size[1])
if diff < 0.005: # 正确性阈值 0.5%
sys.stderr.write('ok \n')
else:
sys.stderr.write("img is different:" + str(diff))
Turtle 题目checker
checker的逻辑很简单,先用turtle画出正确的图形,再调用turtlecompare文件去进行图片大小和像素的匹配
import turtle as t
import turtlecompare
t.speed(0)
# 这里开始是根据题目获取
# 如果为其他题目写checker,只需要改这一部分
t.penup()
t.forward(50)
t.lt(90)
t.bk(50)
t.pendown()
for i in range(4):
t.fd(100)
t.rt(90)
## 注意, 由于是图片比较, 需要根据题面决定是否hideturtle
## 也要明确告知学生没有根据要求hideturtle就是WA
t.hideturtle()
# 需要修改的到这里结束
# 正确图案的画法已经转备好了
# 调用turtlecompare去判断是否一致
turtlecompare.compare()
环境配置
这个主要是再次搭建hydrooj的时候用到,可以不看
配置py.py3turtle语言
在hydrooj网页版 - 控制面板 - 系统设置 - langs里面添加语言设置(这样judge系统才知道后缀是py3.py3turtle的checker文件要怎么运行)
py.py3turtle:
compile: >-
/usr/bin/python3 -c "import py_compile; py_compile.compile('/w/foo.py',
'/w/foo', doraise=True)"
execute: xvfb-run /usr/bin/python3 foo # checker也用了turtle去画出正确图形,所以需要用xvfb-run运行。如果是直接准备好ps图像文件,就不需要了
display: Python 3 Turtle
配置运行环境的包
上述的技术方案中需要使用xvfb-run / ghostscript / python-tkinter / python-pillow
由于hydrooj用nix搭建运行环境,所以上述的安装需要在nix search里面找到对应的包进行安装
nix-env -iA nixpkgs.xvfb-run
nix-env -iA nixpkgs.ghostscript
nix-env -iA nixpkgs.python310Packages.tkinter
nix-env -iA nixpkgs.python310Packages.pillow
此外,在hydrooj的系统设置中,还需要配置pythonlib的位置
PYTHONPATH=/lib/python3.10/site-packages
最后通过重启hydrooj / hydro-sandbox两个应用,环境就可以用了
pm2 restart hydrooj
pm2 restart hydro-sandbox