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
标签:tkinter,randint,python,move,2048,item,print,data,row From: https://www.cnblogs.com/wancy/p/17489643.html