# 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)
