python 算24游戏

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。