相信大家或多或少都聽說過五子棋,三子棋也是類似,即達(dá)成每行或每列中有三顆連續(xù)棋子,亦或是在對角線上有三顆連續(xù)的棋子即為勝利。今天,我們就來實(shí)現(xiàn)一下。
目前創(chuàng)新互聯(lián)建站已為1000多家的企業(yè)提供了網(wǎng)站建設(shè)、域名、虛擬主機(jī)、成都網(wǎng)站托管、企業(yè)網(wǎng)站設(shè)計(jì)、安岳網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。目錄
一、文件的準(zhǔn)備
二、功能的實(shí)現(xiàn)
1.菜單與用戶的選擇
2.游戲的函數(shù)
3.棋盤的初始化
4.打印棋盤
5.下棋->玩家下棋
6.下棋->電腦下棋
7.判斷結(jié)果
a.當(dāng)一行中三個(gè)相等時(shí)
b.當(dāng)一列中三個(gè)相等時(shí)
c.當(dāng)對角線上相等時(shí)
d.判斷平局
8.程序補(bǔ)全
為了后期代碼的封裝,我們將測試代碼,函數(shù)代碼和函數(shù)的聲明分開存放到不同的文件中。如下:
test.c????????——??????? 用于存放測試游戲功能實(shí)現(xiàn)的代碼
game.c???? ——??????? 用于存放游戲相關(guān)的函數(shù)的具體內(nèi)容
game.h??? ? ——??????? 用于存放游戲中功能函數(shù)的聲明以及相關(guān)類型的定義
為了便于區(qū)分,將在后文的代碼演示處首行以注釋方式寫明所屬文件。
二、功能的實(shí)現(xiàn) ??????? 1.菜單與用戶的選擇市面上的游戲的選項(xiàng)有很多,我們只完成最基礎(chǔ)的玩游戲和退出。
我們創(chuàng)建無返回值的menu作為菜單,由于只用來測試,寫在test.c中。
// test.c
void menu()
{
printf("****************\n");
printf("**** 1.play ****\n");
printf("**** 0.exit ***\n");
printf("****************\n");
}
為了使用戶有較好的游戲體驗(yàn),我們使用循環(huán)來判斷,只有當(dāng)用戶選擇退出游戲才會(huì)退出,選擇的不是玩游戲或者退出就提示錯(cuò)誤并重新輸入。
// test.c
int main()
{
int input = 0;
do
{
menu();
printf("請選擇:>");
scanf("%d", &input);
switch (input)
{
case 1:
Game();
break;
case 0:
printf(*"退出游戲\n");
break;
default:
printf("選擇錯(cuò)誤,請重新選擇\n");
break;
}
} while (input);
return 0;
}
2.游戲的函數(shù)當(dāng)用戶輸入1選擇進(jìn)入游戲后,就需要進(jìn)入具體的游戲程序中,我們在play的選項(xiàng)后創(chuàng)建Game函數(shù)用來存放游戲代碼。Game的使用在上文的代碼段中已有體現(xiàn),接下來只講聲明與定義。
我們將Game函數(shù)也存放在test.c中,基礎(chǔ)代碼如下:
// test.c
void Game()
{
char board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL);
PrintBoard(board, ROW, COL);
...
}
下棋,必不可少的就是棋盤。
我們創(chuàng)建一個(gè)二維數(shù)組來存放棋盤,棋盤的大小就設(shè)定為3X3,在二維數(shù)組中即為每行3個(gè)元素,共3行。
為了方便后期代碼的維護(hù),我們使用#define自定義行和列,并存放在我們編寫的game.h中,方便調(diào)用。
// game.h
#include#include#include#include#define ROW 3
#define COL3
為了方便,已經(jīng)后文需要引用的頭文件一起添加,后文有關(guān)內(nèi)容將僅做提示。
特別注意:由于自定義類型在別的文件中需要引用,也為了減少代碼內(nèi)容,另外兩個(gè).c需要引用頭文件game.h,如下:
// test.c game.c
#include "game.h"
創(chuàng)建字符類型二維數(shù)組board作為棋盤,行和列分別使用已定義的ROW和COL,Game函數(shù)中已有體現(xiàn)。
3.棋盤的初始化在開始下棋之前,需要先清理棋盤,程序中也是一樣,我們需要對棋盤進(jìn)行初始化,創(chuàng)建InitBoard用于實(shí)現(xiàn)初始化。
由于自此之后絕大部分函數(shù)都涉及到具體的游戲內(nèi)功能,故函數(shù)的使用均在Game函數(shù)中,有使用方式特別的會(huì)單獨(dú)指出;函數(shù)的聲明存放到頭文件game.h中;函數(shù)的具體內(nèi)容存放到game.c中,在此僅作演示,之后的聲明和定義將省略。
聲明:
// game.h
void InitBoard(char board[ROW][COL], int row, int col);
定義:
// game.c
void InitBoard(char board[ROW][COL], int row, int col)
{
;
}
具體的內(nèi)容在之后會(huì)有體現(xiàn)。
我們將棋盤上的落棋點(diǎn),也就是二維數(shù)組中的元素初始化為空格字符,即' ',可以使用嵌套的for循環(huán)來實(shí)現(xiàn),具體如下:
// game.c
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] = ' ';
}
}
}
4.打印棋盤在下棋之前,必須要能看到棋盤的內(nèi)容,所以在初始化后就需要打印出來,方便觀察。
都初始化為空格,直接打印肯定不方便觀察,而且下棋也需要使用其他符號(hào)作為每個(gè)格子的分界,我們使用“-”和”|“作為分界,且分隔符與單元格并不是一一對應(yīng),而是只在兩個(gè)各自之間才需要分割,所以循環(huán)的條件就是行數(shù)/列數(shù) 減去1,這里類似于數(shù)組元素和下標(biāo)的關(guān)系。
代碼如下:
// contact.c
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
打印出來的棋盤樣式如圖:
5.下棋->玩家下棋我們創(chuàng)建PlayMove函數(shù)用作玩家下棋,并將玩家可以出的棋子定義為'*':
給出玩家下棋的提示,使用printf打印。
在二維數(shù)組中行和列的下標(biāo)均是從0開始,但是玩家并不一定知道下標(biāo)這個(gè)概念,進(jìn)而輸入為從1開始的任意數(shù)值,我們就需要判斷輸入玩家輸入的坐標(biāo)是否在現(xiàn)有的棋盤內(nèi),使用if判斷,由于有多個(gè)條件,我們使用C語言邏輯運(yùn)算符中的與&&連接判斷條件。
程序設(shè)計(jì)為人機(jī)對戰(zhàn),當(dāng)用戶輸入的坐標(biāo)是處于棋盤上的時(shí)候,我們還需要對所輸入的坐標(biāo)是否已有用戶或者電腦使用過此坐標(biāo)。若為我們初始化的' '就是沒有被使用過,就將'*'置入該坐標(biāo)中。代碼如下:
// game.c
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家走:>\n");
while (1)
{
printf("請輸入下棋的坐標(biāo):>");
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("坐標(biāo)已被占用, 請重新輸入\n");
}
}
else
{
printf("坐標(biāo)非法, 請重新輸入\n");
}
}
}
6.下棋->電腦下棋我們創(chuàng)建ComMove函數(shù)來表示電腦下棋,使用'#'作為電腦所下的棋子:
電腦下棋無法像玩家一樣輸入自己要下的,我們需要使用隨機(jī)數(shù)來獲取行和列。
C語言中,一般使用rand()函數(shù)來生成隨機(jī)數(shù),但隨機(jī)數(shù)的范圍太大,且多次連續(xù)運(yùn)行時(shí)產(chǎn)生的結(jié)果相近或?yàn)榻y(tǒng)一結(jié)果,不適用于直接生成想要的隨機(jī)數(shù)。
我們使用srand()函數(shù)對隨機(jī)范圍進(jìn)行指定,在srand中則使用time函數(shù)獲取每時(shí)每刻都在變化的時(shí)間(精確到秒)。
用獲取得到的隨機(jī)數(shù)在求與行/列的模,求出的隨機(jī)數(shù)即在二維數(shù)組的范圍內(nèi),只需判斷所隨機(jī)得到的坐標(biāo)是否有棋子即可,為空表示可以將棋子落下,有內(nèi)容則重新進(jìn)行隨機(jī)。
關(guān)于time函數(shù)僅作使用,不做過多描述,可自行查閱。
srand即為以下內(nèi)容:
// test.c
srand((unsigned int)time(NULL));
rand函數(shù)需要引用頭文件
函數(shù)內(nèi)容如下:
// game.c
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("電腦走:>\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
7.判斷結(jié)果是比賽就有勝利、失敗以及平局。
三子棋中當(dāng)一方棋子連成三點(diǎn)一線(包括對角線)時(shí),即為勝利,另一方失??;
當(dāng)棋盤下滿仍無三顆同一方棋子連線時(shí),即為平局
我們創(chuàng)建IsFull函數(shù)用來判斷期盼是否已滿,并返回1或0作為滿或未滿。
只需要對二維數(shù)組進(jìn)行遍歷,逐個(gè)判斷是否為' ',即可確定棋盤是否已滿。
如下:
// game.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;
}
然后就是判斷棋盤上的棋子是否有一方滿足勝利條件,創(chuàng)建IsWin函數(shù)來進(jìn)行判斷
a.當(dāng)一行中三個(gè)相等時(shí)使用for循環(huán)判斷當(dāng)棋盤中行數(shù)不變時(shí),每一列的格子內(nèi)的棋子都相同且不為空時(shí),就返回相同的那種棋子;
b.當(dāng)一列中三個(gè)相等時(shí)與上一種判定方法類似,不同之處在于列不變,每一行相同且不為空,返回相同的棋子
c.當(dāng)對角線上相等時(shí)對角線相同有兩種情況,一種是從左上到右下,即[0][0],[1][1],[2][2]相同且不為空;另一種是從右上到左下,即[0][2],[1][1],[2][0]相同且不為空。兩種情況滿足一種即返回相同的棋子。這里同樣使用邏輯或&&對判斷條件進(jìn)行連接
d.判斷平局在創(chuàng)建判斷棋盤是否已滿的函數(shù)時(shí),我們定義為了int類型,設(shè)定了返回值為0或1,在IsWin中,我們創(chuàng)建變量ret對IsFull的結(jié)果進(jìn)行判斷,若為1(表示棋盤已滿)就返回'D',表示平局;若為0(棋盤未滿)就返回'N'
函數(shù)代碼如下:
// game.c
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][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];
}
int ret = IsFull(board, row, col);
if (ret == 1)
{
return 'D';
}
return 'N';
}
8.程序補(bǔ)全函數(shù)的功能和定義已經(jīng)完成,接下來回到測試文件對邏輯進(jìn)行補(bǔ)全。
下棋需要多次的玩家和電腦進(jìn)行落子,故使用while循環(huán)進(jìn)行輪流下棋,逐步顯示當(dāng)前棋盤的內(nèi)容并判斷是否滿足勝利或者平局,有一方勝利或者棋盤已滿便退出循環(huán),不再落子。
然后就可以對返回值進(jìn)行判斷:
?????如果返回的是表示玩家的棋子'*',就輸出玩家勝利并打印棋盤;
???? 如果返回的是表示電腦的棋子'#',就打印電腦勝利并打印棋盤;
?????若返回其他內(nèi)容則表示棋盤已滿,打印平局并打印棋盤。
代碼如下:
// test.c
void Game()
{
// 一個(gè)存放棋盤的3x3的二維數(shù)組
char board[ROW][COL] = { 0 };
// 初始化棋盤
InitBoard(board, ROW, COL);
// 打印棋盤
PrintBoard(board, ROW, COL);
char ret = 0;
while (1)
{
//玩家下棋
PlayerMove(board, ROW, COL);
PrintBoard(board, ROW, COL);
//判斷玩家是否贏得游戲
ret = IsWin(board, ROW, COL);
if (ret != 'N')
break;
//電腦下棋
ComMove(board, ROW, COL);
PrintBoard(board, ROW, COL);
//判斷電腦是否贏得游戲
ret = IsWin(board, ROW, COL);
if (ret != 'N')
break;
}
if (ret == '*')
{
printf("玩家贏了\n");
}
else if (ret == '#')
{
printf("電腦贏了\n");
}
else
{
printf("平局\n");
}
PrintBoard(board, ROW, COL);
}
至此,簡單的三子棋游戲已經(jīng)完成,具體的代碼文件已上傳,可點(diǎn)擊下方鏈接進(jìn)行查看:
GitCode-shiwuqing-game1
Gitee-shiwuqing-game1
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
文章題目:C語言----小游戲三子棋-創(chuàng)新互聯(lián)
網(wǎng)址分享:http://aaarwkj.com/article42/ddddhc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化、企業(yè)網(wǎng)站制作、營銷型網(wǎng)站建設(shè)、微信公眾號(hào)、微信小程序、網(wǎng)站營銷
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容