文章目錄
- 前言
- 一、三子棋游戲整體實作思路
- 二、實作步驟
- 分模板實作 (以及具體應用實列)
- 1.test.c 源檔案講解:
- 2. game.c 源檔案講解:
- 3.game.h 源檔案講解
- 三 game.c 源檔案整體展示
- 總結
前言
在初步學習C語言初階知識后,我們可以嘗試用C語言來完成一個三子棋小游戲,這不僅僅可以檢驗自己知識學習的扎實度,也可以作為一個很好的練習專案,幫助自己進行知識的歸納總結與實作具體應用,
ps.相信大家寫出來后一定會成就感滿滿的~
附上gitee地址(完整代碼都已上傳,需要的話可自行查閱):
https://gitee.com/yang-xinshang
一、三子棋游戲整體實作思路
三子棋是對函式呼叫,分模塊實作,分支與回圈等等知識進行整合的一個小游戲,在正式開始寫三子棋游戲代碼之前,我們先來了解一下多檔案的使用,在進行類似三子棋等等小專案的時候,如果我們把所有代碼都放在一個源檔案中,整體寫下來就會發現代碼比較亂,甚至有時候連自己都看不下去,這時候出個bug更是搞得焦頭爛額,這時我們就必須學會分模塊來實作代碼,將不同型別的代碼放在同一個源檔案中,這樣可以使思路更加清晰,代碼可讀性也大大提高,bug找起來也會容易得多,
二、實作步驟
分模板實作 (以及具體應用實列)
比如我這里就用了三個源檔案:
1.test.c 這里寫整個游戲實作思路,
2.game.c 這里寫游戲實作思路中的各個函式的定義,
3.game.h 這里參考需要用到的頭檔案,以及對各個自定義函式的宣告,(這樣的話在其他模板上方只需要加上 #include “game.h”,避免重復參考相同頭檔案)
三個源檔案如下(示例):

1.test.c 源檔案講解:
這里寫出整個游戲的大致實作思路:
1.玩家通過輸入1/0 來選擇是開始游戲還是退出游戲(用do…while陳述句可以很好的實作),并寫出列印選單函式,
2.寫出三子棋的游戲程序,包含了 初始化棋盤 玩家下棋 電腦下棋 重現棋盤 判斷輸贏
下面給出 test.c 的源代碼,細節部分已在代碼注釋中給出,
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h" //game.h包含所有用到的頭檔案以及函式宣告;
void meum()
{
// 列印選單
printf("*****************************\n");
printf("*****************************\n");
printf("******* 1.play *********\n");
printf("******* 0.exit *********\n");
printf("*****************************\n");
printf("*****************************\n");
}
void game()
{
int ret = 0;
//三子棋游戲程序
char board[ROW][COL];
InitBoard(board, ROW, COL); //初始化棋盤 - board的元素都給成空格
DisplayBoard(board, ROW, COL);
while (1)
{
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWin(board, ROW, COL); // 玩家下棋 判斷輸贏
if (ret != 'C')
{
break;
}
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWin(board, ROW, COL); // 電腦下棋 判斷輸贏
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家贏\n");
}
else if (ret == '#')
{
printf("電腦贏\n");
}
else
{
printf("平局\n");
}
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do{
meum();
printf("請選擇:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戲\n");
break;
default:
printf("請重新輸入\n");
break;
}
} while (input);
return 0;
}
注 : 輸贏條件 >
* 玩家贏 C—游戲繼續
# 電腦贏 Q----棋盤滿了,沒出勝負,平局
2. game.c 源檔案講解:
這個檔案中放的主要就是test.c檔案的定義出來的函式具體怎么實作,下面我就把函式具體挑出來給大家一一講解,
1.初始化棋盤:
void InitBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
這里對棋盤(二維陣列) row 行 col 列進行每個元素一一列印出空格,作為空棋盤,
2.棋盤樣式具體列印,

要列印出如圖所示的三行三列棋盤,這里我們就需要稍加思考,整個思路如下:
1.每一行列印出三個空格,
2. “|”的列印在最后一列不列印,(col-1)
3. "—"的列印在最后一行不列印,(row-1)
4. 具體實作如下代碼: for回圈實作:
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
}
printf("\n");
}
}
3.玩家下棋函式,
ps. 這里需要特別注意,玩家不是程式員,不一定懂得陣列下標從1開始,所以我們傳坐標進去就要記得加上 橫豎坐標都-1 ,
(其他需要注意的點在代碼中用注釋展示)
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1) // 用while回圈實作重復輸入游玩,
{
printf("請輸入坐標:>\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col) //坐標不能超出棋盤范圍,
{
if (board[x-1][y-1] = ' ') // 玩家不是程式員,不一定懂得陣列下標從1開始
{
board[x-1][y-1] = '*'; // 玩家棋子是 *
break;
}
else
{
printf("坐標被占用,請重新輸入\n");
}
}
else
{
printf("輸入非法,請重新輸入\n");
}
}
}
4.電腦下棋函式,
ps. 電腦下棋的坐標用亂數函式rand()生成并對其分別進行取模row和取模col,實作生成隨機棋盤坐標,
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("電腦走:\n");
while (1)
{
x = rand() % row; //亂數%坐標可以得到1~3之間的數字
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';// 電腦棋子是 #
break;
}
}
}
補充說明:
srand((unsigned long)time(NULL)),這個函式經常跟rand函式一起使用,是亂數生成器的初始化函式,在C語言中它們都位于<stdlib.h>頭檔案中以及<time.h>頭檔案中,
————————————————
5.判斷棋盤是否滿了 (平局與繼續情況生成的函式),
1.沒滿回傳 0 -----繼續情況 (C)
2.滿了回傳 1 -----平局情況 (Q)
int IsFull(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
5.判斷輸贏函式,
ps. 分別考慮行和列滿了的情況,并將棋子進行回傳,實作輸贏判斷,
char IsWin(char board[ROW][COL], int row, int col)
{
int i = 0; //判斷行
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][i] == board[i][2] && board[i][1] != ' ')
return board[i][1];
}
for (i = 0; i < col; i++) //判斷列
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
return board[1][i];
}
// 下面兩個都是判斷對角線
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
// 判斷平局
int ret = IsFull(board, row, col);
if (ret == 1)
{
return 'Q'; // 棋盤滿了 平局
}
else
{
return 'C'; //棋盤沒滿 繼續
}
}
3.game.h 源檔案講解
這個源檔案主要放上各個函式的宣告,以及呼叫函式需要的頭檔案,再加上 #define定義的行和列 (ROW和COL),
#pragma once // 用于防止出現重復參考頭檔案引起的報錯(無論參考多少個只識別一個)
#include <stdio.h>
#include <stdlib.h> // srand rand 函式
#include <time.h> // time 函式
#define ROW 3 // 定義棋盤規格為3行3列
#define COL 3
// 初始化棋盤 全部列印上空格
void InitBoard(char board[ROW][COL],int row ,int col );
// 列印棋盤
void DisplayBoard(char board[ROW][COL], int row, int col);
// 玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
// 電腦下棋
void ComputerMove(char board[ROW][COL], int row, int col);
// 判斷輸贏
char IsWin(char board[ROW][COL], int row, int col);
// 判斷棋盤是否滿了
int IsFull(char board[ROW][COL], int row, int col);
三 game.c 源檔案整體展示
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h" //參考game.h 里面所有的頭檔案,簡化步驟
void InitBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
}
printf("\n");
}
}
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("請輸入坐標:>\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x-1][y-1] = ' ') // 玩家不是程式員,不一定懂得陣列下標從1開始
{
board[x-1][y-1] = '*';
break;
}
else
{
printf("坐標被占用,請重新輸入\n");
}
}
else
{
printf("輸入非法,請重新輸入\n");
}
}
}
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("電腦走:\n");
while (1)
{
x = rand() % row; //亂數%坐標可以得到1~3之間的數字
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
int IsFull(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
char IsWin(char board[ROW][COL], int row, int col)
{
int i = 0; //判斷行
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][i] == board[i][2] && board[i][1] != ' ')
return board[i][1];
}
for (i = 0; i < col; i++) //判斷列
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
return board[1][i];
}
// 下面兩個都是判斷對角線
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
{
return board[1][1];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
// 判斷平局
int ret = IsFull(board, row, col);
if (ret == 1)
{
return 'Q'; // 棋盤滿了 平局
}
else
{
return 'C'; //棋盤沒滿 繼續
}
}
總結
寫到這里,我們的三子棋小游戲就算整體完成了,只要我們縷清各個源檔案所寫的內容,進行分模塊書寫,并將game.c里面的游戲函式具體實作,這樣一個復雜的專案被我們拆分成各個小的函式,最后在拼裝在一起,就可以實作一個三子棋小專案啦~創作不易,希望大家給博主能點個贊!跪謝!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/290969.html
標籤:其他
下一篇:一位小白的自我介紹
