三子棋小游戏实现
目錄
簡易版
主函數部分
游戲部分
初識化棋盤
打印棋盤
玩家輸入
電腦輸入
?判斷輸贏
優化版
主函數部分
游戲部分
一:初始化數組
二:打印棋盤
三:玩家輸入
四:電腦輸入
五:判斷輸贏
簡易版
主函數部分
我們先創建兩個頭文件,一個test.c, 一個game.c, 一個源文件game.h。
我們的主函數和游戲實現的函數引用放再test.c。
函數的聲明放在game.h。
函數的實現放在game.c。
第一步主函數:
要實現游戲我們要先讓他運行一次,然后我們輸入選擇玩還是不玩。
打印一個菜單,然后選擇1? /? ?0,選擇錯誤,提示一下,然后重新選擇。
?這樣寫一個是方便別人看,有時候代碼太長了閱讀感不是很好,所以分模塊封裝,一個是也可以當知識產權的保護。
游戲部分
主函數部分寫完了下面就是游戲部分的實現。
首先我們創建一個數組字符數組char board[3][3],因為我們下棋里面要放*和#,所以使用字符數組,然后三子棋嘛,就創建一個3 * 3 的格子。
然后將這個二維數組全部初識化為空格,再把棋盤打印出來。
初識化棋盤
打印棋盤
?代碼實現
玩家輸入
玩家要輸入兩個值,所以先創建整型的X? ?Y變量,然后用scanf讀取。
玩家習慣的應該第一個坐標是1? 1,但是數組的坐標是0? 0, 所以再讀取完后我們再給他加個1。
然后判斷玩家輸入的是不是再1~3之間,也就是判斷合法性。
再判斷玩家輸入的這個坐標是否為空格,也就是是否被占用。
這些判斷如果不成立就需要重新輸入,所以這里應該是一個循環
電腦輸入
電腦輸入就要生成隨機數,我們會用到srand,只要調用一次,所以我們在主函數里面加上。
生成的是0~2的數字,表示數組代表的坐標,所以不用判斷合法性。
這里也要判斷是否被占用。
判斷條件失敗的話要重新產生隨機數,所以這里也是個循環。
?判斷輸贏
下完一次棋無非有四種情況:
- 玩家贏了
- 電腦贏了
- 平局
- 游戲繼續
我們寫一個函數,判斷玩家贏了輸出*。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?電腦贏了輸出#。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?平局輸出“Q”。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?游戲繼續輸出“C”。
判斷輸贏:
三行是否相等:board[0][0] 和?board[0][1] 和 board[0][2] 這是第一行,用for循環3次,把三行都遍歷一遍。
三列是否相等:board[0][0] 和?board[1][0] 和board[2][0]?這是第一列,用for循環3次,把三列都遍歷一遍。
對角線是否相等:?board[0][0] 和?board[1][1] 和?board[2][2]這是正對角,board[0][2] 和?board[1][1]
和board[2][0] 這是反對角是否相等。
上面判斷完相等之后并且不能等于空格。
判斷平局:
將整個數組遍歷一遍,看看數組里面是否還有空格,沒有了就是平局。
?
如果以上三個都不成立就是游戲繼續。
我們在玩家下完后和電腦下完后都判斷一下,輸出的是C就繼續游戲,不是C就跳出循環,打印結果。
當判斷結果是C的時候,要繼續游戲,所以應該是個循環。
完整代碼如下:
test.c部分
#include "game.h"void game() {char ret = 0;char board[3][3];initialization(board, 3, 3); //初識化數組print(board, 3, 3); //打印棋盤while (1){player_move(board, 3, 3); //玩家輸入ret = judge_win_or_lose_board(board, 3, 3); //判斷輸贏if (ret != 'C'){break;}computer_move(board, 3, 3); //電腦輸入ret = judge_win_or_lose_board(board, 3, 3); //判斷輸贏if (ret != 'C'){break;}}if (ret == '*'){printf("玩家贏了!\n");}else if (ret == '#'){printf("電腦贏了!\n");}else if (ret == 'Q'){printf("平局!\n");} }game.c部分
#define _CRT_SECURE_NO_WARNINGS 1 #include "game.h" void meun() {printf("*******************\n");printf("**** 1. play ****\n");printf("**** 0. exit ****\n");printf("*******************\n"); }void initialization(char board[3][3], int row, int col) {for (int i = 0; i < 3; i++) //通過兩層for循環遍歷整個數組,然后全部初識化為空格{for (int j = 0; j < 3; j++){board[i][j] = ' ';}} }void print(char board[3][3], int row, int col) {int i = 0;int 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 < col; j++) //打印第一行的第二部分{printf("---"); //先打印---if (j < col - 1) //最后一個 | 不用打印, 所以減1{printf("|");}}printf("\n"); //第一行打印完換行}} }void player_move(char board[3][3], int row, int col) {int x, y; //創建兩個變量用來儲存要輸入的值while (1){printf("(第一個坐標為1 1,后面依次類推) 玩家輸入:<\n");scanf("%d %d", &x, &y);if (x >= 1 && x <= 3 && y >= 1 && y <= 3) //判斷合法性{if (board[x - 1][y - 1] == ' ') // 判斷坐標是否被占用{board[x - 1][y - 1] = '*';break; //替換成功跳出循環}else{printf("此坐標被占用,請重新選擇!\n"); //被占用提示一下重新輸入}}else{printf("輸入錯誤,請重新輸入!\n"); //坐標不合法提示一下,重新輸入}} }void computer_move(char board[3][3], int row, int col) {printf("電腦輸入!\n");while (1){int x = rand() % row; //產生0~2的數字int y = rand() % col; //產生0~2的數字if (board[x][y] == ' ')//判斷是否被占用{board[x][y] = '#';break;}} }int already_expired(char board[3][3], 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; //還有空格返回0}}return 1; //如果沒空格了返回1 }char judge_win_or_lose_board(char board[3][3], 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][2] != ' '){return board[i][0];}}for (i = 0; i < row; i++) //判斷三列{if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[2][i] != ' '){return board[0][i];}}if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')return board[1][1]; //判斷對角if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')return board[1][1]; //判斷對角if (already_expired(board, row, col) == 1){return 'Q'; //判斷平局}return 'C'; //游戲繼續 }game.h部分
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <stdlib.h> #include <time.h>//打印菜單 void meun();//初始化數組 void initialization(char board[3][3], int row, int col);//打印棋盤 void print(char board[3][3], int row, int col);//玩家下棋 void player_move(char board[3][3], int row, int col);//電腦下棋 void computer_move(char board[3][3], int row, int col);//判斷輸贏 char judge_win_or_lose_board(char board[3][3], int row, int col);//判斷平局 int already_expired(char board[3][3], int row, int col);優化版
主函數部分
主函數部分和基礎版的一樣,其中肯定也要產生隨機數和菜單,我們直接將基礎版的復制過來。
我們要優化的部分是玩家不僅僅限于三個格子,還可以產生更大的格子,所以我們的棋盤要改為可以變換的,判斷方式也要改。
?
主函數部分還是一樣。
游戲部分
第一步肯定也是創建一個字符數組,然后初識化,我們的數組不能直接寫死,所以在game.h部分定義兩個常量,來決定數組的大小。
?
?
然后我們創建數組的時候把數組創大一點,在ROW的基礎上加個4,到判斷的時候用的上。
一:初始化數組
這個和基礎版也是一樣,將整個數組都初識化為空格。
?
就是注意在游戲傳參的時候要傳ROW+4這樣才是整個數組。
二:打印棋盤
?
黑色部分是我們需要用到的格子,紅色部分是我們留著后面判斷用的,所以我們要把棋盤打印出來,并且要將對應的數組放入格子中,我們在基礎版上要進行一定的更改。
可以看出我們第一個格子的位置是2-2, 最后一個是6-6,在基礎版上我們是從0開始打印的,所以在這里我們要從二開始,然后傳進去的是5,但是最后一個是6,所以后面要在ROW的基礎上加個2
其他的打印空格+字符+空格+ | 是一行的第一部分不變,--- + |是第一行的第二部分也不變。
三:玩家輸入
玩家輸入的第一個肯定是1 1,我們的下標指向的卻是2 2,所以我們在玩家輸入的基礎上還要加上一個1,。
在判斷他的合法性,是否在2?到 ROW+1中。
在判斷是否是空格。
?
輸入錯誤或者被占用要重新輸入,所以也是個循環。
四:電腦輸入
電腦輸入我們讓他產生隨機數是2~6就行,所以合法性不用判斷,只需要判斷是否被占用。
?
五:判斷輸贏
這次我們不能像之前一樣把把所有可以贏的格子都表示出來,那么我們怎么判斷呢。
我們可以從玩家和電腦輸入的坐標去找,上下左右對角是否相等。如圖:
大上下左右:
大對角:
?
小上下左右:
小對角:
?
?
然后用if語句把他們都寫進去就行,那么問題來了,怎么知道玩家和電腦下的坐標呢,出來電腦和玩家的輸入函數就消失了,那么我們直接寫一個函數,然后再輸入函數內調用他,那么我們的輸入函數不能再使用void類型了,要改為char型。
上面是玩家輸贏,接下來就是平局了,和之前一樣把整個數組遍歷一遍看看有沒有空格。
以上情況都不是就是平局。
?
然后再玩家和電腦輸入后都判斷一下,將判斷結果返回。所以改完之后變這樣。
?
后面再判斷輸出的是 # 、 * 、 Q 、C中的哪一個,然后進行選擇。
完整代碼如下:
test.c部分:
#define _CRT_SECURE_NO_WARNINGS 1 #include "game.h"void game() {char ret = 0;char board[ROW + 4][COL + 4];init_board(board, ROW + 4, COL + 4); //初識化整個數組print_borad(board, ROW, COL); //打印棋盤while (1){ret = player_move(board, ROW, COL); //玩家輸入if (ret != 'C'){break;}ret = computer_move(board, ROW, COL); //電腦輸入if (ret != 'C'){break;}}if (ret == '#'){printf("電腦贏了!!\n");print_borad(board, ROW, COL);}else if (ret == '*'){printf("玩家贏了!!\n");print_borad(board, ROW, COL);}else if (ret == 'Q'){printf("平局!!\n");print_borad(board, ROW, COL);} }int main() {int input = 0;srand((unsigned int)(time(NULL)));do {meun();printf("請選擇是否游戲\n");scanf("%d", &input);printf("\n");switch (input){case 1:game();break;case 0:printf("退出游戲");break;default:printf("選擇錯誤請重新選擇\n");break;}} while (input);return 0; }game.c部分:
#define _CRT_SECURE_NO_WARNINGS 1 #include "game.h"void meun() {printf("*******************\n");printf("**** 1. play ****\n");printf("**** 0. exit ****\n");printf("*******************\n"); }void init_board(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 print_borad(char board[ROW][COL], int row, int col) {int i = 2;int j = 2;for (i = 2; i < row + 2; i++) //傳入的是5,下標從2開始放入,到7停止,{//打印第一行第一部分for (j = 2; j < col + 2; j++){printf(" %c ", board[i][j]);//此時第一個下標為2 - 2if (j < col + 1) //跟基礎版一樣,最后一列的 | 不用打印,本來+2現在-1就變成+1.{printf("|");}}printf("\n");if (i < row + 1) //跟基礎版一樣,最后一行的 --- 不用打印,本來+2現在-1就變成+1.{//打印第一行第二部分--- + | for (j = 2; j < col + 2; j++){printf("---");if (j < col + 1) //同上{printf("|");}}printf("\n");}} }int already_expired(char board[ROW][COL], int row, int col) {int i = 2;int j = 2;//遍歷的數組是我們使用的數組,不是整個,所以是從2-ROW+2中for (i = 2; i < row + 2; i++){for (j = 2; j < col + 2; j++){if (board[i][j] == ' ')return 0;}}return 1; } char judge(char board[ROW][COL], int x, int y) {if (board[x][y] == board[x][y + 1] && board[x][y] == board[x][y + 2] && board[x][y] != ' ')return board[x][y];if (board[x][y] == board[x][y - 1] && board[x][y] == board[x][y - 2] && board[x][y] != ' ')return board[x][y];if (board[x][y] == board[x + 1][y] && board[x][y] == board[x + 2][y] && board[x][y] != ' ')return board[x][y];if (board[x][y] == board[x - 1][y] && board[x][y] == board[x - 2][y] && board[x][y] != ' ')return board[x][y];if (board[x][y] == board[x + 1][y + 1] && board[x][y] == board[x + 2][y + 2] && board[x][y] != ' ')return board[x][y];if (board[x][y] == board[x - 1][y - 1] && board[x][y] == board[x - 2][y - 2] && board[x][y] != ' ')return board[x][y];if (board[x][y] == board[x - 1][y + 1] && board[x][y] == board[x - 2][y + 2] && board[x][y] != ' ')return board[x][y];if (board[x][y] == board[x + 1][y - 1] && board[x][y] == board[x + 2][y - 2] && board[x][y] != ' ')return board[x][y];if (board[x][y] == board[x - 1][y] && board[x][y] == board[x + 1][y] && board[x][y] != ' ')return board[x][y];if (board[x][y] == board[x][y - 1] && board[x][y] == board[x][y + 1] && board[x][y] != ' ')return board[x][y];if (board[x][y] == board[x + 1][y - 1] && board[x][y] == board[x - 1][y + 1] && board[x][y] != ' ')return board[x][y];if (board[x][y] == board[x - 1][y - 1] && board[x][y] == board[x + 1][y + 1] && board[x][y] != ' ')return board[x][y];if (already_expired(board, ROW, COL)){return 'Q';}return 'C'; }char player_move(char board[ROW][COL], int row, int col) {printf("玩家下棋:<"); //提示玩家可以下棋了int x = 0;int y = 0;while (1){scanf("%d %d", &x, &y);x = x + 1; //在玩家輸入的基礎上+1y = y + 1;//判斷玩家輸入的是否正確if (x >= 2 && x <= col + 1 && y >= 2 && y <= col + 1){//判斷玩家輸入是否被占用if (board[x][y] == ' '){board[x][y] = '*';break;}else{printf("此坐標被占用,請重新選擇!\n");}}else{printf("輸入錯誤,請重新輸入!\n");}}print_borad(board, ROW, COL); //輸入完打印一下棋盤。return judge(board, x, y); }char computer_move(char board[ROW][COL], int row, int col) {int x = 0;int y = 0;printf("電腦輸入!\n");while (1){x = rand() % row + 2; //+2表示產生從0-4的數字變成2-6。y = rand() % col + 2;//判斷是否被占用if (board[x][y] == ' '){board[x][y] = '#';break;}}print_borad(board, ROW, COL); //輸入完打印一下棋盤。return judge(board, x, y); }game.h部分:
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <stdlib.h> #include <time.h>#define ROW 5 #define COL 5void meun();void init_board(char board[ROW][COL], int row, int col);void print_borad(char board[ROW][COL], int row, int col);int already_expired(char board[ROW][COL], int row, int col);char judge(char board[ROW][COL], int x, int y);char player_move(char board[ROW][COL], int row, int col);char computer_move(char board[ROW][COL], int row, int col);總結
- 上一篇: 安装python2.7和3.6提示报错
- 下一篇: 华夏ERP在虚拟机Ubuntu上的安装(