轉載請注明出處http://www.cnblogs.com/Wxtrkbc/p/5519453.html
以前游戲2048火的時候,正好用其他的語言編寫了一個,現在學習python,正好想起來,便決定用python寫一個2048,由於沒學過python里面的界面編程,所以寫了一個極其簡單的無界面2048。游戲2048的原理和實現都不難,正好可以拿來練手,要是不知道這游戲的話,可以去網上查一下,或者下載一個到手機來玩一下,我就不在說其原理。我知道不放圖的話大家一點興趣都沒,下面首先放一張游戲成型圖,然后我們在來講如何一步步用最基礎的知識來實現。
一、生成4*4的矩陣
游戲的第一步便是生成一個4*4的矩陣,當作我們游戲的主界面,其實說起來也比較簡單,這里用了最原始的方法,直接用print將其打印出來。首先我們要生成一個全為0的4*4二維列表,然后用一些類似 '┌ ├└,┤,┘┐│,─,┬,┴'這樣的字符來組成我們的邊框,下面來看一下代碼的實現
matix=[[0 for i in range(4)] for i in range(4)] # 用列表推導式初始化生成一個4*4的列表,列表元素全為 0 # notzero函數的作用:游戲界面上非零的時候才顯示,當為0的時候,讓其顯示空, def notzero(s): return s if s!=0 else '' # 非零的話返回本身,否則返回 '' def display(): # 顯示界面函數,用┌ ├└,┤,┘┐│,─,┬,┴ 等顯示邊框,中間顯示4*4矩陣里的的元素 print("\r\ ┌──┬──┬──┬──┐\n\ │%4s│%4s│%4s│%4s│\n\ ├──┬──┬──┬──┤\n\ │%4s│%4s│%4s│%4s│\n\ ├──┬──┬──┬──┤\n\ │%4s│%4s│%4s│%4s│\n\ ├──┬──┬──┬──┤\n\ │%4s│%4s│%4s│%4s│\n\ └──┴──┴──┴──┘"\ %(notzero(matix[0][0]),notzero(matix[0][1]),notzero(matix[0][2]),notzero(matix[0][3]),\ notzero(matix[1][0]),notzero(matix[1][1]),notzero(matix[1][2]),notzero(matix[1][3]),\ notzero(matix[2][0]),notzero(matix[2][1]),notzero(matix[2][2]),notzero(matix[2][3]), \ notzero(matix[3][0]),notzero(matix[3][1]),notzero(matix[3][2]),notzero(matix[3][3]),) ) display()
來看一下上面代碼的效果,是不是感覺一個游戲的框架已經到搭好了,由於初始化的時候,矩陣元素都為零,下面的圖也就沒有顯示出0,是不是很簡單,一個游戲的界面就被我們搭好了,不過畢竟沒學過界面,所以大家就不要抱怨這界面有多么丑了哈。
二、初始化生成隨機數
這個游戲每次開始的時候都會隨機在上面的一個矩陣中生成兩個隨機數2或4,那么我們要如何來實現在上面矩陣中隨機的一個位置生成一個隨機數2或4了,當然是用到我們前面學過的random模塊以及divmod(),下面我們就來看一下如何用random模塊實現着一功能。
def init(): # 初始化矩陣 initNumFlag = 0 while 1: k = 2 if random.randrange(0, 10) > 1 else 4 # 當生成隨機數大於1的時候k=2否則k=4 生成2和4的概率為9:1 s = divmod(random.randrange(0, 16), 4) # 生成矩陣初始化的下標 比如divmod(15,4)的話,s為(3,3)正好可以作為矩陣下標 if matix[s[0]][s[1]] == 0: # 只有當其值不為0的時候才賦值,避免第二個值重復 matix[s[0]][s[1]] = k initNumFlag += 1 if initNumFlag == 2: # 當initNumFlag==2 的話表示矩陣里兩個隨機數都已經生成了,退出循環 break init() display()
來看一下上面代碼的效果,是不是已經在兩個隨機的位置生成了兩個數,如果大家有時間的試一下,可以看見每次執行的時候,出現在矩陣上面位置不一樣,而且每次出現的數也不一樣,因為我上面設置了出現2:4的概率為9:1所以大多時候出現2,這也是游戲的需要。到了這里矩陣已經可以動起來了,游戲的功能也可以說完成了一半。
三、游戲邏輯部分實現
如果玩過這游戲的話就知道,游戲中每次向上下左右移動的時候,比如像下移動的話,所有的數都會向下移動,碰到相同的數,就會成一個新的數,比如2和2碰到的話,就會生成4,然后再隨機在其他位置生成一個2或4 ,同理4和4碰到的話也會生成8,直到合成了2048游戲就算成功了,或者說矩陣中的數字都不能移動那就是Game Over。當然我們在手機上玩游戲的話,隨便滑動一下,所有的數字就可以向其中一個方向滑動,但是這里沒有界面,條件比較艱苦,所以只能從控制台讀入用戶輸入的字母,然后一個個來判斷是向哪里移動了,所以我們要寫4個函數來分別處理用戶的上下左右移動,讓后一個函數處理在每次用戶移動后,如何添加一個隨機數,下面先寫一段偽代碼來解釋流程
def addRandomNum(): #每次移動后隨機在矩陣中在生成一個數 pass def moveDown(): #向上移動的處理函數 pass
addRandomNum() #移動處理完成后,隨機生成一個數 def moveLeft(): #向左移動的處理函數 pass addRandomNum() def moveUp(): #向上移動的處理函數 pass addRandomNum() def moveRight(): #向右移動的處理函數 pass addRandomNum() def main(): while flag: #定義一個死循環,不斷讀入用戶的輸入,然后在做判斷,看是向哪里移動 d = input(' (↑:w) (↓:s) (←:a) (→:d),q(uit) :“) if d == 'a': moveLeft() elif d == 's': moveDown() elif d == 'w': moveUp() elif d == 'd': moveRight() elif d == 'q': break else: pass
上面是一段為了理解的偽代碼,下面我們來看一下如何實現移動處理函數,這里是整個游戲中最難處理的部分,完成了這一部分的話,整個游戲也就基本上實現了,這里我以向下的移動處理函數為例,其他的都一樣,當用戶輸入向下移動的時候,所有的數字都向下移動,如果碰到相同的數字要和並,有數字的方塊向沒有數字的方塊移動。這里需要用循環實現,有4列所以最外層的循環有4次,每一列里面又需要循環處理,下面來看一下具體怎么實現,
def addRandomNum(): # 跟初始化生成隨機數一樣,只不過這里只是生成一個隨機數 while 1: k = 2 if random.randrange(0, 10) > 1 else 4 s = divmod(random.randrange(0, 16), 4) if matix[s[0]][s[1]] == 0: matix[s[0]][s[1]] = k break display() # 隨機數添加完成后就直接調用顯示函數,直接顯示一下游戲界面 def moveDown(): #處理向下移動的函數 for i in range(4): #外層4次循環處理4例,內層兩個3層循環,來處理相鄰的兩個數 for j in range(3, 0, -1): for k in range(j - 1, -1, -1): if matix[k][i] > 0: # 從最下面的數開始處理相鄰的兩個數 if matix[j][i] == 0: matix[j][i] = matix[k][i] # 如果下面的數為空,上面的數字不為空就移動上面的數為下面的數 matix[k][i] = 0 elif matix[j][i] == matix[k][i]: # 如果相鄰的兩個數相等的話,就和並,並把上面的輸置零,下面的數變成兩倍 matix[j][i] *= 2 matix[k][i] = 0 break addRandomNum() # 移動完成后再隨機生成一個數
寫完了向下移動的處理函數,那么向其他方向的移動函數也一樣,照着寫,就可以,到這里游戲中最難的部分就完成,可以說勝利就在眼前了,好了在這之前,我們還需要處理一下其他問題,那就是每次移動后都要檢查,游戲是不是Game Over了,還有就是定義一個變量來紀錄分數了,這些實現起來都比較簡單。
四、游戲紀錄分數和檢查游戲是否結束
游戲結束的標志是矩陣中所有的數都不為0,而且所有相鄰的數都不能合並,根據這個我們就可以來寫一個函數來判斷游戲是否GG,至於分數紀錄,我們只需定義一個變量,然后每次有何並的時候,就加上一定的分數即可。下面我們來看檢查函數的實現。
def check(): for i in range(4): #按每一排循環4 次 for j in range(3): # 如果矩陣中有0存在,或者有相鄰的數就表示游戲還可以繼續經行,否則就是GG if matix[i][j] == 0 or matix[i][j] == matix[i][j + 1] or matix[j][i] == matix[j + 1][i]: return True else: return False
五、完整游戲源碼
完成了上面的部分,整個游戲的過程就實現了,下面附上整個游戲的源碼。游戲還有很多不夠完善的地方,比如說游戲中如果出現2048的話,就表示玩家勝利,游戲結束,但是我這里沒有做處理,所以這個游戲可以一直玩到4096....沒有結束,除非你游戲中GG了,要處理也很簡單,還可以將矩陣存在文件中,完成一個游戲存檔的功能。有興趣的話大家去實現一下。
import random score = 0 # 紀錄游戲的分數 matix = [[0 for i in range(4)] for i in range(4)] # 初始化生成一個4*4的列表 def notzero(s): return s if s != 0 else '' def display(): print("\r\ ┌──┬──┬──┬──┐\n\ │%4s│%4s│%4s│%4s│\n\ ├──┬──┬──┬──┤\n\ │%4s│%4s│%4s│%4s│\n\ ├──┬──┬──┬──┤\n\ │%4s│%4s│%4s│%4s│\n\ ├──┬──┬──┬──┤\n\ │%4s│%4s│%4s│%4s│\n\ └──┴──┴──┴──┘" \ % (notzero(matix[0][0]), notzero(matix[0][1]), notzero(matix[0][2]), notzero(matix[0][3]), \ notzero(matix[1][0]), notzero(matix[1][1]), notzero(matix[1][2]), notzero(matix[1][3]), \ notzero(matix[2][0]), notzero(matix[2][1]), notzero(matix[2][2]), notzero(matix[2][3]), \ notzero(matix[3][0]), notzero(matix[3][1]), notzero(matix[3][2]), notzero(matix[3][3]),) ) def init(): # 初始化矩陣 initNumFlag = 0 while 1: k = 2 if random.randrange(0, 10) > 1 else 4 # 隨機生成 2 或 4 s = divmod(random.randrange(0, 16), 4) # 生成矩陣初始化的下標 if matix[s[0]][s[1]] == 0: # 只有當其值不為0的時候才賦值,避免第二個值重復 matix[s[0]][s[1]] = k initNumFlag += 1 if initNumFlag == 2: break display() def addRandomNum(): #處理完移動后添加一個新的隨機數 while 1: k = 2 if random.randrange(0, 10) > 1 else 4 s = divmod(random.randrange(0, 16), 4) if matix[s[0]][s[1]] == 0: matix[s[0]][s[1]] = k break display() def check(): #檢查游戲是否GG for i in range(4): for j in range(3): if matix[i][j] == 0 or matix[i][j] == matix[i][j + 1] or matix[j][i] == matix[j + 1][i]: return True else: return False def moveRight(): # 向右移動處理函數 global score for i in range(4): for j in range(3, 0, -1): for k in range(j - 1, -1, -1): if matix[i][k] > 0: if matix[i][j] == 0: matix[i][j] = matix[i][k] matix[i][k] = 0 elif matix[i][j] == matix[i][k]: matix[i][j] *= 2 score += matix[i][j] #將當前數作為score加上 matix[i][k] = 0 break addRandomNum() def moveUp(): global score for i in range(4): for j in range(3): for k in range(j + 1, 4): if matix[k][i] > 0: if matix[j][i] == 0: matix[j][i] = matix[k][i] matix[k][i] = 0 elif matix[k][i] == matix[j][i]: matix[j][i] *= 2 score += matix[j][i] matix[k][i] = 0 break addRandomNum() def moveDown(): global score for i in range(4): for j in range(3, 0, -1): for k in range(j - 1, -1, -1): if matix[k][i] > 0: if matix[j][i] == 0: matix[j][i] = matix[k][i] matix[k][i] = 0 elif matix[j][i] == matix[k][i]: matix[j][i] *= 2 score += matix[j][i] matix[k][i] = 0 break addRandomNum() def moveLeft(): global score for i in range(4): for j in range(3): for k in range(1 + j, 4): if matix[i][k] > 0: if matix[i][j] == 0: matix[i][j] = matix[i][k] matix[i][k] = 0 elif matix[i][j] == matix[i][k]: matix[i][j] *= 2 score += matix[i][j] matix[i][k] = 0 break addRandomNum() def main(): print(" \033[33;1mWelcome to the Game of 2048!\033[0m") flag = True init() while flag: #循環的標志 print(' \033[33;1m You Score:%s\033[0m' % (score)) d = input('\033[33;1m (↑:w) (↓:s) (←:a) (→:d),q(uit) :\033[0m') #不斷處理用戶輸入 if d == 'a': moveLeft() if not check(): #檢查游戲是否GG print('GG') flag = False #GG的話直接退出 elif d == 's': moveDown() if not check(): print('GG') flag = False elif d == 'w': moveUp() if not check(): print('GG') flag = False elif d == 'd': moveRight() if not check(): print('GG') flag = False elif d == 'q': # 退出 break else: # 對用戶的其他輸入不做處理 pass if __name__ == '__main__': main()
最后在附上一張圖片最為結束