Skip to content

Commit

Permalink
史诗级更新:使用PyQt5制作program-compare-UI
Browse files Browse the repository at this point in the history
  • Loading branch information
xtf0214 committed Jul 14, 2023
1 parent 9585dd2 commit 81bec0f
Show file tree
Hide file tree
Showing 7 changed files with 251 additions and 1 deletion.
169 changes: 169 additions & 0 deletions MainWindow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import os
import sys
import time

from PyQt5.QtGui import QColor, QFont, QPalette
from PyQt5.QtWidgets import (QApplication, QCheckBox, QComboBox, QFileDialog, QHBoxLayout, QLabel, QLineEdit, QMainWindow,
QPushButton, QTextEdit, QVBoxLayout, QWidget)

from ProgramCompareUI import ProgramCompare


class MainWindow(QMainWindow):

def __init__(self):
super().__init__()
self.initUI()
self.std = None
self.cmp = None
self.setData = None
self.programCompare = None

def initUI(self):
self.setWindowTitle("ProgramCompare")

# 创建主窗口的中心部件
central_widget = QWidget(self)
self.setCentralWidget(central_widget)

# 创建主布局
main_layout = QVBoxLayout()
central_widget.setLayout(main_layout)

########## 创建文件选择部件
file_layout = QHBoxLayout()
main_layout.addLayout(file_layout)

# 创建按钮上传std.cpp
self.std_button = QPushButton("std.cpp")
self.std_button.clicked.connect(self.upload_std)
file_layout.addWidget(self.std_button)

# 创建按钮上传cmp.cpp
self.cmp_button = QPushButton("cmp.cpp")
self.cmp_button.clicked.connect(self.upload_cmp)
file_layout.addWidget(self.cmp_button)

# 创建按钮上传setData.py
self.setData_button = QPushButton("setData.py")
self.setData_button.clicked.connect(self.upload_setData)
file_layout.addWidget(self.setData_button)

# 创建选择菜单设置cppstd
self.cppstd_comboBox = QComboBox()
self.cppstd_comboBox.addItem("c++17")
self.cppstd_comboBox.addItem("c++14")
self.cppstd_comboBox.addItem("c++11")
file_layout.addWidget(self.cppstd_comboBox)

self.compile_button = QPushButton("compile")
self.compile_button.clicked.connect(self.compile)
file_layout.addWidget(self.compile_button)

########## 创建中心文本框
self.textbox = QTextEdit()
self.textbox.setReadOnly(True) # 设置为只读
main_layout.addWidget(self.textbox)

########## 创建执行部件
run_layout = QHBoxLayout()
main_layout.addLayout(run_layout)

# 创建输入框输入样例数
self.test_label = QLabel("test number")
self.testNum_LineEdit = QLineEdit()
self.testNum_LineEdit.setText("10")
run_layout.addWidget(self.test_label)
run_layout.addWidget(self.testNum_LineEdit)

# 创建选择框选择是否显示输入内容和输出内容
self.show_input_checkBox = QCheckBox("show_input")
run_layout.addWidget(self.show_input_checkBox)
self.show_output_checkBox = QCheckBox("show_output")
run_layout.addWidget(self.show_output_checkBox)

# 创建按钮执行makeData
self.makeData_button = QPushButton("makeData")
self.makeData_button.clicked.connect(self.makeData)
run_layout.addWidget(self.makeData_button)

# 创建按钮执行bruteJudge
self.bruteJudge_button = QPushButton("bruteJudge")
self.bruteJudge_button.clicked.connect(self.bruteJudge)
run_layout.addWidget(self.bruteJudge_button)

def log(self, message: str):
self.textbox.append(f"[{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())}] " + message)

def upload_std(self):
file_path, _ = QFileDialog.getOpenFileName(self, "std.cpp", "", "CPP Files (*.cpp)")
if file_path:
self.std = file_path
self.log(f"Upload std.cpp: {file_path}")

def upload_cmp(self):
file_path, _ = QFileDialog.getOpenFileName(self, "cmp.cpp", "", "CPP Files (*.cpp)")
if file_path:
self.cmp = file_path
self.log(f"Upload cmp.cpp: {file_path}")

def upload_setData(self):
file_path, _ = QFileDialog.getOpenFileName(self, "setData.py", "", "Python Files (*.py)")
if file_path:
# 加载生成器
with open(file_path, "r") as file:
setData_code = file.read()
namespace = {}
exec(setData_code, namespace)
self.setData = namespace.get("setData")
self.log(f"Upload setData.py: {file_path}")

def compile(self):
if self.std == None or self.cmp == None or self.setData == None:
self.log("Please upload file first.")
return
cppstd = self.cppstd_comboBox.currentText()
self.log("Compiling...")
self.programCompare = ProgramCompare(self.setData, self.std, self.cmp, self.textbox.append, cppstd)

def makeData(self):
if self.programCompare == None:
self.log("Please complie first.")
return
testNum = int(self.testNum_LineEdit.text())
for id in range(1, testNum + 1):
self.programCompare.makeData(id)
self.log(f"Make {testNum} test data finish.")

def bruteJudge(self):
if self.programCompare == None:
self.log("Please complie first.")
return
testNum = int(self.testNum_LineEdit.text())
show_input = self.show_input_checkBox.isChecked()
show_output = self.show_output_checkBox.isChecked()
correct, wrong = 0, 0
for id in range(1, testNum + 1):
if self.programCompare.compare(id, show_input, show_output):
correct += 1
else:
wrong += 1
self.log(f"Brute judge {testNum} test data finish. {correct} correct, {wrong} wrong.")


if __name__ == "__main__":
# 设置./temp为workspace
workspace = os.path.join(os.getcwd(), 'temp')
if not os.path.exists(workspace):
os.mkdir(workspace)
os.chdir(workspace)

font = QFont()
font.setFamily("Consolas")
font.setPointSize(14)
app = QApplication(sys.argv)
window = MainWindow()
window.setFont(font)
window.show()
window.resize(1024, 640)
sys.exit(app.exec_())
54 changes: 54 additions & 0 deletions ProgramCompareUI.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# https://github.com/luogu-dev/cyaron/wiki
import os


def setColor(s, color):
return f"<span style='color: {color};font-weight: bold;'>{s}</span>"


class ProgramCompare:

def __init__(self, setData, std: str, cmp: str, writeln, cppstd='c++17', optimize='O2'):
# 编译源代码
self.setData = setData
self.writeln = writeln
self.std_exe = os.path.splitext(std)[0] + '.exe'
self.cmp_exe = os.path.splitext(cmp)[0] + '.exe'
if os.system(f'g++ "{std}" -o "{self.std_exe}" -std={cppstd} -{optimize} -fexec-charset=GBK -w') != 0:
writeln(setColor("std.cpp compile failed.", "red"))
elif os.system(f'g++ "{cmp}" -o "{self.cmp_exe}" -std={cppstd} -{optimize} -fexec-charset=GBK -w') != 0:
writeln(setColor("cmp.cpp compile failed.", "red"))
else:
writeln(setColor("Compile successful.", "green"))

def __del__(self):
os.system('del *.exe')

def compare(self, id: int = 1, show_input=True, show_output=True):
# 产生样例输入
with open(f'test{id}.in', 'w') as file:
self.setData(file, id)
# 获取样例答案和样例输出
std_out = os.popen(self.std_exe + ' < ' + f'test{id}.in').read()
cmp_out = os.popen(self.cmp_exe + ' < ' + f'test{id}.in').read()
if std_out == cmp_out:
self.writeln(setColor('AC:', 'green') + f'test{id}.in')
return True
else:
self.writeln(setColor('WA:', 'red') + f'test{id}.in')
if show_input:
with open(f'test{id}.in', 'r', encoding='utf-8') as file:
self.writeln(setColor('input:', 'Chocolate'))
self.writeln(file.read())
if show_output:
self.writeln(setColor('std_out:', 'blue'))
self.writeln(std_out)
self.writeln(setColor('cmp_out:', 'purple'))
self.writeln(cmp_out)
return False

def makeData(self, id: int = 1):
# 使用setData产生样例输入并用std_exe产生样例答案
with open(f'test{id}.in', 'w') as file:
self.setData(file, id)
os.system(f'{self.std_exe} < test{id}.in > test{id}.out')
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# program-compare-UI

![](img\GUI.png)

# program-compare

This is a program-comparer for programming competition. It's base on `cyaron`, but some simple encapsulation was made.

## Usage

1. Copy `ProgramCompare.py` to you workspace
1. Copy `ProgramCompare.py` to you workspace.
2. New a python file and write `from ProgramCompare import *`
3. New a `ProgramCompare` class and appoint the `std_cpp` path and the `cmp_cpp` path.
4. Write the `setData` methods, it is a function object for making data according to the problem.
Expand Down
6 changes: 6 additions & 0 deletions cmp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <iostream>
int main() {
int a, b;
std::cin >> a >> b;
std::cout << a + b << '\n';
}
Binary file added img/GUI.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions setData.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from io import TextIOWrapper
from random import randint


def setData(file: TextIOWrapper, id=1):
write = lambda *x: file.write(' '.join([str(i) for i in x]) + ' ')
writeln = lambda *x: file.write(' '.join([str(i) for i in x]) + '\n')
###################
a = randint(1, 2e9)
b = randint(1, 2e9)
writeln(a, b)
6 changes: 6 additions & 0 deletions std.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <iostream>
int main() {
long long a, b;
std::cin >> a >> b;
std::cout << a + b << '\n';
}

0 comments on commit 81bec0f

Please sign in to comment.