添加 生成表达式 功能

main
zart 10 months ago
parent c22d011ee1
commit b3ae5007b2

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

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

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

Loading…
Cancel
Save