Python制作2048小游戏
Python制作2048小游戲
文章目錄
- Python制作2048小游戲
- 前言
- 一、關于2048小游戲
- 二、設計
- 1.引入庫
- 2.調出窗口代碼
- 3.矩陣的展示
- 4.各方向數據計算準備
- 5.計算
- 6.數據的視角返回
- 7.隨機生成一個數字
- 8.函數按鈕的添加
- 三、完整代碼
- 總結
前言
今天我們設計python實現經典的2048小游戲,實現的方式比較淺顯易懂,同樣也是個人思路的實現,走通了游戲的流程,前期的操作還是比較快,當運行到后期由于數字比較大,導致運行時間比較長,會出現延遲感,有一種卡頓的感覺,主要是代碼寫得比較基礎,所以運行就比較耗時間。
一、關于2048小游戲
2048百度百科:https://baike.baidu.com/item/2048/13383511#1
網上找的一個在線版:https://cn.newdoku.com/2048.php。
大家可以去耍一下,可能會上癮,哈哈!
二、設計
1.引入庫
代碼如下:
import tkinter as tk #窗口庫 import numpy as np import random #隨機函數,用于每次操作后的新數字添加numpy庫只是為了調試初期顯示每次計算后的矩陣的展示,可以更加方便的觀察。
2.調出窗口代碼
初始代碼準備:
首先將窗口調出,調好顏色,設計好大小。
num和num_color分別存儲了數字和對應顏色,暫時只設計了0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,當數字超出2048時程序會出錯,修改一下這兩個列表里面的數據即可。
num_color是每一個數字對應的位置的方塊的顏色,增強直觀的視覺效果,增強游戲體驗,二維列表a是我所設置的初始矩陣,當然我們也可以設計隨機產生數字和位置。方法也比較簡單,只需要將后文的產生隨機數字的代碼調用過來即可。
3.矩陣的展示
將矩陣展示在畫布上:
for i in range(0, 4):for j in range(0, 4):num_index=num.index(a[i][j])if a[i][j] == 0:canvas.create_rectangle(100 * j + 10, 100 * i + 10, 100 * j + 100, 100 * i + 100, fill='burlywood',outline='wheat')else:canvas.create_rectangle(100 * j + 10, 100 * i + 10, 100 * j + 100, 100 * i + 100, fill=num_color[num_index],outline='wheat') # outline='blue'canvas.create_text(100 * j + 55, 100 * i + 55, text=a[i][j], font=('Time New Roman', 35),fill='maroon') canvas.pack()通過index找到元素在num列表中的位置,對應num_color的地址就可以將每個數字對應的顏色調出來,進行展示。加入循環來找也可以,在較小的數據范圍里,for查找和index查找時間的消耗相差不大,當數據比較大的時候index會更快一些。
canvas.create_rectangle通過畫布畫矩形,填充顏色,實現每個數字一個顏色方框,實現數字的直觀視覺效果。
canvas.create_text 添加文字到指定位置,定義大小,顏色等。
代碼添加在每個函數的后面,將計算好的矩陣展示出來。
4.各方向數據計算準備
我是將所有的數據變化到同一個計算方向上,水平方向,從左向右排列,再進行計算。
將數據都轉換到上圖的計算方向之后再進行計算,通過實現矩陣數據的位置轉化,再進行統一的計算會降低設計難度。我們只需設計三個方向的矩陣轉化。
數據向上計算前的轉化:
數據向上計算那么位置數據考慮先后為:1,5,9,13以此類推,按照列方向計算
矩陣變化為行方向:
數據向下:
數據向下計算那么位置數據考慮先后從左向右展示為:13,9,5,1以此類推,按照列方向計算
數據向右:
數據向右計算那么位置數據考慮先后為:4,3,2,1以此類推,按照行方向計算
我們可以通過調用語句print(np.array(b))將二維列表以矩陣的方式打印出來,可以更加直觀,便于我們分析程序。
5.計算
我們計算的方向是從左向右計算,當然其實就是數據向左擠壓,當數據一樣時就進行疊加。
比如:“2,2,4,2”這四個數字的疊加將展示為:4,4,2 ,_
操作時只有2,2可以疊加,
若再次進行此方向的疊加結果為:8,2,_ ,_
數據集中:我們需要將空位后移,在矩陣中我們使用0代表空位,方便我們的計算。集中的方法是:從前向后遍歷,遇到0則刪除,同時在尾部添加0,保證不產生遺漏,四個位置都進行遍歷。
數據計算:每一行四個數據,我將每種情況考慮一遍出現如下情況:
例:a,b,c,d為其中一行,那么可能出現的計算情況(數據已經集中完畢),一共會出現如下五種結果:
那么以此類推四次,即可實現這個矩陣的計算。
6.數據的視角返回
a矩陣是全局變量,每次操作都需要使用a矩陣,所以在矩陣計算完以后,我們需要將數據恢復到計算前的視圖,我們還是采用之前的轉化思路:首先將a矩陣清空,將b矩陣轉化,元素添加至a中。
通過如下代碼,我們可以實現矩陣的變化和再變化。為我們的計算提供便利條件。在中間添加計算的代碼即可實現2048游戲的核心計算代碼。
7.隨機生成一個數字
每次操作以后需要隨機選擇一個空位替換為一個隨機數字2或4。
設計思路:我們需要隨機選擇一個空位,再產生一個隨機數字2或4替換該空位,隨機位置的直接產生暫時沒想到。我們轉化思路,將位置分別添加進x,y列表內,在小于列表長度的正整數范圍內產生一個數字,這個位置對應兩個列表里面的數字,產生一個空位,等同于產生一個隨機空位。再隨機產生一個數字2或4進行替換。
當然這一步操作在計算之后畫圖之前即可。
8.函數按鈕的添加
原計劃是設計按鈕的監聽,綁定四個方位按鍵,使操作更方便,后來在操作中發現,按鈕的監聽占據了進程,導致后續的操作無法進行,沒找的解決的辦法,后來就妥協了,設計了按鈕使用鼠標點擊操作。比較原始的操作,如果有解決的辦法或者相似的經歷,并且已經解決了,可一起討論,還請不吝賜教,定虛心請教。
按鈕的代碼比較簡單,代碼如下:
如果沒有lambda會出現未點擊按鈕就運行一次函數。
三、完整代碼
import tkinter as tk import numpy as np #打印矩陣便于分析 import random #隨機函數 win = tk.Tk() # 創建窗口 win.title("2048小游戲") # 窗口名稱 win.geometry("410x600") # 窗口的大小 win.resizable(width=True, height=True) # 窗口大小可變,True可變 # 創建畫布 canvas = tk.Canvas(win, width=410, height=410, bg="tan") #畫布 num_color = ['burlywood', 'oldlace', 'moccasin', 'orange', 'coral', 'tomato', 'orangered', 'khaki', 'gold','goldenrod', 'lightgreen', 'limegreen'] #每一個數字的方格設置對應一種顏色 num = [0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048] #判斷數字 a = [[0, 2, 0, 0], [2, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]#初始矩陣,可以隨機產生一個,只需要調用隨機生成的幾行代碼 #循環打印出畫布,將數字矩陣顯示,對應的顏色數字 for i in range(0, 4):for j in range(0, 4):num_index=num.index(a[i][j])if a[i][j] == 0:canvas.create_rectangle(100 * j + 10, 100 * i + 10, 100 * j + 100, 100 * i + 100, fill='burlywood',outline='wheat')else:canvas.create_rectangle(100 * j + 10, 100 * i + 10, 100 * j + 100, 100 * i + 100, fill=num_color[num_index],outline='wheat') # outline='blue'canvas.create_text(100 * j + 55, 100 * i + 55, text=a[i][j], font=('Time New Roman', 35),fill='maroon') canvas.pack() print(np.array(a)) def up():global a #設為全局變量,實現不同按鈕之間可以循環使用ab=[]# 我們將所有的需要計算的矩陣,計算方向全都轉化為在行方向,從左到右的計算方式進行,簡化計算#不同的方向轉化的方式也不相同,有難有易for i in range(0,4):b.append([])for j in range(0,4):b[i].append(a[j][i])# print('切換',np.array(b))#在每一個方向的計算之前都進行轉化,之后就可以使用下面的計算方法#首先將數據進行集中,非零數據靠左,方便進行計算。#采用的方法是,從左向右遍歷,若有零則刪去第一個零,末尾添加一個零,代表零的后移。for i in range(0,4):for j in range(0,4):if b[i][j]==0:b[i].remove(0)b[i].append(0)#從左向右計算將每一種情況都檢查一遍,進行計算。for i in range(0, 4):if b[i][0] == b[i][1]:b[i][0] = 2 * b[i][0]if b[i][2] == b[i][3]:b[i][1] = 2 * b[i][2]b[i][2] = 0b[i][3] = 0else:b[i][1] = b[i][2]b[i][2] = b[i][3]b[i][3] = 0elif b[i][1] == b[i][2]:b[i][1] = 2 * b[i][1]b[i][2] = 0elif b[i][1] != b[i][2]:if b[i][2] == b[i][3]:b[i][2] = 2 * b[i][2]b[i][3] = 0# print('計算', np.array(a))#計算完以后,我們需要還原之前轉化的矩陣,還原到他應該展示的視角。并且還給a,保證后續的操作順利a=[]for i in range(0,4):a.append([])for j in range(0,4):a[i].append(b[j][i])# 隨機選擇一個元素為零的地址,隨機選擇2或4,進行替換r_i = []r_j = []for i in range(0, 4):for j in range(0, 4):if a[i][j] == 0:r_i.append(i)r_j.append(j)index_random = random.randint(0, len(r_i) - 1) # 產生一個元素為零的隨機地址index_num = random.choice([2, 4]) # 隨機產生一個數字2或4a[r_i[index_random]][r_j[index_random]] = index_num # 替換對應位置的數字print(np.array(a))for i in range(0, 4):for j in range(0, 4):num_index = num.index(a[i][j])if a[i][j] == 0:canvas.create_rectangle(100 * j + 10, 100 * i + 10, 100 * j + 100, 100 * i + 100, fill='burlywood',outline='wheat')else:canvas.create_rectangle(100 * j + 10, 100 * i + 10, 100 * j + 100, 100 * i + 100,fill=num_color[num_index],outline='wheat') # outline='blue'canvas.create_text(100 * j + 55, 100 * i + 55, text=a[i][j], font=('Time New Roman', 35),fill='maroon')def down():global ab=[[],[],[],[]]for i in range(0,4):for j in range(3,-1,-1):b[i].append(a[j][i])# print('切換',np.array(b))for i in range(0,4):for j in range(0,4):if b[i][j]==0:b[i].remove(0)b[i].append(0)# print('集中', np.array(b))for i in range(0, 4):if b[i][0] == b[i][1]:b[i][0] = 2 * b[i][0]if b[i][2] == b[i][3]:b[i][1] = 2 * b[i][2]b[i][2] = 0b[i][3] = 0else:b[i][1] = b[i][2]b[i][2] = b[i][3]b[i][3] = 0elif b[i][1] == b[i][2]:b[i][1] = 2 * b[i][1]b[i][2] = 0elif b[i][1] != b[i][2]:if b[i][2] == b[i][3]:b[i][2] = 2 * b[i][2]b[i][3] = 0# print('計算', np.array(b))a=[]i=0for j in range(3,-1,-1):a.append([])for k in range(0,4):a[i].append(b[k][j])i=i+1r_i = []r_j = []for i in range(0, 4):for j in range(0, 4):if a[i][j] == 0:r_i.append(i)r_j.append(j)index_random = random.randint(0, len(r_i) - 1) # 產生一個元素為零的隨機地址index_num = random.choice([2, 4]) # 隨機產生一個數字2或4a[r_i[index_random]][r_j[index_random]] = index_num # 替換對應位置的數字print(np.array(a))for i in range(0, 4):for j in range(0, 4):num_index = num.index(a[i][j])if a[i][j] == 0:canvas.create_rectangle(100 * j + 10, 100 * i + 10, 100 * j + 100, 100 * i + 100, fill='burlywood',outline='wheat')else:canvas.create_rectangle(100 * j + 10, 100 * i + 10, 100 * j + 100, 100 * i + 100,fill=num_color[num_index],outline='wheat') # outline='blue'canvas.create_text(100 * j + 55, 100 * i + 55, text=a[i][j], font=('Time New Roman', 35),fill='maroon')def left():global ab=a# print('切換',np.array(b))for i in range(0,4):for j in range(0,4):if b[i][j]==0:b[i].remove(0)b[i].append(0)for i in range(0, 4):if b[i][0] == b[i][1]:b[i][0] = 2 * b[i][0]if b[i][2] == b[i][3]:b[i][1] = 2 * b[i][2]b[i][2] = 0b[i][3] = 0else:b[i][1] = b[i][2]b[i][2] = b[i][3]b[i][3] = 0elif b[i][1] == b[i][2]:b[i][1] = 2 * b[i][1]b[i][2] = 0elif b[i][1] != b[i][2]:if b[i][2] == b[i][3]:b[i][2] = 2 * b[i][2]b[i][3] = 0# print('計算', np.array(a))a=br_i = []r_j = []for i in range(0, 4):for j in range(0, 4):if a[i][j] == 0:r_i.append(i)r_j.append(j)index_random = random.randint(0, len(r_i) - 1) # 產生一個元素為零的隨機地址index_num = random.choice([2, 4]) # 隨機產生一個數字2或4a[r_i[index_random]][r_j[index_random]] = index_num # 替換對應位置的數字print(np.array(a))for i in range(0, 4):for j in range(0, 4):num_index = num.index(a[i][j])if a[i][j] == 0:canvas.create_rectangle(100 * j + 10, 100 * i + 10, 100 * j + 100, 100 * i + 100, fill='burlywood',outline='wheat')else:canvas.create_rectangle(100 * j + 10, 100 * i + 10, 100 * j + 100, 100 * i + 100,fill=num_color[num_index],outline='wheat') # outline='blue'canvas.create_text(100 * j + 55, 100 * i + 55, text=a[i][j], font=('Time New Roman', 35),fill='maroon')def right():global ab=[]for i in range(0,4):b.append([])for j in range(3,-1,-1):b[i].append(a[i][j])# print('切換',np.array(b))for i in range(0,4):for j in range(0,4):if b[i][j]==0:b[i].remove(0)b[i].append(0)for i in range(0, 4):if b[i][0] == b[i][1]:b[i][0] = 2 * b[i][0]if b[i][2] == b[i][3]:b[i][1] = 2 * b[i][2]b[i][2] = 0b[i][3] = 0else:b[i][1] = b[i][2]b[i][2] = b[i][3]b[i][3] = 0elif b[i][1] == b[i][2]:b[i][1] = 2 * b[i][1]b[i][2] = 0elif b[i][1] != b[i][2]:if b[i][2] == b[i][3]:b[i][2] = 2 * b[i][2]b[i][3] = 0# print('計算', np.array(a))a=[]for i in range(0,4):a.append([])for j in range(3,-1,-1):a[i].append(b[i][j])r_i = []r_j = []for i in range(0, 4):for j in range(0, 4):if a[i][j] == 0:r_i.append(i)r_j.append(j)index_random = random.randint(0, len(r_i) - 1) # 產生一個元素為零的隨機地址index_num = random.choice([2, 4]) # 隨機產生一個數字2或4a[r_i[index_random]][r_j[index_random]] = index_num # 替換對應位置的數字print(np.array(a))for i in range(0, 4):for j in range(0, 4):num_index = num.index(a[i][j])if a[i][j] == 0:canvas.create_rectangle(100 * j + 10, 100 * i + 10, 100 * j + 100, 100 * i + 100, fill='burlywood',outline='wheat')else:canvas.create_rectangle(100 * j + 10, 100 * i + 10, 100 * j + 100, 100 * i + 100,fill=num_color[num_index],outline='wheat') # outline='blue'canvas.create_text(100 * j + 55, 100 * i + 55, text=a[i][j], font=('Time New Roman', 35),fill='maroon')canvas.pack()#上下左右按鈕,實現操作的調用 button1 = tk.Button(win, text="上", font=('楷體', 20), command=lambda:up()) button1.pack() button2 = tk.Button(win, text="下", font=('楷體', 20), command=lambda:down()) button2.pack() button1.bind("up", lambda:up()) button3 = tk.Button(win, text="左", font=('楷體', 20), command=lambda:left()) button3.pack() button4 = tk.Button(win, text="右", font=('楷體', 20), command=lambda:right()) button4.pack() win.mainloop()總結
代碼的設計是比較簡單的,采用最基礎的代碼,可能想法比較繞,導致代碼比較長,寫到最后發現少設計了幾個細節:
一個是,當某一方向上的操作沒有數據的疊加且數字都沒有移動時,應該不產生新的數字,這個我們可以判斷沒有進行操作前的矩陣和疊加以后且轉化為相同視角的矩陣是否相等,若相等則說明沒有數字疊加且沒有數字移動。
還有就是沒有設計達到2048的提示和矩陣填滿了不為零的數字且任意相鄰的數字不同是的游戲結束提示。這個也好解決:成功提示只需判斷2048是否在矩陣內即可。游戲失敗的結束提示只需要判斷空位的列表是否為零且任意相鄰數字不相同即可,滿足就彈窗提示結束游戲。
總結
以上是生活随笔為你收集整理的Python制作2048小游戏的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux的vim替换字符串,Linux
- 下一篇: Mentor软件盗版