|
|
|
|
# Function: 24点游戏
|
|
|
|
|
import math
|
|
|
|
|
import random
|
|
|
|
|
|
|
|
|
|
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 "
|
|
|
|
|
f"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()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 写一个函数从TreeNode中还原出表达式
|
|
|
|
|
def get_expression(TreeNode):
|
|
|
|
|
root = TreeNode[-1]
|
|
|
|
|
def get_node_rlt(node):
|
|
|
|
|
if node.NodeType == 'Operator':
|
|
|
|
|
left_idx = node.LeftNodeID
|
|
|
|
|
right_idx = node.RightNodeID
|
|
|
|
|
if left_idx is not None:
|
|
|
|
|
left_node = find_node_by_id(left_idx, TreeNode)
|
|
|
|
|
left_rlt = get_node_rlt(left_node)
|
|
|
|
|
else:
|
|
|
|
|
left_rlt = None
|
|
|
|
|
if right_idx is not None:
|
|
|
|
|
right_node = find_node_by_id(right_idx, TreeNode)
|
|
|
|
|
right_rlt = get_node_rlt(right_node)
|
|
|
|
|
else:
|
|
|
|
|
right_rlt = None
|
|
|
|
|
if left_rlt is None and right_rlt is None:
|
|
|
|
|
return None
|
|
|
|
|
elif left_rlt is None and right_rlt is not None:
|
|
|
|
|
return f"{node.Ops}({right_rlt})"
|
|
|
|
|
else:
|
|
|
|
|
return f"({left_rlt}{node.Ops}{right_rlt})"
|
|
|
|
|
elif node.NodeType == 'Value':
|
|
|
|
|
return node.FaceValue
|
|
|
|
|
return get_node_rlt(root)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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)
|