文章目錄
- C語言人機大戰之三子棋
- 一、游戲規則
- 二、游戲實作
- (1)游戲界面
- (2)游戲ing
- 初始化棋盤
- 列印棋盤
- 玩家落子
- 電腦落子
- 判斷輸贏
- 棋盤滿否
- 三、代碼總結
- (1)game.h
- (2)test.c
- (3)game.c
- 四、代碼效果
- 五、游戲總結
C語言人機大戰之三子棋
三子棋又名九宮格,是我學生時代閑來無事經常玩的簡單小游戲,它以它的棋盤簡單,游戲規則簡單,深受閑的發慌的我的喜愛,沒事就來幾局,此次就由我用C語言來細細道來小游戲三子棋的簡易實作程序
一、游戲規則
一共有九個格子,玩家雙方各自輪流下棋,直至有人將自己的棋子連成了一條線(可以是橫線,豎線或對角線)或者再也沒有空余的棋格子可以落子,游戲結束,先連成直線的玩家獲勝,否則就視為平局,
二、游戲實作
在計算機編程的程序中,為了使代碼看起來井然有序,遂將游戲主體分在三個檔案里,兩個源檔案,一個頭檔案
- test.c 在該源檔案里實作三子棋游戲的主體流程
- game.c 在該源檔案里實作游戲程序中具體的函式
- game.h 在該頭檔案里放入各個函式的宣告,庫函式使用所需的頭檔案,以及需要定義的常量,如此一來,只需要在其他兩個源檔案里引這個頭檔案,就會有包含所有的內容,避免代碼的重復冗余
(1)游戲界面
游戲界面的列印以及游戲的進入與結束都放在主函式(main函式)中
代碼展示📜:
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("請選擇\n");
printf("請輸入1/0:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
//選擇進入游戲
break;
case 0:
printf("退出游戲\n");
break;
default:
printf("輸入錯誤,請重新輸入\n");
break;
}
} while (input);
return 0;
}
說明:
-
在main函式當中,我運用了do…while陳述句來實作游戲的進入與結束,保證游戲界面至少進入一次,
-
在do…while陳述句中首先進行了游戲選單的列印,1代表玩游戲,0代表退出游戲,
代碼展示📜:
void menu()
//列印選單
{
printf("**********************************\n");
printf("********** 1、Play ********\n");
printf("********** 0、Exit ********\n");
printf("**********************************\n");
}
- 在main函式中定義一個整形變數input來接受玩家的意愿,通過switch分支陳述句來實作,當玩家選擇1時代表想要來盤三子棋,就會執行game函式從而進行游戲,選擇0時代表想要退出游戲,如果選擇了其他非1或0的數字就會進行提醒“輸入錯誤,請重新輸入”,
代碼效果👀:

(2)游戲ing
當選擇數字1進入游戲函式(game函式)后,便進入了游戲的主體,為了使代碼分工明確,實作游戲程序中的函式的詳細內容將會被放在game.c之中,
代碼展示📜:
void game()
{
//存盤資料
char Board[ROW][COL];
//初始化棋盤,初始化空格
InitBoard(Board, ROW, COL);
//列印棋盤,實際上是列印陣列的內容
PrintBoard(Board, ROW, COL);
//接收游戲狀態
char result = 0;
while (1)
{
//玩家下
PlayerMove(Board, ROW, COL);
PrintBoard(Board, ROW, COL);
result = IsWin(Board, ROW, COL);
if (result != 'C')
break;
//電腦下
ComputerMove(Board, ROW, COL);
PrintBoard(Board, ROW, COL);
result = IsWin(Board, ROW, COL);
if (result != 'C')
break;
}
if (result == '*')
printf("玩家獲勝\n");
else if (result == '#')
printf("電腦獲勝\n");
else
printf("平局\n");
PrintBoard(Board, ROW, COL);
}
說明:
- 進入游戲之后先創建了一個字符型二維陣列Board[ROW][COL]來存盤三子棋棋盤中要落子的地方的資料,ROW和COL代表著行和列,在game.h這個頭檔案里進行了宏定義,這樣未來想要修改行和列只需要在頭檔案里進行修改即可,方便大大地增加,
- 然后進行初始化棋盤,將棋盤中的內容初始化為空格(’ '),我將用函式**InitBoard(Board, ROW, COL)**來實作,引數有三子棋的棋盤,行與列,接下來的函式都將傳入這三個引數來實作相關函式,如果不進行初始化的操作會出現什么呢?
代碼效果👀(亂了套,這不是我想看到的😠):

- 接下來進行棋盤的列印,方便看見戰局的實時,
- 定義一個字符變數result來接受游戲狀態,用IsWin(Board, ROW, COL)函式回傳一個字符給result,回傳’*‘代表玩家獲勝,回傳’#'代表電腦獲勝,回傳’Q’表示平局,此三種情況游戲都結束,回傳’C’表示未分出勝負且未平局,游戲繼續,
- 接下來通過while函式來實作人機之間的博弈,先玩家下,列印棋盤,判斷游戲是否結束,如果result != 'C’的話,說明游戲已然辨出輸贏,通過break跳出回圈,
- 通過result里的字符來列印游戲結果,再列印一遍棋盤進行總結展示,
初始化棋盤
代碼展示📜:
void InitBoard(char Board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
Board[i][j] = ' ';
}
}
}
說明:
通過兩層for回圈對棋盤的內容進行初始化,初始化’ ',
列印棋盤
代碼展示📜:
void PrintBoard(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)
{
int j = 0;
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, y = 0;
printf("玩家下\n");
while (1)
{
printf("請玩家輸入坐標:> ");
scanf("%d %d", &x, &y);
//判斷是否合法
if (x - 1 >= 0 && x - 1 < row && y - 1 >= 0 && y - 1 < col )
{
//下棋/判斷是否位置被占
if (Board[x - 1][y - 1] == ' ')
{
Board[x - 1][y - 1] = '*';
break;
}
else
{
printf("位置已被占,請重新輸入\n");
}
}
else
{
printf("坐標不合法,請重新輸入\n");
}
}
}
說明:
- 通過while陳述句讓玩家進行正確的落子(玩家的棋子用’*'代表),定義整形變數x和y來接受橫縱坐標,玩家將先輸入想要落子的地方的橫縱坐標,由于玩家并非程式員,并不知道陣列的下標是從0開始的,所以需要將坐標減一,
- 首先需要判斷橫縱坐標是否合法,橫縱坐標是否超出棋盤的尺寸,如果不合法,輸出"坐標不合法,請重新輸入",
- 在坐標合法的情況下,進行判斷落子之處是否已經被占,通過if陳述句來判斷Board[x - 1][y - 1]中的內容是否為’ ',如果是就落子,并跳出回圈結束本次落子環節,如果不是輸出"位置已被占,請重新輸入"
代碼效果👀:

電腦落子
代碼展示📜:
void ComputerMove(char Board[ROW][COL], int row, int col)
{
int x = 0, y = 0;
printf("電腦下\n");
while (1)
{
x = rand() % row;
y = rand() % col;
//通過rand函式隨機生成0到2的數,形成橫縱坐標
if (Board[x][y] == ' ')
{
Board[x][y] = '#';
break;
}
}
}
說明:
- 通過while陳述句讓電腦進行落子(電腦的棋子用’#'代表),定義整型變數x和y代表橫縱坐標用來接收電腦的落子,
- 此時需要讓電腦隨機生成橫縱坐標,運用到了rand函式隨機生成0到2的數,該函式的頭檔案為#include <stdlib.h>,使用該函式還需要使用srand函式進行配合
srand((unsigned int)time(NULL));
? 這是拿時間戳來設定亂數的生成起始點,里面包含time() 函式,其頭檔案為#include <time.h>,在呼叫rand函式之前呼叫一次即可,所以將其放置在了 main函式的回圈外即可,
判斷輸贏
代碼展示📜:
char IsWin(char Board[ROW][COL], int row, int col)
{
int i = 0,j=0;
//判斷三行
for (i = 0; i < row; i++)
{
if (Board[i][0] == Board[i][1] && Board[i][1] == Board[i][2] && Board[i][0] != ' ')
return Board[i][0];
}
//判斷三列
for (j = 0; j < col; j++)
{
if (Board[0][j] == Board[1][j] && Board[1][j] == Board[2][j] && Board[0][j] != ' ')
return Board[0][j];
}
//判斷對角線
if (Board[0][0] == Board[1][1] && Board[1][1] == Board[2][2] && Board[0][0] != ' ')
return Board[0][0];
if (Board[0][2] == Board[1][1] && Board[1][1] == Board[2][0] && Board[0][2] != ' ')
return Board[0][2];
//判斷棋盤滿了與否,決定平局還是繼續,滿了(平局)回傳0,沒滿(繼續)回傳1
int ret = Isfull(Board, row, col);
if (ret == 1)
return 'C';
else
return 'Q';
}
說明:
- 當有人機有一方先實作將自己的棋子連成一條線(橫線、豎線或者斜對角),獲勝者就出現了!
- 每次玩家和電腦下完棋后,分別判斷三行、三列或對角線的內容是否相等,如果有出現相等的就回傳其中的字符內容,
- 回傳’*‘代表玩家獲勝,回傳’#'代表電腦獲勝,回傳’Q’表示平局,回傳’C’表示未分出勝負且未平局
棋盤滿否
int Isfull(char Board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (Board[i][j] == ' ')
return 1;//棋盤沒有滿
}
}
return 0;
}
說明:
- 在判斷輸贏之時,通過兩層for回圈來判斷棋盤滿了與否,滿了(平局)回傳0,沒滿(繼續)回傳1
三、代碼總結
(1)game.h
代碼展示📜:
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
//各個頭檔案的包含
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//定義棋盤行列
#define ROW 3
#define COL 3
//函式的宣告
//初始化棋盤
void InitBoard(char Board[ROW][COL], int row, int col);
//列印棋盤
void PrintBoard(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);
//判斷游戲輸贏
//玩家贏了回傳'*'
//電腦贏了回傳'#'
//平局了回傳'Q'
//游戲繼續回傳'C'
char IsWin(char Board[ROW][COL], int row, int col);
(2)test.c
代碼展示📜:
#include "game.h"
void menu()
//列印選單
{
printf("**********************************\n");
printf("********** 1、Play ********\n");
printf("********** 0、Exit ********\n");
printf("**********************************\n");
}
void game()
{
//存盤資料
char Board[ROW][COL];
//初始化棋盤,初始化空格
InitBoard(Board, ROW, COL);
//列印棋盤,實際上是列印陣列的內容
PrintBoard(Board, ROW, COL);
//接收游戲狀態
char result = 0;
while (1)
{
//玩家下
PlayerMove(Board, ROW, COL);
PrintBoard(Board, ROW, COL);
result = IsWin(Board, ROW, COL);
if (result != 'C')
break;
//電腦下
ComputerMove(Board, ROW, COL);
PrintBoard(Board, ROW, COL);
result = IsWin(Board, ROW, COL);
if (result != 'C')
break;
}
if (result == '*')
printf("玩家獲勝\n");
else if (result == '#')
printf("電腦獲勝\n");
else
printf("平局\n");
PrintBoard(Board, ROW, COL);
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("請選擇\n");
printf("請輸入1/0:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戲\n");
break;
default:
printf("輸入錯誤,請重新輸入\n");
break;
}
} while (input);
return 0;
}
(3)game.c
代碼展示📜:
#include "game.h"
void InitBoard(char Board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
Board[i][j] = ' ';
}
}
}
void PrintBoard(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)
{
int j = 0;
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, y = 0;
printf("玩家下\n");
while (1)
{
printf("請玩家輸入坐標:> ");
scanf("%d %d", &x, &y);
//判斷是否合法
if (x - 1 >= 0 && x - 1 < row && y - 1 >= 0 && y - 1 < col )
{
//下棋/判斷是否位置被占
if (Board[x - 1][y - 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, y = 0;
printf("電腦下\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (Board[x][y] == ' ')
{
Board[x][y] = '#';
break;
}
}
}
int Isfull(char Board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (Board[i][j] == ' ')
return 1;//棋盤沒有滿
}
}
return 0;
}
char IsWin(char Board[ROW][COL], int row, int col)
{
int i = 0,j=0;
//判斷三行
for (i = 0; i < row; i++)
{
if (Board[i][0] == Board[i][1] && Board[i][1] == Board[i][2] && Board[i][0] != ' ')
return Board[i][0];
}
//判斷三列
for (j = 0; j < col; j++)
{
if (Board[0][j] == Board[1][j] && Board[1][j] == Board[2][j] && Board[0][j] != ' ')
return Board[0][j];
}
//判斷對角線
if (Board[0][0] == Board[1][1] && Board[1][1] == Board[2][2] && Board[0][0] != ' ')
return Board[0][0];
if (Board[0][2] == Board[1][1] && Board[1][1] == Board[2][0] && Board[0][2] != ' ')
return Board[0][2];
//判斷棋盤滿了與否,決定平局還是繼續,滿了(平局)回傳0,沒滿(繼續)回傳1
int ret = Isfull(Board, row, col);
if (ret == 1)
return 'C';
else
return 'Q';
}
四、代碼效果

五、游戲總結
此次三子棋游戲在此就告一段落了 ,由于本人才疏學淺,只會簡易版本,還未能知曉如何實作電腦智能下棋,而不是隨機下棋,那才是真正的人機大戰,望今后本人學的更多,進行代碼優化…
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/280565.html
標籤:其他
上一篇:C語言實作 三子棋小游戲
下一篇:三子棋游戲的實作
