用C語言實現(xiàn)三子棋游戲
本文實例為大家分享了C語言實現(xiàn)三子棋游戲的具體代碼,供大家參考,具體內(nèi)容如下
初始工作,通過#define 定義一個標識符來表示一個常量(棋盤的橫縱坐標)
(因為在代碼的編寫中,會有多處需要用到坐標。那么,在閱讀代碼時就可能會導(dǎo)致讀者疲于理解當前的值到底是代表什么,即會對代碼的解讀造成困擾。所以,在該代碼中通過使用宏定義解決了這個問題,同時也方便后續(xù)更改棋盤的大小。)
#define MAX_ROW 3 #define MAX_COL 3
游戲創(chuàng)建流程
1. 創(chuàng)建棋盤
創(chuàng)建棋盤(二維數(shù)組),并將其初始化(空白,無子狀態(tài))。
//1. 棋盤初始化
void init(char chessBoard[MAX_ROW][MAX_COL]) {
for (int row = 0; row < MAX_ROW; row++) {
for (int col = 0; col < MAX_COL; col++) {
//將這個棋盤(二維數(shù)組)每個位置都初始化為空
chessBoard[row][col] = ' ';
}
}
}
2. 打印棋盤
打印棋盤,令玩家能夠看到此時棋盤的狀態(tài)。
//2. 打印棋盤
void printChessBoard(char chessBoard[MAX_ROW][MAX_COL]) {
printf("+---+---+---+\n");
for(int row = 0; row < MAX_ROW; row++) {
printf("|");
for (int col = 0; col < MAX_COL; col++) {
printf(" %c |", chessBoard[row][col]);
}
printf("\n+---+---+---+\n");
}
}
3. 玩家落子
玩家將通過輸入坐標(row, col)落子。
注意:在玩家選擇坐標后需要做合法性檢驗,即判斷玩家落子的位置是否已經(jīng)有子,如果有,則玩家需要重新輸入坐標落子。
//3. 玩家落子
void playMove(char chessBoard[MAX_ROW][MAX_COL]) {
while (1) {
int row = 0, col = 0;
printf("請玩家通過輸入坐標落子:");
scanf("%d %d", &row, &col);
//檢驗玩家是否輸入錯誤
if (row < 0 || col < 0 || row >= MAX_ROW || col >= MAX_COL) {
printf("輸入錯誤!請重新輸入");
continue;
}
// 檢驗玩家輸入的位置 是否已經(jīng)有子(判斷位置是否為空,不為空即有子)
else if (chessBoard[row][col] != ' ') {
printf("該位置已經(jīng)有子,請重新輸入");
continue;
}
else {
//沒問題,落子,標記為'x',并退出當前循環(huán)
chessBoard[row][col] = 'x';
break;
}
}
}
4. 判定此時勝負情況
4.1 判斷當前勝負情況,有四種獲勝的方式:
1)橫著3個都是一樣的字符;
2)豎著3個都是一樣的字符;
3)1,3象限對角線的3個位置都是一樣的字符;
4)2,4象限對角線的3個位置都是一樣的字符。
//4. 判定勝負情況,檢查棋盤的所有位置,是否符合勝利的4種情況
//玩家獲勝,返回x; 電腦獲勝,返回o; 和棋返回p;
char chessWin(char chessBoard[MAX_ROW][MAX_COL]) {
//判斷橫著的3個位置
for (int row = 0; row < MAX_ROW; row++) {
if (chessBoard[row][0] != ' ' && chessBoard[row][0] == chessBoard[row][1] && chessBoard[row][0] == chessBoard[row][2]) {
return chessBoard[row][0];
}
}
//判斷豎著的3個位置
for (int col = 0; col < MAX_COL; col++) {
if(chessBoard[0][col] != ' ' && chessBoard[0][col] == chessBoard[1][col] && chessBoard[0][col] == chessBoard[2][col] ){
return chessBoard[0][col];
}
}
//判斷2,4象限對角線的3個位置
if (chessBoard[0][0] != ' ' && chessBoard[0][0] == chessBoard[1][1] && chessBoard[0][0] == chessBoard[2][2]) {
return chessBoard[0][0];
}
//判斷1,3象限對角線的3個位置
if (chessBoard[2][0] != ' ' && chessBoard[2][0] == chessBoard[1][1] && chessBoard[2][0] == chessBoard[0][2]) {
return chessBoard[2][0];
}
if (isFull(chessBoard)) {
return 'p';
}
return ' ';
}
4.2 勝負情況判斷后有4種情況,分別是:
1)玩家獲勝,返回 ‘x' ;
2)電腦獲勝,返回 ‘o' ;
3)和棋,棋盤下滿了,但是沒有分出勝負,返回 ‘p' ;
4)棋盤還有位置是空著的,下棋繼續(xù),返回 ‘ ' ;
我們在主函數(shù)中定義一個字符變量,用來判斷程序結(jié)束返回的是什么,繼而判斷是玩家獲勝、電腦獲勝、和棋還是游戲未結(jié)束。
根據(jù)字符型變量的值得知游戲的結(jié)果(具體過程如后主函數(shù)內(nèi)容所示)。
4.3 判斷是否和棋的函數(shù)為:
//4.3 判斷是否和棋(棋盤滿了,但未分勝負),返回1表示棋盤滿了,返回0表示棋盤未滿
int isFull(char chessBoard[MAX_ROW][MAX_COL]) {
for (int row = 0; row < MAX_ROW; row++) {
for (int col = 0; col < MAX_COL; col++) {
if (chessBoard[row][col] == ' ') {
return 0;
}
}
}
return 1;
}
5. 電腦落子(電腦隨機落子)
通過 rand() 函數(shù)實現(xiàn)電腦的隨機落子。
(取余運算是很好的截短方法,在這里,我們通過取余運算將橫縱坐標的值控制在了[0,2]之間。)
//5. 電腦落子(隨機)
void computerPlayMove(char chessBoard[MAX_ROW][MAX_COL]) {
while (1) {
//控制落子的坐標 x,y 在[0,2]之間
int row = rand() % MAX_ROW;
int col = rand() % MAX_COL;
//判斷電腦想落子的位置是否為空(即是否已經(jīng)有子),如若已經(jīng)有子,繼續(xù)循環(huán)
if (chessBoard[row][col] != ' ') {
continue;
}
//如果電腦想落子的位置為空,則將 ‘o' 賦給該位置,并結(jié)束循環(huán)
chessBoard[row][col] = 'o';
break;
}
}
6. 判定此時勝負情況
同過程4。
7. 主函數(shù)
注意,我們將 字符型二維數(shù)組棋盤 寫在了主函數(shù)中,而非整個程序的開頭。
原因是:如果寫在開頭,那么這個變量就是全局變量了。
全局變量的生命周期是整個程序,會占用更多的內(nèi)存,而且如果在程序中間已經(jīng)使用完畢這個變量,也是不能釋放內(nèi)存的。
此外,全局變量的作用域是整個工程。如果在哪里將它改動后,整體都會受到影響,在查問題出在哪里的時候會很麻煩。
所以,本著盡量不使用全局變量的原則,將這個變量寫在了主函數(shù)中。當其他函數(shù)需要這個參數(shù)的時候,再進行傳參使用即可。
int main() {
char chessBoard[MAX_ROW][MAX_COL];
char winner = ' ';
//1. 棋盤初始化
init(chessBoard);
while (1) {
//2. 打印棋盤,令玩家觀察此時棋盤的狀態(tài)
printChessBoard(chessBoard);
//3. 玩家落子
playMove(chessBoard);
//4. 判斷勝負情況
winner = chessWin(chessBoard);
if (winner != ' ') {
//已經(jīng)有非空返回值,游戲結(jié)束
break;
}
//5. 電腦落子
computerPlayMove(chessBoard);
//4. 判斷勝負情況
winner = chessWin(chessBoard);
if (winner != ' ') {
//已經(jīng)有非空返回值,游戲結(jié)束
break;
}
}
if (winner == 'x') {
printChessBoard(chessBoard);
printf("恭喜玩家獲勝!");
}
else if (winner == 'o') {
printChessBoard(chessBoard);
printf("惜敗,電腦獲勝了哦~");
}
else {
printChessBoard(chessBoard);
printf("哎呀,你和電腦打成平手了呢~");
}
system("pause");
return 0;
}
以上就是我在寫三子棋游戲的思路、代碼以及一些需要注意的點。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C++面試題之結(jié)構(gòu)體內(nèi)存對齊計算問題總結(jié)大全
這篇文章主要給大家總結(jié)了關(guān)于C++面試題中結(jié)構(gòu)體內(nèi)存對齊計算問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細,通過這些介紹的內(nèi)容對大家在面試C++工作的時候,會有一定的參考幫助,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-08-08
C語言枚舉(enum)和聯(lián)合(union)實例分享
在本篇文章里小編給大家整理了關(guān)于C語言枚舉(enum)和聯(lián)合(union)實例內(nèi)容,需要的朋友們可以學(xué)習(xí)下。2020-03-03
c語言數(shù)據(jù)結(jié)構(gòu)之并查集 總結(jié)
一種用于管理分組的數(shù)據(jù)結(jié)構(gòu)。它具備兩個操作:(1)查詢元素a和元素b是否為同一組 (2) 將元素a和b合并為同一組,需要的朋友可以參考下2018-08-08
C語言實現(xiàn)求解素數(shù)的N種方法總結(jié)
哈嘍各位友友們,今天又學(xué)到了很多有趣的知識,現(xiàn)在迫不及待的想和大家分享一下!本文將手把手帶領(lǐng)大家探討利用試除法、篩選法求解素數(shù)的n層境界!都是精華內(nèi)容,可不要錯過喲2023-01-01

