upload 24Game project

master
bettleChen 1 year ago
parent 62c341942e
commit 486d72a46e

@ -0,0 +1,357 @@
# -*- encoding: utf-8 -*-
"""
@Author: packy945
@FileName: TreeNode.py
@DateTime: 2023/5/15 14:27
@SoftWare: PyCharm
"""
import re
import tkinter as tk
from data import *
import tkinter.messagebox
sz = []
A = Aexp([0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0])
img_open = []
img_png = []
class Tree:
def __init__(self):
self.bc = 40
self.Node = []
self.rootID = None
self.deepth = []
self.place = []
self.mark = [0] * 110
self.ck = []
def check(self):
self.ck = [1] * len(self.Node)
for N in self.Node:
if N[3]:
self.ck[N[3]] = 0
if N[4]:
self.ck[N[4]] = 0
def remark(self):
self.mark = [0] * 110
def deep(self):
flag = 0
for i in range(len(self.Node)):
if self.Node[i][1] == 'Value':
self.deepth[i] = 0
for i in range(len(self.Node)):
if self.deepth[i] == -1:
flag = 1
if self.Node[i][3] != None and self.Node[i][4] != None:
# print(self.Node[i][3], self.Node[i][4])
self.deepth[i] = max(self.deepth[self.Node[i][3]], self.deepth[self.Node[i][4]]) + 1
# print(self.deepth)
if flag:
self.deep()
def calculate(self, node):
print(node)
if node[1] == 'Value':
return node[5] * 1.0
elif node[1] == 'Operator':
a = self.calculate(self.Node[node[3]])
b = self.calculate(self.Node[node[4]])
if node[2] == '^':
return pow(int(a), int(b))
else:
# print(a,node[2],b)
return eval(str(a) + node[2] + str(b))
def Aexp(self, node):
if node[1] == 'Value':
return str(node[5])
elif node[1] == 'Operator':
a = self.Aexp(self.Node[node[3]])
b = self.Aexp(self.Node[node[4]])
# print(a,node[2],b)
ans = '(' + str(a) + node[2] + str(b) + ')'
# print(ans)
return ans
tree = Tree()
cur = 0
class TreeNode:
def __init__(self, Type, value, left=None, right=None, color='方块'):
global cur
self.NodeID = cur # 节点编号
cur += 1
self.NodeType = Type # 节点类型
self.Ops = None # 运算符类型
self.left = left
self.right = right
self.LeftNodeID = None
self.RightNodeID = None
if self.left:
self.LeftNodeID = left.NodeID # 左节点编号
if self.right:
self.RightNodeID = right.NodeID # 右节点编号
self.FaceValue = None # 节点数值
self.FaceColor = color # 节点花色
if Type == 'Value':
self.FaceValue = value
else:
self.Ops = value
tree.Node.append([self.NodeID, self.NodeType, self.Ops, self.LeftNodeID, self.RightNodeID, self.FaceValue, self.FaceColor])
def build_ast(formula):
'''
建立语法树
:param formula: 表达式表达式的花色
:return: 建立好的语法树
'''
# 去掉空格
global tree, cur
try:
expr, color = formula
except:
expr = formula
color = ['方块'] * 20
if len(expr) == 0:
tk.messagebox.showinfo('', '表达式不存在')
return
cur = 0
tree.__init__()
expr = expr.replace(' ', '')
# 将所有数字和符号分离出来
tokens = re.findall(r'\d+|[()+\-*/^.]', expr)
i = 0
for token in tokens:
if tokens[i] == '.':
tokens[i - 1] = tokens[i - 1] + tokens[i] + tokens[i + 1]
del tokens[i: i + 2]
i += 1
# 定义优先级
precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '^': 3}
# 创建一个操作符栈和一个节点栈
op_stack = []
node_stack = []
color_cur = 0
# 遍历所有 token
for token in tokens:
if token.isdigit():
# print(cur, color[cur])
node_stack.append(TreeNode('Value', int(token), color=color[color_cur]))
color_cur += 1
elif token.count('.') == 1:
node_stack.append(TreeNode('Value', float(token), color=color[color_cur]))
color_cur += 1
elif token in '+-*/^':
while op_stack and op_stack[-1] != '(' and precedence[token] <= precedence[op_stack[-1]]:
op = op_stack.pop()
right = node_stack.pop()
left = node_stack.pop()
node_stack.append(TreeNode('Operator', op, left, right))
op_stack.append(token)
elif token == '(':
op_stack.append(token)
elif token == ')':
while op_stack and op_stack[-1] != '(':
op = op_stack.pop()
right = node_stack.pop()
left = node_stack.pop()
node_stack.append(TreeNode('Operator', op, left, right))
op_stack.pop()
# 处理剩下的操作符
while op_stack:
op = op_stack.pop()
right = node_stack.pop()
left = node_stack.pop()
node_stack.append(TreeNode('Operator', op, left, right))
# 返回抽象语法树的根节点
tree.rootID = node_stack[0].NodeID
# print(tree.rootID)
# print(tree.Node)
return node_stack[0]
def print_ast(node:TreeNode, prefix='', is_left=True):
if node:
if node.NodeType == 'Value':
s = str(node.FaceValue)
else:
s = str(node.Ops)
print(prefix + ('├── ' if is_left else '└── ') + s)
print_ast(node.left, prefix + ('' if is_left else ' '), True)
print_ast(node.right, prefix + ('' if is_left else ' '), False)
if __name__ == '__main__':
expr = "(34-13.121)*2*6"
# ast = build_ast(expr)
# print_ast(ast)
# print(tree.Node)
class Frame_Tree:
# def Frame_tree():
def __init__(self, window):
self.Tree_root = tk.Frame(window, relief="groove", width=610, height=400)
self.Tree_root.place(x=50, y=250) # 树的显示
self.Tree_cv = tk.Canvas(self.Tree_root, width=610, height=400, bg='#b7bcc0')
self.Tree_cv.place(x=0, y=0)
# Tree_cv.create_rectangle(10, 10, 600, 290, width=10, outline='#ff9933')
bot = tk.Button(self.Tree_root, text='添加运算节点', bg='#cca583', fg='black', )
bot.place(x=500, y=40, width=80, height=30)
bot = tk.Button(self.Tree_root, text='添加数值节点', bg='#cca583', fg='black', )
bot.place(x=500, y=75, width=80, height=30)
bot = tk.Button(self.Tree_root, text='改变运算输入', bg='#cca583', fg='black', )
bot.place(x=500, y=110, width=80, height=30)
bot = tk.Button(self.Tree_root, text='改变节点运算', bg='#cca583', fg='black', )
bot.place(x=500, y=145, width=80, height=30)
bot = tk.Button(self.Tree_root, text='数值节点交换', bg='#cca583', fg='black', )
bot.place(x=500, y=180, width=80, height=30)
bot = tk.Button(self.Tree_root, text='产生表达式', bg='#cca583', fg='black', command=lambda: self.Aexp())
bot.place(x=500, y=215, width=80, height=30)
# bot = tk.Button(self.Tree_root, text='计算', bg='#cca583', fg='black', command=lambda: tree.calculate(tree.Node[tree.rootID]))
# bot.place(x=500, y=250, width=80, height=30)
def clear(self):
self.Tree_cv.delete('all')
tree.Node = []
tree.rootID = None
def Aexp(self):
entry.delete(0, "end")
print(tree.Aexp(tree.Node[tree.rootID]))
entry.insert("end", tree.Aexp(tree.Node[tree.rootID]))
label2 = tk.Label(window, text=f'= {float(tree.calculate(tree.Node[tree.rootID])):.2f}',
font=('宋体', 15, 'bold'), width=30, height=10,
# 设置填充区距离、边框宽度和其样式(凹陷式)
borderwidth=5, relief="sunken")
label2.place(x=240, y=160, width=60, height=50)
def show_tree(self, ss):
# 清空画布
self.Tree_cv.delete('all')
build_ast(ss)
for i in range(len(tree.Node)):
tree.deepth.append(-1)
# print(tree.Node)
# print(tree.deepth)
# 格式化树节点的深度
tree.deep()
# print(tree.deepth)
# 初始化节点数与深度
dept, nums = -1, 0
for i in range(len(tree.deepth)):
dept = max(dept, tree.deepth[i])
tree.place.append((None, None))
if tree.deepth[i] == 0:
nums += 1
# print(dept, nums)
tree_length = 500
tree_height = 400
dx = tree_length // (nums + 1)
dy = tree_height // (dept + 2)
bc = 40
# 若为数字节点
cur = 0
for i in range(len(tree.deepth)):
if tree.deepth[i] == 0:
cur += 1
tree.place[i] = (cur * dx, tree_height - dy)
self.Tree_cv.create_rectangle(tree.place[i][0] - bc / 2, tree.place[i][1] - bc / 2,
tree.place[i][0] + bc / 2,
tree.place[i][1] + bc / 2, fill='white', width=0)
self.Tree_cv.create_text(tree.place[i][0], tree.place[i][1], text=str(tree.Node[i][5]),
font=('宋体', 15, 'bold'), anchor='center')
for d in range(dept):
cur_d = d + 1
for i in range(len(tree.deepth)):
if tree.deepth[i] == cur_d:
lnode = tree.place[tree.Node[i][3]]
rnode = tree.place[tree.Node[i][4]]
node = ((lnode[0] + rnode[0]) / 2, tree_height - (cur_d + 1) * dy)
self.Tree_cv.create_line(lnode[0], lnode[1] - bc / 2, node[0], node[1] + bc / 2, fill='#1ffbe9',
width=2)
self.Tree_cv.create_line(rnode[0], rnode[1] - bc / 2, node[0], node[1] + bc / 2, fill='#1ffbe9',
width=2)
tree.place[i] = node
self.Tree_cv.create_rectangle(tree.place[i][0] - bc / 2, tree.place[i][1] - bc / 2,
tree.place[i][0] + bc / 2, tree.place[i][1] + bc / 2,
fill='white', width=0)
self.Tree_cv.create_text(tree.place[i][0], tree.place[i][1], text=str(tree.Node[i][2]),
font=('宋体', 15, 'bold'), anchor='center')
window = tk.Tk()
var = tk.StringVar()
var2 = tk.StringVar()
width = 700
height = 700 # 窗口大小
screen_width = window.winfo_screenwidth() # winfo方法来获取当前电脑屏幕大小
screen_height = window.winfo_screenheight()
x = int((screen_width - width) / 2)
y = int((screen_height - height) / 2) - 40
size = '{}x{}+{}+{}'.format(width, height, x, y)
window.geometry(size)
# 基本组件显示
cv = tk.Canvas(window, width=380, height=136, bg='#FFFFCC')
cv.place(x=100, y=3)
F = Frame_Tree(window)
but = tk.Button(window, text='出题', bg='#ffffcc', fg='black', command=lambda: show_card())
but.place(x=500, y=20, width=100, height=50, )
but2 = tk.Button(window, text='换牌', bg='#ffffcc', fg='black', )
but2.place(x=500, y=80, width=100, height=50, )
entry = tk.Entry(window, show=None, font=('宋体', 15, 'bold'))
entry.place(x=50, y=160, width=180, height=50)
label2 = tk.Label(window, text='= 24', font=('宋体', 15, 'bold'), width=30, height=10,
# 设置填充区距离、边框宽度和其样式(凹陷式)
borderwidth=5, relief="sunken")
but4 = tk.Button(window, text='计算', bg='#ffffcc', fg='black', command=lambda: show_result(entry.get(), sz))
but4.place(x=315, y=165, width=50, height=40, )
label2.place(x=240, y=160, width=60, height=50)
but3 = tk.Button(window, text='自动求解', bg='#ffffcc', fg='black', command=lambda: show_answer())
but3.place(x=250, y=210, width=120, height=40, )
but3 = tk.Button(window, text='所有答案', bg='#ffffcc', fg='black', command=lambda: show_all())
but3.place(x=410, y=210, width=120, height=40, )
but5 = tk.Button(window, text='画树', bg='#ffffcc', fg='black', command=lambda: F.show_tree(expr))
but5.place(x=80, y=210, width=120, height=40, )
# cv1 = tk.Canvas(window, width=380, height=90, bg='#FFFFCC')
# cv1.place(x=100, y=200)
window.mainloop()

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

@ -0,0 +1,96 @@
# -*- encoding: utf-8 -*-
"""
@Author: packy945
@FileName: data.py
@DateTime: 2023/5/11 14:36
@SoftWare: PyCharm
"""
from itertools import permutations
import random
import tkinter as tk
MARK = '#ff0000'
NOMARK = '#cccccc'
class Aexp:
def __init__(self, a, b, c, d):
self.Aexp_cur = 0
self.num = 0
self.card = [a, b, c, d]
# print(self.card)
self.answer = []
self.Color = []
self.Aexp(a, b, c, d)
def refresh(self, a, b, c, d):
self.Aexp_cur = 0
self.num = 0
self.card = [a, b, c, d]
# print(self.card)
self.answer = []
self.Color = []
self.Aexp(a, b, c, d)
def Aexp(self, one, two, three, four):
'''
输入四个数求24点
:param one:
:param two:
:param three:
:param four:
:return: 求解24点结果若无法得出则返回无法求得结果
'''
self.Aexp_cur = 0
my_list = [one, two, three, four]
result = [c for c in permutations(my_list, 4)]
list2 = [] # 算出24的排列组合的列表
symbols = ["+", "-", "*", "/"]
flag = False
for one, two, three, four in result:
for s1 in symbols:
for s2 in symbols:
for s3 in symbols:
express = ["(({0}{1}{2}){3}{4}){5}{6}".format(one[1], s1, two[1], s2, three[1], s3, four[1]),
"({0}{1}{2}){3}({4}{5}{6})".format(one[1], s1, two[1], s2, three[1], s3, four[1]),
"({0}{1}({2}{3}{4})){5}{6}".format(one[1], s1, two[1], s2, three[1], s3, four[1]),
"{0}{1}(({2}{3}{4}){5}{6})".format(one[1], s1, two[1], s2, three[1], s3, four[1]),
"{0}{1}({2}{3}({4}{5}{6}))".format(one[1], s1, two[1], s2, three[1], s3, four[1])]
# if str(one) + str(two) + str(three) + str(four) == "8383":
# print(express)
for e in express:
try:
if round(eval(e), 6) == 24:
e = del_parentheses(e)
list2.append(e)
self.Color.append([one[0], two[0], three[0], four[0]])
flag = True
except ZeroDivisionError:
pass
if flag:
self.answer = list2
self.num = len(list2)
# return list3
else:
self.answer = ["无法得出24点"]
self.Color.append(None)
self.num = 0
#删除最外层括号
def del_parentheses(e):
if e[0] == '(' and e[-1] == ')':
try:
eval(e[1:len(e)-1])
except:
pass
else:
if round(eval(e[1:len(e)-1]),6) == 24:
return e[1:len(e)-1]
return e

@ -0,0 +1,781 @@
# -*- encoding: utf-8 -*-
"""
@Author: packy945
@FileName: main.py
@DateTime: 2023/5/11 11:34
@SoftWare: PyCharm
"""
from data import *
import tkinter.messagebox
from collections import Counter
from PIL import Image, ImageTk
from TreeNode import *
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from ttkbootstrap import *
sz = []
A = Aexp([0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0])
img_open = []
img_png = []
def change_card():
card = []
for n in tree.Node:
if n[1] == 'Value':
if n[5] == 1:
card.append([n[6], 'A'])
else:
card.append([n[6], str(n[5])])
# print(card)
if len(card) == 4:
show(card)
else:
tk.messagebox.showinfo('', '无法显示卡牌')
def TorF(flag):
'''
显示答案是否正确
:param flag: 答案是否正确
:return:
'''
if flag == 1:
clo1 = MARK
clo2 = NOMARK
elif flag == 0:
clo1 = NOMARK
clo2 = NOMARK
else:
clo1 = NOMARK
clo2 = MARK
label3 = tk.Label(window, text='', fg=clo1, font=('宋体', 10, 'bold italic'), borderwidth=5, relief="sunken")
label4 = tk.Label(window, text='×', fg=clo2, font=('宋体', 10, 'bold italic'), borderwidth=5, relief="sunken")
label3.place(x=625, y=240, width=30, height=25)
label4.place(x=625, y=270, width=30, height=25)
def ans_cal(ans = None):
if not ans:
label2 = tk.Label(window, text='= ?', font=('楷体', 18, 'bold'), width=30, height=10,
# 设置填充区距离、边框宽度和其样式(凹陷式)
borderwidth=5, relief="sunken", anchor='w')
else:
label2 = tk.Label(window, text=f'={ans}', font=('楷体', 18, 'bold'), width=30, height=10,
# 设置填充区距离、边框宽度和其样式(凹陷式)
borderwidth=5, relief="sunken", anchor='w')
label2.place(x=425, y=240, width=100, height=50)
def init():
ans_cal()
all_ans["state"] = 'disable'
entry.delete(0, "end")
F.clear()
TorF(0)
#展示卡牌
def show_card():
'''
随机展示四张卡片
:return:
'''
global sz # 全局变量存放点数
sz = []
# 清空卡牌列表
init()
# 清空中间的表达式输入串Aexp, 同时清空中间的表达式输入框、结果显示框和结果正确与错误标志
kp_list = []
size_list = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
col_list = ["Club", "Diamond", "Spade", "Heart"]
sz_list = ['a', 'j', 'q', 'k']
for i in range(4):
kp_list.append([random.choice(col_list), random.choice(size_list)]) # 随机生成花色以及点数
sz.append([kp_list[i][0], kp_list[i][1], kp_list[i][1]])
if kp_list[i][-1] == '1':
kp_list[i][-1] = random.choice(sz_list)
sz[i][2] = kp_list[i][-1]
show(kp_list)
global A
A.refresh(sz[0], sz[1], sz[2], sz[3])
cv.update()
def show(kp_list):
# 根据花色以及点数显示卡牌
# cv = tk.Canvas(window, width=380, height=136, bg='#FFFFCC') # 分配位置
# cv.place(x=100, y=3)
global img_open, img_png
img_open = []
img_png = []
cv.delete('all')
i = 0 #卡牌位置偏移量
for k in range(4):
img_open.append(
Image.open("card/" + kp_list[k][0] + "/" + kp_list[k][0] + kp_list[k][1] + '.png').resize((90, 130)))
img_png.append(ImageTk.PhotoImage(img_open[k]))
cv.create_image(50 + i, 70, image=img_png[k])
i += 95
'''
img_open.append(Image.open("card/" + kp_list[0][0] + "/" + kp_list[0][0] + kp_list[0][1] + '.png').resize((90, 130)))
img_png.append(ImageTk.PhotoImage(img_open[0]))
cv.create_image(50 + i, 70, image=img_png[0])
# img_open = Image.open("card/" + kp_list[0][0] + "/" + kp_list[0][0] + kp_list[0][1] + '.png').resize((90, 130))
# img_png = ImageTk.PhotoImage(img_open)
# cv.create_image(50 + i, 70, image=img_png)
i += 95
img_open.append(
Image.open("card/" + kp_list[1][0] + "/" + kp_list[1][0] + kp_list[1][1] + '.png').resize((90, 130)))
img_png.append(ImageTk.PhotoImage(img_open[1]))
cv.create_image(50 + i, 70, image=img_png[1])
# img_open1 = Image.open("card/" + kp_list[1][0] + "/" + kp_list[1][0] + kp_list[1][1] + '.png').resize((90, 130))
# img_png1 = ImageTk.PhotoImage(img_open1)
# cv.create_image(50 + i, 70, image=img_png1)
i += 95
img_open2 = Image.open("card/" + kp_list[2][0] + "/" + kp_list[2][0] + kp_list[2][1] + '.png').resize((90, 130))
img_png2 = ImageTk.PhotoImage(img_open2)
cv.create_image(50 + i, 70, image=img_png2)
i += 95
img_open3 = Image.open("card/" + kp_list[3][0] + "/" + kp_list[3][0] + kp_list[3][1] + '.png').resize((90, 130))
img_png3 = ImageTk.PhotoImage(img_open3)
cv.create_image(50 + i, 70, image=img_png3)
'''
# window.mainloop()
cv.update()
#展示结果
def show_result(ss, sz):
'''
展示计算结果
:param ss: 输入框中的表达式
:param sz: 题中给的卡牌数字
:return:
'''
if len(sz) != 4:
tk.messagebox.showinfo('', '未出题')
return
char_list = [] #用于存放算式中的数字
for i in range(len(ss)):
if ss[i]>'0' and ss[i]<='9':
char_list.append(ss[i])
a = Counter(char_list) #计数函数Counter
b = Counter([sz[0][1], sz[1][1], sz[2][1], sz[3][1]])
if len(char_list) != 4:
tk.messagebox.showinfo('', '请输入符合所给卡牌点数的可运算表达式')
elif a != b:
tk.messagebox.showinfo('', '你的表达式中的点数与所给卡牌点数不同')
else:
try:
ans = eval(ss)
except:
tk.messagebox.showinfo('', '表达式不可运算')
else:
ans_cal(int(ans))
#设置颜色
if ans == 24:
TorF(1)
else:
TorF(-1)
#展示一个可行算式
def show_answer():
# 自动求解
if len(sz) != 4:
tk.messagebox.showinfo('', '未出题')
return
try:
answer = (A.answer[0], A.Color[0])
A.Aexp_cur = 0
except:
tk.messagebox.showinfo('', '出错')
return
# print()
# print(answer)
if A.num == 0:
entry.delete(0, "end")
tk.messagebox.showinfo('', '无法得出24点')
else:
entry.delete(0, "end")
entry.insert("end", answer[0])
'''
Treenode = Decomposition(answer)
label_answer = tk.Label(window,text=answer+' '+str(Treenode),bg="#FFFFCC",fg="black")
label_answer.place(x=105,y=210)
'''
F.show_tree(answer)
if A.num > 1:
all_ans["state"] = 'normal'
else:
all_ans["state"] = 'disable'
def show_next():
global A
A.Aexp_cur += 1
answer = (A.answer[A.Aexp_cur], A.Color[A.Aexp_cur])
entry.delete(0, "end")
entry.insert("end", answer[0])
F.show_tree(answer)
if A.Aexp_cur == A.num - 1:
all_ans["state"] = 'disable'
tk.messagebox.showinfo('', '已显示所有答案')
#显示所有答案,通过一个新窗口
def show_all():
global Aexp_cur
answer = Aexp(int(sz[0][1]), int(sz[1][1]), int(sz[2][1]), int(sz[3][1]))
# Tree_all = []
# for item in answer:
# Tree_all.append(Decomposition(item))
root = tk.Tk()
# root.geometry('500x300')
width = 500
height = 300
screen_width = window.winfo_screenwidth() # winfo方法来获取当前电脑屏幕大小
screen_height = window.winfo_screenheight()
x = int((screen_width - width) / 2)
y = int((screen_height - height) / 2) - 40
size = '{}x{}+{}+{}'.format(width, height, x, y)
root.geometry(size)
b1 = tk.Scrollbar(root, width=40)
# b1.place(x=410,y=200)
b1.pack(side=tk.RIGHT, fill=tk.Y)
b2 = tk.Listbox(root, yscrollcommand=b1.set,width=100)
for i in range(len(answer)):
b2.insert(tk.END,answer[i])
b2.pack(side=tk.LEFT, fill=tk.BOTH)
# b2.place(x=520,y=100)
b1.config(command=b2.yview)
root.mainloop()
def BUTs():
global all_ans
but = tk.Button(window, text='出题', bg='#ffffcc', fg='black', command=lambda: show_card())
but.place(x=500, y=20, width=100, height=50, )
but2 = tk.Button(window, text='换牌', bg='#ffffcc', fg='black', command=lambda: change_card())
but2.place(x=500, y=80, width=100, height=50, )
but4 = tk.Button(window, text='计算', bg='#ffffcc', fg='black', command=lambda: show_result(entry.get(), sz))
but4.place(x=530, y=240, width=80, height=50, )
but3 = tk.Button(window, text='自动求解', bg='#ffffcc', fg='black', command=lambda: show_answer())
but3.place(x=250, y=210, width=120, height=40, )
all_ans = tk.Button(window, text='所有答案', bg='#ffffcc', fg='black', command=lambda: show_next(), state='disable')
all_ans.place(x=410, y=210, width=120, height=40, )
but5 = tk.Button(window, text='画树', bg='#ffffcc', fg='black', command=lambda: F.show_tree(entry.get()))
but5.place(x=80, y=210, width=120, height=40, )
def left2(event):
# 查找鼠标左键按下时位置是否在某个牌上
# print(event.x, event.y)
# if not A.card
left = [5, 100, 195, 290]
right = [95, 190, 285, 380]
up = 5
down = 135
'''
for i in range(4):
if up <= event.y <= down and right[i] >= event.x >= left[i]:
print(i + 1)
print(A.card[i])
'''
# 添加数值节点
if F.mode == 2:
for cur in range(4):
if up <= event.y <= down and right[cur] >= event.x >= left[cur]:
# 检查数值节点是否已存在
a = []
b = []
for card in A.card:
a.append([card[0], int(card[1])])
for node in tree.Node:
if node[1] == 'Value':
b.append([node[6], node[5]])
c = a.copy()
for x in b:
for i in range(len(c)):
try:
c[i]
except:
break
if x[0] == c[i][0] and x[1] == c[i][1]:
del c[i]
flag = 0
for l in c:
# 若所选card还没有对应的节点则新建一个数值节点
if not flag and l[0] == A.card[cur][0] and l[1] == int(A.card[cur][1]):
tree.Node.append([len(tree.Node), 'Value', None, None, None, int(A.card[cur][1]), A.card[cur][0]])
flag = 1
if not flag:
# 若所选card已经存在则进行警告
tk.messagebox.showinfo('', '所选card已存在')
# 操作完成,进行复位
F.mode = 0
F.tips = ''
tree.remark()
F.draw()
# 改变运算输入的第二步
elif F.mode == 6:
for cur in range(4):
# 若单击了一张card
if up <= event.y <= down and right[cur] >= event.x >= left[cur]:
# 标记的节点序号
mark = -1
for i in range(len(tree.mark)):
if tree.mark[i] == 1:
mark = i
flag = 0
for now in range(len(tree.Node)):
# 若单击的card已经存在一个数值节点
if tree.Node[now][6] == A.card[cur][0] and tree.Node[now][5] == int(A.card[cur][1]):
# 则将这两个数值节点进行交换
tree.Node[now][5] = tree.Node[mark][5]
tree.Node[now][6] = tree.Node[mark][6]
tree.Node[mark][5] = int(A.card[cur][1])
tree.Node[mark][6] = A.card[cur][0]
flag = 1
if not flag:
# 若单击的card没有存在数值节点则将该节点改为这张card
tree.Node[mark][5] = int(A.card[cur][1])
tree.Node[mark][6] = A.card[cur][0]
# 操作完毕,进行复位
F.mode = 0
F.tips = ''
tree.remark()
F.draw()
class Frame_Tree:
def __init__(self, window):
self.opt = '+'
self.mode = 0
'''
当前操作
0
1 添加运算节点
2 添加数值节点
3 改变运算输入
4 改变节点运算
5 数值节点交换
'''
self.tips = ''
self.Tree_root = tk.Frame(window, relief="groove", width=610, height=400)
self.Tree_root.place(x=50, y=250) # 树的显示
self.Tree_cv = tk.Canvas(self.Tree_root, width=610, height=400, bg='#b7bcc0')
self.Tree_cv.place(x=0, y=0)
# Tree_cv.create_rectangle(10, 10, 600, 290, width=10, outline='#ff9933')
self.opt1 = tk.Button(self.Tree_root, text='+', bg='#cca583', fg='black', command=lambda: self.set_opt(1))
self.opt1.place(x=500, y=20, width=30, height=30)
self.opt2 = tk.Button(self.Tree_root, text='-', bg='#cca583', fg='black', command=lambda: self.set_opt(2))
self.opt2.place(x=535, y=20, width=30, height=30)
self.opt3 = tk.Button(self.Tree_root, text='*', bg='#cca583', fg='black', command=lambda: self.set_opt(3))
self.opt3.place(x=500, y=55, width=30, height=30)
self.opt4 = tk.Button(self.Tree_root, text='/', bg='#cca583', fg='black', command=lambda: self.set_opt(4))
self.opt4.place(x=535, y=55, width=30, height=30)
self.set_opt(1)
dy = 50
bot = tk.Button(self.Tree_root, text='添加运算节点', bg='#cca583', fg='black', command=lambda: self.add_opt())
bot.place(x=500, y=40 + dy, width=80, height=30)
bot = tk.Button(self.Tree_root, text='添加数值节点', bg='#cca583', fg='black', command=lambda: self.add_num())
bot.place(x=500, y=75 + dy, width=80, height=30)
bot = tk.Button(self.Tree_root, text='改变运算输入', bg='#cca583', fg='black', command=lambda: self.change_num())
bot.place(x=500, y=110 + dy, width=80, height=30)
bot = tk.Button(self.Tree_root, text='改变节点运算', bg='#cca583', fg='black', command=lambda: self.change_opt())
bot.place(x=500, y=145 + dy, width=80, height=30)
bot = tk.Button(self.Tree_root, text='数值节点交换', bg='#cca583', fg='black', command=lambda: self.change_node())
bot.place(x=500, y=180 + dy, width=80, height=30)
bot = tk.Button(self.Tree_root, text='产生表达式', bg='#cca583', fg='black', command=lambda: self.Aexp())
bot.place(x=500, y=215 + dy, width=80, height=30)
bot = tk.Button(self.Tree_root, text='清空画布', bg='#cca583', fg='black', command=lambda: self.clear())
bot.place(x=500, y=250 + dy, width=80, height=30)
# bot = tk.Button(self.Tree_root, text='计算', bg='#cca583', fg='black', command=lambda: tree.calculate(tree.Node[tree.rootID]))
# bot.place(x=500, y=250, width=80, height=30)
self.Tree_cv.bind('<Button-1>', self.left1)
self.draw()
def set_opt(self, x):
# self.opt1["state"] = "disable"
# exec('self.opt1["state"] = "disable"')
opt = ['+', '-', '*', '/']
self.opt = opt[x - 1]
for i in range(4):
exec('self.opt' + str(i + 1) + '["state"] = "normal"')
exec('self.opt' + str(i + 1) + "['bg']='#cca583'")
exec('self.opt' + str(i + 1) + "['fg']='black'")
exec('self.opt' + str(x) + "['state']='disable'")
exec('self.opt' + str(x) + "['bg']='#8f735c'")
exec('self.opt' + str(x) + "['fg']='white'")
# 8f735c
self.draw()
def add_opt(self):
tree.remark()
self.tips = '请选择两个节点'
self.mode = 1
self.draw()
def change_node(self):
tree.remark()
self.tips = '请选择两个数值节点'
self.mode = 5
self.draw()
def change_opt(self):
tree.remark()
self.tips = '请选择一个运算节点'
self.mode = 4
self.draw()
def add_num(self):
tree.remark()
self.tips = '请选择一张card'
self.mode = 2
self.draw()
def change_num(self):
tree.remark()
self.tips = '请选择一个数值节点'
self.mode = 3
self.draw()
def left1(self, event):
# 查找鼠标左键按下时位置是否在某个节点内,并根据当前操作模式进行反馈
'''
print(event.x, event.y)
i = 0
print(tree.place)
for T in tree.place:
if abs(event.x - T[0]) <= tree.bc / 2 and abs(event.y - T[1]) <= tree.bc / 2:
# tree.mark[i] = not tree.mark[i]
print(tree.Node[i])
i += 1
'''
# 无操作
if self.mode == 0:
return
# 添加运算节点
elif self.mode == 1:
i = 0
for T in tree.place:
if abs(event.x - T[0]) <= tree.bc / 2 and abs(event.y - T[1]) <= tree.bc / 2:
# 标记点击的节点
tree.mark[i] = not tree.mark[i]
i += 1
nodes = []
for i in range(len(tree.Node)):
if tree.mark[i] == 1:
nodes.append(i)
if len(nodes) == 2:
# 若已经选择两个节点
tree.check()
# 检查节点是否合法
if tree.ck[nodes[0]] == 1 and tree.ck[nodes[1]] == 1:
# 若节点合法,则添加新运算节点并将其设置为根节点
ID = len(tree.Node)
tree.Node.append([ID, 'Operator', self.opt, nodes[0], nodes[1], None, None])
tree.rootID = ID
else:
# 若节点不合法则显示警告
tk.messagebox.showinfo('', '所选节点不合法')
# 添加运算节点操作结束
self.mode = 0
self.tips = ''
tree.remark()
# 添加数值节点
elif self.mode == 2:
# 添加数值节点无需点击节点
pass
# 改变运算输入
elif self.mode == 3:
i = 0
flag = 0
for T in tree.place:
if abs(event.x - T[0]) <= tree.bc / 2 and abs(event.y - T[1]) <= tree.bc / 2:
# 若点击节点为数值节点,则标记
if tree.Node[i][1] == 'Value':
tree.mark[i] = 1
flag = 1
# 若点击节点为运算节点,则弹窗警告
else:
tk.messagebox.showinfo('', '所选节点不合法')
flag = 1
i += 1
if flag:
# 选择节点完成过后还需选择card
self.mode = 6
self.tips = '请选择一张card'
self.draw()
# 改变节点运算
elif self.mode == 4:
i = 0
flag = 0
for T in tree.place:
if abs(event.x - T[0]) <= tree.bc / 2 and abs(event.y - T[1]) <= tree.bc / 2:
# 检查节点是否合法,若选择的是运算节点,则进行运算符的改变
if tree.Node[i][1] == 'Operator':
tree.Node[i][2] = self.opt
flag = 1
# 若选择的是数值节点,则弹窗警告
else:
tk.messagebox.showinfo('', '所选节点不合法')
flag = 1
i += 1
if flag:
# 操作完毕,进行复位
self.mode = 0
self.tips = ''
tree.remark()
# 数值节点交换
elif self.mode == 5:
i = 0
for T in tree.place:
# 标记选择的节点
if abs(event.x - T[0]) <= tree.bc / 2 and abs(event.y - T[1]) <= tree.bc / 2:
tree.mark[i] = not tree.mark[i]
i += 1
nodes = []
for i in range(len(tree.Node)):
if tree.mark[i] == 1:
nodes.append(i)
if len(nodes) == 2:
# 已经选择两个节点
if tree.Node[nodes[0]][1] == 'Value' and tree.Node[nodes[1]][1] == 'Value':
# 若选择的节点都是数值节点,则交换两个节点的数值与花色
Value = tree.Node[nodes[0]][5]
Color = tree.Node[nodes[0]][6]
tree.Node[nodes[0]][5] = tree.Node[nodes[1]][5]
tree.Node[nodes[0]][6] = tree.Node[nodes[1]][6]
tree.Node[nodes[1]][5] = Value
tree.Node[nodes[1]][6] = Color
else:
# 若选择的不是数值节点,则进行警告
tk.messagebox.showinfo('', '所选节点不合法')
# 操作结束,复位
self.mode = 0
self.tips = ''
tree.remark()
self.draw()
def clear(self):
self.Tree_cv.delete('all')
tree.Node = []
tree.rootID = None
def Aexp(self):
entry.delete(0, "end")
try:
exp = tree.Aexp(tree.Node[tree.rootID])
except:
tk.messagebox.showinfo('', '语法树不合法')
return
entry.insert("end", exp)
# ans = int(tree.calculate(tree.Node[tree.rootID]))
ans = float(tree.calculate(tree.Node[tree.rootID]))
ans_cal(f'{float(tree.calculate(tree.Node[tree.rootID])):.2f}')
if ans == 24:
TorF(1)
else:
TorF(-1)
char_list = [] # 用于存放算式中的数字
for i in range(len(exp)):
if exp[i] > '0' and exp[i] <= '9':
char_list.append(exp[i])
a = Counter(char_list) # 计数函数Counter
b = Counter([sz[0][1], sz[1][1], sz[2][1], sz[3][1]])
if len(char_list) != 4:
tk.messagebox.showinfo('', '请输入符合所给卡牌点数的可运算表达式')
def show_tree(self, ss):
# 清空画布
self.Tree_cv.delete('all')
if len(ss) == 0:
tk.messagebox.showinfo('', '表达式不存在')
return
build_ast(ss)
self.draw()
def draw(self):
self.Tree_cv.delete('all')
mode = ['', '添加运算节点', '添加数值节点', '改变运算输入', '改变节点运算', '数值节点交换', '添加数值节点']
lab1 = tk.Label(self.Tree_cv, text='当前操作:', bg='#b7bcc0', font=('宋体', 14, 'bold'), borderwidth=5, anchor='w')
lab1.place(x=30, y=10, width=90, height=30)
lab2 = tk.Label(self.Tree_cv, text=mode[self.mode], bg='#b7bcc0', font=('宋体', 14, 'bold'), borderwidth=5, anchor='w')
lab2.place(x=120, y=10, width=150, height=30)
lab3 = tk.Label(self.Tree_cv, text=self.tips, bg='#b7bcc0', font=('宋体', 14, 'bold'), borderwidth=5, anchor='w')
lab3.place(x=300, y=10, width=200, height=30)
tree.deepth = []
for i in range(len(tree.Node)):
tree.deepth.append(-1)
# 格式化树节点的深度
tree.deep()
# 初始化节点数与深度
dept, nums = -1, 0
tree.place = []
for i in range(len(tree.deepth)):
dept = max(dept, tree.deepth[i])
tree.place.append((None, None))
if tree.deepth[i] == 0:
nums += 1
tree_length = 500
tree_height = 400
dx = tree_length // (nums + 1)
dy = tree_height // (dept + 2)
# 若为数字节点
cur = 0
for i in range(len(tree.deepth)):
if tree.deepth[i] == 0:
cur += 1
tree.place[i] = (cur * dx, tree_height - dy)
color = 'white'
if tree.mark[i]:
color = '#d1d2c8'
self.Tree_cv.create_rectangle(tree.place[i][0] - tree.bc / 2, tree.place[i][1] - tree.bc / 2,
tree.place[i][0] + tree.bc / 2,
tree.place[i][1] + tree.bc / 2, fill=color, width=0)
self.Tree_cv.create_text(tree.place[i][0], tree.place[i][1], text=str(tree.Node[i][5]),
font=('宋体', 15, 'bold'), anchor='center')
for d in range(dept):
cur_d = d + 1
for i in range(len(tree.deepth)):
if tree.deepth[i] == cur_d:
lnode = tree.place[tree.Node[i][3]]
rnode = tree.place[tree.Node[i][4]]
node = ((lnode[0] + rnode[0]) / 2, tree_height - (cur_d + 1) * dy)
self.Tree_cv.create_line(lnode[0], lnode[1] - tree.bc / 2, node[0], node[1] + tree.bc / 2,
fill='#1ffbe9', width=2)
self.Tree_cv.create_line(rnode[0], rnode[1] - tree.bc / 2, node[0], node[1] + tree.bc / 2,
fill='#1ffbe9', width=2)
tree.place[i] = node
color = 'white'
if tree.mark[i]:
color = '#d1d2c8'
self.Tree_cv.create_rectangle(tree.place[i][0] - tree.bc / 2, tree.place[i][1] - tree.bc / 2,
tree.place[i][0] + tree.bc / 2, tree.place[i][1] + tree.bc / 2,
fill=color, width=0)
self.Tree_cv.create_text(tree.place[i][0], tree.place[i][1], text=str(tree.Node[i][2]),
font=('宋体', 15, 'bold'), anchor='center')
self.Tree_cv.update()
window = Window()
screen_width = window.winfo_screenwidth() # winfo方法来获取当前电脑屏幕大小
screen_height = window.winfo_screenheight()
var = tk.StringVar()
var2 = tk.StringVar()
width = int(screen_width*0.8)
height = int(screen_height*0.8 ) # 窗口大小
x = int((screen_width - width) / 2)
y = int((screen_height - height) / 2) - 40
size = '{}x{}+{}+{}'.format(width, height, x, y)
window.geometry(size)
F = Frame_Tree(window)
#基本组件显示
cv = Canvas(window, width=width, height=height * 0.3, background='red')
cv.place(x=0, y=3)
cv.bind('<Button-1>', left2)
entry = tk.Entry(window, show=None, font=('宋体', 15, 'bold'))
entry.place(x=25, y=240, width=400, height=50)
all_ans = None
BUTs()
'''
label3 = tk.Label(window,text='',fg='#cccccc',font=('宋体', 10, 'bold italic'), borderwidth=5, relief="sunken")
label4 = tk.Label(window,text='×',fg='#cccccc',font=('宋体', 10, 'bold italic'), borderwidth=5, relief="sunken")
label3.place(x=360,y=160,width=30,height=25)
label4.place(x=360,y=180,width=30,height=25)
label2 = tk.Label(window, text='= ?', font=('宋体', 15, 'bold'), width=30, height=10,
# 设置填充区距离、边框宽度和其样式(凹陷式)
borderwidth=5, relief="sunken")
label2.place(x=240, y=160, width=60, height=50)
'''
init()
# cv1 = tk.Canvas(window, width=380, height=90, bg='#FFFFCC')
# cv1.place(x=100, y=200)
'''
cv = tk.Canvas(window, width=610, height=300, bg='#ffffff')
cv.place(x=3, y=310)
cv.create_rectangle(10,10,600,290,width=10,outline='#ff9933')
bot = tk.Button(window,text='添加运算节点',bg='#ffffcc',fg='black',)
bot.place(x=500,y=340,width=80,height=30)
bot = tk.Button(window,text='添加数值节点',bg='#ffffcc',fg='black',)
bot.place(x=500,y=375,width=80,height=30)
bot = tk.Button(window,text='改变运算输入',bg='#ffffcc',fg='black',)
bot.place(x=500,y=410,width=80,height=30)
bot = tk.Button(window,text='改变节点运算',bg='#ffffcc',fg='black',)
bot.place(x=500,y=445,width=80,height=30)
bot = tk.Button(window,text='数值节点交换',bg='#ffffcc',fg='black',)
bot.place(x=500,y=480,width=80,height=30)
bot = tk.Button(window,text='产生表达式',bg='#ffffcc',fg='black',)
bot.place(x=500,y=515,width=80,height=30)
'''
window.mainloop()
# if __name__ == "__main__":
# # 初始化Tree类的实例
# tree = Tree()
#
# # 调用calculate方法并传递要计算的节点作为参数
# result = tree.calculate(tree.Node[3])
#
# # 在这里对result进行后续操作或者输出它
# print(result)

@ -0,0 +1,63 @@
import random
import tkinter as tk
from anytree import Node, RenderTree
class Game:
def __init__(self):
self.root = tk.Tk()
self.root.title("24点游戏")
self.root.geometry("400x300")
self.root.resizable(False, False)
self.numbers = [random.randint(1, 9) for _ in range(4)]
self.expression = tk.StringVar()
self.expression.set("输入表达式")
self.number_labels = []
for i in range(4):
label = tk.Label(self.root, text=str(self.numbers[i]), font=("Arial", 24))
label.place(x=50 + i * 80, y=50)
self.number_labels.append(label)
input_entry = tk.Entry(self.root, textvariable=self.expression, font=("Arial", 24))
input_entry.place(x=50, y=150)
calculate_button = tk.Button(self.root, text="计算", font=("Arial", 24), command=self.calculate)
calculate_button.place(x=250, y=150)
self.result_label = tk.Label(self.root, text="", font=("Arial", 24))
self.result_label.place(x=50, y=200)
def calculate(self):
try:
root_node = Node("root")
expression = self.expression.get()
for char in expression:
if char.isdigit():
node = Node(char, parent=root_node)
elif char == "+":
node = Node(char, parent=root_node)
elif char == "-":
node = Node(char, parent=root_node)
elif char == "*":
node = Node(char, parent=root_node)
elif char == "/":
node = Node(char, parent=root_node)
else:
raise Exception("Invalid character")
result = eval(expression)
if result == 24:
self.result_label.config(text="正确")
else:
self.result_label.config(text="错误")
for pre, fill, node in RenderTree(root_node):
print("%s%s" % (pre, node.name))
except Exception as e:
print(e)
self.result_label.config(text="错误")
game = Game()
game.root.mainloop()
Loading…
Cancel
Save