目錄
一、主函式的構成
二、test()函式實作回圈選擇結構
三、核心game()函式的組成 實作相應的功能
四、game() 函式中具有獨立功能的實作分析
五、易錯點提出(主要是判斷輸贏板塊容易出錯)
六、完整代碼(game.h game.c test.c)
下面開始正題:->
???????一、主函式的構成
int main()
{
test();
return 0;
}
這里盡量把主函式寫的內容少一點,通過呼叫主函式里的test()函式來實作游戲選單的列印,開始游戲結束游戲的選擇,把游戲主體函式放在test()函式,而不是全寫在一個主函式中,讓主函式更加簡潔可讀性更好,思緒也會更清晰,
二、test()函式實作回圈選擇結構
上面在主函式里呼叫了test()函式,可知test()函式必須要實作特定的功能,
主要功能:我們游戲的開始肯定是要先把選單列印出來,根據選單的提示輸入相應的資訊來控制游戲的開始和結束,敲重點-> 選單列印 游戲開始和結束的選擇(這里會用到回圈和Switch陳述句)
先上代碼,下面會對某些步驟進行相應的解釋,為什么要這樣寫,好處是什么,
void test()
{
int input = 0;
srand((unsigned int)time(NULL)); //亂數的設定 有個小知識 rand() 使用前必須使用srand()
do
{
menu(); //回圈以開水就列印選單 保證每次游戲開始前都有選單提示資訊
printf("請選擇->");
scanf("%d", &input);
switch(input) //用Switch陳述句實作選擇結構 0代表結束 1 代表開始
{
case 1:
game();
break;
case 0:
printf("退出游戲!");
break;
default:
printf("選擇錯誤\n");
break;
}
} while (input);
//這里用do while 實作回圈 while里放我們輸入的input 來實作回圈的是否繼續 我們輸入1 會在第一盤游戲
//結束后回圈繼續 如果是0 直接退出 這就用的非常nice
}
上面代碼中的srand((unsigned int)time(NULL)) 是產生亂數必要 只有先用了srand 后面的rand 函式才能產生亂數 time(NULL)是時間戳的知識 大家沒見過的可以了解一下 時間會時刻變化它利用的就是大概的原理 ,
三、核心game()函式的組成 實作相應的功能
game()
(大家可以先不看這個函式,先看完下面的列印棋盤、初始化棋盤、玩家下棋、電腦下棋、判斷輸贏、判斷棋盤是否滿了的獨立函式,最后看這個包含了這些函式的game()可能就比較好理解 不然一開始就看這個會有一點點懵 ) 我在這些獨立函式的后面也放一個game() 方便大家不用回傳來看,
void game()
{
char board[ROW][COL] = {0};//創建一個字符陣列 用來放我們下的棋子
Initboard(board, ROW, COL);//然后一開始就初始化陣列 設定為空格
displayboard(board, ROW, COL);//一開始列印棋盤 可以看到效果 然后根據棋盤下棋
char ret = 0;//定義一個字符 接受iswin()函式的回傳值 后面通過ret 的值來判斷輸贏 繼續 還是平局
while (1)
{
playerchess(board, ROW, COL);//用一個死回圈來模擬玩家下完電腦下 并且每個人下完列印出棋盤并且判斷輸贏
displayboard(board, ROW, COL);//下完列印
ret = iswin(board, ROW, COL);//判斷ret 的值 判斷輸贏 繼續還是平局
if (ret != 'c') //如果iswin()回傳字‘c'就繼續 否則就跳出玩家和電腦的回圈下棋
{
break;
}
computerchess(board, ROW, COL);
displayboard(board, ROW, COL);
//這里容易漏掉把電腦下完后的iswin 再次賦值給ret 而造成ret還是上次的玩家下后的值,就相當于判斷不了
//電腦的輸贏了 這就是問題所在!!!!
ret = iswin(board, ROW, COL);
if (ret != 'c')
{
break;
}
}
if (ret == '*')//如果判讀輸贏的函式回傳的值是* 或者# 說明有一行 或者一列 或者對角線三個元素相同 如果這三個是* 玩家贏 # 電腦贏 如果是q 就是代表平局
printf("玩家贏!\n");
else if (ret == '#')
printf("電腦贏!\n");
else
{
printf("平局!\n");
}
}
列印棋盤
上面的test()函式中通過選擇結構如果輸入1 就代表游戲開始,那么就要寫一個對應的函式來實作游戲的功能集合,把每個具有獨立功能的小函式放在game()函式里,(如棋盤的列印,棋盤的初始化,玩家下棋,電腦下棋,判斷輸贏等函式)
先 說棋盤的列印吧,
// 1 | 2 | 3
//---|---|---
// 4 | 5 | 6
//---|---|---
// 7 | 8 | 9
我們棋盤的效果就是上面的樣子,棋盤很像二維陣列的形式 所以我們創建一個二維陣列來存放我們的棋子,陣列的創建可以在game()函式里看到 是進入game()才創建的,
仔細觀察一下會發現棋盤由 數字 | 數字| 數字 和 ---|---|--- 兩種結構 組成的,
我們開始就會想著用回圈來解決 例如printf(“ %d | %d | %d \n"); printf("---|---|---\n");這兩個陳述句回圈來實作 ,但是這種方法雖然可以達到我們想要的效果,但是這樣寫就把格式限制死了 只能列印三行三列的棋盤來 如果后期想改變期盼的格式就不好改動,
這種方法不夠好,我們就換一種方法,
把棋盤想成由 行數 (ROW) 組個 1 | 2 | 3 和 ---|---|---(分割行)組成
每一組都是由 列數減一個 空格 數字 空格 | 和 一個 空格 數字 空格 組成的,
注意:這里有一些細節需要處理 比如每一行可以看成是n個 空格 數字 空格 | 但是每行的最后一個是沒有 | 的
還有分割行的數量是行數減一個 例如3x3 的棋盤就只有兩個分割行
代碼如下:
void displayboard(char board[ROW][COL], int row, int col)
{
int x = 0, y = 0;
for (x = 0; x < row; x++)
{
for (y = 0; y < col; y++)
{
printf(" %c ",board[x][y]);
if(y<col-1)
printf("|");
}//這里的回圈是列印一行的 空格 數字 空格|的 回圈三次 最后一次不列印| 上面用if限制了列印的|個數
printf("\n"); // 列印完一行后換行
if (x < row - 1) //這里是列印分割行的 限制了行數 n-1 也就是上面說的
{
for (y = 0; y < col; y++)
{
printf("---");
if (y < col - 1)
printf("|");
}
printf("\n"); // 完成一次回圈換行
}
}
}
棋盤的初始化
把創建的陣列的內容全部設定為空格(也可以是0) 列印出來的棋盤的樣子才會是上面看到的一樣, 后面在通過玩家和電腦下棋后把陣列里的內容改為 * 或者 # 再列印出來 ;
就是通過兩層回圈來遍歷陣列每一個元素 將其設定為 空格
不說廢話 直接上代碼!
void Initboard(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++)
{
board[i][j] = ' ';
}
}
}
玩家下棋
玩家輸入坐標然后程式把棋盤上對應的坐標改為 * ,之后可以列印出來,并且判斷一下輸贏(這是后面的)
void playerchess(char board[ROW][COL], int row, int col)
{
printf("請輸入棋子坐標:>");
int i = 0, j = 0;
while (1)
{
scanf("%d %d", &i, &j);
if (i >= 1 && i <= row && j >= 1 && j <= col)//我們輸的坐標都是1到3 但是陣列是有下標的
所以才有后面的j-1 和 i-1 下標為2就是陣列的第三個元素
{
if (board[i - 1][j - 1] == ' ')// 如果輸入的坐標對應的陣列元素不是空格就把*放進去 再跳出回圈
{
board[i - 1][j - 1] = '*';
break;
}
printf("坐標被占用,請重輸!\n");// 否則說明坐標已經被下過棋了 給出提示
}
else
printf("坐標非法,請重輸!\n");// 如果最上面的if 不滿足就說明輸的坐標不在我們創建的陣列范圍內 如4 4
}
}
電腦下棋
通過前面呼叫的srand((unsigned int)time(NULL)) 我們可以呼叫rand()函式來產生亂數
但是這樣產生的隨機可能會很大 不符合我們的要求 所以我們用產生的亂數%3 再賦值給倆個變數x y 作為橫縱坐標 那這倆個變數的值就是在0到2 之間了 剛好對應我們陣列的下標了
玩家下棋是* 電腦下棋就是 #
上代碼!
void computerchess(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("電腦下棋->\n");
/*int x = rand() % 3;
int y = rand() % 3;*///這里要寫在回圈里面 不然可能電腦找到的點都是重復過的 會一直運行沒結果
while (1)
{
x = rand() % 3;
y = rand() % 3;
if (board[x][y] == ' ')//同玩家下棋的判斷是否為空格 只有不為空格才下 否則再用下一個隨機引數的坐標 所以這里用了個死回圈 只要電腦沒有下棋回圈一直進行 直到找到了個不是空格的把棋子下進去 然后馬上跳出回圈
{
board[x][y] = '#';
break;
}
}
}
判斷輸贏
通過判斷 某一行或者某一列 或者對角線三個棋子是否相同來判斷輸贏 如果沒有就繼續 否則結束輸出某某贏
這里我們可以寫一個具有回傳值的函式,回傳上面三種情況的字符 假如第一行都是* 那就回傳* 后面在根據回傳值判斷是輸是贏 還是繼續 (其實還有平局 后面講)
上代碼!
char iswin(char board[ROW][COL],int row,int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
//判斷是否有一行 所有元素相同 如果相同回傳那三個元素中的一個 *和#是字符型別 所有函式型別為char
if (board[i][0] == board[i][1] && board[i][1] == board[i][2]&& board[i][2]!= ' ')//這里的board不等于空格要再寫一個陣列元素 也就是括號里有五個陣列元素
{
return board[i][2];
}
}
//判斷列
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] &&board[2][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];
}
//如果上面條件都不滿足就是棋盤滿了 并且沒分出輸贏 那就是平局了 這里用 is_full()函式來判斷陣列的每個元素是不是有空格有空格就是棋盤沒有滿 滿和沒滿的情況各自回傳一個數 后面根據回傳的數來判讀是否滿了
if (is_full(board, row, col) == 1)
{
return 'q';
}
return 'c';
}
判斷棋盤滿了沒
int is_full(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (j = 0; j < row; j++)
{
for (i = 0; i < col; i++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
通過回圈遍歷陣列的每個元素 如果有一個是空格 就說明棋盤沒滿 回傳一個數0 否則回傳另一個數1
game()
void game()
{
char board[ROW][COL] = {0};//創建一個字符陣列 用來放我們下的棋子
Initboard(board, ROW, COL);//然后一開始就初始化陣列 設定為空格
displayboard(board, ROW, COL);//一開始列印棋盤 可以看到效果 然后根據棋盤下棋
char ret = 0;//定義一個字符 接受iswin()函式的回傳值 后面通過ret 的值來判斷輸贏 繼續 還是平局
while (1)
{
playerchess(board, ROW, COL);//用一個死回圈來模擬玩家下完電腦下 并且每個人下完列印出棋盤并且判斷輸贏
displayboard(board, ROW, COL);//下完列印
ret = iswin(board, ROW, COL);//判斷ret 的值 判斷輸贏 繼續還是平局
if (ret != 'c') //如果iswin()回傳字‘c'就繼續 否則就跳出玩家和電腦的回圈下棋
{
break;
}
computerchess(board, ROW, COL);
displayboard(board, ROW, COL);
//這里容易漏掉把電腦下完后的iswin 再次賦值給ret 而造成ret還是上次的玩家下后的值,就相當于判斷不了
//電腦的輸贏了 這就是問題所在!!!!
ret = iswin(board, ROW, COL);
if (ret != 'c')
{
break;
}
}
if (ret == '*')//如果判讀輸贏的函式回傳的值是* 或者# 說明有一行 或者一列 或者對角線三個元素相同 如果這三個是* 玩家贏 # 電腦贏 如果是q 就是代表平局
printf("玩家贏!\n");
else if (ret == '#')
printf("電腦贏!\n");
else
{
printf("平局!\n");
}
}
五、易錯點提出(主要是判斷輸贏板塊容易出錯)


畫的是5 有點丑 就是要在前面四個元素的后面寫&&board[2][i]!=' '

常見的錯誤就是這幾個 我都掉坑了 哈哈!
六、完整代碼(game.h test.c game.c )
頭檔案(記得要宣告函式,并且定義了才能呼叫)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
void Initboard(char board[ROW][COL], int row, int col);
void playerchess(char board[ROW][COL], int row, int col);
void computerchess(char board[ROW][COL], int row, int col);
char iswin(char board[ROW][COL], int row, int col);
void displayboard(char board[ROW][COL], int row, int col);
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void menu()
{
printf("**********************************\n");
printf("******** 1.start ********\n");
printf("******** 0.exit ********\n");
printf("**********************************\n");
}
void game()
{
char board[ROW][COL] = {0};
Initboard(board, ROW, COL);
displayboard(board, ROW, COL);
char ret = 0;
while (1)
{
playerchess(board, ROW, COL);
displayboard(board, ROW, COL);
ret = iswin(board, ROW, COL);
if (ret != 'c')
{
break;
}
computerchess(board, ROW, COL);
displayboard(board, ROW, COL);
//這里容易漏掉把電腦下完后的iswin 再次賦值給ret 而造成ret還是上次的玩家下后的值,就相當于判斷不了
//電腦的輸贏了 這就是問題所在!!!!
ret = iswin(board, ROW, COL);
if (ret != 'c')
{
break;
}
}
if (ret == '*')
printf("玩家贏!\n");
else if (ret == '#')
printf("電腦贏!\n");
else
{
printf("平局!\n");
}
}
void test()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("請選擇->");
scanf("%d", &input);
switch(input)
{
case 1:
game();
break;
case 0:
printf("退出游戲!");
break;
default:
printf("選擇錯誤\n");
break;
}
} while (input);
}
int main()
{
test();
return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
int is_full(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (j = 0; j < row; j++)
{
for (i = 0; i < col; i++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
void Initboard(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++)
{
board[i][j] = ' ';
}
}
}
void displayboard(char board[ROW][COL], int row, int col)
{
int x = 0, y = 0;
for (x = 0; x < row; x++)
{
for (y = 0; y < col; y++)
{
printf(" %c ",board[x][y]);
if(y<col-1)
printf("|");
}
printf("\n");
if (x < row - 1)
{
for (y = 0; y < col; y++)
{
printf("---");
if (y < col - 1)
printf("|");
}
printf("\n");
}
}
}
void playerchess(char board[ROW][COL], int row, int col)
{
printf("請輸入棋子坐標:>");
int i = 0, j = 0;
while (1)
{
scanf("%d %d", &i, &j);
if (i >= 1 && i <= row && j >= 1 && j <= col)
{
if (board[i - 1][j - 1] == ' ')
{
board[i - 1][j - 1] = '*';
break;
}
printf("坐標被占用,請重輸!\n");
}
else
printf("坐標非法,請重輸!\n");
}
}
void computerchess(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("電腦下棋->\n");
/*int x = rand() % 3;
int y = rand() % 3;*///這里要寫在回圈里面 不然可能電腦找到的點都是重復過的 會一直運行沒結果
while (1)
{
x = rand() % 3;
y = rand() % 3;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
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][2]!= ' ')//這里的board不等于空格要再寫一個陣列元素 也就是括號里有五個陣列元素
{
return board[i][2];
}
}
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] &&board[2][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];
}
if (is_full(board, row, col) == 1)
{
return 'q';
}
return 'c';
}
// 1 | 2 | 3
//---|---|---
// 4 | 5 | 6
//---|---|---
// 7 | 8 | 9
喜歡就點個贊哈
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/355412.html
標籤:其他
上一篇:三子棋原來可以這樣寫
下一篇:關于三子棋(井字棋)小游戲
