game_2048

自己写的2048小游戏, 运行方式:复制源码在pycharm或者cmd运行,也可以通过 pyinstaller -Fw game_2048.py 打包成exe格式运行,效果下图:

 源码:

# -*-coding:utf-8-*-
# @作   者: Fiona
# @创建时间: 2023/6/23 20:28
# @项目名称: codes
# @文件名称:game_2048.py 
# @描   述: 2048游戏
import os
import sys
import random
import time
import copy
import tkinter as tk


class GUI2048(object):
    """
    top: D9D1E0
    back_page: B49FAC
    0: E9D4D1
    2: D8D7FF
    4: E5E0EA
    8: FBB4BA
    16: FF9B8B
    32: FF7261
    64: F3D8A9
    128: F7C679
    256:FF9B44
    512: FF7019
    1024:FF4001

    重置: 9D99A8,
    字体 ; D3D5FE
    """

    def __init__(self, top=None, seats=None, max_num=0, cur_num=0, move_num=0, play_keybord=None, play_up=None, play_down=None, play_left=None, play_right=None, quit=None, reset=None):
        """
        This class configures and populates the toplevel window.
        top is the toplevel containing window.
        """
        self.top = top
        if not seats:
            seats = [0 for i in range(16)]
        self.seats = seats
        self.max_num = max_num
        self.cur_num = cur_num
        self.move_num = move_num
        self.play_keybord = play_keybord
        self.play_up = play_up
        self.play_down = play_down
        self.play_left = play_left
        self.play_right = play_right

        self.quit = quit
        self.reset = reset

        self.Frame_game_root = None
        self.Label_num = None

        self.Label_max = None
        self.Label_cur = None

        self.Button_up = None
        self.Button_down = None
        self.Button_left = None
        self.Button_right = None

        self.Button_exit = None
        self.Button_reset = None

        self.draw_game_root_page()
        self.draw_game_num_page()
        self.draw_command_button()
        self.draw_keybord_label()
        self.draw_records()

    def draw_game_root_page(self):
        self.top.geometry("600x450+539+43")
        self.top.minsize(120, 1)
        self.top.maxsize(3004, 1901)
        self.top.resizable(0, 0)
        self.top.title("2048")
        self.top.configure(background="#D9D1E0")

    def draw_game_num_page(self, seats=None):
        if seats:
            self.seats = seats

        self.Frame_game_root = tk.Frame(self.top)
        self.Frame_game_root.place(x=10, y=10, height=410, width=410)
        self.Frame_game_root.configure(relief='groove', borderwidth="2", background="#B49FAC")

        label_num_size = 90
        label_num_x_size = 10  # 横轴间隔10
        label_num_y_siee = 10   # 纵轴间隔10
        label_num_x_size_map = [label_num_x_size, label_num_x_size+1*label_num_size, label_num_x_size+2*label_num_size, label_num_x_size+3*label_num_size]
        label_num_y_size_map = [label_num_y_siee, label_num_y_siee+1*label_num_size, label_num_y_siee+2*label_num_size, label_num_y_siee+3*label_num_size]
        num_color_map = {
            0: "#E9D4D1",
            2: "#D8D7FF", 4: "#E5E0EA", 8: "#FBB4BA", 16: "#FF9B8B",
            32: "#FF7261", 64: "#F3D8A9", 128: "#F7C679", 256: "#FF9B44", 512: "#FF7019", 1024: "#FF4001"
        }

        label_num_css_map = {
            0: {"x": label_num_x_size_map[0], "y": label_num_y_size_map[0]}, 1: {"x": label_num_x_size_map[1], "y": label_num_y_size_map[0]}, 2: {"x": label_num_x_size_map[2], "y": label_num_y_size_map[0]}, 3: {"x": label_num_x_size_map[3], "y": label_num_y_size_map[0]},
            4: {"x": label_num_x_size_map[0], "y": label_num_y_size_map[1]}, 5: {"x": label_num_x_size_map[1], "y": label_num_y_size_map[1]}, 6: {"x": label_num_x_size_map[2], "y": label_num_y_size_map[1]}, 7: {"x": label_num_x_size_map[3], "y": label_num_y_size_map[1]},
            8: {"x": label_num_x_size_map[0], "y": label_num_y_size_map[2]}, 9: {"x": label_num_x_size_map[1], "y": label_num_y_size_map[2]}, 10: {"x": label_num_x_size_map[2], "y": label_num_y_size_map[2]}, 11: {"x": label_num_x_size_map[3], "y": label_num_y_size_map[2]},
            12: {"x": label_num_x_size_map[0], "y": label_num_y_size_map[3]}, 13: {"x": label_num_x_size_map[1], "y": label_num_y_size_map[3]}, 14: {"x": label_num_x_size_map[2], "y": label_num_y_size_map[3]}, 15: {"x": label_num_x_size_map[3], "y": label_num_y_size_map[3]},
        }

        for i in range(16):
            self.Label_num = tk.Label(self.Frame_game_root)
            self.Label_num.place(x=label_num_css_map.get(i).get('x'), y=label_num_css_map.get(i).get('y'),
                                 height=label_num_size, width=label_num_size)

            background = num_color_map.get(self.seats[i])
            text = str(self.seats[i]) if self.seats[i] else ""
            self.Label_num.configure(activebackground="#ab5858", activeforeground="#000000",
                                       anchor='w', background=background, compound='center',
                                       border=1,
                                       disabledforeground="#a3a3a3",
                                       font="-family {High Tower Text} -size 36 -weight bold",
                                       foreground="#000000",
                                       relief="solid",
                                       text=text)

    def draw_command_button(self):
        self.Button_exit = tk.Button(self.top)
        self.Button_exit.place(x=510, y=370, height=28, width=49)
        self.Button_exit.configure(activebackground="#793e3e", activeforeground="#793e3e",
                                   background="#b16363", compound='left', disabledforeground="#a3a3a3",
                                   foreground="#000000",
                                   highlightbackground="#d9d9d9",
                                   highlightcolor="black",
                                   pady="0",
                                   text='''退出''',
                                   command=self.quit
                                   )

        self.Button_reset = tk.Button(self.top)
        self.Button_reset.place(x=440, y=370, height=28, width=49)
        self.Button_reset.configure(activebackground="#793e3e", activeforeground="#793e3e",
                                    background="#b16363", compound='left', disabledforeground="#a3a3a3",
                                    foreground="#000000",
                                    highlightbackground="#d9d9d9",
                                    highlightcolor="black",
                                    pady="0",
                                    text='''重置''',
                                    command=self.reset
                                    )

        self.Button_up = tk.Button(self.top)
        self.Button_up.place(x=470, y=150, height=28, width=49)
        self.Button_up.configure(activebackground="beige", activeforeground="black",
                                 background="#b16363", compound='left', cursor="fleur",
                                 foreground="#000000", highlightbackground="#d9d9d9",
                                 highlightcolor="black", pady="0", text='''上''',
                                 command=self.play_up
                                 )

        self.Button_down = tk.Button(self.top)
        self.Button_down.place(x=470, y=250, height=28, width=49)
        self.Button_down.configure(activebackground="beige", activeforeground="black",
                                    background="#b16363", compound='left', cursor="fleur",
                                    foreground="#000000", highlightbackground="#d9d9d9",
                                    highlightcolor="black", pady="0", text='''下''',
                                   command=self.play_down
                                    )

        self.Button_left = tk.Button(self.top)
        self.Button_left.place(x=430, y=200, height=28, width=49)
        self.Button_left.configure(activebackground="beige", activeforeground="black",
                                    background="#b16363", compound='left', cursor="fleur",
                                    foreground="#000000", highlightbackground="#d9d9d9",
                                    highlightcolor="black", pady="0", text='''左''',
                                   command=self.play_left
                                   )

        self.Button_right = tk.Button(self.top)
        self.Button_right.place(x=520, y=200, height=28, width=49)
        self.Button_right.configure(activebackground="beige", activeforeground="black",
                                    background="#b16363", compound='left', cursor="fleur",
                                    foreground="#000000", highlightbackground="#d9d9d9",
                                    highlightcolor="black", pady="0", text='''右''',
                                    command=self.play_right
                                    )

    def draw_keybord_label(self):
        """
        label邦健键盘事件,来控制移动方向
        """
        self.Label_keybord_event = tk.Label(self.top)
        # self.Label_keybord_event.place(x=430, y=10, height=33, width=80)
        # self.Label_keybord_event.configure(anchor='w',
        #                                    compound='left',
        #                                     cursor="fleur",
        #                                    highlightbackground="white",  # 设置为白色
        #                                    highlightthickness=0  # 透明度不可见
        #                                    )

        self.Label_keybord_event.focus_set()
        self.Label_keybord_event.pack()
        self.Label_keybord_event.bind('<Key>', self.play_keybord)
        pass

    def draw_records(self, cur_num=0, move_num=-1):
        if cur_num:
            self.cur_num = cur_num
        if move_num != -1:
            self.move_num = move_num

        self.Label_max = tk.Label(self.top)
        self.Label_max.place(x=430, y=10, height=33, width=80)
        self.Label_max.configure(anchor='w', background="#b16363", compound='left',
                                 cursor="fleur", disabledforeground="#a3a3a3",
                                 foreground="#000000", text=f'''最高:{str(self.max_num)}''')

        self.Label_cur = tk.Label(self.top)
        self.Label_cur.place(x=430, y=60, height=33, width=80)
        self.Label_cur.configure(anchor='w', background="#b16363", compound='left',
                                 cursor="fleur", disabledforeground="#a3a3a3",
                                 foreground="#000000", text=f'''当前:{str(self.cur_num)}''')

        self.Label_move = tk.Label(self.top)
        self.Label_move.place(x=430, y=110, height=33, width=80)
        self.Label_move.configure(anchor='w', background="#b16363", compound='left',
                                 cursor="fleur", disabledforeground="#a3a3a3",
                                 foreground="#000000", text=f'''移动:{str(self.move_num)}''')

    def run(self):
        self.top.mainloop()


class Game2048(object):
    """
    2048游戏大概玩法:
    有4*4=16个方格位置, 刚入场会随机初始化1-2个数,分别是2或者4, 位置随机。
    通过上下左右滑动,控制界面上的数字成倍相加, 数的范围:
    【2、4、8、16、32、64、128、256、512、1024、2048】
    通过上下左右滑动,让最后界面上有的最大数越大,就会越有成就感,其实就是另一种有目标的消消乐,
    当界面的空格数越来越少,就越难滑动,最后没有空格为止,就划不动,代表游戏失败。
    我用了2周的时间认真的玩了下, 后面能够比较有概率的玩到1024, 再往后,就没有达到过了,
    到后面就很难玩动, 最佳战绩就是【1024、512、256、128、64、32、16、8、4、2】 数字都有,
    但是它们合并不到一块去, 所以最后还是游戏结束掉了,所以想要通过仔细研究下算法, 将这个游戏玩通关掉。
    顺便写一个简易的python版的2048。

    1行:[0, 1, 2, 3]
    2行:[4, 5, 6, 7]
    3行:[8, 9, 10, 11]
    4行:[12, 13, 14, 15]
    up = [[0, 4, 8, 12], [1, 5, 9, 13], [2, 6, 10, 14], [3, 7, 11, 15]]
    down = [[12, 8, 4, 0], [13, 9, 5, 1], [14, 10, 6, 2], [15, 11, 7, 3]]
    left = [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]
    right = [[3, 2, 1, 0], [7, 6, 5,4], [11, 10, 9, 8], [15, 14, 13, 12]]

    如果4行数据都没有产生任何计算及唯一,则代表这个方向不能进行移动, 不能产生新的数,改变局面
    0|0|0|0-> 没有计算, 没有位移
    2|4|8|16-> 没有计算, 没有位移
    2|2|2|2 -> 4|4|0|0

    2|2|2|4-> 4|2|4|0

    2|2|4|8-> 4|4|8|0
    2|2|4|4-> 4|8|0|0
    2|4|8|8-> 2|4|16|0
    """
    def __init__(self):
        self.default_val = 0
        self.temp_seats = [self.default_val for i in range(16)]  # 临时区
        self.all_seats = [self.default_val for i in range(16)]  # 改变后的

        self.up = [[0, 4, 8, 12], [1, 5, 9, 13], [2, 6, 10, 14], [3, 7, 11, 15]]
        self.down = [[12, 8, 4, 0], [13, 9, 5, 1], [14, 10, 6, 2], [15, 11, 7, 3]]
        self.left = [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]
        self.right = [[3, 2, 1, 0], [7, 6, 5, 4], [11, 10, 9, 8], [15, 14, 13, 12]]
        self.game_2048_play = None
        self.cur_num = 0
        self.move_num = 0  # 有效的操作次数

    def gen_new_nums(self, indexs):
        # 随机选取1-2个数, 赋值给1-2个空格位置
        n_num = random.randint(1, 2)
        low_n_vals = [random.choices([2, 4], weights=[0.8, 0.6])[0] for i in range(1, n_num+1)]
        low_n_indexs = [random.choices(indexs)[0] for i in range(1, n_num+1)]
        print(f"随机新增:{n_num}个数:{low_n_vals} , 放在方格位置:{low_n_indexs}")
        for i, val in enumerate(low_n_vals):
            self.all_seats[low_n_indexs[i]] = val

    # def init_seat(self):
    #     self.all_seats, self.temp_seats = self.temp_seats, [0 for i in range(16)]

    def draw_2048(self):
        os.system('cls')
        r = 1
        for i in range(1, 17):
            if i % 4 == 0:
                print(f"{str(r)}行:{self.all_seats[i-4:i]}")
                r += 1
        # self.init_seat()  # 画完方格后,重置容器

    def _init_game_2048(self):
        print("最开始初始化:")
        self.all_seats = [self.default_val for i in range(16)]  # 改变后的
        self.gen_new_nums([i for i in range(16)])

    def play_caculate(self, direction_indexs):
        new_lines_val_list = []
        zero_index_list = []
        self.temp_seats = copy.deepcopy(self.all_seats)
        for n, line in enumerate(direction_indexs):
            line_val_list = [self.all_seats[line[i]] for i in range(4) if self.all_seats[line[i]]]  # 当前局面的当前行或列所有值
            new_line_val_list = []   # 每一行或每一列通过位移或计算后的值
            if len(line_val_list) == 0 or len(line_val_list) == 1:
                new_line_val_list = line_val_list
            elif len(line_val_list) == 2:
                if line_val_list[0] == line_val_list[1]:
                    new_line_val_list = [sum(line_val_list)]
                else:
                    new_line_val_list = line_val_list
            elif len(line_val_list) == 3:
                if line_val_list[0] == line_val_list[1]:
                    new_line_val_list = [sum(line_val_list[:2]), line_val_list[2]]
                elif line_val_list[1] == line_val_list[2]:
                    new_line_val_list = [line_val_list[0], sum(line_val_list[1:])]
                else:
                    new_line_val_list = line_val_list
            elif len(line_val_list) == 4:
                if line_val_list[0] == line_val_list[1]:
                    new_line_val_list.append(sum([line_val_list[0], line_val_list[1]]))
                    if line_val_list[2] == line_val_list[3]:
                        new_line_val_list.append(sum([line_val_list[2], line_val_list[3]]))
                    else:
                        new_line_val_list.extend([line_val_list[2], line_val_list[3]])
                elif line_val_list[1] == line_val_list[2]:
                    new_line_val_list = [line_val_list[0], sum([line_val_list[1], line_val_list[2]]), line_val_list[3]]
                elif line_val_list[2] == line_val_list[3]:
                    new_line_val_list = [line_val_list[0], line_val_list[1], sum([line_val_list[2], line_val_list[3]])]
                else:
                    new_line_val_list = line_val_list

            new_line_val_list.extend([0 for i in range(4 - len(new_line_val_list))])
            new_lines_val_list.append(new_line_val_list)
            for i, new_line_val in enumerate(new_line_val_list):
                if not new_line_val:
                    zero_index_list.append(line[i])
                self.all_seats[line[i]] = new_line_val

            # 变换前后局面上的值有变化,才能随机在剩余的空间中生成新的数值
        if self.all_seats != self.temp_seats:
            self.gen_new_nums(zero_index_list)
            self.move_num += 1

        if self.game_2048_play:
            self.cur_num = max(self.all_seats)  # 当前最大值
            self.game_2048_play.draw_records(cur_num=self.cur_num, move_num=self.move_num)
            self.game_2048_play.draw_game_num_page()

    def play_up(self):
        print("【向上移动】")
        self.play_caculate(self.up)

    def play_down(self):
        print("【向下移动】")
        self.play_caculate(self.down)

    def play_left(self):
        print("【向左移动】")
        self.play_caculate(self.left)

    def play_right(self):
        print("【向右移动】")
        self.play_caculate(self.right)

    def play_keybord(self, evt):
        # msg = f"您点击了{evt.char}, ASCII代码{evt.keycode}\n"
        # msg += f"按键名称{evt.keysym}, 代码{evt.keysym_num}"
        if evt.keysym == 'Up':
            self.play_up()
        elif evt.keysym == 'Down':
            self.play_down()
        elif evt.keysym == 'Left':
            self.play_left()
        elif evt.keysym == 'Right':
            self.play_right()

    def play_gui(self):
        init_top = tk.Tk()
        init_seats = [0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 4, 32, 64, 64, 0]  # 临时修改初始值
        self._init_game_2048()
        # self.all_seats = init_seats
        self.cur_num = max(self.all_seats)  # 当前最大值
        self.game_2048_play = GUI2048(top=init_top, seats=self.all_seats, max_num=2048, cur_num=self.cur_num, move_num=self.move_num,
                                      play_keybord=self.play_keybord,
                                      play_up=self.play_up, play_down=self.play_down,
                                      play_left=self.play_left, play_right=self.play_right,
                                      quit=self.quit,
                                      reset=self.reset
                                      )
        self.game_2048_play.run()

    def reset(self):
        """
        重置
        :return:
        """
        if self.game_2048_play:
            self._init_game_2048()
            self.cur_num = max(self.all_seats)  # 当前最大值
            self.move_num = 0
            self.game_2048_play.draw_records(cur_num=self.cur_num, 
                                       move_num=self.move_num)
            self.game_2048_play.draw_game_num_page(seats=self.all_seats)
        print("【重置完成】")

    def quit(self):
        """退出"""
        print("== 退出 ==")
        sys.exit(-1)


if __name__ == "__main__":
    game_2048 = Game2048()
    game_2048.play_gui()


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值