200 行python 代碼實現 2048 遊戲,python2048

來源:互聯網
上載者:User

200 行python 代碼實現 2048 遊戲,python2048

建立遊戲檔案 2048.py

首先匯入需要的包:

import cursesfrom random import randrange, choicefrom collections import defaultdict

主邏輯

使用者行為

所有的有效輸入都可以轉換為"上,下,左,右,遊戲重設,退出"這六種行為,用 actions 表示

actions = ['Up', 'Left', 'Down', 'Right', 'Restart', 'Exit']

有效輸入鍵是最常見的 W(上),A(左),S(下),D(右),R(重設),Q(退出),這裡要考慮到大寫鍵開啟的情況,獲得有效索引值列表:

letter_codes = [ord(ch) for ch in 'WASDRQwasdrq']

將輸入與行為進行關聯:

actionsdict = dict(zip(lettercodes, actions * 2))

狀態機器

處理遊戲主邏輯的時候我們會用到一種十分常用的技術:狀態機器,或者更準確的說是有限狀態機器(FSM)

你會發現 2048 遊戲很容易就能分解成幾種狀態的轉換。

state 儲存目前狀態, state_actions 這個詞典變數作為狀態轉換的規則,它的 key 是狀態,value 是返回下一個狀態的函數:

Init: init()Game: game()Win: lambda: not_game('Win')Gameover: lambda: not_game('Gameover')

Exit: 退出迴圈

狀態機器會不斷迴圈,直到達到 Exit 終結狀態結束程式。

下面是經過提取的主邏輯的代碼,會在後面進行補全:

def main(stdscr): def init(): #重設遊戲棋盤 return 'Game' def not_game(state): #畫出 GameOver 或者 Win 的介面 #讀取使用者輸入得到action,判斷是重啟遊戲還是結束遊戲 responses = defaultdict(lambda: state) #預設是目前狀態,沒有行為就會一直在當前介面迴圈 responses['Restart'], responses['Exit'] = 'Init', 'Exit' #對應不同的行為轉換到不同的狀態 return responses[action] def game(): #畫出當前棋盤狀態 #讀取使用者輸入得到action if action == 'Restart':  return 'Init' if action == 'Exit':  return 'Exit' #if 成功移動了一步:  if 遊戲勝利了:  return 'Win'  if 遊戲失敗了:  return 'Gameover' return 'Game' state_actions = {  'Init': init,  'Win': lambda: not_game('Win'),  'Gameover': lambda: not_game('Gameover'),  'Game': game } state = 'Init' #狀態機器開始迴圈 while state != 'Exit': state = state_actions[state]()

使用者輸入處理

阻塞+迴圈,直到獲得使用者有效輸入才返回對應行為:

def get_user_action(keyboard): char = "N" while char not in actions_dict: char = keyboard.getch() return actions_dict[char]

矩陣轉置與矩陣逆轉

加入這兩個操作可以大大節省我們的代碼量,減少重複勞動,看到後面就知道了。

矩陣轉置:

def transpose(field): return [list(row) for row in zip(*field)]

矩陣逆轉(不是逆矩陣):

def invert(field): return [row[::-1] for row in field]

建立棋盤

初始化棋盤的參數,可以指定棋盤的高和寬以及遊戲勝利條件,預設是最經典的 4×4~2048。

class GameField(object): def __init__(self, height=4, width=4, win=2048): self.height = height #高 self.width = width  #寬 self.win_value = 2048 #過關分數 self.score = 0  #當前分數 self.highscore = 0  #最高分 self.reset()  #棋盤重設

棋盤操作

隨機產生一個 2 或者 4

 def spawn(self):  new_element = 4 if randrange(100) > 89 else 2  (i,j) = choice([(i,j) for i in range(self.width) for j in range(self.height) if self.field[i][j] == 0])  self.field[i][j] = new_element#### 重設棋盤 def reset(self): if self.score > self.highscore:  self.highscore = self.score self.score = 0 self.field = [[0 for i in range(self.width)] for j in range(self.height)] self.spawn() self.spawn()#### 一行向左合并(註:這一操作是在 move 內定義的,拆出來是為了方便閱讀)def move_row_left(row): def tighten(row): # 把零散的非零單元擠到一塊 new_row = [i for i in row if i != 0] new_row += [0 for i in range(len(row) - len(new_row))] return new_row def merge(row): # 對鄰近元素進行合并 pair = False new_row = [] for i in range(len(row)):  if pair:  new_row.append(2 * row[i])  self.score += 2 * row[i]  pair = False  else:  if i + 1 < len(row) and row[i] == row[i + 1]:   pair = True   new_row.append(0)  else:   new_row.append(row[i]) assert len(new_row) == len(row) return new_row #先擠到一塊再合并再擠到一塊 return tighten(merge(tighten(row)))

棋盤走一步

通過對矩陣進行轉置與逆轉,可以直接從左移得到其餘三個方向的移動操作

def move(self, direction): def move_row_left(row): #一行向左合并 moves = {} moves['Left'] = lambda field: [move_row_left(row) for row in field] moves['Right'] = lambda field: invert(moves['Left'](invert(field))) moves['Up'] = lambda field: transpose(moves['Left'](transpose(field))) moves['Down'] = lambda field: transpose(moves['Right'](transpose(field))) if direction in moves: if self.move_is_possible(direction):  self.field = moves[direction](self.field)  self.spawn()  return True else:  return False

判斷輸贏

 def is_win(self): return any(any(i >= self.win_value for i in row) for row in self.field) def is_gameover(self): return not any(self.move_is_possible(move) for move in actions)#### 判斷能否移動def move_is_possible(self, direction): defrow_is_left_movable(row): def change(i):  if row[i] == 0 and row[i + 1] != 0: # 可以移動  return True  if row[i] != 0 and row[i + 1] == row[i]: # 可以合并  return True  return False return any(change(i) for i in range(len(row) - 1)) check = {} check['Left'] = lambda field: any(row_is_left_movable(row) for row in field) check['Right'] = lambda field: check['Left'](invert(field)) check['Up'] = lambda field: check['Left'](transpose(field)) check['Down'] = lambda field: check['Right'](transpose(field)) if direction in check: return check[direction](self.field) else: return False

繪製遊戲介面

def draw(self, screen): help_string1 = '(W)Up (S)Down (A)Left (D)Right' help_string2 = ' (R)Restart (Q)Exit' gameover_string = '  GAME OVER' win_string = '  YOU WIN!' def cast(string): screen.addstr(string + 'n') #繪製水平分割線 def draw_hor_separator(): line = '+' + ('+------' * self.width + '+')[1:] separator = defaultdict(lambda: line) if not hasattr(draw_hor_separator, "counter"):  draw_hor_separator.counter = 0 cast(separator[draw_hor_separator.counter]) draw_hor_separator.counter += 1 def draw_row(row): cast(''.join('|{: ^5} '.format(num) if num > 0 else '| ' for num in row) + '|') screen.clear() cast('SCORE: ' + str(self.score)) if 0 != self.highscore: cast('HGHSCORE: ' + str(self.highscore)) for row in self.field: draw_hor_separator() draw_row(row) draw_hor_separator() if self.is_win(): cast(win_string) else: if self.is_gameover():  cast(gameover_string) else:  cast(help_string1) cast(help_string2)

完成主邏輯

完成以上工作後,我們就可以補完主邏輯了!

def main(stdscr): def init(): #重設遊戲棋盤 game_field.reset() return 'Game' def not_game(state): #畫出 GameOver 或者 Win 的介面 game_field.draw(stdscr) #讀取使用者輸入得到action,判斷是重啟遊戲還是結束遊戲 action = get_user_action(stdscr) responses = defaultdict(lambda: state) #預設是目前狀態,沒有行為就會一直在當前介面迴圈 responses['Restart'], responses['Exit'] = 'Init', 'Exit' #對應不同的行為轉換到不同的狀態 return responses[action] def game(): #畫出當前棋盤狀態 game_field.draw(stdscr) #讀取使用者輸入得到action action = get_user_action(stdscr) if action == 'Restart':  return 'Init' if action == 'Exit':  return 'Exit' if game_field.move(action): # move successful  if game_field.is_win():  return 'Win'  if game_field.is_gameover():  return 'Gameover' return 'Game' state_actions = {  'Init': init,  'Win': lambda: not_game('Win'),  'Gameover': lambda: not_game('Gameover'),  'Game': game } curses.use_default_colors() game_field = GameField(win=32) state = 'Init' #狀態機器開始迴圈 while state != 'Exit': state = state_actions[state]()

運行

填上最後一行代碼:

curses.wrapper(main)

完整版代碼地址:https://github.com/JLUNeverMore/easy_2048-in-200-lines

總結

以上所述是小編給大家介紹的200 行python 代碼實現 2048 遊戲,希望對大家有所協助,如果大家有任何疑問請給我留言,小編會及時回複大家的。在此也非常感謝大家對幫客之家網站的支援!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.