用C語言C++手把手教你編寫“井字棋”小遊戲

用C語言C++手把手教你編寫“井字棋”小遊戲
用C++編寫遊戲容易嗎?有什麼開源的小遊戲嗎?能分享一下嗎? 這個答案中,我提到學習遊戲程式設計可從回合制遊戲開始,例如井字棋。
下面是小編整理好的一套C/C++資料,加小編C/C++程式設計學習群:825414254,獲取系統性學習C/C++的學習資料

用C語言C++手把手教你編寫“井字棋”小遊戲
考慮到一些初學者的學習需求,我就寫一個井字棋的教程吧。

用C語言C++手把手教你編寫“井字棋”小遊戲
1. 遊戲狀態的表示
首先,我認為表示方法(representation)是程式設計中應最先要考慮的事情。對於回合制遊戲,我們需要儲存一個回合中的遊戲狀態(game state)。
以下用一個結構體表示井字棋一個回合中的狀態,並加入函式作初始化:

用C語言C++手把手教你編寫“井字棋”小遊戲
以上用二維陣列儲存棋盤(board)是其中一種表示方式,另一種方式則是記錄每個回合下棋子的位置。我們採用前者是因為它較容易實現勝負判定。有些回合制遊戲可能使用冗餘的表示方式,以方便實現各種規則。
而使用結構體而不是直接用全域性變數,可帶來一些優點,例如增強可讀性及內聚性。
2. 顯示遊戲狀態
編寫遊戲時,我們通常希望先顯示遊戲狀態,之後才加入其他規則,因為這樣可以方便測試。
我希望用這樣的文字顯示遊戲狀態,當空置時寫上位置編號(1-9),以方便玩家輸入下棋位置:

用C語言C++手把手教你編寫“井字棋”小遊戲
簡單直白地編寫程式碼的話:

用C語言C++手把手教你編寫“井字棋”小遊戲
由於 display() 只讀而不改變遊戲狀態,所以其引數型別為 const state*。
我們稍壓縮一下程式碼:

用C語言C++手把手教你編寫“井字棋”小遊戲
我們可以加入 main() 函式去顯示初始化的狀態:

用C語言C++手把手教你編寫“井字棋”小遊戲
3. 實現下棋
然後,我們加入第一個遊戲規則,就是下棋:

用C語言C++手把手教你編寫“井字棋”小遊戲
函式內做了一個合法性判斷,如果該位置已有棋子,則返回 0 表示失敗。成功的話,在偶數回合填入 0,表示 O;奇數回合填入 1,表示 X;然後都把回合加一。
更改 main() 簡單測試:

用C語言C++手把手教你編寫“井字棋”小遊戲
輸出:

用C語言C++手把手教你編寫“井字棋”小遊戲
4. 處理輸入
在每一回閤中,提示當前玩家(O 或 X),並讓玩家輸入一個下棋位置(1-9),如果位置不合法,則重新輸入:

用C語言C++手把手教你編寫“井字棋”小遊戲
在標準輸入中,要到回車鍵才能處理輸入,所以這裡我們讀了第一個輸入字元後,就忽略其他字元直到讀到換行符。我們把表示位置的字元轉換成二維陣列索引。
然後,就可以修改 main() 實現二人下棋的流程:

用C語言C++手把手教你編寫“井字棋”小遊戲
5. 勝負判定
眾所周知,井字棋的勝利條件,是有三個棋子在橫線、直線或斜線連成一線。我們實現一個 evaluate() 函式去評估棋局的狀態,如果 O 勝出則返回 1,X 勝出則返回 -1,不分勝負則返回 0:

用C語言C++手把手教你編寫“井字棋”小遊戲
上面的程式碼使用了一個巨集 CHECK() 去檢測三個位置是否都為相同的棋子,如是則直接返回勝方。
最後,我們在 main() 中,待每次下棋及顯示狀態後, 判定是否出現勝方,如果到達第 9 個回合(回合從 0 開始),則判定是平局(draw):

用C語言C++手把手教你編寫“井字棋”小遊戲
6. 總結
本篇實現了二人井字棋,它是一個簡單的回合制遊戲。我們先選擇了遊戲的狀態表示方式(state結構體及init()函式),然後把狀態以文字形式顯示(display()函式),加入每回合下棋規則(move()函式),以及人類玩家的輸入處理(human()函式),並作勝負判定(evaluate()函式),最後在main()裡則實現了按回合的迴圈及輸出勝負結果。
雖然這個遊戲本身以及 60 行的示例程式碼都很簡單,但這個框架可以用於實現其他(更復雜的)回合制遊戲。實時遊戲(如動作遊戲)的主要區別,其實也只在於把輸入部分做成非阻塞的函式,而該迴圈則稱為遊戲迴圈(game loop)。