C語(yǔ)言實(shí)現(xiàn)三子棋游戲含完整代碼
?三子棋是大家小時(shí)候和同桌在紙上都玩過(guò)的簡(jiǎn)單小游戲,這個(gè)游戲我們?cè)赾語(yǔ)言中就可以實(shí)現(xiàn)。
在這篇文章我推薦大家使用vs2013,vs2019,vs2022等的編譯器。部分學(xué)校使用的vc6.0以及Devc++。前者是1998年推出的c語(yǔ)言編譯器,在現(xiàn)在的win10或者win11的系統(tǒng)中并不兼容,可能會(huì)出現(xiàn)一些問(wèn)題,后者也在2015年停更,這兩款祖?zhèn)鱟語(yǔ)言編譯器并不推薦使用,但是如果你們學(xué)??荚囆枰褂没蛘哂忻鞔_要求,那當(dāng)我沒(méi)說(shuō)。
首先,我們要先創(chuàng)建一個(gè)項(xiàng)目,常見(jiàn)三個(gè)文件分別是頭文件game.h,源文件game.c,text.c。在這個(gè)game.h的頭文件中我們放入函數(shù)的聲明,定義常量以及頭文件的引用,在text.c文件中我們寫(xiě)入游戲進(jìn)行的程序,在game.c文件中我們寫(xiě)入實(shí)現(xiàn)游戲的函數(shù)。?
一、text.c源文件部分
1、main函數(shù)部分
因?yàn)槲覀兺嬉话延螒蚩隙ú贿^(guò)癮,我們要多玩幾把游戲,我們?cè)趖ext.c文件中的main函數(shù)里寫(xiě)入一個(gè)do while循環(huán)語(yǔ)句,實(shí)現(xiàn)多次進(jìn)行游戲。然后我們?cè)谘h(huán)語(yǔ)句中寫(xiě)入一個(gè)menu函數(shù)用來(lái)打印菜單。然后我們要在鍵盤(pán)上輸入一個(gè)值去判斷是否進(jìn)行游戲,這里使用一個(gè)switch分支。當(dāng)使用者輸入正確的輸入值時(shí)開(kāi)始進(jìn)行游戲。這里使用一個(gè)game函數(shù)實(shí)現(xiàn)游戲流程。
int main()
{
int n = 0;
srand((size_t)time(NULL));
do
{
menu();//打印菜單
printf("請(qǐng)輸入 ");
scanf("%d", &n);
switch (n)
{
case 1:game(); break;
case 0:printf("游戲結(jié)束\n"); break;
default:printf("輸入錯(cuò)誤,請(qǐng)重新輸入!\n"); break;
}
} while (n != 0);
}
main函數(shù)部分
?void menu()
{
printf("******************************************\n");
printf("******** 1.play *********\n");
printf("******** 0.exit *********\n");
printf("******************************************\n");
}
menu函數(shù)部分
2、game函數(shù)部分
在game函數(shù)中我們要實(shí)現(xiàn)游戲的主要流程,首先我們要打印一個(gè)3*3的棋盤(pán),大概是這樣的。

(在這里我們先把游戲的流程捋清楚,至于實(shí)現(xiàn)那些游戲步驟的函數(shù)我們放在后面game源文件部分去細(xì)說(shuō)。)
?因?yàn)槊總€(gè)格子在游戲開(kāi)始的時(shí)候都是空著的狀態(tài),而在玩家與電腦進(jìn)行游戲中是要輸入符號(hào)的,所以我們還要定義一個(gè)char型的二維數(shù)組,并初始化為‘? '。然后就是下棋階段,我們要連續(xù)下很多次棋所以說(shuō)這里使用一個(gè)while循環(huán)語(yǔ)句實(shí)現(xiàn),這里可以寫(xiě)成一個(gè)死循環(huán),當(dāng)后面的函數(shù)判斷到有玩家已經(jīng)勝出或者平局的時(shí)候使用break跳出循環(huán),因?yàn)椴徽撌请娔X還是玩家下棋后,我們要看到下到了哪里,所以說(shuō)我們要在玩家和電腦下棋后面再打印一次棋盤(pán)。每個(gè)人在下完棋之后,我們要判斷是否已經(jīng)勝利所以我們使用條件語(yǔ)句來(lái)判斷是否勝利,失敗或是平局。在配合循環(huán)我們基本游戲流程已經(jīng)寫(xiě)完了。
void game()
{
char board[ROW][COL];//定義一個(gè)二維數(shù)組。
initboard(board, ROW, COL);//初始化數(shù)組。
printboard(board, ROW, COL);//打印棋盤(pán)。
while (1)
{
//玩家下棋
playerboard(board, ROW, COL);
//打印棋盤(pán)
printboard(board, ROW, COL);
//判斷是否勝利
if (iswinboard(board, ROW, COL) == '*')
{
printf("玩家勝利\n");
printf("********** 是否進(jìn)行下一局 **********\n");
printf("\n");
break;
}
else if (iswinboard(board, ROW, COL) == '#')
{
printf("電腦獲勝\n");
printf("********** 是否進(jìn)行下一局 **********\n");
printf("\n");
break;
}
else if (iswinboard(board, ROW, COL) == 'Q')
{
printf("平局\n");
printf("********** 是否進(jìn)行下一局 **********\n");
printf("\n");
break;
}
//電腦下棋
computermove(board, ROW, COL);
//打印棋盤(pán)
printboard(board, ROW, COL);
//判斷是否勝利
if (iswinboard(board, ROW, COL) == '*')
{
printf("玩家勝利\n");
printf("********** 是否進(jìn)行下一局 **********\n");
printf("\n");
break;
}
else if (iswinboard(board, ROW, COL) == '#')
{
printf("電腦獲勝\n");
printf("********** 是否進(jìn)行下一局 **********\n");
printf("\n");
break;
}
else if (iswinboard(board, ROW, COL) == 'Q')
{
printf("平局\n");
printf("********** 是否進(jìn)行下一局 **********\n");
printf("\n");
break;
}
}
}
game函數(shù)部分
二、game.h頭文件部分
#pragma once //在game頭文件里面去聲明函數(shù),定義常量。 #include<stdio.h> #include<stdlib.h> #include<time.h> //定義常量 #define ROW 3//這里通過(guò)更改ROW,COL的值來(lái)改變棋盤(pán)的大小 #define COL 3//可以更改成為n*n的棋盤(pán)。 //函數(shù)聲明 //打印棋盤(pán) void printboard(char board[ROW][COL], int row, int col); //初始化數(shù)組 void initboard(char board[ROW][COL], int row, int col); //玩家下棋//二維數(shù)組進(jìn)行函數(shù)傳參時(shí)可以不用寫(xiě)行數(shù) void playerboard(char board[][COL], int row, int col); //電腦下棋 void computermove(char board[ROW][COL], int row, int col); //判斷是否勝利 char iswinboard(char board[ROW][COL], int row, int col);
game.h部分
三、game.c源文件部分
還記得我們?cè)趖ext.c中使用了哪些函數(shù)嗎?
- 1、我們先要初始化二維數(shù)組
- 2、打印棋盤(pán)
- 3、玩家下棋
- 4、電腦下棋
- 5、判斷勝利
接下來(lái)的game.c文件就是要寫(xiě)入實(shí)現(xiàn)這幾個(gè)步驟的函數(shù)。
首先,初始化數(shù)組非常容易,兩個(gè)for循環(huán)即可。
//初始化數(shù)組元素
void initboard(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
//先對(duì)數(shù)組進(jìn)行賦值,因?yàn)槭莕*n的數(shù)組所以要賦值n*n次
//這里使用兩個(gè)for循環(huán)來(lái)實(shí)現(xiàn)。
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
初始化數(shù)組元素函數(shù)
然后是打印棋盤(pán)函數(shù)。
在打印棋盤(pán)中我們要注意,需要打印一行數(shù)組,一行“---”符號(hào)。在每一行的最后“|”不打印。在最下面一行“---|---|---”不打印,在這里我們只需要去控制for循環(huán)條件即可實(shí)現(xiàn),并不困難。

//打印棋盤(pán)
void printboard(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++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
if (i < row - 1)
{
for (j = 0; j < row; j++)
{
printf("---");
if (j < row - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
然后是玩家下棋函數(shù)
也就是對(duì)數(shù)組進(jìn)行賦值,因?yàn)橥婕也灰欢▽W(xué)過(guò)c語(yǔ)言,也不一定知道c語(yǔ)言中數(shù)組的下標(biāo)是從0開(kāi)始的,所以我們要對(duì)輸入的坐標(biāo)-1之后在進(jìn)行數(shù)組的相關(guān)操作。這里可以寫(xiě)上一個(gè)死循環(huán),當(dāng)玩家下出非法坐標(biāo)時(shí)提醒玩家重新下,當(dāng)玩家下出正確時(shí)再break跳出。
//玩家下棋函數(shù)
void playerboard(char board[][COL], int row, int col)
{
int x = 0, y = 0;
printf("請(qǐng)玩家下棋\n");
while (1)//這里可以寫(xiě)上一個(gè)死循環(huán),當(dāng)玩家下出非法坐標(biāo)時(shí)提醒玩家重新下。
//當(dāng)玩家下出正確時(shí)再break跳出。
{
printf("請(qǐng)輸入坐標(biāo),請(qǐng)用空格隔開(kāi)。 \n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//判斷玩家下棋坐標(biāo)是否正確。
{
if (board[x-1][y-1] == ' ')
{
board[x-1][y-1] = '*';
break;
}
else
{
printf("坐標(biāo)已被占用,請(qǐng)重新輸入!");
}
}
else
{
printf("坐標(biāo)非法,請(qǐng)重新輸入!");
}
}
}
再然后是電腦下棋
相較于玩家下棋電腦下棋就比較容易了,只用使用rand()%3隨機(jī)生成0-2之間的值,再判斷是否已被占用即可。
//電腦下棋
void computermove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("電腦下棋:>\n");
while (1)
{
x= rand() % ROW;//隨機(jī)取值如果放在循環(huán)外面則可能陷入死循環(huán)。
y= rand() % COL;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
最后是判斷是否勝利的函數(shù)
這個(gè)比較長(zhǎng),但是基本就是if條件語(yǔ)句進(jìn)行判斷,分別判斷行、列、對(duì)角線以及平局。如果勝利成立則返回已連成線的其中一個(gè)格中的符號(hào)即可,這樣就不用再麻煩這判斷到底是電腦贏還是玩家贏了。返回到text.c中再進(jìn)行相應(yīng)的輸出。
//判斷是否勝利
char iswinboard(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0, count = 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];
break;
}
}
//判斷列是否勝利
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];
break;
}
}
//判斷對(duì)角線
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];
}
//判斷是否平局
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
count++;
}
}
}
if (count == 0)
{
return 'Q';
}
return 'C';
}
這樣我們的一個(gè)三子棋游戲就寫(xiě)好了。你就可以發(fā)給朋友,或是自己私藏了。(steam是上不了了,自己玩玩算了。)
運(yùn)行

最后全部代碼放在這里
game.h
#pragma once //在game頭文件里面去聲明函數(shù),定義常量。 #include<stdio.h> #include<stdlib.h> #include<time.h> //定義常量 #define ROW 3//這里通過(guò)更改ROW,COL的值來(lái)改變棋盤(pán)的大小 #define COL 3//可以更改成為n*n的棋盤(pán)。 //函數(shù)聲明 //打印棋盤(pán) void printboard(char board[ROW][COL], int row, int col); //初始化數(shù)組 void initboard(char board[ROW][COL], int row, int col); //玩家下棋//二維數(shù)組進(jìn)行函數(shù)傳參時(shí)可以不用寫(xiě)行數(shù) void playerboard(char board[][COL], int row, int col); //電腦下棋 void computermove(char board[ROW][COL], int row, int col); //判斷是否勝利 char iswinboard(char board[ROW][COL], int row, int col);
text.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
printf("******************************************\n");
printf("******** 1.play *********\n");
printf("******** 0.exit *********\n");
printf("******************************************\n");
}
void game()
{
char board[ROW][COL];//定義一個(gè)二維數(shù)組。
initboard(board, ROW, COL);//初始化數(shù)組。
printboard(board, ROW, COL);//打印棋盤(pán)。
while (1)
{
//玩家下棋
playerboard(board, ROW, COL);
//打印棋盤(pán)
printboard(board, ROW, COL);
//判斷是否勝利
if (iswinboard(board, ROW, COL) == '*')
{
printf("玩家勝利\n");
printf("********** 是否進(jìn)行下一局 **********\n");
printf("\n");
break;
}
else if (iswinboard(board, ROW, COL) == '#')
{
printf("電腦獲勝\n");
printf("********** 是否進(jìn)行下一局 **********\n");
printf("\n");
break;
}
else if (iswinboard(board, ROW, COL) == 'Q')
{
printf("平局\n");
printf("********** 是否進(jìn)行下一局 **********\n");
printf("\n");
break;
}
//電腦下棋
computermove(board, ROW, COL);
//打印棋盤(pán)
printboard(board, ROW, COL);
//判斷是否勝利
if (iswinboard(board, ROW, COL) == '*')
{
printf("玩家勝利\n");
printf("********** 是否進(jìn)行下一局 **********\n");
printf("\n");
break;
}
else if (iswinboard(board, ROW, COL) == '#')
{
printf("電腦獲勝\n");
printf("********** 是否進(jìn)行下一局 **********\n");
printf("\n");
break;
}
else if (iswinboard(board, ROW, COL) == 'Q')
{
printf("平局\n");
printf("********** 是否進(jìn)行下一局 **********\n");
printf("\n");
break;
}
}
}
int main()
{
int n = 0;
srand((size_t)time(NULL));
do
{
menu();//打印菜單
printf("請(qǐng)輸入 ");
scanf("%d", &n);
switch (n)
{
case 1:game(); break;
case 0:printf("游戲結(jié)束\n"); break;
default:printf("輸入錯(cuò)誤,請(qǐng)重新輸入!\n"); break;
}
} while (n != 0);
}
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
//初始化數(shù)組元素
void initboard(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0;
//先對(duì)數(shù)組進(jìn)行賦值,因?yàn)槭莕*n的數(shù)組所以要賦值n*n次
//這里使用兩個(gè)for循環(huán)來(lái)實(shí)現(xiàn)。
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
//打印棋盤(pán)
void printboard(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++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
if (i < row - 1)
{
for (j = 0; j < row; j++)
{
printf("---");
if (j < row - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
//玩家下棋函數(shù)
void playerboard(char board[][COL], int row, int col)
{
int x = 0, y = 0;
printf("請(qǐng)玩家下棋\n");
while (1)//這里可以寫(xiě)上一個(gè)死循環(huán),當(dāng)玩家下出非法坐標(biāo)時(shí)提醒玩家重新下。
//當(dāng)玩家下出正確時(shí)再break跳出。
{
printf("請(qǐng)輸入坐標(biāo),請(qǐng)用空格隔開(kāi)。 \n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)//判斷玩家下棋坐標(biāo)是否正確。
{
if (board[x-1][y-1] == ' ')
{
board[x-1][y-1] = '*';
break;
}
else
{
printf("坐標(biāo)已被占用,請(qǐng)重新輸入!");
}
}
else
{
printf("坐標(biāo)非法,請(qǐng)重新輸入!");
}
}
}
//電腦下棋
void computermove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("電腦下棋:>\n");
while (1)
{
x= rand() % ROW;//隨機(jī)取值如果放在循環(huán)外面則可能陷入死循環(huán)。
y= rand() % COL;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//判斷是否勝利
char iswinboard(char board[ROW][COL], int row, int col)
{
int i = 0, j = 0, count = 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];
break;
}
}
//判斷列是否勝利
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];
break;
}
}
//判斷對(duì)角線
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];
}
//判斷是否平局
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
count++;
}
}
}
if (count == 0)
{
return 'Q';
}
return 'C';
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C++實(shí)現(xiàn)LeetCode(41.首個(gè)缺失的正數(shù))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(41.首個(gè)缺失的正數(shù)),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
c++只保留float型的小數(shù)點(diǎn)后兩位問(wèn)題
這篇文章主要介紹了c++只保留float型的小數(shù)點(diǎn)后兩位問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
C++中實(shí)現(xiàn)矩陣的加法和乘法實(shí)例
這篇文章主要介紹了C++中實(shí)現(xiàn)矩陣的加法和乘法實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-03-03
OpenCV鼠標(biāo)繪制矩形和截取矩形區(qū)域圖像
這篇文章主要為大家詳細(xì)介紹了OpenCV鼠標(biāo)繪制矩形和截取矩形區(qū)域圖像,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
win32下進(jìn)程間通信(共享內(nèi)存)實(shí)例分析
這篇文章主要介紹了win32下進(jìn)程間通信(共享內(nèi)存)實(shí)例分析,對(duì)win32應(yīng)用程序及進(jìn)程的原理做了較為深入的剖析,需要的朋友可以參考下2014-07-07
詳解C語(yǔ)言中strcpy函數(shù)與memcpy函數(shù)的區(qū)別與實(shí)現(xiàn)
這篇文章主要介紹了C語(yǔ)言中字符串拷貝函數(shù)(strcpy)與內(nèi)存拷貝函數(shù)(memcpy)的不同及內(nèi)存拷貝函數(shù)的模擬實(shí)現(xiàn),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-12-12
Qt基礎(chǔ)開(kāi)發(fā)之Qt多線程類QThread與Qt定時(shí)器類QTimer的詳細(xì)方法與實(shí)例
這篇文章主要介紹了Qt基礎(chǔ)開(kāi)發(fā)之Qt多線程類QThread與Qt定時(shí)器類QTimer的詳細(xì)方法與實(shí)例,需要的朋友可以參考下2020-03-03

