【干货】造数据自动机
stripe_python · · 科技·工程
前言
使用 Testlib 造数据门槛较高,cyaron 虽然比较方便,但仍然需要预先编译和手动打包。
为了造数据方便,笔者使用 Python 开发了一个自动造数据的轻量级网页,只需要输入 std 和造数据代码,就可以自动打包生成数据 Zip 文件。
环境
- Python3.6 及以上环境
- G++ 编译器
- flask 库和 tqdm 库,安装命令如下:
pip install flask tqdm
服务器
import os
import zipfile
import tqdm
from flask import Flask, render_template, request, send_file
from lib import global_vars
app = Flask(__name__)
GCC_PATH = 'g++.exe' # 本机 G++ 地址
@app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'GET':
return render_template('index.html', error=None)
print('开始生成数据', flush=True)
std = request.form.get('std')
data = request.form.get('data')
num = int(request.form.get('num'))
if num <= 0:
return render_template('index.html', error='数据组数必须为正整数')
cwd = os.getcwd()
if 'data' not in cwd:
os.chdir('./data')
with open('std.cpp', 'w', encoding='utf-8') as f:
f.write(std)
print('开始编译 C++ 程序', flush=True)
os.system(f'{GCC_PATH} -O2 --static -Wl,--stack=204800000 -o std.exe std.cpp')
print('编译完成', flush=True)
for i in tqdm.trange(1, num + 1):
var = global_vars.copy()
var['num'] = i
try:
exec(data, var)
except (Exception, SystemExit) as err:
return render_template('index.html', error=str(err))
os.system(f'std.exe < {i}.in > {i}.out')
print('\n数据生成完毕,开始打包 Zip 文件')
with zipfile.ZipFile('data.zip', 'w', zipfile.ZIP_DEFLATED) as zf:
for i in tqdm.trange(1, num + 1):
zf.write(f'{i}.in')
zf.write(f'{i}.out')
print('\nZip 文件打包完成')
os.chdir(cwd)
return send_file('data/data.zip', as_attachment=True)
@app.route('/help/')
def help_info():
return render_template('help.html')
if __name__ == '__main__':
app.run(port=7075, debug=True)
lib.py 如下,可以根据需要自行添加功能:
import random
import math
import string
# import cyaron
global_vars = {
'random': random.random,
'randint': random.randint,
'uniform': random.uniform,
'choice': random.choice,
'sample': random.sample,
'seed': random.seed,
'randrange': random.randrange,
'Random': random,
'Math': math,
'PI': math.pi,
'E': math.e,
'ASCII_LOWERCASE': string.ascii_lowercase,
'ASCII_UPPERCASE': string.ascii_uppercase,
'DIGITS': string.digits,
'ASCII_LETTERS': string.ascii_letters,
'SENTENCE_SEPARATORS': ',,,,,,,;;:',
'SENTENCE_TERMINATORS': '....!',
# 'cyaron': cyaron,
} # 这个字典存的变量是造数据代码能够使用的
index.html 位于 templates 文件夹下,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>自动造数据</title>
</head>
<body>
<form action="/" method="post">
<label>程序 Std(C++14):</label>
<br>
<textarea rows="18" cols="100" id="std" name="std"></textarea>
<hr>
<label>
数据生成器(Python3)
<a href="/help">查看帮助说明?</a>
</label>
<br>
<textarea rows="18" cols="100" id="data" name="data">with open(f'{num}.in', 'w', encoding='utf-8') as f:
</textarea>
<br>
<label> 数据组数: </label>
<input type="number" value="10" id="num" name="num">
<br>
<input type="submit" value="提交">
</form>
{% if cinfo %}
<p><strong>编译信息: </strong> {{ cinfo }}
{% endif %}
<br>
{% if error %}
<p><strong>错误: </strong> {{ error }}
{% endif %}
</body>
</html>
使用说明
运行 app.py 后,打开 http://127.0.0.1:7075/,如图:
粘贴 std 和数据生成代码,例如:
点击“提交”按钮即可。等待一会,就可以自动下载 data.zip 文件。
快捷安装及使用
在本题的附件中下载 Zip 文件解压即可。
python -m SpnDataMaker
即可使用。若需要修改 G++ 地址,找到相关库的源代码修改即可。
使用示例
这里以 [SPN D-Struct 01] Iridescent 为例。
造数据代码如下:
with open(f'{num}.in', 'w', encoding='utf-8') as f:
n,q=randint(180000,200000),randint(180000,200000)
print(n,q,file=f)
for i in range(n):
print(randint(-(10**9),10**9),end=' ',file=f)
print(file=f)
cnt3 = 0
for i in range(q):
if cnt3 >= 60:
opt = choice([1,2,3,4,5,6])
else:
opt = choice([1,2,4,5,6])
if opt == 3:
cnt3 += 1
l,r=randint(1,n),randint(1,n)
if l>r:
l,r=r,l
if opt == 2 and num > 3:
r=l+randint(1,3) # 此处卡掉odt
if opt <= 2:
print(opt,l,r,randint(-(10**9),10**9),file=f)
else:
print(opt,l,r,file=f)