今天博主將為大家帶來C語言入門級小游戲——三子棋(井字棋)的詳細介紹,希望這篇文章對大家能有幫助 ,

在編程的學習程序中,撰寫一些中這樣的小游戲,是非常有樂趣的事情,完成之后會非常非常有成就感,我們需要這樣的小專案來提高對編程學習的信心,培養對編程的興趣,由于博主是一個編程學習的小白,所以這只是三子棋的初級版,此版本只能實作人機對戰,并且電腦隨機下棋,電腦的演算法比較低級,在后續的學習中,我會持續更新,不斷對這個小游戲進行優化,期待大家的關注,還有,這篇文章中若有錯誤或不當的地方,歡迎大家指正!
關于這個專案的代碼,歡迎訪問我的gitee代碼倉庫:
Living_Amethyst/code2021 - Gitee.com
那么正文開始咯!
目錄
一.游戲的整體思路
二.創建游戲選單
三.游戲主體的實作
1.棋盤的初始化
2.列印棋盤
3.玩家下棋
4.電腦自動下棋
5.游戲勝負的判斷
四.全部的代碼
五.游戲的運行實況
一.游戲的整體思路
為了讓代碼的可讀性更高,思維性更強,我們需要創建三個檔案來完成這個專案
- test.c —— 測驗游戲
- game.h—— 游戲函式的宣告
- game.c—— 游戲函式的實作
二.創建游戲選單
作為游戲,選單是肯定少不了的,這里我們也為三子棋小游戲準備了游戲的選單
由于一進入游戲,我們首先就要看到選單,所以這里我們采用do...while回圈
我們的選單需要實作的功能有:
- 游戲的進入
- 游戲的退出
- 非法輸入的回傳提示和說明
void menu()
{
printf("************************\n");
printf("***** 1.play *******\n");
printf("***** 0.exit *******\n");
printf("************************\n");
}
void test()
{
int input = 0;
do
{
menu();
printf("請選擇");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戲\n");
break;
default:
printf("選擇錯誤\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
這里我們創建了test函式和menu函式,為的是讓邏輯更清晰,現在我們的選單部分就完成了
對于這個游戲選單,我們能實作的游戲功能有:
- 輸入1進入游戲
- 輸入0退出游戲
- 輸入其他數字提示選擇錯錯誤,將重新輸入

這是選單的運行效果
三.游戲主體的實作
1.棋盤的初始化

這張圖大概就是棋盤的樣子,為了實作棋盤,我們需要用到二維陣列,在下棋時,我們要將資料存盤到一個字符的二維陣列中,我們設定玩家下棋是 ' * ',電腦下棋是 ‘ # ’

通過這個函式,我們實作了棋盤的初始化,我們給陣列中每個元素初始化為一個空格
代碼如下
char board[ROW][COL] = { 0 };
//函式宣告
void InitBoard(char board[ROW][COL], int row, int col);
//函式定義
void InitBoard(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++)
{
board[i][j] = ' ';
}
}
}
//函式呼叫
InitBoard(board, ROW, COL);
這里有一個小細節,在陣列的初始化程序中,我并沒有在[ ]中輸入具體的數字,而是用ROW,COL取代,這是因為通過這樣操作,我們可以用define定義它們為常量,這樣如果我們想修改成五子棋或n子棋,就不用一個一個改了,直接在define定義常量時修改即可


2.列印棋盤
對棋盤的列印,我我們使用DisplayBoard這一函式來實作,代碼如下:
//函式宣告
void DisplayBoard(char board[ROW][COL], int row, int col);
//函式定義
void DisplayBoard(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++)
{
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");
}
}
}
//函式呼叫
DisplayBoard(board,ROW,COL);
值得一提的是,在函式呼叫部分我們一開始寫的代碼并不是這個,而是
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0;i < row;i++)
{
//資料
printf(" %c | %c | %c \n", board[i][0],board[i][1],board[i][2]);
//分割行
if (i < row - 1) //第三行資料不用列印分割行
{
printf("---|---|---\n");
}
但很快,我們就發現了這個代碼的局限性:
版本1,不方便代碼的改動,如要列印10*10的棋盤,無法完成,只能10*3,也就是我們把這個代碼寫死了
所以我們做了如下的改動,希望大家好好體會兩者的區別

下面展示一下棋盤列印出來的效果!

是不是有點那個意思了?
3.玩家下棋
接下來我們來實作玩家下棋這一功能,
為了完成這一功能,我們需要注意以下幾點:
- 接收玩家所輸入的地址位置(我們所判斷的陣列元素應該是玩家輸入值-1)
- 判斷玩家所輸入的地址所在是否已有落子
- 將玩家的棋子落入對應處
代碼如下:
//函式的宣告
void player_move(char board[ROW][COL],int row,int col);
//函式的定義
void player_move(char board[ROW][COL], int row, int col)
{
printf("玩家下棋:\n");
int x = 0;
int y = 0;
while (1)
{
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("該坐標被占用,請重新輸入!\n");
}
}
else
{
printf("坐標非法!請重新輸入\n");
}
}
}
//函式的呼叫
//玩家下棋
player_move(board,ROW,COL);
//棋下完要列印
DisplayBoard(board, ROW, COL);
ret = is_win(board, ROW, COL);
4.電腦自動下棋
與前面的玩家下棋類似,只是這里我們需要電腦隨機下棋,所以我們要用到rand函式獲取隨機值
我們需要創建亂數,這就需要呼叫以下頭檔案:
<stdlib.h>
<time.h>
同時,我們還需要使用:
srand((unsigned int)time(NULL)); 來進行初始化
x = rand() % row;
y = rand() % col; 來進行創建坐標的亂數
代碼實作如下
//函式的宣告
void player_move(char board[ROW][COL],int row,int col);
//函式的定義
void computer_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("電腦下棋\n");
while (1)
{
x = rand() % ROW;//取余數3后范圍是0~2
y = rand() % COL;//0~2
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//函式的呼叫
//電腦下棋
computer_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//用時間戳生成亂數
srand((unsigned int)time(NULL));
5.游戲勝負的判斷
在我們下棋的程序中,由于規則的特殊性,我們需要在玩家和電腦下的每一步后都對比賽的結果進行判斷,確保程式的邏輯正確性,
在這里,我們使用 Is_win()函式 來實作這一功能,
在這一函式中,我們需要實作以下四個邏輯:
- 回傳四種不同的狀態
- 玩家贏 : 回傳'*'
- 電腦贏 : 回傳'#'
- 平局 : 回傳'Q'
- 游戲繼續 : 回傳'C'
首先我們要確立判斷函式再整個游戲主體中的位置和作用,邏輯如下:
void game()
{
//資料存盤到一個字符的二維陣列中,玩家下棋是' * ',電腦下棋是' # ' ,
char board[ROW][COL] = { 0 };//陣列的內容應該是全部空格(二維陣列初始化一般是{})
//初始化棋盤
InitBoard(board, ROW, COL);
//列印棋盤
DisplayBoard(board,ROW,COL);
//下棋
char ret = is_win(board, ROW, COL);
while (1)
{
//玩家下棋
player_move(board,ROW,COL);
//棋下完要列印
DisplayBoard(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
//電腦下棋
computer_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家贏\n");
}
else if (ret == '#')
{
printf("電腦贏\n");
}
else
{
printf("平局\n");
}
}
我們在實作Iswin()這一函式時,需要注意以下幾點:
- 判斷行
- 判斷列
- 判斷對角線
- 判斷棋盤是否已經放滿 -- > 確認游戲是否繼續(需要一個Is_full()函式來實作這一功能)
以下是Is-win()函式的實作:
char is_win(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][1]==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];
}
//判斷平局
if ( is_full(board, row, col)==1)
{
return 'Q';
}
//繼續
return 'C';
}
這個代碼的缺陷是也只適用于三子棋,后續會進行改進
下面時is_full函式的實作
int is_full(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;
}
最后再看一下游戲整體的邏輯實作
void game()
{
//資料存盤到一個字符的二維陣列中,玩家下棋是' * ',電腦下棋是' # ' ,
char board[ROW][COL] = { 0 };//陣列的內容應該是全部空格(二維陣列初始化一般是{})
//初始化棋盤
InitBoard(board, ROW, COL);
//列印棋盤
DisplayBoard(board,ROW,COL);
//下棋
char ret = is_win(board, ROW, COL);
while (1)
{
//玩家下棋
player_move(board,ROW,COL);
//棋下完要列印
DisplayBoard(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
//電腦下棋
computer_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家贏\n");
}
else if (ret == '#')
{
printf("電腦贏\n");
}
else
{
printf("平局\n");
}
}
四.全部的代碼
game.h—— 游戲函式的宣告
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 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 player_move(char board[ROW][COL],int row,int col);
//電腦下棋
void computer_move(char board[ROW][COL], int row, int col);
//判斷輸贏的代碼
//玩家贏- '*'
//電腦贏- '#'
//平局---'Q'
//繼續---'C'
char is_win(char board[ROW][COL], int row, int col);
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void InitBoard(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++)
{
board[i][j] = ' ';
}
}
}
// (把每一格看成一組資料,一組一組地列印)
//這樣代碼的可擴展性就高了
void DisplayBoard(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++)
{
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 player_move(char board[ROW][COL], int row, int col)
{
printf("玩家下棋:\n");
int x = 0;
int y = 0;
while (1)
{
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("該坐標被占用,請重新輸入!\n");
}
}
else
{
printf("坐標非法!請重新輸入\n");
}
}
}
//電腦下棋
void computer_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("電腦下棋\n");
while (1)
{
x = rand() % ROW;//取余數3后范圍是0~2
y = rand() % COL;//0~2
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
int is_full(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 is_win(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][1]==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];
}
//判斷平局
if ( is_full(board, row, col)==1)
{
return 'Q';
}
//繼續
return 'C';
}
test.c —— 測驗游戲
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void menu()
{
printf("************************\n");
printf("***** 1.play *******\n");
printf("***** 0.exit *******\n");
printf("************************\n");
}
void game()
{
//資料存盤到一個字符的二維陣列中,玩家下棋是' * ',電腦下棋是' # ' ,
char board[ROW][COL] = { 0 };//陣列的內容應該是全部空格(二維陣列初始化一般是{})
//初始化棋盤
InitBoard(board, ROW, COL);
//列印棋盤
DisplayBoard(board,ROW,COL);
//下棋
char ret = is_win(board, ROW, COL);
while (1)
{
//玩家下棋
player_move(board,ROW,COL);
//棋下完要列印
DisplayBoard(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
//電腦下棋
computer_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家贏\n");
}
else if (ret == '#')
{
printf("電腦贏\n");
}
else
{
printf("平局\n");
}
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("請選擇");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戲\n");
break;
default:
printf("選擇錯誤\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
五.游戲的運行實況

你看,這個電腦玩家是不是有點不太聰明的樣子~
其實,電腦的”聰明程度“取決于我們程式員的技術水平程度,如果我們給電腦設計更優秀的演算法,那它也會更聰明哦
以上就是三子棋游戲的全部內容,相信大家看到這里應該也能夠獨立的完成屬于自己專有的三子棋游戲了,也相信你在這程序中對編程有了更進一步的認知,
好了,這篇文章就到這里了,歡迎大家點贊評論哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/354780.html
標籤:其他
