添加 生成表达式 功能

main
zart 10 months ago
parent c22d011ee1
commit b3ae5007b2

@ -3,6 +3,8 @@ import math
import random
OPS = ['+', '-', '*', '/', '^', 'sin', 'cos', 'tan']
def get_Aexps(nums=None):
ops = OPS[:4]
if nums is None:
@ -30,6 +32,7 @@ def get_Aexps(nums=None):
else:
return "无法得出24点"
def gen_exp(nums): # 生成表达式
ops = OPS[:4]
result = 0
@ -47,6 +50,8 @@ def gen_exp(nums): # 生成表达式
continue # 跳过0除错误
if result != 24:
return "无法得出24点"
def get_nums_group(nums): # 获取4个数的排列组合
group = []
for i in range(4):
@ -69,8 +74,9 @@ class Node:
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}"
return (
f"NodeID: {self.NodeID}\t NodeType: {self.NodeType}\t Ops: {self.Ops}\t LeftNodeID: {self.LeftNodeID}\t "
f"RightNodeID: {self.RightNodeID}\t FaceValue: {self.FaceValue}\t FaceColor: {self.FaceColor}")
def split_exp(expression): # 将表达式拆分为数字和运算符
@ -128,7 +134,7 @@ def get_postfix_expression_(expression): # 将中缀表达式转化为后缀表
return postfix
def get_postfix_expression(expression):
def get_postfix_expression(expression): # 将中缀表达式转化为后缀表达式
# 多位数拆分
expression = split_exp(expression)
precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '^': 3, "sin": 4, "cos": 4, "tan": 4}
@ -137,8 +143,10 @@ def get_postfix_expression(expression):
def is_number(char):
try:
float(char);return True
except ValueError: return False
float(char)
return True
except ValueError:
return False
for char in expression:
if is_number(char):
@ -153,7 +161,6 @@ def get_postfix_expression(expression):
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())
@ -193,7 +200,7 @@ def calculate(root, TreeNode): # 计算节点树表达式
elif root.Ops == '/':
if right_value == 0:
return None # 除数为0返回None表示计算错误
return left_value / right_value
return left_value / right_value # 除法结果为浮点数
return None # 节点类型不合法返回None表示计算错误
@ -202,6 +209,8 @@ def find_node_by_id(node_id, TreeNode):
if node.NodeID == node_id:
return node
return None
def evaluate_postfix(expression): # 计算后缀表达式
stack = []
for char in expression:
@ -223,6 +232,7 @@ def evaluate_postfix(expression): # 计算后缀表达式
stack.append(result)
return stack.pop()
def exp_to_treeNode_dict(exp_ls): # 返回嵌套节点字典
stack = []
for char in exp_ls:
@ -238,6 +248,23 @@ def exp_to_treeNode_dict(exp_ls): # 返回嵌套节点字典
return stack.pop()
# 写一个函数从TreeNode中还原出表达式
def get_expression(TreeNode):
stack = []
for node in TreeNode:
if node.NodeType == 'Value':
stack.append(node.FaceValue)
elif node.NodeType == 'Operator':
if node.Ops in ('sin', 'cos', 'tan'): # 三角函数
right = stack.pop() # 三角函数只有右操作数
stack.append(f"{node.Ops}({right})")
else:
right = stack.pop()
left = stack.pop()
stack.append(f"({left}{node.Ops}{right})")
return stack.pop()
def ExpressionAnalyse(exp_ls): # 返回语法树
stack = [] # 符合和数值栈
TreeNode = []
@ -319,5 +346,4 @@ if __name__ == '__main__':
for node in TreeNode:
print(node)
# print_tree(Aexp)

@ -6,6 +6,7 @@ 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)
@ -65,5 +66,4 @@ class RoundedRectangleItem(QGraphicsItem, QObject):
else:
self.unselected.emit(self.id)
super().mousePressEvent(event)

@ -1,11 +1,11 @@
import random
from PySide6.QtGui import QPainter, QPen, QFont, QPixmap
from PySide6.QtGui import QFont
from PySide6.QtWidgets import QApplication, QMainWindow, QGraphicsLineItem, QMessageBox, QGraphicsScene
from main_ui import Ui_MainWindow
import data
from graph_24 import *
from main_ui import Ui_MainWindow
class MainWindow(QMainWindow, Ui_MainWindow):
@ -27,37 +27,36 @@ class MainWindow(QMainWindow, Ui_MainWindow):
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_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)
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) # 交换两个节点
self.pushButton_exp.clicked.connect(self.agent_exp) # 生成表达式
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_id = [] # 选中的节点ID
self.value_nodes = [] # 数值节点
self.TreeNode = [] # 所有节点
self.adds_id = set() # 已经用过的ID
self.trees_root = [] # 保存所有树的根节点
self.drawn_tree_id = set() # 已经绘制了树的节点
self.selected_value = None # 当前选择的卡片值.
self.selected_ops = None # 选择的运算符
# 清空运算符显示
self.lb_ops_selected.setText("")
self.lb_ops_selected.setText("") # 运算符显示
def select_ops(self, ops):
self.lb_ops_selected.setText(ops)
@ -87,7 +86,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
if node.LeftNodeID == id or node.RightNodeID == id:
return True
def add_operator_node(self):
def add_operator_node(self): # 添加运算符节点
if self.selected_ops is not None:
if len(self.selected_id) == 2:
# 判断已选节点是否已经被连接
@ -125,6 +124,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.seq = 1 # 重置序号
for noed in self.TreeNode:
print("运算符节点", noed)
exps = data.get_expression(self.TreeNode)
print("表达式", exps)
else:
QMessageBox.warning(self, '警告', '请先选择两个节点')
else:
@ -200,7 +201,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
else:
QMessageBox.warning(self, '警告', '请选择两个节点')
def selected_node(self, id):
if len(self.selected_id) < 2:
self.selected_id.append(id)
@ -212,7 +212,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
nodet.isSelected = False # 取消选中
nodet.update() # 更新图元
def unselected_node(self, id):
self.selected_id.remove(id)
print(self.selected_id)
@ -223,11 +222,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
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)
@ -239,7 +238,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.pushButton_allan.setEnabled(False)
self.pushButton_dtree.setEnabled(False)
self.pushButton_autosv.setEnabled(False)
print(value)
# print(value)
if index == 0:
self.p1.setStyleSheet(f"border-image: url({path});")
@ -254,7 +253,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
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)
@ -319,22 +317,22 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.on_calc() # 自动计算
self.draw_tree() # 绘制语法树
def calculate_button(self): #
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}")
self.label_result.setText(f"={round(result, 2)}")
except:
QMessageBox.warning(self, '警告', '表达式错误!')
return
if self.TreeNode:
if self.TreeNode: # 如果节点树不为空
root = self.TreeNode[-1]
result = data.calculate(root, self.TreeNode)
self.label_result.setText(f"={result}")
self.result_ToF(int(result))
result = data.calculate(root, self.TreeNode) # 计算表达式的值
self.label_result.setText(f"={round(result, 2)}")
self.result_ToF(int(result)) # 判断结果是否为24
if self.has_both_operators(self.TreeNode):
self.offset = 35
self.ShowTree(root, self.TreeNode)
@ -342,10 +340,12 @@ class MainWindow(QMainWindow, Ui_MainWindow):
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)
@ -353,8 +353,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
if opl in ops and opr in ops:
return True
def draw_tree(self):
self.scene.clear()
aexp = self.lineEdit.text()
@ -372,20 +370,22 @@ class MainWindow(QMainWindow, Ui_MainWindow):
except Exception as e:
QMessageBox.warning(self, '警告', '表达式错误')
def ShowTree(self, root, TreeNode, startx=0, starty=0, depth=0):
self.selected_id = [] # 清空选中的节点
self.drawn_tree_id = set() # 清空已绘制的节点ID
# 绘制根节点
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)
self.adds_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)
self.adds_id.add(root.NodeID)
nds_root.setZValue(1)
self.scene.addItem(nds_root)
@ -418,7 +418,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
line_right.setPen(QPen(Qt.red, 3))
self.scene.addItem(line_right)
def on_calc(self):
aexp = self.lineEdit.text()
if aexp == '':
@ -433,7 +432,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
QMessageBox.warning(self, '警告', '表达式错误')
return
def result_ToF(self, result):
font = QFont('Microsoft YaHei', 16)
font.setBold(True) # 将字体设置为粗体
@ -443,6 +441,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# 将文本颜色设置为红色
self.label_TF.setStyleSheet("color: red;background-color:rgb(219, 205, 166)")
def agent_exp(self):
if self.TreeNode is not None:
exp_str = data.get_expression(self.TreeNode)
if exp_str is not None:
self.label_result.clear() # 清空显示结果
self.lineEdit.clear() # 清空显示表达式
self.lineEdit.setText(exp_str) # 显示表达式
else:
QMessageBox.warning(self, '警告', '无法生成表达式')
else:
QMessageBox.warning(self, '警告', '当前无语法树')
if __name__ == '__main__':
app = QApplication()

Loading…
Cancel
Save