您好,登錄后才能下訂單哦!
這篇文章主要介紹了C語言怎么實現三子棋的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇C語言怎么實現三子棋文章都會有所收獲,下面我們一起來看看吧。
三子棋是黑白棋的一種。三子棋是一種民間傳統游戲,又叫九宮棋、圈圈叉叉、一條龍、井字棋等。將正方形對角線連起來,相對兩邊依次擺上三個雙方棋子,只要將自己的三個棋子走成一條線,對方就算輸了。但是,有很多時候會出現和棋的情況。
通過觀察上圖,三子棋是下在一個井字形或者九宮格的棋盤內的。因此,我們可以先從打印一個棋盤入手開始編寫程序。為了方便起見,我們規定輸出下面這樣的九宮格棋盤。
參照三子棋的下棋規則,制定初步的編程思路:
1、在玩游戲開始前輸出一些符號和文字,讓界面更加有儀式感,例如:
printf("*********************\n"); printf("*****1. 開始游戲*****\n"); printf("*****0. 退出游戲*****\n"); printf("*********************\n");
2、提示玩家選擇:
輸入1代表玩游戲
輸入0代表退出游戲
輸入其他,提示輸入錯誤,需要玩家重新輸入
3、下棋開始前先初始化棋盤,在打印出棋盤
4、玩家下棋后,再次打印出棋盤
5、電腦下棋后,再次打印出棋盤
6,如此循環往復幾步后,判斷贏家是誰,下棋結束
7、玩家可選擇繼續玩還是退出程序
我們首先搭建程序框架,讓程序能夠跑起來,再接著修改程序,實現基本功能。
因為游戲是多次進行的,選擇do-while循環結構,編寫程序主題結構。
void menu() {//輸出提示字符 printf("*********************\n"); printf("*****1. 開始游戲*****\n"); printf("*****0. 退出游戲*****\n"); printf("*********************\n"); } void play() {//玩游戲的代碼 printf("玩家選擇玩游戲!\n"); } int main() {//利用do-while循環,寫成主體結構 int input = 0; do { menu();//輸出提示信息 printf("請選擇1或者0==> ");//1代表玩,0代表退出游戲 scanf("%d", &input);//玩家輸入 switch (input) {//通過分支結構,決定輸入是什么 case 1://玩游戲 play();//調用玩游戲的函數 break; case 0://退出游戲 printf("退出游戲!\n"); break; default://重新輸入 printf("輸入錯誤,請重新輸入1或0 \n"); break; }//先進入循環輸出提示信息,當輸入1時,滿足循環條件,接著執行循環里面的程序,也就是玩游戲 //當輸入0時,不滿足循環條件,也就是退出游戲 //使用do-while循環符合邏輯 } while (input); return 0; }
運行程序,分別輸入1 2 0,輸出結果如下所示,達到了預期的界面效果:
輸入1代表玩游戲
輸入其他,提示輸入錯誤,需要玩家重新輸入
輸入0代表退出游戲
上面一小節的代碼搭建了程序的框架,能實現程序的基礎功能,我們接著進一步play函數中添加代碼,完善玩游戲的功能
由于代碼較多,將采用模塊化編程,這一使代碼可讀性更高一點。將不同功能的函數實現放在不同的源文件中。
將函數main 、test、menu、play放入源文件test.c中,這里只是初步規劃,代碼會隨著實現功能慢慢增加。
//后續將會逐步添加,不表明只有這些 #include "play.h"//頭文件必須添加,printf等函數正常工作 void menu() {//輸出提示字符 printf("*********************\n"); printf("*****1. 開始游戲*****\n"); printf("*****0. 退出游戲*****\n"); printf("*********************\n"); } void play() {//玩游戲的具體實現代碼 printf("玩家選擇玩游戲!\n"); //存放下棋的數據 char board[ROW][COL] = { 0 }; //初始化棋盤為全空格 InitBoard(board, ROW, COL); } void test() {//游戲界面代碼 int input = 0; do { menu(); printf("請選擇1或者0==> "); scanf("%d", &input); switch (input) { case 1: play(); break; case 0: printf("退出游戲!\n"); break; default: printf("輸入錯誤,請重新輸入1或0 \n"); break; } } while (input); } int main() { test(); return 0; }
將函數初始化棋盤、打印棋盤、玩家下棋,等等放入源文件play.c,這里只是初步規劃,代碼會隨著實現功能慢慢增加。
//后續將會逐步添加,不表明只有這些 #include "play.h"//頭文件必須添加,包含stdio.h,使printf等函數正常工作 //初始化棋盤 void InitBoard(char board[ROW][COL], int row, int col) { } //打印棋盤 void DisplayBoard(char board[ROW][COL], int row, int col) { } //玩家下棋 void PlayMover(char board[ROW][COL], int row, int col) { } //電腦下棋 void ComputerMove(char board[ROW][COL], int row, int col) { }
將宏定義,函數聲明放在這個頭文件件play.h,這里只是初步規劃,代碼會隨著實現功能慢慢增加。
//后續將會逐步添加,不表明只有這些 #include<stdio.h>//添加頭文件 #define ROW 3//棋盤行數 #define COL 3//棋盤列數 void play(); //初始化棋盤 void InitBoard(char board[ROW][COL], int row, int col); //打印棋盤 void DisplayBoard(char board[ROW][COL], int row, int col); //玩家下棋 void PlayMover(char board[ROW][COL], int row, int col); //電腦下棋 void ComputerMove(char board[ROW][COL], int row, int col);
在玩家下棋前,需要完成兩件事情
使用函數 InitBoard: 初始化棋盤,用空格初始化
使用函數 DisplayBoard: 將棋盤打印出來。
//test.c void play() { printf("玩家選擇玩游戲!\n"); //存放下棋的數據 ROW代表棋盤行數,COL代表棋盤列數 char board[ROW][COL] = { 0 }; //初始化棋盤為全空格 InitBoard(board, ROW, COL); //展示棋盤,打印 DisplayBoard(board, ROW, COL); } //play.c void InitBoard(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++) { board[i][j] = ' ';//賦值空格,進行格式化 } } } //第一稿 void DisplayBoard(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]);//都是空格看不見 } printf("\n"); } }
運行結果顯示,函數InitBoard使用空格完成初始化,但是空格直接打印都是空白,看不見,因此需要修改打印函數DisplayBoard
2.3.1.1 打印函數DisplayBoard——修改1
//第二稿 void DisplayBoard(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]); //打印分隔符 printf("---|---|---\n"); }ruxiat }
打印結果如上圖,基本上是一個九宮格棋盤了。但是第三行的字符是多余的,需要再次修改。
2.3.1.2 打印函數DisplayBoard——修改2
//第三稿 void DisplayBoard(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) {//但是這里有問題,每行的輸出是固定的3個,當行列改變時,這里就不能用了 printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]); //打印分隔符 if(i<ROW-1)//第三行不打印 printf("---|---|---\n"); } }
運行結果如上所示。但是上面的代碼也存在問題,每行字符輸出是固定的3個,當行列改變時,這里就會出問題。
printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
將棋盤的行數、列數改為10 ,運行結果如下:
因此,這行代碼需要修改。
2.3.1.3 打印函數DisplayBoard——修改3
//第四稿 void DisplayBoard(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { for (int j = 0; j < col; j++) {//將這里改為自動化輸出 printf(" %c ", board[i][j]); printf("|"); } printf("\n"); //打印分隔符 if (i < row - 1)//第三行不打印 printf("---|---|---\n"); } }
上圖為顯示結果,第三列有問題,對代碼進行修改。
2.3.1.4 打印函數DisplayBoard——修改4
//第五稿 void DisplayBoard(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { for (int j = 0; j < col; j++) { printf(" %c ", board[i][j]); if(j<col-1)第三列不打印 printf("|"); } printf("\n"); //打印分隔符 if (i < row - 1)//第三行不打印 printf("---|---|---\n");//這里也有問題,寫成固定的 } }
上面是運行結果,**程序代碼也存在問題,同前面一樣,輸出的字符是固定的,**因此再次修改代碼。
printf("---|---|---\n");//這里也有問題,寫成固定的
2.3.1.5 打印函數DisplayBoard——修改5
//第六稿,至此改完 void DisplayBoard(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { for (int j = 0; j < col; j++) { printf(" %c ", board[i][j]); if (j < col - 1)第三列不打印 printf("|"); } printf("\n");//每一行打完就換行 //打印分隔符 if (i < row - 1)//第三行不打印 { for (int j = 0; j < col; j++) {//此時可以測試10行10列了 printf("---");//純粹的符號打印,沒有輸入的字符 if (j < col - 1)//第三列不打印 printf("|"); } printf("\n");//每一行打完就換行 } } }
運行結果如上圖。將棋盤行數、列數改為10,再次運行,結果見下圖,由此,打印函數DisplayBoard修改結束,符合使用要求了。
在初始化并打印棋盤后,接著就要邀請玩家下棋了,下完后也要打印出棋盤。在函數 paly 里添加 PlayMover 和 DisplayBoard。
void play() { printf("玩家選擇玩游戲!\n"); //存放下棋的數據 char board[ROW][COL] = { 0 }; //初始化棋盤為全空格 InitBoard(board, ROW, COL); //展示棋盤,打印 DisplayBoard(board, ROW, COL); //玩家下棋 PlayMover(board, ROW, COL); //展示棋盤,打印 DisplayBoard(board, ROW, COL); }
玩家下棋函數 PlayMover,根據玩家輸入的坐標信息,在對應的位置輸入*,代表落下棋子。
void PlayMover(char board[ROW][COL], int row, int col) { int x = 0; int y = 0; printf("游戲已開始,請玩家下棋\n"); while (1) { printf("請輸入落棋子位置 ==> "); scanf("%d %d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col) {//玩家的角度,行列都是1開始的 //下棋 if (board[x - 1][y - 1] == ' ')//數組角度,代碼要減1 {//落棋位置,就是前面打印棋盤 %c 的位置 board[x - 1][y - 1] = '*';//輸入字符,代表落下棋子 break; } else { printf("該位置已有棋子,請重新選擇落子位置\n"); } } else { printf("坐標非法,請重新輸入\n"); } } }
輸入坐標1 1,結果顯示:在對應位置輸出*,代表落下棋子。由此表明,玩家下棋函數 PlayMover符合預期效果。
玩家下棋后,打印出棋盤,緊接著就輪到電腦下棋了,同樣打印出棋盤。在函數 paly 里添加 ComputerMove 和 DisplayBoard。
void play() { printf("玩家選擇玩游戲!\n"); //存放下棋的數據 char board[ROW][COL] = { 0 }; //初始化棋盤為全空格 InitBoard(board, ROW, COL); //展示棋盤,打印 DisplayBoard(board, ROW, COL); //玩家下棋 PlayMover(board, ROW, COL); //展示棋盤,打印 DisplayBoard(board, ROW, COL); //電腦下棋 ComputerMove(board, ROW, COL); //展示棋盤,打印 DisplayBoard(board, ROW, COL); }
電腦是自己隨機下棋的,電腦的行數、列數先隨機產生一個0-2的坐標位置,再判斷這個位置是否為空:
為空,輸入字符#,代表電腦在此落下棋子
否則,會循環再次產生隨機數,直到為空
下面將在源文件 play.c 中添加函數 ComputerMove 的實現代碼,并在頭文件 play.h 中添加函數聲明。
//頭文件 play.h中 void ComputerMove(char board[ROW][COL], int row, int col); //源文件 play.c中 void ComputerMove(char board[ROW][COL], int row, int col) { int x = 0; int y = 0; printf("電腦下棋 ==> \n"); while (1) {//電腦下棋是隨機的 x = rand() % row;//輸出0-2之間的隨機數 0 1 2 y = rand() % col;//輸出0-2之間的隨機數 0 1 2 if (board[x][y]==' ')//先判斷對應坐標是否為空格 {//空格代表沒有棋子,則電腦將落下棋子 board[x][y] = '#';//#代表電腦下棋 break;//下完就跳出循環 } } }
由于坐標位置隨機產生的,要在 頭文件 play.h 中添加兩個頭文件
#include <stdlib.h>//庫函數 #include <time.h>//與系統時間有關的
在源文件 test.c 中的函數test中,添加函數srand,放在do-while循環之前,這樣電腦下棋的位置將是真正的隨機產生。
srand((unsigned int)time(NULL));
運行結果見上圖,由于下棋是雙方輪流下棋的,所以玩家下棋和電腦下棋是一個循環的動作。在此在函數play 添加while循環:
void play() { printf("玩家選擇玩游戲!\n"); //存放下棋的數據 char board[ROW][COL] = { 0 }; //初始化棋盤為全空格 InitBoard(board, ROW, COL); //展示棋盤,打印 DisplayBoard(board, ROW, COL); while (1) { //玩家下棋 PlayMover(board, ROW, COL); //展示棋盤,打印 DisplayBoard(board, ROW, COL); //電腦下棋 ComputerMove(board, ROW, COL); //展示棋盤,打印 DisplayBoard(board, ROW, COL); } }
運行結果見上圖。到此,代碼已經實現了正常的下棋功能并顯示出來。
三子棋棋盤一共只能下9個棋子,因此經過雙方幾輪下棋后,勢必會分出勝負,結果分為三種:
玩家贏,約定返回 *
電腦贏,約定返回 #
平局,約定返回 q,此時棋盤已滿是棋子,不分勝負
其他情況,約定返回 c,繼續下棋
當然,以上結果是不包括掀了棋盤的。
基于前面的代碼基礎上,在函數 paly 里添加判斷贏家的函數WhoIsWin ,修改后的函數 play邏輯是:
在while循環中,玩家先下棋
函數 WhoIsWin 會判斷棋盤的結果,并以字符的方式返回,賦值給result
if判斷result的值
(1)若返回的字符是c,則程序往下運行,輪到電腦下棋
(2)若返回的字符不是c,說明下棋出結果了,break直接跳出while循環,進行剩下的3個if判斷
(3)返回 *,代表玩家贏; 返回 #,代表電腦贏;返回 c,代表平局;
void play() { printf("玩家選擇玩游戲!\n"); char result = 0;//棋盤最終結果根據result判斷 //存放下棋的數據 char board[ROW][COL] = { 0 }; //初始化棋盤為全空格 InitBoard(board, ROW, COL); //展示棋盤,打印 DisplayBoard(board, ROW, COL); while (1) { //玩家下棋 PlayMover(board, ROW, COL); //展示棋盤,打印 DisplayBoard(board, ROW, COL); result = WhoIsWin(board, ROW, COL);//函數判斷下棋結果后,返回對應的字符 if (result !='c')//玩家下棋后進行一次判斷 {//不繼續下棋,說明已經分出勝負了 break; } //電腦下棋 ComputerMove(board, ROW, COL); //展示棋盤,打印 DisplayBoard(board, ROW, COL); result = WhoIsWin(board, ROW, COL);//函數判斷下棋結果后,返回對應的字符 if (result != 'c')//電腦下棋后進行一次判斷 {//不繼續下棋,說明已經分出勝負了 break; } } //根據函數WhoIsWin返回的字符,輸出下棋結果 if (result == '*') { printf("玩家贏了\n"); } else if (result == '#') { printf("電腦贏了\n"); } else { printf("平局\n"); } }
在源文件 play.c 添加 WhoIsWin 的代碼,并在**頭文件 play.h **添加函數聲明:
//頭文件 play.h中 char WhoIsWin(char board[ROW][COL], int row, int col); int IfFull(char board[ROW][COL], int row, int col);
函數 WhoIsWin 的邏輯:
判斷每一行、每一列、對角線上,三個棋子相同嗎?相同且不是空格,直接返回代表棋子的字符, *為玩家,#為電腦
棋盤棋子都是滿的,則代表平局,返回字符 q
其他情況,代表繼續下棋,還沒分出勝負,返回字符 c
//源文件 play.c中 //判斷棋盤是否滿了? 此函數包含在 WhoIsWin 中 int IfFull(char board[ROW][COL], int row, int col) { for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { if (board[i][j] == ' ') { return 0;//存在空格棋盤沒有滿 } } } } //判斷贏家 char WhoIsWin(char board[ROW][COL], int row, int col) { //判斷行,每一行連續三個棋子相同 for (int 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 (int j = 0; j < row; j++) { if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ') { return board[1][j]; } } //對角線,連續三個棋子相同 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 (IfFull(board, row, col) == 1) { return 'q';//quit表示平局 } //沒有贏家,棋盤也沒滿,繼續下棋 return 'c';//continue,表示繼續 }
運行結果見下圖,基本上一個完整的三子棋游戲代碼已經實現了。
但是上述代碼還有一個小問題,在判斷每一行、每一列、對角線上,三個棋子是否相同時,代碼直接寫固定的3個,如果將棋盤改成5行5列的五子棋時,這里就會出現問題了。這里留到以后在修改成能適應五子棋的游戲。三子棋的代碼實現就告一段落了。
關于“C語言怎么實現三子棋”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“C語言怎么實現三子棋”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。