今年年初,新一季的《最強大腦》開播了,第一集選拔的時候大家做了一個數字遊戲,名叫《數字華容道》,當時何猷君以二十幾秒的成績奪得該項目的冠軍,看了這個遊戲之後我決定要寫一個《數字華容道》的程序,過去了半年,我終于記起了這件事,今天就來實現。
數字推盤遊戲(n-puzzle)是一種智力遊戲,常見的類型有十五數字推盤遊戲和八數字推盤遊戲等。十五數字推盤遊戲的闆上會有十五個方塊和一個大小相當于一個方塊的空位(供方塊移動之用),當15個數字依次排序并且最後一個格子為空位即代表挑戰成功。
本文使用 PyQt5 進行設計與實現,PyQt5 是該程序的一個呈現方式,最重要的是算法,學會了算法,完全可以使用 PyGame 或者 Tkinter 實現。
PyQt5安裝:pip install PyQt5
本文使用環境:
做一個簡版的數字華容道,布局設計如圖所示:
簡版數字華容道布局
如上圖所示,本遊戲共需要15個方塊,每個方塊代表一個數字。我們可以使用 一個二維 list來存儲方塊上的數字。其實我們要創建一個 4x4 的 list 存儲 0~15 各個數字,0 代表空的位置。
2.1 創建并初始化數組
創建數組的方法:
2.2 移動算法
假如移動之前個數字位置如左圖所示,那麼當按下左箭頭時,會變成如右圖所示:
左移
可以看到 (1, 2) 和 (1, 3) 兩個位置上的數字互換了,即 0 和 8 互換;如果右圖所示再次按下左箭頭,那麼所有數字都不會改變,因為 數字 0 右邊沒有數了。
總結一下:如果 數字 0 所在位置為 (row, column),并且 column≠3 那麼按下左箭頭之後,(row, column) 和 (row, column 1) 位置上的數組互換,同理可得:
将移動算法封裝成一個函數如下:
2.3 是否勝利檢測算法
檢測是否勝利其實很簡單:前15個位置分别對應,最後一個為0即為勝利 ,不過為了避免不必要的計算,我們先檢測最後一個是否為 0 ,如果不為0 前面的就不用比較了。具體代碼實現如下:
3、實現
下面講解所有功能模塊的實現。
3.1 框架搭建
創建 QWidget 作為整個遊戲的載體:
運行結果如下圖所示:
框架運行結果
框架運行結果
3.2 數字方塊實現
前面已經提到,用一個二維數組來存放 0~16 個數字,最終我們要轉換成一個數字方塊,單獨創建一個類:
該類繼承自 QLablel ,初始化需要傳入一個參數 number ,number就是數字方塊上顯示的數字。
3.3 将數字轉換成方塊添加到布局
布局采用 QGridLayout 創建一個 4X4 的 self.gltMain,将16個 Block 添加到 self.gltMain:
3.4 初始化布局
初始化布局包括随機數據的産生與将數字轉換成方塊添加到布局:
3.5 按鍵檢測
QWidget 有一個 keyPressEvent 事件句柄,我們隻需要重新實現該方法即可:
按鍵檢測到按鍵按下之後判斷該鍵值是否為 “↑↓←→”或“WSAD”,并作出相應的移動(move),移動之後刷新布局(updatePannel),最後檢測是否完成挑戰(checkResult),如果完成挑戰,彈出提示框。如果點擊了 OK 按鈕,遊戲重新開始(onInit)。
3.6 試玩測試
至此,所有功能模塊介紹完畢,不要着急看完整代碼,我們先運行一下程序看是否還有 Bugs。
玩了幾局之後發現,并不是所有的局都能都還原,如下面這種情況:
無法還原
如圖所示,14 和 15 方塊位置反了,無論如何也還原不聊了,這種情況是随機出現的。到底是怎麼回事呢?經過一番上網搜索,确實如果隻有兩個數字的位置反了,無論如何也還原不了的。那這是由什麼造成的呢?還記得我們的二維數組是怎麼産生的吧,随機的,也就是說可能會随機到無法還原的情況。
如何避免這種情況呢?初始化數組時,所有的位置都是正确的數字,然後使用 move 進行移動打亂。
3.7 改進完善
由于前面已經将各個功能模塊單獨寫成了方法,因此我們隻需修改 onInit 方法即可。
先生成一個順序數組,裡面保存着[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0],然後轉為二維數組 blocks,再後随即移動500次,最後添加到布局。
4、完整代碼5、總結
在做的過程中遇到最大的坑就是随機數組導緻無法還原。另外在做這個遊戲的時候我已經找到還原規律了,這樣在測試的時候可以做完完整測試,否則根本無法測試都挑戰成功那一步。
另外要對《最強大腦》做一下吐槽:這個項目根本就是有偏袒的,玩過的人會很快,沒有玩過的找規律的時間就很長。我在手機上玩4X4的最快還原用了 33 秒,對于該節目的冠軍(即便是玩過)很是敬仰。
,
更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!