Initial commit

main
zart 8 months ago
parent 1b529bc05d
commit caa3d306b3

137
.gitignore vendored

@ -0,0 +1,137 @@
### pycharm template
### Your template template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.idea/
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
media
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
# Python profiling files
profiling/
*.pyc
# virtualenv
VENV/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# Sublime Text
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
*.sublime-workspace
*.sublime-project
# PyCharm files
.idea/
# Visual Studio Code
.vscode/
# Windows directories
Thumbs.db
ehthumbs.db
# macOS directories
.DS_Store
.AppleDouble
.LSOverride
# Linux directories
*~
# Python Jupyter Notebooks
.ipynb_checkpoints

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

@ -0,0 +1,324 @@
# Function: 24点游戏
import math
import random
import re
OPS = ['+', '-', '*', '/','^','sin','cos','tan']
def get_Aexps(nums=None):
ops = OPS[:4]
if nums is None:
nums = []
for i in range(4):
num = input("请输入第%d个数字:" % (i + 1))
if num.isdigit():
if 1 <= int(num) <= 9:
nums.append(num)
group_nums = get_nums_group(nums)
results = []
for nums in group_nums:
for op1 in ops:
for op2 in ops:
for op3 in ops:
Aexp = f"(({nums[0]}{op1}{nums[1]}){op2}{nums[2]}){op3}{nums[3]}" # 枚举表达式
try:
result = eval(Aexp)
if result == 24 and Aexp not in results:
results.append(Aexp)
except ZeroDivisionError:
continue # 跳过0除错误
if len(results) != 0:
return results
else:
return "无法得出24点"
def gen_exp(nums): # 生成表达式
ops = OPS[:4]
result = 0
group_nums = get_nums_group(nums)
for nums in group_nums:
for op1 in ops:
for op2 in ops:
for op3 in ops:
Aexp = f"(({nums[0]}{op1}{nums[1]}){op2}{nums[2]}){op3}{nums[3]}"
try:
result = eval(Aexp)
if result == 24:
return Aexp
except ZeroDivisionError:
continue # 跳过0除错误
if result != 24:
return "无法得出24点"
def get_nums_group(nums): # 获取4个数的排列组合
group = []
for i in range(4):
for j in range(4):
for k in range(4):
for l in range(4):
if i != j and i != k and i != l and j != k and j != l and k != l:
group.append([nums[i], nums[j], nums[k], nums[l]])
return group
class Node:
def __init__(self, treeNode_value):
self.NodeID = treeNode_value[0]
self.NodeType = treeNode_value[1]
self.Ops = treeNode_value[2]
self.LeftNodeID = treeNode_value[3]
self.RightNodeID = treeNode_value[4]
self.FaceValue = treeNode_value[5]
self.FaceColor = treeNode_value[6]
def __str__(self):
return f"NodeID: {self.NodeID}\t NodeType: {self.NodeType}\t Ops: {self.Ops}\t LeftNodeID: {self.LeftNodeID}\t RightNodeID: {self.RightNodeID}\t FaceValue: {self.FaceValue}\t FaceColor: {self.FaceColor}"
def split_exp(expression): # 将表达式拆分为数字和运算符
stack = []
current_number = ''
for char in expression:
if char.isdigit() or char == '.':
current_number += char
elif char.isalpha(): # 处理sin,cos等函数
current_number += char
elif char == '(':
if current_number:
stack.append(current_number)
current_number = ''
stack.append(char)
elif char == ')' and current_number:
stack.append(current_number)
stack.append(char)
current_number = ''
elif char in OPS:
if current_number:
stack.append(current_number)
current_number = ''
stack.append(char)
if current_number:
stack.append(current_number)
return stack
def get_postfix_expression_(expression): # 将中缀表达式转化为后缀表达式
expression = split_exp(expression) # 多位数拆分
precedence = {'+': 1, '-': 1, '*': 2, '/': 2}
postfix = []
stack = []
for char in expression:
if char.isdigit():
postfix.append(char)
elif char == '(':
stack.append(char)
elif char == ')':
while stack and stack[-1] != '(':
postfix.append(stack.pop())
stack.pop() # 弹出 '('
elif char in precedence:
while stack and stack[-1] != '(' and precedence[stack[-1]] >= precedence[char]:
'''这行代码的作用是在中缀表达式转换为后缀表达式的过程中,检查当前运算符与栈顶运算符的优先级。具体来说,它的功能是:
确保栈不为空避免了索引错误
确保栈顶元素不是左括号 '('因为左括号的优先级最低不需要进行比较
确保栈顶元素的优先级大于等于当前运算符的优先级因为栈中的运算符都应该在当前运算符之前执行栈顶元素的优先级大于等于当前运算符表示栈顶元素的操作要优先于当前操作执行'''
postfix.append(stack.pop())
stack.append(char)
while stack:
postfix.append(stack.pop())
return postfix
def get_postfix_expression(expression):
# 多位数拆分
expression = split_exp(expression)
precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '^': 3, "sin": 4, "cos": 4, "tan": 4}
postfix = []
stack = []
def is_number(char):
try:
float(char);return True
except ValueError: return False
for char in expression:
if is_number(char):
postfix.append(char)
elif char == '(':
stack.append(char)
elif char == ')':
while stack and stack[-1] != '(':
postfix.append(stack.pop())
stack.pop() # 弹出 '('
elif char in precedence:
while stack and stack[-1] != '(' and precedence.get(stack[-1], 0) >= precedence.get(char, 0):
postfix.append(stack.pop())
stack.append(char)
while stack:
postfix.append(stack.pop())
return postfix
def calculate(root, TreeNode): # 计算节点树表达式
if root.NodeType == 'Value':
return float(root.FaceValue) if root.FaceValue.replace('.', '').isdigit() else None # 将操作数转换为浮点数
elif root.NodeType == 'Operator':
if root.Ops in ('sin', 'cos', 'tan'): # 检查是否是三角函数
if root.LeftNodeID is not None:
operand_value = calculate(find_node_by_id(root.LeftNodeID, TreeNode), TreeNode)
else:
operand_value = calculate(find_node_by_id(root.RightNodeID, TreeNode), TreeNode)
if operand_value is None:
return None
if root.Ops == 'sin':
return math.sin(operand_value)
elif root.Ops == 'cos':
return math.cos(operand_value)
elif root.Ops == 'tan':
return math.tan(operand_value)
else:
left_value = calculate(find_node_by_id(root.LeftNodeID, TreeNode), TreeNode)
right_value = calculate(find_node_by_id(root.RightNodeID, TreeNode), TreeNode)
if left_value is None or right_value is None:
return None
if root.Ops == '+':
return left_value + right_value
elif root.Ops == '-':
return left_value - right_value
elif root.Ops == '*':
return left_value * right_value
elif root.Ops == '^':
return left_value ** right_value
elif root.Ops == '/':
if right_value == 0:
return None # 除数为0返回None表示计算错误
return left_value / right_value
return None # 节点类型不合法返回None表示计算错误
def find_node_by_id(node_id, TreeNode):
for node in TreeNode:
if node.NodeID == node_id:
return node
return None
def evaluate_postfix(expression): # 计算后缀表达式
stack = []
for char in expression:
if char.isdigit():
stack.append(int(char))
elif char in OPS:
operand2 = stack.pop()
operand1 = stack.pop()
if char == '+':
result = operand1 + operand2
elif char == '-':
result = operand1 - operand2
elif char == '*':
result = operand1 * operand2
elif char == '^':
result = operand1 ** operand2
elif char == '/':
result = operand1 / operand2 # 这里假设除法结果为浮点数
stack.append(result)
return stack.pop()
def exp_to_treeNode_dict(exp_ls): # 返回嵌套节点字典
stack = []
for char in exp_ls:
two = {}
if char.isdigit():
stack.append(char)
elif char in OPS:
right = stack.pop()
left = stack.pop()
root = char
two[root] = [left,right]
stack.append(two)
return stack.pop()
def ExpressionAnalyse(exp_ls): # 返回语法树
stack = [] # 符合和数值栈
TreeNode = []
face_color = ['Club', 'Diamond', 'Heart', 'Spade']
id = 0
for char in exp_ls:
fc = random.sample(face_color, 1)
if char.replace('.', '').isdigit(): # 检查字符是否是数字(包括小数)
stack.append(char)
elif char in OPS:
if char in ('sin', 'cos', 'tan'): # 检查运算符是否是三角函数
operand = stack.pop()
if isinstance(operand, str) and operand.replace('.', '').isdigit():
TreeNode.append(Node([id, 'Value', None, None, None, operand, fc]))
op_id = id
id += 1
else:
op_id = operand
root = char
TreeNode.append(Node([id, 'Operator', root, None, op_id, None, None]))
root_id = id
id += 1
stack.append(root_id)
else:
right = stack.pop()
if isinstance(right, str) and right.replace('.', '').isdigit():
TreeNode.append(Node([id, 'Value', None, None, None, right, fc]))
r_id = id
id += 1
else:
r_id = right
left = stack.pop()
if isinstance(left, str) and left.replace('.', '').isdigit():
TreeNode.append(Node([id, 'Value', None, None, None, left, fc]))
l_id = id
id += 1
else:
l_id = left
root = char
TreeNode.append(Node([id, 'Operator', root, l_id, r_id, None, None]))
root_id = id
id += 1
stack.append(root_id)
return TreeNode
if __name__ == '__main__':
# Aexps = get_Aexps()
# Aexp = '((2+92)*3)+35'
# treeNode = get_TreeNode(Aexp)
# for node in treeNode:
# print(node)
# print(get_ast("2+9"))
#
# print(get_ast('(2+9)*3'))
#
# print("表达式","((6*3)+8)-6")
# print(get_ast('((6*(3-2))+8)-6'))
# print(infix_to_postfix('((9+8*3)+8)-6'))
# exp = '6.1+2^3*3'
exp = 'cos(0)+sin(0)+5'
exp_ls = get_postfix_expression(exp)
print(exp_ls)
# print(exp_to_treeNode_dict(exp_ls))
# exp_ls = ['3.3', '2', '^', '3', '3', '*', '-']
TreeNode= ExpressionAnalyse(exp_ls)
result = calculate(TreeNode[-1], TreeNode)
print(result)
#
# # print(TreeNode)
for node in TreeNode:
print(node)
# print_tree(Aexp)

@ -0,0 +1,69 @@
from PySide6.QtCore import Qt, QRectF, Signal, QObject
from PySide6.QtGui import QPainter, QPen, QColor, QFontMetricsF, QPainterPath
from PySide6.QtWidgets import QGraphicsItem
class RoundedRectangleItem(QGraphicsItem, QObject):
selected = Signal(int)
unselected = Signal(int)
def __init__(self, x, y, text, id):
QGraphicsItem.__init__(self)
QObject.__init__(self)
self.rect = QRectF(x, y, 70, 70)
self.radius = 10
self.text = text
self.id = id
self.isSelected = False # 是否被选中
def boundingRect(self):
return self.rect
def shape(self):
path = QPainterPath()
path.addRoundedRect(self.rect, self.radius, self.radius)
return path
def paint(self, painter, option, widget):
painter.setRenderHint(QPainter.Antialiasing) # 设置抗锯齿
pen = QPen(Qt.black)
painter.setPen(pen)
if self.isSelected:
# 如果被选中,设置不同的填充颜色和边框样式
painter.setBrush(QColor(255, 0, 0, 255)) # 设置选中时的填充颜色
pen.setWidth(2) # 设置边框宽度
pen.setStyle(Qt.DashLine) # 设置虚线边框样式
painter.setPen(pen)
else:
painter.setBrush(QColor(0, 255, 0, 255)) # 设置默认的填充颜色
# 绘制圆角矩形
painter.drawRoundedRect(self.rect, self.radius, self.radius)
# 计算文本的位置
font = painter.font()
font.setPointSize(36)
painter.setFont(font)
metrics = QFontMetricsF(font)
text_bounding_rect = metrics.boundingRect(str(self.text))
text_width = text_bounding_rect.width()
text_height = text_bounding_rect.height()
text_x = self.rect.center().x() - text_width / 2
text_y = self.rect.center().y() + text_height / 4
# 绘制文本
painter.drawText(text_x, text_y, str(self.text))
def mousePressEvent(self, event):
# 鼠标点击时切换选中状态
self.isSelected = not self.isSelected
self.update()
# 发射选中信号
if self.isSelected:
self.selected.emit(self.id)
else:
self.unselected.emit(self.id)
super().mousePressEvent(event)

@ -0,0 +1,453 @@
import math
import random
from PySide6.QtGui import QPainter, QPen, QFont, QPixmap
from PySide6.QtWidgets import QApplication, QMainWindow, QGraphicsLineItem, QMessageBox, QGraphicsScene
from PySide6.QtCore import QPoint
from main_ui import Ui_MainWindow
import data
from graph_24 import *
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.drawn_tree_id = set() # 已经绘制了树的节点
self.seq = 1 # 在有树的情况下,添加节点的序号,以确定新加的节点位置
self.trees_root = [] # 保存所有树的根节点
self.selected_id = [] # 选中的节点ID
self.adds_id = set() # 已经用过的ID
self.value_nodes = [] # 数值节点
# self.operator_nodes = []
self.selected_ops = None # 选择的运算符
self.selected_value = None # 当前选择的卡片值
self.r_count = 0 # 记录所有答案点击次数
self.offset = 0 # 语法树遍历时随深度平移长度,避免节点重合
self.TreeNode = []
self.Tree_4_nums = None
self.setupUi(self)
self.init_ui()
self.init_slot()
self.pushButton_q.clicked.connect(self.show_card)
self.pushButton_ex.clicked.connect(self.show_card)
self.pushButton_autosv.clicked.connect(self.AutoTest_9_10)
self.pushButton_dtree.clicked.connect(self.draw_tree)
self.pushButton_ast.clicked.connect(self.calculate_button)
self.pushButton_allan.clicked.connect(self.AutoTest)
self.clear_button.clicked.connect(self.secen_clear)
self.pushButton_add.clicked.connect(lambda :self.select_ops('+'))
self.pushButton_sub.clicked.connect(lambda :self.select_ops('-'))
self.pushButton_mul.clicked.connect(lambda :self.select_ops('*'))
self.pushButton_div.clicked.connect(lambda :self.select_ops('/'))
self.add_val_node.clicked.connect(self.add_value_node)
self.add_ops_node.clicked.connect(self.add_operator_node)
self.ex_node_value.clicked.connect(self.exchange_value_node)
self.ex_node_ops.clicked.connect(self.exchange_ops_node)
self.ex_node_self.clicked.connect(self.exchange_two_nodes)
def secen_clear(self):
self.scene.clear()
self.selected_id = []
self.value_nodes = []
self.TreeNode = []
self.adds_id = set()
self.trees_root = []
self.drawn_tree_id = set()
self.selected_value = None # 当前选择的卡片值.
self.selected_ops = None # 选择的运算符
# 清空运算符显示
self.lb_ops_selected.setText("")
def select_ops(self, ops):
self.lb_ops_selected.setText(ops)
self.selected_ops = ops
def add_value_node(self):
# self.scene.clear()
if self.selected_value is not None: # 选择了卡片值
self.value_nodes.append(self.selected_value) # 添加到节点数值列表
for i in range(len(self.adds_id)+1):
if i not in self.adds_id:
value = self.selected_value
nodet = RoundedRectangleItem(150*self.seq, 0, str(value), i)
self.seq += 1 # 序号加1
nodet.selected.connect(lambda id: self.selected_node(id)) # 连接信号
nodet.unselected.connect(lambda id: self.unselected_node(id))
node = data.Node([i, 'Value', None, None, None, value, None])
self.adds_id.add(i) # 添加全局id
self.TreeNode.append(node)
self.scene.addItem(nodet)
else:
QMessageBox.warning(self, '警告', '请先选择一张牌')
def judge_node_conn(self): # 判断节点是否已经连接
for id in self.selected_id:
for node in self.TreeNode:
if node.LeftNodeID == id or node.RightNodeID == id:
return True
def add_operator_node(self):
if self.selected_ops is not None:
if len(self.selected_id) == 2:
# 判断已选节点是否已经被连接
if self.judge_node_conn():
QMessageBox.warning(self, '警告', '节点已经连接')
return
for i in range(len(self.adds_id)+1): # 确保id唯一
if i not in self.adds_id:
node = data.Node([i, 'Operator', self.selected_ops, None, None, None, None])
self.TreeNode.append(node)
self.adds_id.add(i) # 全局ID
node.LeftNodeID = int(self.selected_id[1])
node.RightNodeID = int(self.selected_id[0])
self.flash_node(self.selected_id[0])
self.flash_node(self.selected_id[1])
self.selected_id = [] # 清空选中的节点
self.trees_root.append(node) # 保存根节点
# 从根节点列表中删去作为子节点连接的节点
node_to_remove = []
for root in self.trees_root:
if root.NodeID == node.LeftNodeID or root.NodeID == node.RightNodeID:
node_to_remove.append(root)
for root in node_to_remove:
self.trees_root.remove(root)
print("已用ID", self.adds_id)
self.scene.clear()
for i, root in enumerate(self.trees_root):
if self.has_both_operators(self.TreeNode):
self.offset = 35
self.ShowTree(root, self.TreeNode,i*300, 0)
self.offset = 0
self.seq = 1 # 重置序号
for noed in self.TreeNode:
print("运算符节点", noed)
else:
QMessageBox.warning(self, '警告', '请先选择两个节点')
else:
QMessageBox.warning(self, '警告', '请先选择一个运算符')
def exchange_value_node(self):
# 修改节点值
if len(self.selected_id) == 1:
if self.selected_value:
if self.TreeNode:
for node in self.TreeNode:
if node.NodeID == self.selected_id[0]:
node.FaceValue = self.selected_value
for nodet in self.scene.items():
if isinstance(nodet, RoundedRectangleItem):
if nodet.id == self.selected_id[0]:
nodet.text = str(self.selected_value)
nodet.update()
else:
QMessageBox.warning(self, '警告', '请先选择一张牌')
else:
QMessageBox.warning(self, '警告', '请先选择一个节点')
def exchange_ops_node(self):
# 修改节点运算符
if len(self.selected_id) == 1:
if self.selected_ops:
if self.TreeNode:
for node in self.TreeNode:
if node.NodeID == self.selected_id[0]:
node.Ops = self.selected_ops
for nodet in self.scene.items():
if isinstance(nodet, RoundedRectangleItem):
if nodet.id == self.selected_id[0]:
nodet.text = str(self.selected_ops)
nodet.update()
else:
QMessageBox.warning(self, '警告', '请先选择一个运算符')
else:
QMessageBox.warning(self, '警告', '请先选择一个节点')
def exchange_two_nodes(self):
# 交换选中两个节点FaceValue的值
if len(self.selected_id) == 2:
if self.TreeNode:
node_1 = None
node_2 = None
for node in self.TreeNode:
if node.NodeID == self.selected_id[0]:
if node.NodeType == 'Value':
node_1 = node
else:
QMessageBox.warning(self, '警告', '请选择两个数值节点')
return
elif node.NodeID == self.selected_id[1]:
if node.NodeType == 'Value':
node_2 = node
else:
QMessageBox.warning(self, '警告', '请选择两个数值节点')
return
if node_1 and node_2:
node_1.FaceValue, node_2.FaceValue = node_2.FaceValue, node_1.FaceValue
for item in self.scene.items():
if isinstance(item, RoundedRectangleItem):
if item.id == self.selected_id[0]:
item.text = str(node_1.FaceValue)
item.update()
elif item.id == self.selected_id[1]:
item.text = str(node_2.FaceValue)
item.update()
else:
QMessageBox.warning(self, '警告', '请选择两个节点')
def selected_node(self, id):
if len(self.selected_id) < 2:
self.selected_id.append(id)
else:
QMessageBox.warning(self, '警告', '不能选择超过3个节点')
for nodet in self.scene.items(): # 遍历场景中的所有图元
if isinstance(nodet, RoundedRectangleItem): # 如果是圆角矩形
if nodet.id == id: # 如果是当前选中的节点
nodet.isSelected = False # 取消选中
nodet.update() # 更新图元
def unselected_node(self, id):
self.selected_id.remove(id)
print(self.selected_id)
def flash_node(self, id): # 还原节点为未选中状态
for nodet in self.scene.items(): # 遍历场景中的所有图元
if isinstance(nodet, RoundedRectangleItem): # 如果是圆角矩形
if nodet.id == id: # 如果是当前选中的节点
nodet.isSelected = False # 取消选中
nodet.update() # 更新图元
def init_ui(self):
self.scene = QGraphicsScene()
self.graphicsView.setScene(self.scene)
def init_slot(self):
self.pushButton.clicked.connect(self.on_calc)
def load_image(self, path, Tree_4_nums, index):
def current_selection(value, path):
self.selected_value = value
self.p1_selected.setStyleSheet(f"border-image: url({path});")
self.pushButton_ast.setEnabled(False)
self.pushButton_allan.setEnabled(False)
self.pushButton_dtree.setEnabled(False)
self.pushButton_autosv.setEnabled(False)
print(value)
if index == 0:
self.p1.setStyleSheet(f"border-image: url({path});")
self.p1.clicked.connect(lambda :current_selection(Tree_4_nums[index], path))
elif index == 1:
self.p2.setStyleSheet(f"border-image: url({path});")
self.p2.clicked.connect(lambda :current_selection(Tree_4_nums[index], path))
elif index == 2:
self.p3.setStyleSheet(f"border-image: url({path});")
self.p3.clicked.connect(lambda :current_selection(Tree_4_nums[index], path))
elif index == 3:
self.p4.setStyleSheet(f"border-image: url({path});")
self.p4.clicked.connect(lambda :current_selection(Tree_4_nums[index], path))
def show_card(self):
self.pushButton_ast.setEnabled(True)
self.pushButton_allan.setEnabled(True)
self.pushButton_dtree.setEnabled(True)
self.pushButton_autosv.setEnabled(True)
self.p1_selected.setStyleSheet("border-image: none;")
# 原始数组
self.lineEdit.clear()
self.label_result.setText(" =? ")
self.label_TF.setText("")
original_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
face_card = ['Club', 'Diamond', 'Heart', 'Spade']
# 从原始数组中随机选择4个元素组成新列表
self.Tree_4_nums = random.sample(original_list, 4)
# 从花色中随机选择一个
for index, num in enumerate(self.Tree_4_nums):
card_face = random.choice(face_card)
if num == 11:
card_path = f"card/{card_face}/{card_face}j.png"
elif num == 12:
card_path = f"card/{card_face}/{card_face}q.png"
elif num == 13:
card_path = f"card/{card_face}/{card_face}k.png"
else:
card_path = f"card/{card_face}/{card_face}{num}.png"
self.load_image(card_path, self.Tree_4_nums, index)
# return self.Tree_4_nums
def AutoTest(self):
if self.Tree_4_nums is None:
QMessageBox.warning(self, '警告', '请先出题')
return
else:
results = data.get_Aexps(self.Tree_4_nums)
if results == "无法得出24点":
self.lineEdit.clear()
self.lineEdit.setText("无法得出24点")
return
else:
if self.r_count < len(results):
self.lineEdit.clear()
self.lineEdit.setText(f"{results[self.r_count]}")
self.on_calc() # 自动计算
self.draw_tree() # 绘制语法树
self.r_count += 1
else:
QMessageBox.information(self, '提示', '已经是最后一个表达式了')
self.r_count = 0
def AutoTest_9_10(self):
if self.Tree_4_nums is None:
QMessageBox.warning(self, '警告', '请先出题')
return
else:
aexp = data.gen_exp(self.Tree_4_nums)
if aexp == "无法得出24点":
self.lineEdit.clear()
self.lineEdit.setText("无法得出24点")
else:
self.lineEdit.clear()
self.lineEdit.setText(f"{aexp}")
self.on_calc() # 自动计算
self.draw_tree() # 绘制语法树
def calculate_button(self): #
self.scene.clear()
aexp = self.lineEdit.text()
try:
exp_ls = data.get_postfix_expression(aexp) # 获取后缀表达式列表
self.TreeNode = data.ExpressionAnalyse(exp_ls) # 将后缀表达式转化为节点树
result = data.calculate(self.TreeNode[-1], self.TreeNode)
self.label_result.setText(f"={result}")
except:
QMessageBox.warning(self, '警告', '表达式错误!')
return
if self.TreeNode:
root = self.TreeNode[-1]
result = data.calculate(root, self.TreeNode)
self.label_result.setText(f"={result}")
self.result_ToF(int(result))
if self.has_both_operators(self.TreeNode):
self.offset = 35
self.ShowTree(root, self.TreeNode)
self.offset = 0
def has_both_operators(self, TreeNode): # 判断是否同时有两个运算符
ops = data.OPS
def find_op_by_id(id): # 根据ID查找运算符
for node in TreeNode:
if node.NodeID == id and node.NodeType == "Operator":
return node.Ops
for node in TreeNode: # 遍历节点树
if node.NodeType == "Operator":
opl = find_op_by_id(node.LeftNodeID)
opr = find_op_by_id(node.RightNodeID)
if opl in ops and opr in ops:
return True
def draw_tree(self):
self.scene.clear()
aexp = self.lineEdit.text()
if aexp == "":
QMessageBox.warning(self, '警告', '请输入表达式')
return
try:
exp_ls = data.get_postfix_expression(aexp) # 获取后缀表达式列表
self.TreeNode = data.ExpressionAnalyse(exp_ls) # 将后缀表达式转化为节点树
root = self.TreeNode[-1]
if self.has_both_operators(self.TreeNode):
self.offset = 35
self.ShowTree(root, self.TreeNode, depth=0)
self.offset = 0
except Exception as e:
QMessageBox.warning(self, '警告', '表达式错误')
def ShowTree(self, root, TreeNode, startx=0, starty=0, depth=0):
# 绘制根节点
if root.NodeType == 'Value':
nds_root = RoundedRectangleItem(startx, starty, root.FaceValue, root.NodeID)
nds_root.selected.connect(lambda id: self.selected_node(id))
nds_root.unselected.connect(lambda id: self.unselected_node(id))
self.drawn_tree_id.add(root.NodeID)
else:
nds_root = RoundedRectangleItem(startx, starty, root.Ops, root.NodeID)
nds_root.selected.connect(lambda id: self.selected_node(id))
nds_root.unselected.connect(lambda id: self.unselected_node(id))
self.drawn_tree_id.add(root.NodeID)
nds_root.setZValue(1)
self.scene.addItem(nds_root)
# 计算节点间的水平偏移量
horizontal_offset = 100 - depth*self.offset
# 计算左子树和右子树的位置
left_x, left_y = startx - horizontal_offset, starty + 100
right_x, right_y = startx + horizontal_offset, starty + 100
# 绘制左子树
if root.LeftNodeID is not None:
left_child = next(node for node in TreeNode if node.NodeID == root.LeftNodeID)
self.ShowTree(left_child, TreeNode, left_x, left_y, depth + 1)
# 绘制左子树与根节点之间的连线
line_left = QGraphicsLineItem(startx + 35, starty + 35, left_x + 35, left_y + 35)
line_left.setZValue(-1)
line_left.setPen(QPen(Qt.red, 3))
self.scene.addItem(line_left)
# 绘制右子树
if root.RightNodeID is not None:
right_child = next(node for node in TreeNode if node.NodeID == root.RightNodeID)
self.ShowTree(right_child, TreeNode, right_x, right_y, depth + 1)
# 绘制右子树与根节点之间的连线
line_right = QGraphicsLineItem(startx + 35, starty + 35, right_x + 35, right_y + 35)
line_right.setZValue(-1)
line_right.setPen(QPen(Qt.red, 3))
self.scene.addItem(line_right)
def on_calc(self):
aexp = self.lineEdit.text()
if aexp == '':
QMessageBox.warning(self, '警告', '请输入表达式')
return
try:
result = eval(aexp)
self.label_result.setText(f"={int(result)}")
# 设置字体样式
self.result_ToF(result)
except Exception as e:
QMessageBox.warning(self, '警告', '表达式错误')
return
def result_ToF(self,result):
font = QFont('Microsoft YaHei', 16)
font.setBold(True) # 将字体设置为粗体
self.label_TF.setText('' if result == 24 else '×')
# 将字体样式应用到 QLabel 上
self.label_TF.setFont(font)
# 将文本颜色设置为红色
self.label_TF.setStyleSheet("color: red;background-color:rgb(219, 205, 166)")
if __name__ == '__main__':
app = QApplication()
window = MainWindow()
window.show()
app.exec()

@ -0,0 +1,267 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'main_ui.ui'
##
## Created by: Qt User Interface Compiler version 6.6.1
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
QMetaObject, QObject, QPoint, QRect,
QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
QFont, QFontDatabase, QGradient, QIcon,
QImage, QKeySequence, QLinearGradient, QPainter,
QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QFrame, QGraphicsView, QHBoxLayout,
QLabel, QLineEdit, QMainWindow, QMenuBar,
QPushButton, QSizePolicy, QStatusBar, QVBoxLayout,
QWidget)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
MainWindow.resize(1190, 923)
font = QFont()
font.setPointSize(16)
MainWindow.setFont(font)
MainWindow.setStyleSheet(u"")
self.centralwidget = QWidget(MainWindow)
self.centralwidget.setObjectName(u"centralwidget")
self.centralwidget.setStyleSheet(u"")
self.verticalLayout = QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName(u"verticalLayout")
self.frame = QFrame(self.centralwidget)
self.frame.setObjectName(u"frame")
self.frame.setFrameShape(QFrame.StyledPanel)
self.frame.setFrameShadow(QFrame.Raised)
self.horizontalLayoutWidget = QWidget(self.frame)
self.horizontalLayoutWidget.setObjectName(u"horizontalLayoutWidget")
self.horizontalLayoutWidget.setGeometry(QRect(40, 10, 651, 222))
self.horizontalLayout = QHBoxLayout(self.horizontalLayoutWidget)
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.p4 = QPushButton(self.horizontalLayoutWidget)
self.p4.setObjectName(u"p4")
self.p4.setMinimumSize(QSize(148, 220))
self.p4.setMaximumSize(QSize(148, 16777215))
self.horizontalLayout.addWidget(self.p4)
self.p3 = QPushButton(self.horizontalLayoutWidget)
self.p3.setObjectName(u"p3")
self.p3.setMinimumSize(QSize(148, 220))
self.p3.setMaximumSize(QSize(148, 16777215))
self.horizontalLayout.addWidget(self.p3)
self.p2 = QPushButton(self.horizontalLayoutWidget)
self.p2.setObjectName(u"p2")
self.p2.setMinimumSize(QSize(148, 220))
self.p2.setMaximumSize(QSize(148, 16777215))
self.horizontalLayout.addWidget(self.p2)
self.p1 = QPushButton(self.horizontalLayoutWidget)
self.p1.setObjectName(u"p1")
self.p1.setMinimumSize(QSize(148, 220))
self.p1.setMaximumSize(QSize(148, 16777215))
self.horizontalLayout.addWidget(self.p1)
self.lineEdit = QLineEdit(self.frame)
self.lineEdit.setObjectName(u"lineEdit")
self.lineEdit.setGeometry(QRect(40, 230, 821, 31))
self.label_result = QLabel(self.frame)
self.label_result.setObjectName(u"label_result")
self.label_result.setGeometry(QRect(880, 230, 141, 31))
self.label_result.setStyleSheet(u"background-color:rgb(74, 203, 105)")
self.label_result.setAlignment(Qt.AlignCenter)
self.label_TF = QLabel(self.frame)
self.label_TF.setObjectName(u"label_TF")
self.label_TF.setGeometry(QRect(1030, 230, 31, 31))
self.label_TF.setStyleSheet(u"background-color:rgb(219, 205, 166)")
self.label_TF.setAlignment(Qt.AlignCenter)
self.pushButton = QPushButton(self.frame)
self.pushButton.setObjectName(u"pushButton")
self.pushButton.setGeometry(QRect(1080, 220, 81, 51))
font1 = QFont()
font1.setPointSize(16)
font1.setBold(True)
self.pushButton.setFont(font1)
self.pushButton.setStyleSheet(u"")
self.pushButton_q = QPushButton(self.frame)
self.pushButton_q.setObjectName(u"pushButton_q")
self.pushButton_q.setGeometry(QRect(950, 50, 151, 51))
self.pushButton_q.setFont(font1)
self.pushButton_ex = QPushButton(self.frame)
self.pushButton_ex.setObjectName(u"pushButton_ex")
self.pushButton_ex.setGeometry(QRect(950, 130, 151, 51))
self.pushButton_ex.setFont(font1)
self.pushButton_autosv = QPushButton(self.frame)
self.pushButton_autosv.setObjectName(u"pushButton_autosv")
self.pushButton_autosv.setGeometry(QRect(40, 270, 141, 41))
self.pushButton_autosv.setFont(font1)
self.pushButton_dtree = QPushButton(self.frame)
self.pushButton_dtree.setObjectName(u"pushButton_dtree")
self.pushButton_dtree.setGeometry(QRect(200, 270, 141, 41))
self.pushButton_dtree.setFont(font1)
self.pushButton_allan = QPushButton(self.frame)
self.pushButton_allan.setObjectName(u"pushButton_allan")
self.pushButton_allan.setGeometry(QRect(360, 270, 141, 41))
self.pushButton_allan.setFont(font1)
self.pushButton_exp = QPushButton(self.frame)
self.pushButton_exp.setObjectName(u"pushButton_exp")
self.pushButton_exp.setGeometry(QRect(520, 270, 141, 41))
self.pushButton_exp.setFont(font1)
self.pushButton_ast = QPushButton(self.frame)
self.pushButton_ast.setObjectName(u"pushButton_ast")
self.pushButton_ast.setGeometry(QRect(690, 270, 141, 41))
self.pushButton_ast.setFont(font1)
self.pushButton_9 = QPushButton(self.frame)
self.pushButton_9.setObjectName(u"pushButton_9")
self.pushButton_9.setGeometry(QRect(860, 270, 141, 41))
self.pushButton_9.setFont(font1)
self.label = QLabel(self.frame)
self.label.setObjectName(u"label")
self.label.setGeometry(QRect(760, 170, 101, 31))
self.p1_selected = QPushButton(self.frame)
self.p1_selected.setObjectName(u"p1_selected")
self.p1_selected.setGeometry(QRect(750, 20, 100, 150))
self.p1_selected.setMinimumSize(QSize(100, 150))
self.p1_selected.setMaximumSize(QSize(100, 150))
self.verticalLayout.addWidget(self.frame)
self.line = QFrame(self.centralwidget)
self.line.setObjectName(u"line")
self.line.setMinimumSize(QSize(0, 0))
self.line.setFrameShape(QFrame.HLine)
self.line.setFrameShadow(QFrame.Sunken)
self.verticalLayout.addWidget(self.line)
self.frame_2 = QFrame(self.centralwidget)
self.frame_2.setObjectName(u"frame_2")
self.frame_2.setFrameShape(QFrame.StyledPanel)
self.frame_2.setFrameShadow(QFrame.Raised)
self.graphicsView = QGraphicsView(self.frame_2)
self.graphicsView.setObjectName(u"graphicsView")
self.graphicsView.setGeometry(QRect(0, 0, 1000, 541))
self.pushButton_add = QPushButton(self.frame_2)
self.pushButton_add.setObjectName(u"pushButton_add")
self.pushButton_add.setGeometry(QRect(1040, 120, 41, 41))
font2 = QFont()
font2.setPointSize(24)
font2.setBold(False)
self.pushButton_add.setFont(font2)
self.pushButton_add.setStyleSheet(u"")
self.pushButton_sub = QPushButton(self.frame_2)
self.pushButton_sub.setObjectName(u"pushButton_sub")
self.pushButton_sub.setGeometry(QRect(1090, 120, 41, 41))
self.pushButton_sub.setFont(font2)
self.pushButton_sub.setStyleSheet(u"")
self.pushButton_div = QPushButton(self.frame_2)
self.pushButton_div.setObjectName(u"pushButton_div")
self.pushButton_div.setGeometry(QRect(1090, 170, 41, 41))
self.pushButton_div.setFont(font2)
self.pushButton_div.setStyleSheet(u"")
self.pushButton_mul = QPushButton(self.frame_2)
self.pushButton_mul.setObjectName(u"pushButton_mul")
self.pushButton_mul.setGeometry(QRect(1040, 170, 41, 41))
self.pushButton_mul.setFont(font2)
self.pushButton_mul.setStyleSheet(u"")
self.add_ops_node = QPushButton(self.frame_2)
self.add_ops_node.setObjectName(u"add_ops_node")
self.add_ops_node.setGeometry(QRect(1020, 220, 141, 41))
font3 = QFont()
font3.setPointSize(14)
font3.setBold(False)
self.add_ops_node.setFont(font3)
self.add_val_node = QPushButton(self.frame_2)
self.add_val_node.setObjectName(u"add_val_node")
self.add_val_node.setGeometry(QRect(1020, 270, 141, 41))
self.add_val_node.setFont(font3)
self.ex_node_value = QPushButton(self.frame_2)
self.ex_node_value.setObjectName(u"ex_node_value")
self.ex_node_value.setGeometry(QRect(1020, 320, 141, 41))
self.ex_node_value.setFont(font3)
self.ex_node_ops = QPushButton(self.frame_2)
self.ex_node_ops.setObjectName(u"ex_node_ops")
self.ex_node_ops.setGeometry(QRect(1020, 370, 141, 41))
self.ex_node_ops.setFont(font3)
self.ex_node_self = QPushButton(self.frame_2)
self.ex_node_self.setObjectName(u"ex_node_self")
self.ex_node_self.setGeometry(QRect(1020, 420, 141, 41))
self.ex_node_self.setFont(font3)
self.label_2 = QLabel(self.frame_2)
self.label_2.setObjectName(u"label_2")
self.label_2.setGeometry(QRect(1030, 70, 121, 41))
self.lb_ops_selected = QLabel(self.frame_2)
self.lb_ops_selected.setObjectName(u"lb_ops_selected")
self.lb_ops_selected.setGeometry(QRect(1060, 10, 53, 51))
font4 = QFont()
font4.setPointSize(18)
font4.setBold(True)
self.lb_ops_selected.setFont(font4)
self.lb_ops_selected.setStyleSheet(u"background-color:rgb(255, 255, 255)")
self.lb_ops_selected.setAlignment(Qt.AlignCenter)
self.clear_button = QPushButton(self.frame_2)
self.clear_button.setObjectName(u"clear_button")
self.clear_button.setGeometry(QRect(1020, 470, 141, 41))
self.clear_button.setFont(font3)
self.verticalLayout.addWidget(self.frame_2)
self.verticalLayout.setStretch(0, 3)
self.verticalLayout.setStretch(2, 5)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(MainWindow)
self.menubar.setObjectName(u"menubar")
self.menubar.setGeometry(QRect(0, 0, 1190, 32))
MainWindow.setMenuBar(self.menubar)
self.statusbar = QStatusBar(MainWindow)
self.statusbar.setObjectName(u"statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QMetaObject.connectSlotsByName(MainWindow)
# setupUi
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"\u8ba1\u7b97\u601d\u7ef424\u70b9", None))
self.p4.setText("")
self.p3.setText("")
self.p2.setText("")
self.p1.setText("")
self.label_result.setText(QCoreApplication.translate("MainWindow", u" = \uff1f", None))
self.label_TF.setText("")
self.pushButton.setText(QCoreApplication.translate("MainWindow", u"\u8ba1\u7b97", None))
self.pushButton_q.setText(QCoreApplication.translate("MainWindow", u"\u51fa\u9898", None))
self.pushButton_ex.setText(QCoreApplication.translate("MainWindow", u"\u6362\u724c", None))
self.pushButton_autosv.setText(QCoreApplication.translate("MainWindow", u"\u81ea\u52a8\u6c42\u89e3", None))
self.pushButton_dtree.setText(QCoreApplication.translate("MainWindow", u"\u753b\u6811", None))
self.pushButton_allan.setText(QCoreApplication.translate("MainWindow", u"\u6240\u6709\u7b54\u6848", None))
self.pushButton_exp.setText(QCoreApplication.translate("MainWindow", u"\u751f\u6210\u8868\u8fbe\u5f0f", None))
self.pushButton_ast.setText(QCoreApplication.translate("MainWindow", u"\u751f\u6210\u8bed\u6cd5\u6811", None))
self.pushButton_9.setText(QCoreApplication.translate("MainWindow", u"\u4e00\u81f4\u6027\u68c0\u67e5", None))
self.label.setText(QCoreApplication.translate("MainWindow", u"\u5df2\u9009\u724c\u9762", None))
self.p1_selected.setText("")
self.pushButton_add.setText(QCoreApplication.translate("MainWindow", u"+", None))
self.pushButton_sub.setText(QCoreApplication.translate("MainWindow", u"-", None))
self.pushButton_div.setText(QCoreApplication.translate("MainWindow", u"/", None))
self.pushButton_mul.setText(QCoreApplication.translate("MainWindow", u"*", None))
self.add_ops_node.setText(QCoreApplication.translate("MainWindow", u"\u6dfb\u52a0\u8fd0\u7b97\u8282\u70b9", None))
self.add_val_node.setText(QCoreApplication.translate("MainWindow", u"\u6dfb\u52a0\u6570\u503c\u8282\u70b9", None))
self.ex_node_value.setText(QCoreApplication.translate("MainWindow", u"\u6539\u53d8\u8fd0\u7b97\u8f93\u5165", None))
self.ex_node_ops.setText(QCoreApplication.translate("MainWindow", u"\u6539\u53d8\u8282\u70b9\u8fd0\u7b97", None))
self.ex_node_self.setText(QCoreApplication.translate("MainWindow", u"\u6570\u503c\u8282\u70b9\u4ea4\u6362", None))
self.label_2.setText(QCoreApplication.translate("MainWindow", u"\u5df2\u9009\u8fd0\u7b97\u7b26", None))
self.lb_ops_selected.setText("")
self.clear_button.setText(QCoreApplication.translate("MainWindow", u"\u6e05\u7a7a\u753b\u5e03", None))
# retranslateUi

@ -0,0 +1,676 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1190</width>
<height>923</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="windowTitle">
<string>计算思维24点</string>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<widget class="QWidget" name="centralwidget">
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="3,0,5">
<item>
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>40</x>
<y>10</y>
<width>651</width>
<height>222</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="p4">
<property name="minimumSize">
<size>
<width>148</width>
<height>220</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>148</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="p3">
<property name="minimumSize">
<size>
<width>148</width>
<height>220</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>148</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="p2">
<property name="minimumSize">
<size>
<width>148</width>
<height>220</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>148</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="p1">
<property name="minimumSize">
<size>
<width>148</width>
<height>220</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>148</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QLineEdit" name="lineEdit">
<property name="geometry">
<rect>
<x>40</x>
<y>230</y>
<width>821</width>
<height>31</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_result">
<property name="geometry">
<rect>
<x>880</x>
<y>230</y>
<width>141</width>
<height>31</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">background-color:rgb(74, 203, 105)</string>
</property>
<property name="text">
<string> = </string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QLabel" name="label_TF">
<property name="geometry">
<rect>
<x>1030</x>
<y>230</y>
<width>31</width>
<height>31</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">background-color:rgb(219, 205, 166)</string>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>1080</x>
<y>220</y>
<width>81</width>
<height>51</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>计算</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_q">
<property name="geometry">
<rect>
<x>950</x>
<y>50</y>
<width>151</width>
<height>51</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>出题</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_ex">
<property name="geometry">
<rect>
<x>950</x>
<y>130</y>
<width>151</width>
<height>51</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>换牌</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_autosv">
<property name="geometry">
<rect>
<x>40</x>
<y>270</y>
<width>141</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>自动求解</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_dtree">
<property name="geometry">
<rect>
<x>200</x>
<y>270</y>
<width>141</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>画树</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_allan">
<property name="geometry">
<rect>
<x>360</x>
<y>270</y>
<width>141</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>所有答案</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_exp">
<property name="geometry">
<rect>
<x>520</x>
<y>270</y>
<width>141</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>生成表达式</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_ast">
<property name="geometry">
<rect>
<x>690</x>
<y>270</y>
<width>141</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>生成语法树</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_9">
<property name="geometry">
<rect>
<x>860</x>
<y>270</y>
<width>141</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>一致性检查</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>760</x>
<y>170</y>
<width>101</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>已选牌面</string>
</property>
</widget>
<widget class="QPushButton" name="p1_selected">
<property name="geometry">
<rect>
<x>750</x>
<y>20</y>
<width>100</width>
<height>150</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>150</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>150</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QFrame" name="frame_2">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<widget class="QGraphicsView" name="graphicsView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1000</width>
<height>541</height>
</rect>
</property>
</widget>
<widget class="QPushButton" name="pushButton_add">
<property name="geometry">
<rect>
<x>1040</x>
<y>120</y>
<width>41</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>24</pointsize>
<bold>false</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>+</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_sub">
<property name="geometry">
<rect>
<x>1090</x>
<y>120</y>
<width>41</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>24</pointsize>
<bold>false</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>-</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_div">
<property name="geometry">
<rect>
<x>1090</x>
<y>170</y>
<width>41</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>24</pointsize>
<bold>false</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>/</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_mul">
<property name="geometry">
<rect>
<x>1040</x>
<y>170</y>
<width>41</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>24</pointsize>
<bold>false</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>*</string>
</property>
</widget>
<widget class="QPushButton" name="add_ops_node">
<property name="geometry">
<rect>
<x>1020</x>
<y>220</y>
<width>141</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>添加运算节点</string>
</property>
</widget>
<widget class="QPushButton" name="add_val_node">
<property name="geometry">
<rect>
<x>1020</x>
<y>270</y>
<width>141</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>添加数值节点</string>
</property>
</widget>
<widget class="QPushButton" name="ex_node_value">
<property name="geometry">
<rect>
<x>1020</x>
<y>320</y>
<width>141</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>改变运算输入</string>
</property>
</widget>
<widget class="QPushButton" name="ex_node_ops">
<property name="geometry">
<rect>
<x>1020</x>
<y>370</y>
<width>141</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>改变节点运算</string>
</property>
</widget>
<widget class="QPushButton" name="ex_node_self">
<property name="geometry">
<rect>
<x>1020</x>
<y>420</y>
<width>141</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>数值节点交换</string>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>1030</x>
<y>70</y>
<width>121</width>
<height>41</height>
</rect>
</property>
<property name="text">
<string>已选运算符</string>
</property>
</widget>
<widget class="QLabel" name="lb_ops_selected">
<property name="geometry">
<rect>
<x>1060</x>
<y>10</y>
<width>53</width>
<height>51</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">background-color:rgb(255, 255, 255)</string>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QPushButton" name="clear_button">
<property name="geometry">
<rect>
<x>1020</x>
<y>470</y>
<width>141</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>14</pointsize>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>清空画布</string>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1190</width>
<height>32</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

@ -0,0 +1,71 @@
import math
def split_exp(expression): # 将表达式拆分为数字、运算符和三角函数
stack = []
current_item = ''
for char in expression:
if char.isdigit() or char == '.':
current_item += char
elif char.isalpha(): # 识别字母表示的函数名
current_item += char
elif char == '(':
if current_item:
stack.append(current_item)
current_item = ''
stack.append(char)
elif char == ')' and current_item:
stack.append(current_item)
stack.append(char)
current_item = ''
elif char in OPS:
if current_item:
stack.append(current_item)
current_item = ''
stack.append(char)
if current_item:
stack.append(current_item)
return stack
def get_postfix_expression(expression):
# 多位数拆分
expression = split_exp(expression)
precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '^': 3,"sin":4,"cos":4,"tan":4}
postfix = []
stack = []
def is_number(char):
try:
float(char)
return True
except ValueError:
return False
for char in expression:
if is_number(char):
postfix.append(char)
elif char == '(':
stack.append(char)
elif char == ')':
while stack and stack[-1] != '(':
postfix.append(stack.pop())
stack.pop() # 弹出 '('
elif char in precedence:
while stack and stack[-1] != '(' and precedence.get(stack[-1], 0) >= precedence.get(char, 0):
postfix.append(stack.pop())
stack.append(char)
# elif char in ('sin', 'cos', 'tan'): # 处理三角函数
# stack.append(char)
while stack:
postfix.append(stack.pop())
return postfix
exp = 'sin(3.3)^2+cos(3.3)^2'
OPS = ['+', '-', '*', '/', '^']
exp_ls = split_exp(exp)
print(exp_ls)
print(get_postfix_expression(exp)) # ['3.3', 'sin', '2', '^', '3.3', 'cos', '2', '^', '+']
Loading…
Cancel
Save