Python 練習 —— 2048

來源:互聯網
上載者:User

1. 引言     2048 這段時間火的不行啊,大家都紛紛仿造,“百家爭鳴”,於是出現了各種技術版本:除了手機版本,還有C語言版、Qt版、Web版、java版、C#版等,剛好我接觸Python不久,於是弄了個Python版——控制台的2048,正好熟悉下Python文法,程式運行效果如下:
圖 1  Python版控制台2048運行

     程式碼加上注釋大概150行左右,利用了一些Python內建資料類型的操作節省了不少代碼量。下面說說我的編寫思路,最後會給出原始碼。
2. 2048 實現思路
     2.1 遊戲規則     這個遊戲可玩性很好,簡單的移動方向鍵讓數字疊加,並且獲得這些數字每次疊加後的得分,當出現2048這個數字時遊戲勝利。同時每次移動方向鍵時,都會在這個4*4的方格矩陣的空白地區隨機產生一個數字2或者4,如果方格被數字填滿了,那麼就GameOver了。    

     2.2 實現思路     這個遊戲的全部操作都是圍繞著一個4*4的矩陣進行,每次從使用者介面擷取使用者的操作(即移動方向),然後重新計算這個4*4矩陣的狀態,最後重新整理使用者介面顯示4*4矩陣的最新狀態,不斷的迴圈這個過程,直到出現2048或沒有空白方塊了,下面是一個處理流程:    
     我寫的是控制台程式,沒有UI介面,因此用字元(W/S/A/D)代表方向鍵的輸入,以數字0代表空白方格。接下來是計算部分,以向左移動為例,4*4矩陣在接收到向左移動的指令後,應該將每行的數字向左疊加, 將一行的疊加操作定義為函數 handle(list, direction),其第一個參數用來儲存4*4矩陣中的某一行(列),第二個參數表示移動的方向(上下左右)。
     這樣當左右移動方向鍵時,可以這樣來計算矩陣:遍曆矩陣的每行,並將每行的數字沿左或右進行疊加操作。for row in matrix:         handle(row, direction)
     對於上下移動方向鍵時,由於矩陣是按行儲存的,不能直接處理矩陣中的列,可以通過變通採用上面的函數handle()。對於矩陣中每一列,先將其拷貝到一個列表中,然後調用handle()函數對該列表進行疊加處理,最後再將疊加後的新列表拷貝回原始矩陣中其所在的列,其邏輯上等同於下面的代碼操作。for col in matrix:          handle(col, direction)
     handle(row, direction)函數的作用是沿指定方向疊加一行中的數字,請看下面幾個例子:

移動方向 移動前 移動後
handle(x, 'left') x = [0, 2, 2, 2]  x = [4, 2, 0, 0]
handle(x, 'left') x = [2, 4, 2, 2] x = [2, 8, 0, 0]
handle(x, 'right') x = [2, 4, 2, 2] x = [0, 0, 2, 8]

實現 handle(row, direction) 函數
    根據上面的介紹,實現handle函數是關鍵。仔細觀察疊加的過程,其都是由兩個子過程組成的:(1) align(row, direction)   沿direction方向對齊列表row中的數字,例如:x = [0, 4, 0, 2]align(x, 'left')  後 x = [4, 2, 0, 0]在 align(x, 'right') 後 x = [0, 0, 4, 2]
(2) addSame(row, direction) 尋找相同且相鄰的數字。如果找到,將其中一個翻倍,另一個置0(如果direction是'left'將左側翻倍,右側置0,如果direction為'right',將右側翻倍,左側置0),並返回True;否則,返回False。例如:x = [2, 2, 2, 2]addSame(x, 'left') 後 x = [4, 0, 2, 2]      返回 True再 addSame(x, 'left') 後 x = [4, 0, 4, 0]   返回 True再 addSame(x, 'left') 後 x = [4, 0, 4, 0]   返回 False 
     有了上面兩個子函數,應該不難實現。有了這兩個子函數,函數handle()就很好實現了,如下:handle(row, direction):          align(row, direction)          result = addSame(row, direction)          while result == True:                    align(row, direction)                    result = addSame(row, direction)
     下面結合一個實際例子再來看看handle函數的處理過程:x = [2, 4, 2, 2]調用 handle(x, 'right'),變數 x 變化過程:align(x, 'right')          ->     [2, 4, 2, 2]addSame(x, 'right')   ->     [2, 4, 0, 4]     ->     return Truealign(x, 'right')          ->     [0, 2, 4, 4]    addSame(x, 'right')   ->     [0, 2, 0, 8]     ->     return Truealign(x, 'right')          ->     [0, 0, 2, 8]    addSame(x, 'right')   ->     [0, 0, 2, 8]     ->     return False最終得到的 x = [0, 0, 2, 8]          最主要的部分已經說完了,下面就貼出代碼吧,由於代碼不多就直接貼出來吧。
3. 代碼
   
這些是全部代碼,儲存在單一檔案中即可運行,運行環境 Python3.0+
# -*- coding:UTF-8 -*-#! /usr/bin/python3import randomv = [[0, 0, 0, 0],     [0, 0, 0, 0],     [0, 0, 0, 0],     [0, 0, 0, 0]]def display(v, score):        '''顯示介面        '''        print('{0:4} {1:4} {2:4} {3:4}'.format(v[0][0], v[0][1], v[0][2], v[0][3]))        print('{0:4} {1:4} {2:4} {3:4}'.format(v[1][0], v[1][1], v[1][2], v[1][3]))        print('{0:4} {1:4} {2:4} {3:4}'.format(v[2][0], v[2][1], v[2][2], v[2][3]))        print('{0:4} {1:4} {2:4} {3:4}'.format(v[3][0], v[3][1], v[3][2], v[3][3]), '    Total score: ', score)def init(v):        '''隨機分布網格值                '''        for i in range(4):                v[i] = [random.choice([0, 0, 0, 2, 2, 4]) for x in v[i]]def align(vList, direction):        '''對齊非零的數字        direction == 'left':向靠左對齊,例如[8,0,0,2]靠左對齊後[8,2,0,0]        direction == 'right':向靠右對齊,例如[8,0,0,2]靠右對齊後[0,0,8,2]        '''        # 移除列表中的0        for i in range(vList.count(0)):                vList.remove(0)        # 被移除的0        zeros = [0 for x in range(4 - len(vList))]        # 在非0數位一側補充0        if direction == 'left':                vList.extend(zeros)        else:                vList[:0] = zeros        def addSame(vList, direction):        '''在列表尋找相同且相鄰的數字相加, 找到合格返回True,否則返回False,同時還返回增加的分數                direction == 'left':從右向左尋找,找到相同且相鄰的兩個數字,左側數字翻倍,右側數字置0        direction == 'right':從左向右尋找,找到相同且相鄰的兩個數字,右側數字翻倍,左側數字置0        '''        score = 0        if direction == 'left':                for i in [0, 1, 2]:                        if vList[i] == vList[i+1] != 0:                                 vList[i] *= 2                                vList[i+1] = 0                                score += vList[i]                                return {'bool':True, 'score':score}        else:                for i in [3, 2, 1]:                        if vList[i] == vList[i-1] != 0:                                vList[i-1] *= 2                                vList[i] = 0                                score += vList[i-1]                                return {'bool':True, 'score':score}        return {'bool':False, 'score':score}def handle(vList, direction):        '''處理一行(列)中的資料,得到最終的該行(列)的數字狀態值, 返回得分        vList: 列表結構,儲存了一行(列)中的資料        direction: 移動方向,向上和向左都使用方向'left',向右和向下都使用'right'        '''        totalScore = 0        align(vList, direction)        result = addSame(vList, direction)        while result['bool'] == True:                totalScore += result['score']                align(vList, direction)                result = addSame(vList, direction)        return totalScore        def operation(v):        '''根據移動方向重新計算矩陣狀態值,並記錄得分        '''        totalScore = 0        gameOver = False        direction = 'left'        op = input('operator:')        if op in ['a', 'A']:    # 向左移動                direction = 'left'                for row in range(4):                        totalScore += handle(v[row], direction)        elif op in ['d', 'D']:  # 向右移動                direction = 'right'                for row in range(4):                        totalScore += handle(v[row], direction)        elif op in ['w', 'W']:  # 向上移動                direction = 'left'                for col in range(4):                        # 將矩陣中一列複製到一個列表中然後處理                        vList = [v[row][col] for row in range(4)]                        totalScore += handle(vList, direction)                        # 從處理後的列表中的數字覆蓋原來矩陣中的值                        for row in range(4):                                v[row][col] = vList[row]        elif op in ['s', 'S']:  # 向下移動                direction = 'right'                for col in range(4):                        # 同上                        vList = [v[row][col] for row in range(4)]                        totalScore += handle(vList, direction)                        for row in range(4):                                v[row][col] = vList[row]        else:                print('Invalid input, please enter a charactor in [W, S, A, D] or the lower')                return {'gameOver':gameOver, 'score':totalScore}        # 統計空白地區數目 N        N = 0        for q in v:            N += q.count(0)        # 不存在剩餘的空白地區時,遊戲結束        if N == 0:                gameOver = True                return {'gameOver':gameOver, 'score':totalScore}        # 按2和4出現的幾率為3/1來產生隨機數2和4        num = random.choice([2, 2, 2, 4])         # 產生隨機數k,上一步產生的2或4將被填到第k個空白地區        k = random.randrange(1, N+1)        n = 0        for i in range(4):                for j in range(4):                        if v[i][j] == 0:                                n += 1                                if n == k:                                        v[i][j] = num                                        break        return {'gameOver':gameOver, 'score':totalScore}init(v)score = 0print('Input:W(Up) S(Down) A(Left) D(Right), press <CR>.')while True:        display(v, score)        result = operation(v)        if result['gameOver'] == True:                print('Game Over, You failed!')                print('Your total score:', score)        else:                score += result['score']                if score >= 2048:                        print('Game Over, You Win!!!')                        print('Your total score:', score)


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.