# -*- 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, "", 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('', 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()