python+tkinter开发2048游戏

发布时间 2023-06-18 20:03:59作者: wancy

1. 界面设计

  如果开发这个游戏,相信一定玩过。这里不过多介绍。我最后的效果。

2. 代码

import random
import tkinter as tk
from tkinter import messagebox
from tkinter.constants import W, N, E, S

def random_2()->bool:
    """
    在空位置随机生成一个2
    :return:
    """
    count_0 = sum(row.count(0) for row in data)#统计0的个数
    if count_0==0:
        print_data()
        return False
    # 生成一个 [0, 3] 范围内的整数
    randint_row = random.randint(0, 3)
    randint_col = random.randint(0, 3)
    while True:
        print(data[randint_row][randint_col])
        if data[randint_row][randint_col]==0:
            data[randint_row][randint_col]=2
            break
        else:
            randint_row = random.randint(0, 3)
            randint_col = random.randint(0, 3)
    print_data()
    return True

def up_move():
    """
    得到上移后的data
    :return:
    """
    #相当于将原data先转置,再左移,再转置回来
    data[:] = [list(item) for item in zip(*data)]
    print("转置后")
    print_data()
    left_move()
    #再次转置
    data[:] = [list(item) for item in zip(*data)]

def down_move():
    """
    得到下移后的数据
    :return:
    """
    # 相当于将原data先转置,再右移,再转置回来
    data[:] = [list(item) for item in zip(*data)]
    print("转置后")
    print_data()
    right_move()
    # 再次转置
    data[:] = [list(item) for item in zip(*data)]

def print_data():
    for item in data:
        print(item,end="\n")
    print("=============")

def left_move(right=False):
    """
    得到左移后的数据
    :return:
    """
    global sum_score
    for row in data:
        for i in range(len(row)-1,-1,-1):
            if row[i]==0:
                del row[i]
                row.append(0)
        #合并
        for i in range(0,len(row)-1,1):
            if row[i]==row[i+1] and row[i]!=0:
                # 累计总分
                sum_score += row[i] * 2
                #合并
                row[i]=row[i]*2
                row[i+1]=0
        #合并后产生的0放最后面
        for i in range(len(row) - 1, -1, -1):
            if row[i] == 0:
                del row[i]
                row.append(0)
    if right==False:
        print_data()


def right_move():
    """
    得到右移后的数据
    :return:
    """
    for i in range(len(data)):
        data[i] = data[i][::-1]
    """
或者
for item in lst3: item[:]=reversed(item) """ #有个简单的做法,向右移动,相当于可以先将每行反转逆序,在向左移动,移动完后,再反转 #相当于调用向左移动left_move() left_move(True) #再次反转 for item in data: item[:] = reversed(item) print_data() def stop_game(): mb = messagebox.askyesno( title="退出游戏", message="是否退出游戏!") if mb: win.quit() def reset(): global data global sum_score sum_score = 0 data = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] # 随机生成两个2 random_2() random_2() def is_merge():#判断是否还能够合并 #遍历元素,判断元素的右方与下方是否相等,相等,则能合并 #最右边的元素右边没有元素,最下面的元素,下面没有元素 for i in range(len(data)):#[0,len(data)-1] for j in range(len(data)): #判断右边 if 0<=j+1<=len(data)-1 and data[i][j]==data[i][j+1]:#前面为False时,and后面语句不会执行到,不会越界报错 return True #能合并 elif 0<=i+1<=len(data)-1 and data[i][j]==data[i+1][j]: return True #能合并 return False#不能合并了 def is_game_over(): #遍历,如果不能合并了,且格子满了,就结束游戏了 if is_blank()==True or is_merge()==True: return True # else: return False def game_over(): print("游戏结束") mb = messagebox.askyesno( title="游戏结束", message="是否重新开始") if mb: #重新开始游戏 reset() update_ui() else: win.quit() move_dic={"Up":up_move,"Down":down_move,"Left":left_move,"Right":right_move} def condition(key): return move_dic[key] def is_blank()->bool: """ 如果有0元素存在,则返回True,否则返回False :return: """ return any(0 in row for row in data) def update_ui(): '''刷新界面函数 根据计算出的f地图数据,更新各个Label的设置 ''' for r in range(4): for c in range(len(data[0])): number = data[r][c] # 设置数字 label = data_labels[r][c] # 选中Lable控件 label['text'] = str(number) if number else '' label['bg'] = mapcolor[number][0] label['foreground'] = mapcolor[number][1] label_score['text'] = str(sum_score) # 重设置分数 def press_key(event): # move=condition(key) # move() print("调用了press_key") key=event.keysym print(f"按下了{key}键") if key in move_dic: move=move_dic[key] #移动 move() #计算得分 print("当前得分",sum_score) random_2() update_ui() if is_game_over()==False:#不能合并了 game_over() if key=="q": print("退出游戏吗?") stop_game()
#背景颜色与数字颜色 mapcolor
= { 0: ("#cdc1b4", "#776e65"), 2: ("#eee4da", "#776e65"), 4: ("#ede0c8", "#f9f6f2"), 8: ("#f2b179", "#f9f6f2"), 16: ("#f59563", "#f9f6f2"), 32: ("#f67c5f", "#f9f6f2"), 64: ("#f65e3b", "#f9f6f2"), 128: ("#edcf72", "#f9f6f2"), 256: ("#edcc61", "#f9f6f2"), 512: ("#e4c02a", "#f9f6f2"), 1024: ("#e2ba13", "#f9f6f2"), 2048: ("#ecc400", "#f9f6f2"), } if __name__ == '__main__': #初始化全局变量 sum_score=0 data=[[0,0,0,0], [0,0,0,0], [0,0,0,0], [0,0,0,0]] #随机生成两个2 random_2() random_2() print_data() # print(data) win = tk.Tk() win.title("2048游戏") # win.geometry("400x500") win.resizable(False, False)# 固定宽和高 #按键事件监听 game_bg_color = "#bbada0" # 设置背景颜色 frame = tk.Frame(win, bg=game_bg_color) frame.grid(sticky=N + E + W + S) # # 设置焦点能接收按键事件 frame.focus_set() frame.bind("<Key>", press_key) # 初始化图形界面 data_labels = [] for r in range(4): row = [] for c in range(len(data[0])): value = data[r][c] text = str(value) if value else '' print(text) label = tk.Label(frame, text=text, width=4, height=2, font=("黑体", 30, "bold")) label.grid(row=r, column=c, padx=2, pady=2, sticky=N + E + W + S) row.append(label) data_labels.append(row) # 设置显示分数的Lable label = tk.Label(frame, text='分数', font=("黑体", 30, "bold"), bg="#bbada0", fg="#eee4da") label.grid(row=4, column=0, padx=5, pady=5) label_score = tk.Label(frame, text='0', font=("黑体", 30, "bold"), bg="#bbada0", fg="#ffffff") label_score.grid(row=4, columnspan=2, column=1, padx=5, pady=5) win.mainloop()

3.  打包成exe程序

  先安装pyinstaller,可以将tkinter或者pyqt开发的带界面的程序打包成exe可执行文件。

pip install pyinstaller  -i https://pypi.tuna.tsinghua.edu.cn/simple

  再在pycharm的terminal中输入如下:

pyinstaller -Fw -i ./2048game.ico my2048.py

  关于参数:-F是将所有文件打包成一个exe文件,到处拷贝都可以执行,w参数是不显示控制台窗口(自己可以不要w尝试),-i是给exe程序加上图标。最后生成的dist文件夹有个exe程序。最后拷贝在桌面上就是下面这个样子。

4. 运行效果

  

 小结:可能程序存在冗余之处,还可以改善的。界面的tkinter程序参考了网上的。

  若存在不足之处,欢迎之处或评论。

 参考资料:

https://www.cnblogs.com/shijieli/p/10641299.htmlhttps://www.cnblogs.com/shijieli/p/10641299.html

http://www.xoxxoo.com/index.php/index/index/article/id/641.html