1. 前情提要
2022年9月10日,为IMAU七十周年校庆,我计算机院了举办“校庆杯”大学生程序设计大赛。其中有一道题J题,使用了SPJ,用来收集所有参赛者的祝福。
1576: 祈愿imau
时间限制:1s 内存限制:128MB Special Judge
题目描述
嗨 亲爱的农大IT人,相信点开这道题的时候,比赛已经接近尾声。 我想告诉你的是,这道题是一道特殊判断题(Special Judge),也就是说,这道题的答案不唯一,是否判题通过取决于一个智能程序,而不是单纯的文本比对。 用任意编程语言的输出方法,输出你们队伍对农大的祝福,并留下你的队名,提交即可AC。并且,我们会在比赛结束后将你们的祝福收集,作为本次比赛的额外收获。 同时也祝你们中秋快乐!——出题组
输入格式
无
输出格式
你对农大的祝福
由于队伍比较多,从管理后台一条一条复制粘贴显然是不合适的,所以接下来记录一下我导出的过程。
2. SSH 登录判题服务器
学校OJ采用的是 开源项目 hustoj(https://github.com/zhblue/hustoj),并在内网部署,其提交的代码以文本形式存在数据库中。
2.1 登录ssh
打开cmd,输入ssh远程连接指令。 (这里的user为判题用户,如果有root账户的密码也可以用root)
ssh user@172.xx.xx.xx
如果是第一次登录,会给出提示:
The authenticity of host ‘172.20.25.11 (172.20.25.11)’ can’t be established. ECDSA key fingerprint is SHA256:xNk0TUMV41iUcslAClIk1AqddxIQHFfWOrjiakPbIWw. Are you sure you want to continue connecting (yes/no/[fingerprint])?
这里我们输入 yes 即可。
再次连接,提示输入密码,验证后成功进入服务器。
2.2 查看判题数据库配置
hustoj有一键安装脚本,所有的流程都是全自动执行的,所以我们事先不知道数据库相关配置,这时候就需要查看配置文件。根据hustoj官方文档,我们得知,其配置信息都存放在 /home/judge/etc/judge.conf 中。
但是直接提取会显示权限不足,遂换用root用户
我们使用 su 提权
su
输入root密码后,当前账户变成了root,这时我们再访问
vi /home/judge/etc/judge.conf
然后就会看到配置,其中含mysql的账户和密码。
OJ_HOST_NAME=127.0.0.1
OJ_USER_NAME=debian-sys
OJ_PASSWORD=**********
OJ_DB_NAME=jol
OJ_PORT_NUMBER=3306
我们再来查看一下该账户是否支持远程访问。
在ssh上:
mysql -uroot
然后输入SQL查询语句
select user, host from mysql.user;
查询结果:
+------------------+-----------+
| user | host |
+------------------+-----------+
| debian-sys | % |
| mysql.infoschema | localhost |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+------------------+-----------+
5 rows in set (0.00 sec)
可以看到,debian-sys账户的host为 % ,说明支持远程访问,我们接下来就可以脱离SSH进行操作了。如果这里不是 %,可以去百度一下mysql账户如何开启远程访问。
3. 写SQL
3.1 使用 Navicat 连接数据库
我们使用上述配置,用 Navicat连接,查看表结构。
3.2 查看模型
可知,我们需要的数据集中在 solution 和 source_code 表中。
逆向模型后: 已知题目IDproblem_id = 1576,通过题的 result = 4
3.3 写出SQL
select user_id, nick, source, result, `language`
from solution
left join source_code
on solution.solution_id = source_code.solution_id
where problem_id = 1576 and result = 4;
这样,我们就拿到了所有源代码及提交记录信息。
3.4 用Python实现
import os
import time
import pymysql
from tqdm import tqdm
import sys
database = {
"host": "172.xx.xx.xxx",
"username": "debian-sys",
"password": "******",
"database": "jol"
}
conn = pymysql.connect(
host=database["host"],
port=3306,
user=database["username"],
password=database["password"],
database=database["database"],
charset='utf8'
)
cursor = conn.cursor()
sql = "select user_id, nick, source, result, `language` from solution left join source_code on solution.solution_id = source_code.solution_id where problem_id = 1576 and result = 4";
cursor.execute(sql)
data = cursor.fetchall()
4. 源码处理
我们拿到了源码,但只是源码,我们还需要在本地编译运行后拿取stdout输出的内容。
我们可以针对不同语言,编写对应的编译运行代码,然后通过 重定向 >xxx.txt 的方式,将结果保存在文本文件中。
lang_dict = {
"0": ".c",
"1": ".cpp",
"3": ".java",
"6": ".py"
}
complier_dict = {
"0": [
"g++ -o Main {filename}",
"Main <nullptr.txt > {filename}.txt"
],
"1": [
"g++ -o Main {filename}",
"Main <nullptr.txt > {filename}.txt"
],
"3": [
"copy {filename} Main.java",
"javac Main.java",
"java Main <nullptr.txt > {filename}.txt"
],
"6": [
"python {filename} <nullptr.txt > {filename}.txt"
]
}
你可能会问为什么有一个 <nullptr.txt ,是因为有的队伍写了input.hasNext() 等类似语句,使得初次导出时卡在那里了,所以索性直接把输入流也重定向了。 运行时需要在脚本同目录下建一个 nullptr.txt,内容为空。
循环执行指令,生成.txt文件
for item in tqdm(data):
file_path = f"{item[0]}{lang_dict[str(item[4])]}"
with open(file_path,"w") as f:
f.write(item[2])
for i in complier_dict[str(item[4])]:
cmd= str(i).replace("{filename}", file_path)
os.system(cmd)
time.sleep(1)
完整代码:
import os
import subprocess
import time
import pymysql
from tqdm import tqdm
import sys
database = {
"host": "172.xx.xx.xx",
"username": "debian-sys",
"password": "*******",
"database": "jol"
}
conn = pymysql.connect(
host=database["host"],
port=3306,
user=database["username"],
password=database["password"],
database=database["database"],
charset='utf8'
)
# 获取游标对象
cursor = conn.cursor()
# 查询 SQL 语句
# sql = "select solution_id,source from source_code where solution_id in (select solution_id from solution where problem_id = 1576) limit 10"
sql = "select user_id, nick, source, result, `language` from solution left join source_code on solution.solution_id = source_code.solution_id where problem_id = 1576 and result = 4";
cursor.execute(sql)
data = cursor.fetchall()
# 6 = python
# 0 = c
# 1 = c++
# 3 = java
lang_dict = {
"0": ".c",
"1": ".cpp",
"3": ".java",
"6": ".py"
}
complier_dict = {
"0": [
"g++ -o Main {filename}",
"Main <nullptr.txt > {filename}.txt"
],
"1": [
"g++ -o Main {filename}",
"Main <nullptr.txt > {filename}.txt"
],
"3": [
"copy {filename} Main.java",
"javac Main.java",
"java Main <nullptr.txt > {filename}.txt"
],
"6": [
"python {filename} <nullptr.txt > {filename}.txt"
]
}
res_list = []
for item in tqdm(data):
file_path = f"{item[0]}{lang_dict[str(item[4])]}"
# print(file_path)
# print(item)
with open(file_path,"w") as f:
f.write(item[2])
for i in complier_dict[str(item[4])]:
cmd= str(i).replace("{filename}", file_path)
print(cmd)
os.system(cmd)
time.sleep(1)
|