import os
import tkinter as tk
from PIL import Image,ImageTk
from random import shuffle
import random
import numpy as np
from tkinter import messagebox
from itertools import combinations
import re
win = tk.Tk()
win.state("zoomed")
win.title("算24纸牌游戏")
numb = 0
gfournum=[]
paused = False
cancalnum = []
file_name = 'cancalnum.txt'
with open(file_name) as file_object:
for line in file_object:
tmpline=line.replace('[', '').replace(']', '').split(",")
tmpline=[int(z) for z in tmpline]
cancalnum.append(tmpline)
class Poker:
def __init__(self,height=720,width=1280):
self.height = height
self.width = width
self.game_round = 0
self.cv = tk.Canvas(win, height=self.height, width=self.width)
self.desk = Image.open("desk.png")
self.background_image = ImageTk.PhotoImage(self.desk)
self.cv.create_image(0,0,image=self.background_image,anchor=tk.NW)
self.cv.pack()
self.every_round()
self.start()
self.numb = 0
#self.fournum =[]
self.listbox =tk.Listbox()
def random_cards(self):
# 洗牌,对扑克牌进行随机排列
'''
tmp=[]
for i in range(4):
tmp.append(random.randint(1, 4)*100+random.randint(1,10))
return tmp
'''
global gfournum
gfournum=random.choice(cancalnum)
tmp=[]
for i in range(4):
tmp.append(random.randint(1, 4)*100+gfournum[i])
return tmp
def read_img(self,poker_list):
# 由于tkinter要求图片格式为gif,因此利用ImageTK模块对手中纸牌图片进行格式转换
img_list = []
for i in range(len(poker_list)):
file_name = "./pokerImage/" + str(poker_list[i])+ ".jpg"
card_img = Image.open(file_name)
img_list.append(ImageTk.PhotoImage(card_img))
return img_list
def every_round(self):
#
#self.poker_list = self.cards_name()
self.poker_list = self.random_cards()
#print(self.poker_list)
self.game_round += 1
self.score_board()
self.poker_list_img = self.read_img(self.poker_list)
tmplist = []
for i in range(4):
tmplist.append(self.poker_list[i] % 100)
print("显示数字牌",tmplist)
for k in range(4):
self.poker_cv = self.cv.create_image(350-(105+20*4)/2+200*k,215,image=self.poker_list_img[k],anchor=tk.NW)
def restart(self):
# 点击再来一局后的响应
global paused
paused = False
self.cv.delete(self.poker_cv)
self.every_round()
global numb
numb = 0
self.run_num(self.label)
if hasattr(self,"listbox"):
#self.listbox.delete(0,tk.END)
self.listbox.destroy()
def answer(self):
task = Solver()
tmp_solution = task.solution(gfournum)
anscount= len(tmp_solution)
self.listbox = tk.Listbox(self.cv,setgrid=True,font=("Helvetica",16))
self.listbox.place(relx=0.4, rely=0.6)
for j in range(anscount):
self.listbox.insert(tk.END,tmp_solution[j])
global paused
paused = True
#self.listbox(tk.ACTIVE)
def start(self):
# 再来一局按钮及其响应事件
self.start_button = tk.Button(self.cv, text="再玩一次", bg='grey', fg='red',
font=('微软雅黑 Bold', 18),
command=self.restart)
self.start_button.place(relx=0.85, rely=0.9, height=40, width=100)
self.label = tk.Label(self.cv,bg="lightyellow",fg='red',font=('微软雅黑 Bold', 18))
self.label.place(relx=0.25, rely=0.04)
self.run_num(self.label)
self.answer_button = tk.Button(self.cv, text="给我答案", bg='grey', fg='blue',
font=('微软雅黑 Bold', 18),
command=self.answer)
self.answer_button.place(relx=0.15, rely=0.9, height=40, width=100)
global paused
paused = False
def score_board(self):
# 分数显示牌
self.round_label = tk.Label(self.cv, text="第 " + str(self.game_round) + " 局", height=1, width=21,
font=("微软雅黑", 20), fg="#00ff00", bg="#cccccc")
self.round_label.place(relx=0.75, rely=0.04)
def run_num(self,target):
def counting():
global numb
global paused
numb += 1
target.config(text="已经 " + str(numb) + " 秒")
if paused == False:
target.after(1000, counting) # 间隔1000毫秒再次执行counting函数
counting()
class Solver:
# 需要达成的目标结果值
target = 24
# 四则运算符号定义,其中,a -- b = b - a,a // b = b / a
ops = ['+', '-', '*', '/', '--', '//']
# precise_mode为精准模式,若开启,则减号及除号后开启括号
def __init__(self, precise_mode=False):
self.precise_mode = precise_mode
def solution(self, nums):
result = []
groups = self.dimensionality_reduction(self.format(nums))
for group in groups:
for op in self.ops:
exp = self.assemble(group[0], group[1], op)['exp']
if self.check(exp, self.target) and exp not in result:
result.append(exp)
return [exp + '=' + str(self.target) for exp in result]
# 对需要处理的数字或表达式组合进行降维,降低到二维
def dimensionality_reduction(self, nums):
result = []
# 如果维数大于2,则选出两个表达式组合成一个,从而降低一个维度,通过递归降低到二维
if len(nums) > 2:
for group in self.group(nums, 2):
for op in self.ops:
new_group = [self.assemble(group[0][0], group[0][1], op)] + group[1]
result += self.dimensionality_reduction(new_group)
else:
result = [nums]
return result
# 将两个表达式组合成一个新表达式
def assemble(self, exp1, exp2, op):
# 如果运算符为'--'或者'//',则交换数字顺序重新计算
if op == '--' or op == '//':
return self.assemble(exp2, exp1, op[0])
# 如果是乘法,则根据两个表达式的情况加括号
if op in r'*/':
exp1 = self.add_parenthesis(exp1)
exp2 = self.add_parenthesis(exp2)
if self.precise_mode:
if op == '-':
exp2 = self.add_parenthesis(exp2)
elif op == '/':
exp2 = self.add_parenthesis(exp2, True)
exp = self.convert(exp1['exp'] + op + exp2['exp'], op)
return {'op': op, 'exp': exp}
# 根据需要为表达式添加相应的括号
@staticmethod
def add_parenthesis(exp, is_necessary=False):
# 如果上一计算步骤的运算符号为加号或减号,则需加括号
if (is_necessary and not exp['exp'].isdigit()) or exp['op'] in r'+-':
result = {
'exp': '(' + exp['exp'] + ')',
'op': exp['op']
}
else:
result = exp
return result
# 检查表达式是否与结果相等,考虑到中间步骤的除法,因此不采用相等判断,而是采用计算值和目标值的绝对值是否符合某个精度
@staticmethod
def check(exp, target, precision=0.0001):
try:
return abs(eval(exp) - target) < precision
except ZeroDivisionError:
return False
# 将表达式各项重新排序成为等价标准表达式
@staticmethod
def convert(exp, op):
if op in r'+-':
pattern = r'([\+\-]((\(.+\)|\d+)[\*\/](\(.+\)|\d+)|\d+))'
exp = '+' + exp
else:
pattern = r'([\*\/](\(.+?\)|\d+))'
exp = '*' + exp
result = ''.join(sorted([i[0] for i in re.findall(pattern, exp)]))
if len(result) != len(exp):
result = exp
return result[1:]
# 将输入的数字格式化为字典,数字的运算符号为空格,注意不是空字符
@staticmethod
def format(nums):
return [{'op': ' ', 'exp': str(num)} for num in nums]
# 对表达式列表进行分组,返回列表,[[[n1, n2], [n3, n4]], [[n1, n3], [n2, n4]], ...]
@staticmethod
def group(exp_list, counter):
# 生成以下标号为元素的列表
index_list = [i for i in range(len(exp_list))]
# 以下标号列表取出不重复的组合
combination = list(combinations(index_list, counter))
# 使用下标得到原表达式并组成最终的结果数组
for group1 in combination:
group2 = list(set(index_list) - set(group1))
yield [
[exp_list[g1] for g1 in group1],
[exp_list[g2] for g2 in group2]
]
poker = Poker()
win.mainloop()
24-1.jpg
24-2.jpg