You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

350 lines
9.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 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):
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 = []
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)