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.

918 lines
35 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.

# -*- encoding: utf-8 -*-
"""
@Author: packy945
@FileName: main.py
@DateTime: 2023/5/11 11:34
@SoftWare: PyCharm
"""
from tkinter import simpledialog
from data import *
import tkinter as tk
import tkinter.messagebox
from collections import Counter
import random
from itertools import permutations
from TreeNode import *
from setting import *
from tkinter import *
from PIL import ImageTk
from PIL import Image as imim
import sys
sz = []
A = Aexp([0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0])
img_open = []
img_png = []
def set_canvas_button(button_pot: list, button_photo: ImageTk.PhotoImage, command, tags=None, bg="#3E97C1"):
button = C.create_image(button_pot[0], button_pot[1], anchor=tk.NW, image=button_photo)
C.tag_bind(button, "<Button-1>", command)
def to_image(path, resize=None) -> ImageTk.PhotoImage:
if resize:
return ImageTk.PhotoImage(imim.open(path).resize(resize))
return ImageTk.PhotoImage(imim.open(path))
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 = to_image(sys.path[0] + "/./images/对-高亮.png", (30, 30))
clo2 = to_image(sys.path[0] + "/./images/错.png", (30, 30))
clo3 = to_image(sys.path[0] + '/./images/chushi.png', (30, 30))
elif flag == 0:
clo1 = to_image(sys.path[0] + "/./images/对.png", (30, 30))
clo2 = to_image(sys.path[0] + "/./images/错.png", (30, 30))
clo3 = to_image(sys.path[0] + '/./images/chushi.png', (30, 30))
else:
clo1 = to_image(sys.path[0] + "/./images/对.png", (30, 30))
clo2 = to_image(sys.path[0] + "/./images/错-高亮.png", (30, 30))
clo3 = to_image(sys.path[0] + '/./images/chushi.png', (30, 30))
label3 = tk.Label(window, image=clo1, relief="sunken", borderwidth=0)
label4 = tk.Label(window, image=clo2, relief="sunken", borderwidth=0)
label5 = tk.Label(window, image=clo3, relief="sunken", borderwidth=0)
label3.image = clo1
label4.image = clo2
label5.image = clo3
if flag == 1:
label3.place(x=ENTRY_WIDTH + 200, y=CARD_CANVAS_HEIGHT + 18, width=30, height=30)
elif flag == 0:
label5.place(x=ENTRY_WIDTH + 200, y=CARD_CANVAS_HEIGHT + 18, width=30, height=30)
else:
label4.place(x=ENTRY_WIDTH + 200, y=CARD_CANVAS_HEIGHT + 18, width=30, height=30)
# label3.place(x=ENTRY_WIDTH + 200, y=CARD_CANVAS_HEIGHT + 18, width=30, height=15)
# label4.place(x=ENTRY_WIDTH + 200, y=CARD_CANVAS_HEIGHT + 8 + 30, width=30, height=15)
def ans_cal(ans=None):
"""
绘制结果框
:param ans:
:return:
"""
if not ans:
label2 = tk.Label(window, text='= ?', font=('楷体', 18, 'bold'), width=30, height=10, background="#4acb69",
# 设置填充区距离、边框宽度和其样式(凹陷式)
borderwidth=0, relief="raised")
else:
label2 = tk.Label(window, text=f'={ans}', font=('楷体', 18, 'bold'), width=30, height=10, background="#4acb69",
# 设置填充区距离、边框宽度和其样式(凹陷式)
borderwidth=0, relief="raised")
label2.place(x=ENTRY_WIDTH + LEFT_PADDING + 25, y=CARD_CANVAS_HEIGHT + 15, width=100, height=ENTRY_HEIGHT)
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])
C.update()
def show(kp_list):
# 根据花色以及点数显示卡牌
global img_open, img_png
img_open = []
img_png = []
C.delete('card')
i = 150 # 卡牌位置偏移量
for k in range(4):
img_open.append(
imim.open(sys.path[0] + "/./card/" + kp_list[k][0] + "/" + kp_list[k][0] + kp_list[k][1] + '.png').resize(
(int((CARD_CANVAS_HEIGHT - 10) * 0.6) + 10, CARD_CANVAS_HEIGHT - 10)))
img_png.append(ImageTk.PhotoImage(img_open[k]))
C.create_image(50 + i, 100, image=img_png[k], tags="card")
i += int((CARD_CANVAS_HEIGHT - 10) * 0.6) + 80
C.update()
# 展示结果
def show_result(ss, sz):
'''
展示计算结果
:param ss: 输入框中的表达式
:param sz: 题中给的卡牌数字
:return:
'''
numbers = [int(number) for number in re.findall(r'\d+', ss)]
a = Counter(numbers)
# char_list = [] # 用于存放算式中的数字
# for i in range(len(ss)):
# if '0' < ss[i] <= '9':
# char_list.append(ss[i])
# a = Counter(char_list) # 计数函数Counter
if sz:
b = Counter([sz[0][1], sz[1][1], sz[2][1], sz[3][1]])
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
answer = (A.answer[0], A.Color[0])
# 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])
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
global but5
but_image = to_image(sys.path[0] + "/./images/chuti.png", (TOP_BUTTON_WIDTH, TOP_BUTTON_HEIGHT))
but = Button(window, image=but_image, command=show_card, bd=0, relief="solid", bg="#141414", highlightthickness=0)
but.image = but_image
but.place(x=CARD_CANVAS_WIDTH + TOP_BUTTON_WIDTH + 50, y=40, width=TOP_BUTTON_WIDTH, height=TOP_BUTTON_HEIGHT)
but2_image = to_image(sys.path[0] + "/./images/换牌.png", (TOP_BUTTON_WIDTH, TOP_BUTTON_HEIGHT))
but2 = tk.Button(window, image=but2_image, command=show_card, bd=0, relief="solid", bg="#141414",
highlightthickness=0)
but2.image = but2_image
but2.place(x=CARD_CANVAS_WIDTH + TOP_BUTTON_WIDTH + 50, y=70 + TOP_BUTTON_HEIGHT, width=TOP_BUTTON_WIDTH,
height=TOP_BUTTON_HEIGHT, )
but4_image = to_image(sys.path[0] + "/./images/计算.png", (MIDDLE_BUTTON_WIDTH, MIDDLE_BUTTON_HEIGHT))
but4 = tk.Button(window, image=but4_image, command=lambda: show_result(entry.get(), sz), bd=0, relief="solid",
bg="#141414", highlightthickness=0)
but4.place(x=ENTRY_WIDTH + 245, y=CARD_CANVAS_HEIGHT + 15, width=MIDDLE_BUTTON_WIDTH, height=MIDDLE_BUTTON_HEIGHT, )
but4.image = but4_image
##报错
but3_image = to_image(sys.path[0] + "/./images/自动求解.png", (MIDDLE_BUTTON_WIDTH, MIDDLE_BUTTON_HEIGHT))
but3 = tk.Button(window, image=but3_image, command=lambda: show_answer(), bd=0, relief="solid", bg="#141414",
highlightthickness=0)
but3.place(x=60, y=CARD_CANVAS_HEIGHT + 65, width=MIDDLE_BUTTON_WIDTH,
height=MIDDLE_BUTTON_HEIGHT, )
but3.image = but3_image
all_ans_image = to_image(sys.path[0] + "/./images/所有答案.png", (MIDDLE_BUTTON_WIDTH, MIDDLE_BUTTON_HEIGHT))
all_ans = tk.Button(window, image=all_ans_image, command=lambda: show_next(), bd=0, relief="solid", bg="#141414",
highlightthickness=0, state='disable')
all_ans.place(x=60 + MIDDLE_BUTTON_WIDTH * 2 + 50 * 2, y=CARD_CANVAS_HEIGHT + 65, width=MIDDLE_BUTTON_WIDTH,
height=MIDDLE_BUTTON_HEIGHT, )
all_ans.image = all_ans_image
##报错
but5_image = to_image(sys.path[0] + "/./images/画树.png", (MIDDLE_BUTTON_WIDTH, MIDDLE_BUTTON_HEIGHT))
but5 = tk.Button(window, image=but5_image, command=lambda: F.show_tree(entry.get()), bd=0, relief="solid",
bg="#141414",
highlightthickness=0)
but5.place(x=60 + MIDDLE_BUTTON_WIDTH + 50, y=CARD_CANVAS_HEIGHT + 65, width=MIDDLE_BUTTON_WIDTH,
height=MIDDLE_BUTTON_HEIGHT, )
but5.image = but5_image
but6_image = to_image(sys.path[0] + '/./images/生成表达式.png', (MIDDLE_BUTTON_WIDTH, MIDDLE_BUTTON_HEIGHT))
but6 = tk.Button(window, image=but6_image, command=lambda: expressions(), bd=0, relief="solid",
bg="#141414",
highlightthickness=0)
but6.place(x=60 + MIDDLE_BUTTON_WIDTH * 3 + 50 * 3, y=CARD_CANVAS_HEIGHT + 65, width=MIDDLE_BUTTON_WIDTH,
height=MIDDLE_BUTTON_HEIGHT, )
but6.image = but6_image
##报错
but7_image = to_image(sys.path[0] + '/./images/生成语法树.png', (MIDDLE_BUTTON_WIDTH, MIDDLE_BUTTON_HEIGHT))
but7 = tk.Button(window, image=but7_image, command=lambda: F.show_tree(expression_tree()), bd=0, relief="solid",
bg="#141414",
highlightthickness=0)
but7.place(x=60 + MIDDLE_BUTTON_WIDTH * 4 + 50 * 4, y=CARD_CANVAS_HEIGHT + 65, width=MIDDLE_BUTTON_WIDTH,
height=MIDDLE_BUTTON_HEIGHT, )
but7.image = but7_image
but8_image = to_image(sys.path[0] + '/./images/一致性检查.png', (MIDDLE_BUTTON_WIDTH, MIDDLE_BUTTON_HEIGHT))
but8 = tk.Button(window, image=but8_image, command=lambda: examine(), bd=0, relief="solid",
bg="#141414",
highlightthickness=0)
but8.place(x=60 + MIDDLE_BUTTON_WIDTH * 5 + 50 * 5, y=CARD_CANVAS_HEIGHT + 65, width=MIDDLE_BUTTON_WIDTH,
height=MIDDLE_BUTTON_HEIGHT, )
but8.image = but8_image
def left2(event):
# 查找鼠标左键按下时位置是否在某个牌上
# print(event.x, event.y)
# if not A.card
left = []
right = []
i = 150
for j in range(4):
left.append(i)
right.append(i + (CARD_CANVAS_HEIGHT - 10) * 0.6)
i += int((CARD_CANVAS_HEIGHT - 10) * 0.6) + 80
up = 5
down = CARD_CANVAS_HEIGHT - 10
# 添加数值节点
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]])
print(tree.Node)
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_cv = C
add_image = to_image(sys.path[0] + "/./images/+.png", (40, 40))
self.opt1 = tk.Button(window, image=add_image, command=lambda: self.set_opt(1), bd=0, relief="solid",
bg="#141414",
highlightthickness=0)
self.opt1.image = add_image
self.opt1.place(x=TREE_CANVAS_WIDTH - 50, y=CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 200, width=40, height=40)
jian_image = to_image(sys.path[0] + "/./images/-.png", (40, 40))
self.opt2 = tk.Button(window, image=jian_image, command=lambda: self.set_opt(2), bd=0, relief="solid",
bg="#141414",
highlightthickness=0)
self.opt2.place(x=TREE_CANVAS_WIDTH - 10, y=CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 200, width=40, height=40)
self.opt2.image = jian_image
chen_image = to_image(sys.path[0] + "/./images/X.png", (40, 40))
self.opt3 = tk.Button(window, image=chen_image, command=lambda: self.set_opt(3), bd=0, relief="solid",
bg="#141414",
highlightthickness=0)
self.opt3.place(x=TREE_CANVAS_WIDTH - 50, y=CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 250, width=40, height=40)
self.opt3.image = chen_image
chu_image = to_image(sys.path[0] + "/./images/÷.png", (40, 40))
self.opt4 = tk.Button(window, image=chu_image, command=lambda: self.set_opt(4), bd=0, relief="solid",
bg="#141414",
highlightthickness=0)
self.opt4.place(x=TREE_CANVAS_WIDTH - 10, y=CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 250, width=40, height=40)
self.opt4.image = chu_image
self.set_opt(1)
dy = 150
bot_image = to_image(sys.path[0] + "/./images/添加运算节点.png", (100, 50))
bot1 = tk.Button(window, image=bot_image, bd=0, relief="solid", bg="#141414",
highlightthickness=0, command=lambda: self.add_opt())
bot1.place(x=TREE_CANVAS_WIDTH - 50, y=CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 150 + dy, width=100, height=50)
bot1.image = bot_image
bot2_image = to_image(sys.path[0] + "/./images/添加数值节点.png", (100, 50))
bot2 = tk.Button(window, image=bot2_image, bd=0, relief="solid", bg="#141414",
highlightthickness=0, command=lambda: self.add_number())
bot2.place(x=TREE_CANVAS_WIDTH - 50, y=CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 200 + dy, width=100, height=50)
bot2.image = bot2_image
bot3_image = to_image(sys.path[0] + "/./images/改变运算输入.png", (100, 50))
bot3 = tk.Button(window, image=bot3_image, bd=0, relief="solid", bg="#141414",
highlightthickness=0, command=lambda: self.change_num())
bot3.place(x=TREE_CANVAS_WIDTH - 50, y=CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 250 + dy, width=100, height=50)
bot3.image = bot3_image
bot4_image = to_image(sys.path[0] + "/./images/改变节点运算.png", (100, 50))
bot4 = tk.Button(window, image=bot4_image, bd=0, relief="solid", bg="#141414",
highlightthickness=0, command=lambda: self.change_opt())
bot4.place(x=TREE_CANVAS_WIDTH - 50, y=CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 300 + dy, width=100, height=50)
bot4.image = bot4_image
bot5_image = to_image(sys.path[0] + "/./images/数值节点交换.png", (100, 50))
bot5 = tk.Button(window, image=bot5_image, bd=0, relief="solid", bg="#141414",
highlightthickness=0, command=lambda: self.change_node())
bot5.place(x=TREE_CANVAS_WIDTH - 50, y=CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 350 + dy, width=100, height=50)
bot5.image = bot5_image
#bot6_image = to_image(sys.path[0] + "/./images/产生表达式.png", (80, 30))
#bot6 = tk.Button(window, image=bot6_image, bd=0, relief="solid", bg="#141414",
# highlightthickness=0, command=lambda: self.Aexp())
#bot6.place(x=TREE_CANVAS_WIDTH - 50, y=CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 400 + dy, width=80, height=30)
#bot6.image = bot6_image
bot7_image = to_image(sys.path[0] + "/./images/清空画布.png", (100, 50))
bot7 = tk.Button(window, image=bot7_image, bd=0, relief="solid", bg="#141414",
highlightthickness=0, command=lambda: self.clear())
bot7.place(x=TREE_CANVAS_WIDTH - 50, y=CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 400 + dy, width=100, height=50)
bot7.image = bot7_image
self.draw()
def set_opt(self, x):
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']='#131415'")
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'")
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 add_number(self):
root = Tk()
root.withdraw()
number = simpledialog.askfloat("输入框", "请输入数字:")
if number is not None:
tree.remark()
self.mode = 2
tree.Node.append(
[len(tree.Node), 'Value', None, None, None, int(number), 'Spade'])
self.draw()
def change_num(self):
tree.remark()
self.tips = '请选择一个数值节点'
self.mode = 3
self.draw()
def left1(self, event):
# 无操作
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('tree')
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 = 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('tree')
if len(ss) == 0:
tk.messagebox.showinfo('', '表达式不存在')
return
build_ast(ss)
self.draw()
def element(self, path):
# 加载图元对应的图片文件
img = Image.open(path)
# 使用resize方法调整图片
img = img.resize((70, 70))
# 把Image对象转换成PhotoImage对象
img = ImageTk.PhotoImage(img)
# 保存图片的引用,防止被垃圾回收
window.img = img
return img
def draw(self):
self.Tree_cv.delete('tree')
mode = ['', '添加运算节点', '添加数值节点', '改变运算输入', '改变节点运算', '数值节点交换', '添加数值节点']
lab1 = tk.Label(self.Tree_cv, text='当前操作:', bg='#131415', fg="white", font=('微软雅黑', 14, 'bold'),
borderwidth=0, anchor='w')
lab1.place(x=30, y=CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 100, width=90, height=30)
lab2 = tk.Label(self.Tree_cv, text=mode[self.mode], bg='#131415', fg="white", font=('微软雅黑', 14, 'bold'),
borderwidth=5, anchor='w')
lab2.place(x=120, y=CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 100, width=150, height=30)
lab3 = tk.Label(self.Tree_cv, text=self.tips, bg='#131415', fg="white", font=('微软雅黑', 14, 'bold'),
borderwidth=5, anchor='w')
lab3.place(x=300, y=CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 100, 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 = TREE_CANVAS_WIDTH
tree_height = TREE_CANVAS_HEIGHT * 0.7
dx = tree_length // (nums + 1)
dy = tree_height // (dept + 2)
# 若为数字节点
cur = 0
for i in range(len(tree.deepth)):
if tree.deepth[i] == 0:
draw_number(str(tree.Node[i][5])) # 生成数字图片
img = self.element(sys.path[0] + "/./images/{}.png".format(tree.Node[i][5])) # 生成图片对象 img
NUMBER_IMAGES.append(img) # 防止覆盖,将图片保存在图片列表里
cur += 1
tree.place[i] = (cur * dx, tree_height - dy + CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 200)
self.Tree_cv.create_image(tree.place[i][0] - tree.bc / 2, tree.place[i][1] - tree.bc / 2,
image=img, anchor=NW, tags="tree")
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 + CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 150)
self.Tree_cv.create_line(lnode[0], lnode[1] - tree.bc / 2 + 10, node[0], node[1] + tree.bc / 2 - 10,
fill='#246B80', width=1, tags="tree")
self.Tree_cv.create_line(rnode[0], rnode[1] - tree.bc / 2 + 10, node[0], node[1] + tree.bc / 2 - 10,
fill='#246B80', width=1, tags="tree")
tree.place[i] = node
color = 'white'
if tree.mark[i]:
color = '#d1d2c8'
self.Tree_cv.create_image(tree.place[i][0] - tree.bc / 2, tree.place[i][1] - tree.bc / 2,
image=FUNCTION_IMAGES[str(tree.Node[i][2])], anchor=NW, tags="tree")
self.Tree_cv.update()
# 随机生成表达式
def expressions():
init()
but5.configure(state='disabled')
with open(sys.path[0]+'/./expressions.txt', 'r') as file:
expressions = file.readlines()
random_expression = random.choice(expressions)
entry.insert("end", random_expression.strip())
# 随机生成语法树
def expression_tree():
init()
with open(sys.path[0]+'/./expressions.txt', 'r') as file:
expressions = file.readlines()
random_expression = random.choice(expressions)
return random_expression
# 一致性检查
def examine():
expression = entry.get()
if expression == '':
return tk.messagebox.showinfo(message='请输入表达式!')
expression_ans = eval(expression) # 计算用户输入的表达式的值
try:
tree_ans = float(tree.calculate(tree.Node[tree.rootID]))
if expression_ans == tree_ans:
but5.configure(state='active')
tk.messagebox.showinfo('', '语法树与表达式一致!')
else:
tk.messagebox.showinfo('', '语法树与表达式不一致!')
except:
return tk.messagebox.showinfo(message='请绘制语法树!')
from PIL import Image, ImageDraw, ImageFont
# 绘制数字图片
def draw_number(number):
# 打开背景图片
background_image = Image.open(sys.path[0] + "/./images/number_ground.png")
# 设置图片尺寸
image_width = 48
image_height = 48
# 缩放背景图片
background_image = background_image.resize((image_width, image_height))
# 创建空白图片
image = Image.new("RGBA", (image_width, image_height), (255, 255, 255, 0))
# 在空白图片上绘制背景图片
image.paste(background_image, (0, 0))
# 设置字体和字号
#以下字体出现问题,已经注释
# if int(number) < 100:
# font = ImageFont.truetype("arial.ttf", 15)
# elif 100 <= int(number) <= 999:
# font = ImageFont.truetype("arial.ttf", 13)
# else:
# font = ImageFont.truetype("arial.ttf", 9)
# 创建绘图对象
draw = ImageDraw.Draw(image)
# 计算文字位置居中
#以下字体出现问题已经注释font=font
bbox = draw.textbbox((0, 0), number)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
# text_width, text_height = 15,9
# text_width, text_height = draw.textsize(number, font=font)
text_x = (image_width - text_width) // 2 - 1
text_y = (image_height - text_height) // 2 - 1
# 在图片上绘制数字
#以下字体出现问题已经注释font=font
draw.text((text_x, text_y), number,fill="rgb(88,204,230)")
# 保存图片
file = sys.path[0] + "/./images/" + number + ".png"
image.save(file)
def click(event):
if event.y < CARD_CANVAS_HEIGHT:
left2(event)
else:
F.left1(event)
window = tk.Tk()
window.title('二十四点')
NUMBER_IMAGES = []
FUNCTION_IMAGES = {
"+": ImageTk.PhotoImage(imim.open(sys.path[0] + "/./images/+.png").resize((70, 70))),
"-": ImageTk.PhotoImage(imim.open(sys.path[0] + "/./images/-.png").resize((70, 70))),
"*": ImageTk.PhotoImage(imim.open(sys.path[0] + "/./images/X.png").resize((70, 70))),
"/": ImageTk.PhotoImage(imim.open(sys.path[0] + "/./images/÷.png").resize((70, 70)))
}
var = tk.StringVar()
var2 = tk.StringVar()
width = WINDOW_WIDTH
height = WINDOW_HEIGHT # 窗口大小
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)
window.resizable(True, True)
window.resizable(False, False)
C = Canvas(window, bg="blue", height=WINDOW_HEIGHT, width=WINDOW_WIDTH)
filename = ImageTk.PhotoImage(imim.open(BACKGROUND_IMG).resize((WINDOW_WIDTH, WINDOW_HEIGHT))) # 创建语法树的背景图片
C.create_image(0, 0, image=filename, anchor=NW)
qianzhi = ImageTk.PhotoImage(imim.open(sys.path[0] + "/./images/前置背景.png").resize((WINDOW_WIDTH, 30)))
C.create_image(0, CARD_CANVAS_HEIGHT + ENTRY_HEIGHT + 70, image=qianzhi, anchor=NW)
C.pack()
F = Frame_Tree(window)
C.bind('<Button-1>', click)
entry = tk.Entry(window, show=None, font=('宋体', 15, 'bold'))
entry.place(x=LEFT_PADDING, y=CARD_CANVAS_HEIGHT + 15, width=ENTRY_WIDTH, height=ENTRY_HEIGHT)
all_ans = None
Buts()
init()
window.mainloop()