用C語言編寫小遊戲——“井字棋”
用C++編寫遊戲容易嗎?有什麼開源的小遊戲嗎?能分享一下嗎? 這個答案中,我提到學習遊戲程式設計可從回合制遊戲開始,例如井字棋。
考慮到一些初學者的學習需求,我就寫一個井字棋的教程吧。
關於怎麼快速學C/C++,可以加下小編的C/C++學習群:341+636+727,不管你是小白還是大牛,小編我都歡迎,不定期分享乾貨,歡迎初學和進階中的小夥伴。
每天晚上20:00都會開直播給大家分享C/C++遊戲程式設計學習知識和路線方法,群裡會不定期更新最新的教程和學習方法,最後祝所有程式設計師都能夠走上人生巔峰,讓程式碼將夢想照進現實
1. 遊戲狀態的表示
首先,我認為表示方法(representation)是程式設計中應最先要考慮的事情。對於回合制遊戲,我們需要儲存一個回合中的遊戲狀態(game state)。
以下用一個結構體表示井字棋一個回合中的狀態,並加入函式作初始化:
typedef struct {
int board[3][3]; // -1 = empty, 0 = O, 1 = X
int turn; // O first} state;void init(state* s) {
int i, j;
for (j = 0; j < 3; j++)
for (i = 0; i < 3; i++)
s->board[j][i] = -1;
s->turn = 0;}
以上用二維陣列儲存棋盤(board)是其中一種表示方式,另一種方式則是記錄每個回合下棋子的位置。我們採用前者是因為它較容易實現勝負判定。有些回合制遊戲可能使用冗餘的表示方式,以方便實現各種規則。
而使用結構體而不是直接用全域性變數,可帶來一些優點,例如增強可讀性及內聚性。
2. 顯示遊戲狀態
編寫遊戲時,我們通常希望先顯示遊戲狀態,之後才加入其他規則,因為這樣可以方便測試。
我希望用這樣的文字顯示遊戲狀態,當空置時寫上位置編號(1-9),以方便玩家輸入下棋位置:
1 | 2 | 3
---+---+---
4 | 5 | 6
---+---+---
7 | 8 | 9
簡單直白地編寫程式碼的話:
void display(const state* s) {
int i, j;
for (j = 0; j < 3; j++) {
for (i = 0; i < 3; i++) {
switch (s->board[j][i]) {
case -1: printf(" %d ", j * 3 + i + 1); break;
case 0: printf(" O "); break;
case 1: printf(" X "); break;
}
if (i < 2)
printf("|");
else
printf("\n");
}
if (j < 2)
printf("---+---+---\n");
else
printf("\n");
}}
由於 display()
只讀而不改變遊戲狀態,所以其引數型別為 const state*
。
我們稍壓縮一下程式碼:
void display(const state* s) {
int i, j;
for (j = 0; j < 3; printf(++j < 3 ? "---+---+---\n" : "\n"))
for (i = 0; i < 3; putchar("||\n"[i++]))
printf(" %c ", s->board[j][i] == -1 ? '1' + j * 3 + i : "OX"[s->board[j][i]]);}
我們可以加入 main()
函式去顯示初始化的狀態:
int main() {
state s;
init(&s);
display(&s);}
3. 實現下棋
然後,我們加入第一個遊戲規則,就是下棋:
int move(state* s, int i, int j) {
if (s->board[j][i] != -1)
return 0;
s->board[j][i] = s->turn++ % 2;
return 1;}
函式內做了一個合法性判斷,如果該位置已有棋子,則返回 0 表示失敗。成功的話,在偶數回合填入 0,表示 O;奇數回合填入 1,表示 X;然後都把回合加一。
更改 main()
簡單測試:
int main() {
state s;
init(&s);
display(&s);
move(&s, 1, 1);
display(&s);
move(&s, 0, 1);
display(&s);}
輸出:
4. 處理輸入
在每一回閤中,提示當前玩家(O 或 X),並讓玩家輸入一個下棋位置(1-9),如果位置不合法,則重新輸入:
void human(state* s) {
char c;
do {
printf("%c: ", "OX"[s->turn % 2]);
c = getchar();
while (getchar() != '\n');
printf("\n");
} while (c < '1' || c > '9' || !move(s, (c - '1') % 3, (c - '1') / 3));}
在標準輸入中,要到Enter鍵才能處理輸入,所以這裡我們讀了第一個輸入字元後,就忽略其他字元直到讀到換行符。我們把表示位置的字元轉換成二維陣列索引。
然後,就可以修改 main()
實現二人下棋的流程:
int main() {
state s;
init(&s);
display(&s);
while (s.turn < 9) {
human(&s);
display(&s);
} }
5. 勝負判定
眾所周知,井字棋的勝利條件,是有三個棋子在橫線、直線或斜線連成一線。我們實現一個 evaluate()
函式去評估棋局的狀態,如果 O 勝出則返回 1,X 勝出則返回 -1,不分勝負則返回 0:
#define CHECK(j1, i1, j2, i2, j3, i3) \ if (s->board[j1][i1] != -1 && s->board[j1][i1] == s->board[j2][i2] && s->board[j1][i1] == s->board[j3][i3]) \ return s->board[j1][i1] == 0 ? 1 : -1;int evaluate(const state* s) {
int i;
for (i = 0; i < 3; i++) {
CHECK(i, 0, i, 1, i, 2); // horizontal
CHECK(0, i, 1, i, 2, i); // vertical
}
CHECK(0, 0, 1, 1, 2, 2); // diagnoal
CHECK(0, 2, 1, 1, 2, 0); // diagnoal
return 0;}
上面的程式碼使用了一個巨集 CHECK()
去檢測三個位置是否都為相同的棋子,如是則直接返回勝方。
最後,我們在 main()
中,待每次下棋及顯示狀態後, 判定是否出現勝方,如果到達第 9 個回合(回合從 0 開始),則判定是平局(draw):
int main() {
state s;
init(&s);
display(&s);
while (s.turn < 9) {
human(&s);
display(&s);
switch (evaluate(&s)) {
case 1: printf("O win\n"); return 0;
case -1: printf("X win\n"); return 0;
}
}
printf("Draw\n");}
6. 總結
本篇實現了二人井字棋,它是一個簡單的回合制遊戲。我們先選擇了遊戲的狀態表示方式(state
結構體及init()
函式),然後把狀態以文字形式顯示(display()
函式),加入每回合下棋規則(move()
函式),以及人類玩家的輸入處理(human()
函式),並作勝負判定(evaluate()
函式),最後在main()
裡則實現了按回合的迴圈及輸出勝負結果。
雖然這個遊戲本身以及 60 行的示例程式碼都很簡單,但這個框架可以用於實現其他(更復雜的)回合制遊戲。實時遊戲(如動作遊戲)的主要區別,其實也只在於把輸入部分做成非阻塞的函式,而該迴圈則稱為遊戲迴圈(game loop)。
相關文章
- C語言五子棋小遊戲C語言遊戲
- 用C++語言寫遊戲——打怪小遊戲C++遊戲
- 基於落點打分的井字棋智慧下棋演算法(C語言實現)演算法C語言
- C語言實現小遊戲:五子棋C語言遊戲
- Python:用海龜實現井字棋Python
- Python程式碼 | 井字棋Python
- 採用α-β演算法實現井字棋遊戲演算法遊戲
- 用C語言編寫windows服務程式C語言Windows
- C語言(C++語言)中##(兩個井號)和#(一個井號)用法[轉]C語言C++
- 人人都可以用C語言寫推箱子小遊戲C語言遊戲
- 用C語言編寫的公式計算器C語言公式
- C++ 很有趣:編寫一個井字遊戲 (Tic Tac Toe)C++遊戲
- 用“Whitespace”程式語言編寫無字天書
- [CareerCup] 17.2 Tic Tac Toe 井字棋遊戲遊戲
- C語言 編寫線段樹C語言
- C語言小遊戲------貪吃蛇----小白專用C語言遊戲
- 用C語言編寫Linux實用程式的藝術(轉)C語言Linux
- 用洛書幻方對抗人類玩家的井字棋程式
- C語言簡易三子棋C語言
- 用 C 語言編寫多程式 Web 伺服器【粗暴版】Web伺服器
- 用 C 語言編寫一個簡單的垃圾回收器
- 使用C語言編寫貪食蛇程式原始碼C語言原始碼
- 用Excel編寫小遊戲 (轉)Excel遊戲
- 用C語言寫strcat、strcpy、strlen、strcmpC語言
- C語言初學者(自學)做的一個猜數字小遊戲C語言遊戲
- c語言編寫經驗逐步積累4C語言
- 期末前端web大作業——用前端語言寫一個小遊戲前端Web遊戲
- C語言的本質(32)——C語言與彙編之C語言內聯彙編C語言
- C語言陣列實現三子棋C語言陣列
- HTML語言編寫指南HTML
- 快速排序用C語言可以這麼寫排序C語言
- 用C++語言寫遊戲——蟲戰世界C++遊戲
- 用C語言寫的程式不安全C語言
- 教你在 C 語言上編寫自己的協程
- C語言編寫靜態連結庫及其使用C語言
- 選擇使用c語言編寫的phalcon框架C語言框架
- 使用Golang語言編寫Hello World Web應用GolangWeb
- 用python語言編寫網路爬蟲Python爬蟲