天天看點

周末在家,整理我的第二個Python小項目

作者:程式員zhenguo

你好,我是 zhenguo

今天是Python項目系列第二期,與大家一起動手制作2048遊戲。

這個遊戲當年風靡全球,遊戲規則極其簡單,玩起來也是相當簡單,但是要想最後拼出2048,也絕非是一件容易的事。并且玩起來,也很有意思,總想一把一把的挑戰。

與2048遊戲風格相似的是,它的代碼實作起來也是非常簡潔,代碼隻有區區不到200行,并且是純Python,不用任何第三方包的情況下。

1 Python實作的2048遊戲界面

我們先來一覽最終實作的遊戲界面,順帶幫助不了解2048遊戲的讀者,熟悉下它。

遊戲主界面:

周末在家,整理我的第二個Python小項目

遊戲基本規則:

  1. 鍵盤中上、下、左、右四個箭頭,對應4個漂流方向
  2. 合并。數值相等的兩個方格可以合并為1個方格,且值乘以2,如下圖左下角,兩個2方格可合并為一個4方格
周末在家,整理我的第二個Python小項目

合并後,最左下角就是4方格:

周末在家,整理我的第二個Python小項目

但是為什麼它的上方又多了2方格呢?注意,這是第三個規則:

  1. 随機2方格。發生合并操作時,會從灰色的單元格中随機選擇一個,并建立出2方格
  2. 漂流。再有1個好玩的操作,我稱它為漂流,緊鄰上圖,我如果按下右箭頭,兩個左下角的4方格根據規則2首先合并為8方格。同時,所有方格整體向右漂流(沿着箭頭方向)。因為發生了合并操作,根據規則3,再生成一個2方格。是以得到了如下界面:
周末在家,整理我的第二個Python小項目

這就是遊戲的規則,大家下載下傳我的完整代碼後,玩耍一下後,了解規應該會更深,玩起來真的賊爽。

2 項目環境

本項目不使用任何第三方包,全都是Python自帶的子產品,且隻用到2個子產品,可見2048遊戲的魅力,實作的代碼都毫不費力。

一個子產品是Tkinter,用來做界面,還用到的随機子產品random。

3 項目代碼講解

不到200行代碼,是個小架構。主要包括2個類:

  • Board
  • Game

下面逐一介紹。

3.1Board類

主要提供三個能力,分别對應上面的三個規則:

  • 合并規則,對應Board類的方法merge_grid
  • 随機建立2方格,對應Board類的方法random_cell
  • 漂流,對應Board類的方法drifting_left

3.2Game類

主要提供Tkinter的鍵盤消息和事件處理能力,對應方法event_handlers,比較簡單,是以主要講解Board類

merge_grid方法

編寫merge_grid方法的邏輯,假定是在按下左箭頭時,為什麼這樣假定,後面我會重點分析,這是了解這套代碼的核心。基于此,合并鄰近的兩個非零相等單元格,實作邏輯很簡單:

def merge_grid(self):
        """
        向左移動,合并鄰近的兩個非零相等單元格
        :return:
        """
        self.merge = False
        for i in range(4):
            for j in range(3):
                if self.grid_cell[i][j] == self.grid_cell[i][j + 1] and self.grid_cell[i][j] != 0:
                    self.grid_cell[i][j] *= 2
                    self.grid_cell[i][j + 1] = 0
                    self.score += self.grid_cell[i][j]
                    self.merge = True
           

random_cell方法

實作random_cell方法就更簡單了,随機從灰色(沒有數字的方格)方格中,挑選一個,并指派為2就行:

def random_cell(self):
        """
        從零單元格中随機産生一個2号單元格
        :return:
        """
        i, j = random.choice([(i, j) for i in range(4) for j in range(4) if self.grid_cell[i][j] == 0])
        self.grid_cell[i][j] = 2
           

drifting_left方法

實作漂流drifting_left方法,使用的是最基本的快慢指針,cnt是慢指針,j是快指針。

def drifting_left(self):
        """
        向左偏流,消除0方格
        :return:
        """
        self.compress = False
        temp = [[0] * 4 for _ in range(4)]
        for i in range(4):
            # cnt:慢指針,j: 快指針
            cnt = 0
            for j in range(4):
                if self.grid_cell[i][j] != 0:
                    temp[i][cnt] = self.grid_cell[i][j]
                    if cnt != j:
                        self.compress = True
                    cnt += 1

        self.grid_cell = temp
           

3.3 代碼核心

2048遊戲會有4個漂流方向,分别為上、下、左、右。

而上面代碼,假定漂流是向左,并基于此編寫了向左漂流的邏輯。

這正是此套代碼實作的高明之處,其他上、下、右三方向的漂流,經過reverse(反轉)或transpose(轉秩)後,都可以轉成向左漂流的邏輯。這兩個中間操作也都在Board類裡提供了。

比如,實作向右漂流時,先執行一次reverse,然後執行drifting_left,再執行一次reverse,就實作了右漂。

實作上漂時,先轉秩,再左漂,再轉秩。

這個變化思路,大家紙上畫一畫,一看便知。

還是有疑問的,留言區交流。

4 項目代碼講解

上面完整py代碼檔案,感興趣的可以私信我。

繼續閱讀