目錄
前言
三子棋規則
代碼實作
代碼剖析
前言
大噶好,今天整點三子棋,此三子棋并沒有加入AI演算法,電腦下棋純屬隨機下棋(大佬繞行),所以真正的玩法其實是想辦法讓電腦獲勝!(bushi ,這個小游戲的代碼全部用C語言寫出,涉及多維陣列、函式以及一些零碎的知識點,為了增加可讀性并深化函式的理解,代碼由三個檔案構成,
1.text.c(游戲的測驗)
2.game.c(游戲實作、主體代碼)
3.game.h (函式宣告、頭檔案)
代碼總計200+行,本文篇幅較長,需要對函式和陣列,有一定理解,

三子棋規則
三子棋是一種民間傳統游戲,又叫九宮棋、圈圈叉叉、一條龍、井字棋等,將正方形對角線連起來,相對兩邊依次擺上三個雙方棋子,只要將自己的三個棋子走成一條線,對方就算輸了,但是,有很多時候會出現和棋的情況,——源自百度百科,CSGO白給小鎮匪家下棋!!

可以類比五子棋的規則理解
代碼實作
test.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()//列印選單
{
printf("******************\n");
printf("******1.game******\n");
printf("******0.exit******\n");
printf("******************\n");
}
void game()
{
//初始化棋盤元素全部為0
char board[ROW][COL] = { 0 };
//將棋盤每一個元素變為空格
InitBoard(board, ROW, COL);
//列印棋盤
DisplayBoard(board, ROW, COL);
char win = 0;
while (1)
{
//玩家開始下棋
player_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
win = IsWin(board, ROW, COL);
if (win != 'C')
break;
//電腦開始下棋
computer_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
win = IsWin(board, ROW, COL);
if (win != 'C')
break;
//判斷輸贏,回傳為*玩家勝,#電腦勝,'C'繼續,'E'平局
//char win = IsWin(board, ROW, COL);
}
if (win == '#')
printf("很遺憾,您連人工智障都沒下過\n");
else if (win == '*')
printf("恭喜,您把人工智障吊起來錘\n");
else
printf("很遺憾,您和人工智障五五開\n");
}
void test_game()//測驗游戲面板
{
int input = 0;
srand((unsigned int)time(NULL));//亂數
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戲\n");
break;
default:
printf("輸入錯誤請重新輸入\n");
break;
}
} while (input);
}
int main()
{
test_game();
return 0;
}
game.c:
#define _CRT_SECURE_NO_WARNINGS 1
#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++)
{
if (i < row)//列印分隔行
{
for (j = 0; j < row; j++)
{
printf("---");
if (j < col - 1)
printf("+");
}
}
printf("\n"); //換行
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");//列印棋格之間的間隔
}
printf("\n");//換行
}
for (j = 0; j < row; 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 && y >= 1 && x <= row && 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)
{
printf("電腦下棋->\n");
int x = 0;
int y = 0;
while (1)
{
x = rand() % row;//x屬于0到2
y = rand() % col;//y屬于0到2
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '#';
break;
}
}
}
char IsWin(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 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 (IsFull(board, ROW, COL))
{
return 'E';
}
else
return 'C';
}
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;//沒找到空格回傳1,平局
}
game.h:
#define _CRT_SECURE_NO_WARNINGS 1
#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);
char IsWin(char board[ROW][COL], int row, int col);
運行結果:

代碼剖析
頭檔案只是一些參考頭檔案和對常量的定義以及函式的宣告,不再解釋,
下面對兩個源檔案中涉及的所有代碼按游戲實作的思考順序開始解釋,注意以下ROW為3,COL為3

為了簡便,主函式中呼叫test_game函式

這里我們先看do while陳述句里面的內容,進入游戲看到的第一個東西肯定是游戲面板啊,不然怎么選擇,所以先列印面板,也就是menu函式,

哈哈哈哈哈這里懶得美化了,可以更好看的,輸入1就是開始游戲,輸入0就是退出游戲(代碼結束) 至于為啥

再看回來,Switch是不是和我們輸入1或者0或者其他數字的結果一一對應,這里我們輸入1,開始進入游戲

現在我們進入游戲了,第一件事是啥,肯定是生成棋盤,不然在哪下啊,我們首先先定義一個二維陣列并將元素全部初始化為0(在后面陣列總結會再次說明)
好了,現在進入初始化棋盤的函式,也就是把每一個元素變成空格

這一步比較簡單,兩個for回圈嵌套遍歷二位陣列,把每一個元素賦值成空格即可
回到game函式

下一步就是列印棋盤,我們要把棋盤列印出來,不然玩家怎么能看到呢?進入該函式

這里每個人有自己美化的風格,我比較喜歡的就是我這種

每一個小格子里面有兩個空格,兩個空格之間夾著對應行、列的元素(因為這里元素也是空格所以不太好分辨,可以去上面看代碼運行結果)
再回到game函式

好了,準備作業做完了,該開始下棋了,注意這里需要放到回圈里面,一直一直到分出勝負或者平局(棋盤滿了),先不看代碼函式怎么實作,我們先剖析底層邏輯,當玩家下完棋以后,我們要列印出現在的棋盤表示玩家下在了哪里,再判斷玩家是否獲勝,如果獲勝了那電腦就不需要下了,如果沒獲勝,那電腦再接著下,同理,也需要判斷是否獲勝,以此回圈,

下面看玩家下棋的代碼

這里輸入x和y,x和y屬于1到3,所以要進行判斷只有輸入的x、y符合標準再下棋,但是我們知道陣列的下標是從0開始的(后面陣列總結會說明),所以外if陳述句內部的if要-1,這里還要進行判斷,如果這個地方沒有棋,也就是x、y所對應元素為空格時再下,這里標記玩家下的棋是*,如果有棋了,就需要重新下,
再來看電腦下棋的邏輯:

這里可以進行優化,但是因為我實在是太菜了,還寫不出來相關的AI演算法,只能隨機生成x和y,這里用到了rand函式(隨機生成數字),需要配合rand函式的定義
![]()
具體如何使用大家可以參考MSDN上的定義
下完棋當然要判斷輸贏,然后再來看判斷輸贏的函式

分別判斷每一行、每一列、兩條對角線的元素是否出現全為*或者#的情況,如果出現則分別回傳*或者#,還有一種情況就是平局,也就是棋盤下滿了,這里再來看如何判斷棋盤滿

這里一樣,遍歷二維陣列,看能不能找到空格,如果能找到就說明沒下完,繼續下,如果下完了就沒找到空格,平局,

這里注意如果平局了IsFull函式就會回傳 1,執行if陳述句,回傳字符E,沒平局就繼續下,IsFull回傳0,執行else陳述句回傳字符C

主要不是繼續下,就一直回圈,直到出現贏家或者平局跳出回圈
然后再分別列印對應結果
至此所有代碼完成
其實發現只要思路清晰,按部就班一步一步來,代碼還是很好理解很好寫出來的,重在耐心與除錯,中了繼續肝博客了,下次整個掃雷,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/354774.html
標籤:其他
上一篇:小游戲系列——低配版三子棋
下一篇:三子棋的實作--二維陣列的應用
