
在此之前我們學(xué)習(xí)了循環(huán),函數(shù),數(shù)組等相關(guān)知識(shí),我們來(lái)寫(xiě)一個(gè)小游戲練練手
代碼大致分為三部分程序主函數(shù),函數(shù),聲明函數(shù)(這一點(diǎn)我們?cè)谕ㄓ嶄涰?xiàng)目是就介紹過(guò)了,將代碼分為三部分可以是代碼各司其職,不冗余,可讀性高),游戲框架大概分為以下幾部分,主函數(shù)main,菜單函數(shù),初始化棋盤(pán),打印棋盤(pán),玩家走函數(shù),電腦走函數(shù),判斷輸贏函數(shù),所以我們也會(huì)按照這幾個(gè)部分來(lái)講解,先給大家演示一下,我們是通過(guò)輸入坐標(biāo)的形式來(lái)落子
我們先搭建好程序的主體部分,然后在慢慢添加相應(yīng)功能,這里進(jìn)入主函數(shù)然后調(diào)用test函數(shù)
(資料圖片)
int main(){ test(); return 0;}
在test函數(shù)中我們可以加入菜單和根據(jù)用戶(hù)輸入判斷出對(duì)應(yīng)的不同提示語(yǔ)句,
srand((unsigned int)time(NULL));這句代碼我們?cè)诓聰?shù)字游戲是就介紹過(guò),他是用來(lái)生成隨機(jī)數(shù)的(等函數(shù)部分涉及到我們?cè)谥v解),先說(shuō)結(jié)構(gòu),利用一個(gè)do...while循環(huán)嵌套switch....case語(yǔ)句,根據(jù)用戶(hù)輸入判斷出相應(yīng)的功能(這里說(shuō)明一點(diǎn)將0作為退出結(jié)束,是因?yàn)?在c語(yǔ)言中可以作為假,在進(jìn)行while(0)即可跳出do...while循環(huán))
void test(){ int input = 0; srand((unsigned int)time(NULL)); do { menu(); printf("請(qǐng)選擇:"); scanf("%d", &input); switch (input) { case 1: printf("游戲開(kāi)始\n"); game(); break; case 0: printf("退出游戲\n"); break; default: printf("輸入錯(cuò)誤,請(qǐng)重新輸入\n"); break; } } while (input);}
void menu(){ printf("********************************\n"); printf("****** 1 .play 0.exit ******\n"); printf("********************************\n");}
在game中涉及到初始化棋盤(pán),打印棋盤(pán),玩家走函數(shù),電腦走函數(shù),判斷輸贏函數(shù)的調(diào)用,首先進(jìn)入函數(shù)設(shè)置棋盤(pán)信息,然后初始化棋盤(pán)(目的是將棋盤(pán)置空),然后是打印棋盤(pán),我們來(lái)探討一下重點(diǎn),就是判斷輸贏一共有四種狀態(tài)
*代表玩家贏
#代表電腦贏
q代表平局
c代表繼續(xù)
通過(guò)調(diào)用函數(shù)iswin得到的返回值來(lái)判斷是誰(shuí)贏還是繼續(xù)或者平局,判斷機(jī)制是玩家或者電腦每下一步棋就進(jìn)行一次判斷,while循環(huán)是為了讓玩家和電腦循環(huán)下棋,如果得到的返回值不得c了,即游戲不在繼續(xù),利用break跳出循環(huán),根據(jù)返回值判斷出對(duì)弈結(jié)果
void game(){ char ret = 0; char board[ROW][COL] = { 0 };//數(shù)組存放走出的棋盤(pán)信息 initboard(board, ROW, COL);//初始化棋盤(pán) displayboard(board,ROW,COL);//打印棋盤(pán) while (1) { //玩家下棋 playermove(board, ROW, COL); displayboard(board, ROW, COL);//打印棋盤(pán) //判斷玩家是否贏 ret=iswin(board,ROW,COL); if (ret != "c") { break; } //電腦下棋 computermove(board, ROW, COL); displayboard(board, ROW, COL);//打印棋盤(pán) //判斷電腦是否贏 ret=iswin(board, ROW, COL); if (ret != "c") { break; } } if (ret == "*") printf("玩家贏\n"); else if (ret == "#") printf("電腦贏\n"); else printf("平局\n");}
這里特別聲明一點(diǎn)define宏定義,之前我們沒(méi)有把棋盤(pán)的row和col寫(xiě)死,而是利用一個(gè)變量,這里的變量就利用了宏定義,(我們單獨(dú)將函數(shù)的聲明寫(xiě)在一個(gè)文件里是因?yàn)榭梢栽鰪?qiáng)函數(shù)的可讀性)這樣只需要在主函數(shù)文件(course-8.c)的頂部引用#include "game.h"即可
#define ROW 3#define COL 3#include#include #include //函數(shù)的聲明void initboard(char board[ROW][COL], int row, int col);void displayboard(char board[ROW][COL], int rw, int col);void playermove(char board[ROW][COL], int row, int col);void computermove(char board[ROW][COL], int row, int col);char iswin(char board[ROW][COL], int row, int col);
我們按照順序依次介紹
利用兩個(gè)for循環(huán)把每一個(gè)位置置為空
void initboard(char board[ROW][COL], int row, int col)//初始化函數(shù)體{ int i = 0; for (i = 0; i < row; i++) { int j = 0; for (j = 0; j < col; j++) { board[i][j] = " ";//給棋盤(pán)初始化成空格 } }}
首先展示一下我們棋盤(pán)的樣子,他是由sanbufenzucheng,數(shù)據(jù),| ,___ ,
我們是按行打印,首先我們利用for循環(huán)的嵌套先打印第一行數(shù)據(jù),因?yàn)?“ | ”一行只需要兩個(gè)所以if(j < col - 1),打印一行數(shù)據(jù)后換行,接著打印第二行也就是分割線" ___ ",(這里提示row是控制行,而col則是控制列)
void displayboard(char board[ROW][COL], int row, int col)//打印棋盤(pán)優(yōu)化函數(shù){ int i = 0; for (i = 0; i < row; i++) { int j = 0; ////////////1.打印一行數(shù)據(jù) for (j = 0; j < col; j++) { printf(" %c ",board[i][j]); if(j < col - 1) printf("|"); } printf("\n"); /////////////2.打印分割行 if (i < row - 1) { for (j = 0; j < col; j++) { printf("---"); if (j < col - 1) printf("|"); } printf("\n"); } }}
玩家走起的邏輯也很簡(jiǎn)單,就一個(gè)循環(huán),之所以使用循環(huán)是因?yàn)橥婕铱赡芟碌淖鴺?biāo)不合法,所以首先我們使用一個(gè)while循環(huán),讓玩家落子,直接判斷其坐標(biāo)是否合法if (x >= 1 && x <= row && y >= 1 && y <= col),因?yàn)槠遄右湓谄灞P(pán)內(nèi)且為空,如果條件滿(mǎn)足則合法可以落子,否則循環(huán)回去重新下,如下,由于我們的數(shù)組是從0開(kāi)始計(jì)數(shù)的但是玩家不知道,所以在玩家下完棋后我們需要將坐標(biāo)減1才行
void playermove(char board[ROW][COL], int row, int col)//玩家走函數(shù){ int x = 0; int y = 0; printf("玩家走\(yùn)n"); while (1) { printf("請(qǐng)輸入要下的坐標(biāo):"); scanf("%d%d", &x, &y); //判斷坐標(biāo)合法性 if (x >= 1 && x <= row && y >= 1 && y <= col) { if (board[x - 1][y - 1] == " ") { board[x - 1][y - 1] = "*"; break; } else { printf("該坐標(biāo)已被占用\n"); } } else { printf("該坐標(biāo)非法,請(qǐng)重新輸入\n"); } }}
電腦落子和玩家落子邏輯其實(shí)差不多,要坐標(biāo)合法,重點(diǎn)就是生成隨機(jī)數(shù)的問(wèn)題,我們利用rand函數(shù)生成隨機(jī)數(shù)(rand需要srand函數(shù)的調(diào)用,俄日srand又需要時(shí)間戳的來(lái)生成隨機(jī)數(shù)列,即srand((unsigned int)time(NULL));),通過(guò)處理rand() % row;則可以是隨機(jī)數(shù)達(dá)到我們想要的范圍,rand()%n,范圍肯定是0~n-1即0-2,這里可能就有小伙伴問(wèn)了,不是需要1-3的數(shù)嘛,大家仔細(xì)想一想,我們的數(shù)組是從0開(kāi)始的
void computermove(char board[ROW][COL], int row, int col)//電腦走函數(shù){ int x = 0; int y = 0; printf("電腦走\(yùn)n"); while (1) { x = rand() % row; y = rand() % col; if (board[x][y] == " ") { board[x][y] = "#"; break; } }}
如果棋盤(pán)滿(mǎn)了還沒(méi)分出勝負(fù),那就是平局唄,返回值0代表沒(méi)滿(mǎn),1代表滿(mǎn)了,我們遍歷棋盤(pán)但凡是碰到一個(gè)空就是沒(méi)滿(mǎn)返回0,否則返回1
//判斷棋盤(pán)滿(mǎn)沒(méi)滿(mǎn)//返回1滿(mǎn)了//返回0沒(méi)滿(mǎn)int isfull(char board[ROW][COL], 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;//沒(méi)滿(mǎn) } } return 1;//滿(mǎn)了}
判斷輸贏是整個(gè)游戲的核心,也是代碼最復(fù)雜的,大家要多動(dòng)腦思考其中的邏輯,首先我們進(jìn)入函數(shù),先判斷行存不存在贏棋,我們利用for循環(huán)一行一行的判斷,根據(jù)畫(huà)圖總結(jié)一行只需要判斷兩次即可確定,定義一個(gè)判斷返回標(biāo)志為int count = 0;//用來(lái)記錄兩次判斷的結(jié)果(因?yàn)橐恍幸袛鄡纱危?,因?yàn)橐恍信袛鄡纱嗡詂ol-1,例如第一行 第一次00=01&&00!=‘ ’第二次01=02&&01!= ‘ ’,一行判斷兩次,如果count值為2則證明此行數(shù)據(jù)相同,則返回本行的第一個(gè)數(shù)據(jù)在主函數(shù)中的game函數(shù)中根據(jù)相關(guān)邏輯給出相應(yīng)提示并結(jié)束游戲,判斷列,和判斷行相同原理,只是行列顛倒
接下來(lái)就是判斷斜行,左斜行,count一樣用來(lái)記錄兩次判斷的結(jié)果,即00=11&&00!="" 和 11=22&&11!=‘’,此時(shí)的for循環(huán)就有需要兩個(gè)變量了,做到同增同減
右斜行判斷 02=11&&02!="" 和 11=20&&11!=‘’
如果,行列斜行都判斷過(guò)了均沒(méi)有返回,就剩下兩種可能,平局或者游戲繼續(xù)
棋盤(pán)滿(mǎn)了則平局,否則游戲繼續(xù)
char iswin(char board[ROW][COL], int row, int col)//判斷輸贏 { int i = 0; //判斷行 for (i = 0; i < row; i++) { int count = 0;//用來(lái)記錄兩次判斷的結(jié)果(因?yàn)橐恍幸袛鄡纱危? int j = 0; for (j = 0; j < col-1; j++)//一行判斷兩次所以col-1,例如第一行 第一次00=01&&00!=‘’第二次01=02&&01!=‘’ { if (board[i][j] == board[i][j+ 1] && board[i][j] != " ") { count++;//符合條件count++ } } if (count == col - 1)//一行判斷兩次,如果count值為2則證明此行數(shù)據(jù)相同 { return board[i][0];//返回本行的第一個(gè)數(shù)據(jù) } } //判斷列,和判斷行相同原理,只是行列顛倒 for (i = 0; i < col; i++) { int count = 0; int j = 0; for (j = 0; j < row-1; j++) { if (board[j][i] == board[j+1][i] && board[j][i] != " ") { count++; } } if (count == row - 1) { return board[0][i]; } } //判斷兩斜行 //左斜行 int j = 0; int count = 0;//用來(lái)記錄兩次判斷的結(jié)果 for (i = 0,j=0; i < row-1; i++,j++)//00=11&&00!="" 和 11=22&&11!=‘’ { if (board[i][j] == board[i + 1][j + 1] && board[i][j] != " ") { count++; } if (count == row-1) { return board[i][j]; } } //右斜行 int counts = 0; for (i = 0, j = row - 1; i < row - 1; i++, j--)//02=11&&02!="" 和 11=20&&11!=‘’ { if (board[i][j] == board[i + 1][j - 1] && board[i][j] != " ") { counts++; } if (counts == row - 1) { return board[i][j]; } } //平局 if (isfull(board, ROW, COL) == 1) { return "q";//平局 } return "c"; //繼續(xù)}
#define _CRT_SECURE_NO_WARNINGS 1#include#include #include "game.h"http://三子棋游戲void game(){ char ret = 0; char board[ROW][COL] = { 0 };//數(shù)組存放走出的棋盤(pán)信息 initboard(board, ROW, COL);//初始化棋盤(pán) displayboard(board,ROW,COL);//打印棋盤(pán) while (1) { //玩家下棋 playermove(board, ROW, COL); displayboard(board, ROW, COL);//打印棋盤(pán) //判斷玩家是否贏 ret=iswin(board,ROW,COL); if (ret != "c") { break; } //電腦下棋 computermove(board, ROW, COL); displayboard(board, ROW, COL);//打印棋盤(pán) //判斷電腦是否贏 ret=iswin(board, ROW, COL); if (ret != "c") { break; } } if (ret == "*") printf("玩家贏\n"); else if (ret == "#") printf("電腦贏\n"); else printf("平局\n");}void menu(){ printf("********************************\n"); printf("****** 1 .play 0.exit ******\n"); printf("********************************\n");}void test(){ int input = 0; srand((unsigned int)time(NULL)); do { menu(); printf("請(qǐng)選擇:"); scanf("%d", &input); switch (input) { case 1: printf("游戲開(kāi)始\n"); game(); break; case 0: printf("退出游戲\n"); break; default: printf("輸入錯(cuò)誤,請(qǐng)重新輸入\n"); break; } } while (input);}int main(){ test(); return 0;}
#define ROW 3#define COL 3#include#include #include //函數(shù)的聲明void initboard(char board[ROW][COL], int row, int col);void displayboard(char board[ROW][COL], int rw, int col);void playermove(char board[ROW][COL], int row, int col);void computermove(char board[ROW][COL], int row, int col);char iswin(char board[ROW][COL], int row, int col);
#define _CRT_SECURE_NO_WARNINGS 1#include "game.h"void initboard(char board[ROW][COL], int row, int col)//初始化函數(shù)體{ int i = 0; for (i = 0; i < row; i++) { int j = 0; for (j = 0; j < col; j++) { board[i][j] = " ";//給棋盤(pán)初始化成空格 } }}//void displayboard(char board[ROW][COL], int row, int col)//打印棋盤(pán)函數(shù)//{// int i = 0;// for (i = 0; i < row; i++)// {// printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);//打印一行數(shù)據(jù)// if (i < row - 1)// {// printf("---|---|---\n"); //打印分割行// }// }//}void displayboard(char board[ROW][COL], int row, int col)//打印棋盤(pán)優(yōu)化函數(shù){ int i = 0; for (i = 0; i < row; i++) { int j = 0; ////////////1.打印一行數(shù)據(jù) for (j = 0; j < col; j++) { printf(" %c ",board[i][j]); if(j < col - 1) printf("|"); } printf("\n"); /////////////2.打印分割行 if (i < row - 1) { for (j = 0; j < col; j++) { printf("---"); if (j < col - 1) printf("|"); } printf("\n"); } }}// | | //---|---|---// | | //---|---|---// | | void playermove(char board[ROW][COL], int row, int col)//玩家走函數(shù){ int x = 0; int y = 0; printf("玩家走\(yùn)n"); while (1) { printf("請(qǐng)輸入要下的坐標(biāo):"); scanf("%d%d", &x, &y); //判斷坐標(biāo)合法性 if (x >= 1 && x <= row && y >= 1 && y <= col) { if (board[x - 1][y - 1] == " ") { board[x - 1][y - 1] = "*"; break; } else { printf("該坐標(biāo)已被占用\n"); } } else { printf("該坐標(biāo)非法,請(qǐng)重新輸入\n"); } }}void computermove(char board[ROW][COL], int row, int col)//電腦走函數(shù){ int x = 0; int y = 0; printf("電腦走\(yùn)n"); while (1) { x = rand() % row; y = rand() % col; if (board[x][y] == " ") { board[x][y] = "#"; break; } }}//判斷棋盤(pán)滿(mǎn)沒(méi)滿(mǎn)//返回1滿(mǎn)了//返回0沒(méi)滿(mǎn)int isfull(char board[ROW][COL], 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;//沒(méi)滿(mǎn) } } return 1;//滿(mǎn)了}//一共有四種狀態(tài)//*代表玩家贏//#代表電腦贏//q代表平局//c代表繼續(xù)//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][1] != " ")// {// return board[i][1];// }// }// //判斷豎三列// for (i = 0; i < col; i++)// {// if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][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[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != " ")// return board[1][1];// if (isfull(board, ROW, COL) == 1)// {// return "q";//平局// }// return "c"; //繼續(xù)//}char iswin(char board[ROW][COL], int row, int col)//判斷輸贏 自己寫(xiě)的優(yōu)化代碼{ int i = 0; //判斷行 for (i = 0; i < row; i++) { int count = 0;//用來(lái)記錄兩次判斷的結(jié)果(因?yàn)橐恍幸袛鄡纱危? int j = 0; for (j = 0; j < col-1; j++)//一行判斷兩次所以col-1,例如第一行 第一次00=01&&00!=‘’第二次01=02&&01!=‘’ { if (board[i][j] == board[i][j+ 1] && board[i][j] != " ") { count++;//符合條件count++ } } if (count == col - 1)//一行判斷兩次,如果count值為2則證明此行數(shù)據(jù)相同 { return board[i][0];//返回本行的第一個(gè)數(shù)據(jù) } } //判斷列,和判斷行相同原理,只是行列顛倒 for (i = 0; i < col; i++) { int count = 0; int j = 0; for (j = 0; j < row-1; j++) { if (board[j][i] == board[j+1][i] && board[j][i] != " ") { count++; } } if (count == row - 1) { return board[0][i]; } } //判斷兩斜行 //左斜行 int j = 0; int count = 0;//用來(lái)記錄兩次判斷的結(jié)果 for (i = 0,j=0; i < row-1; i++,j++)//00=11&&00!="" 和 11=22&&11!=‘’ { if (board[i][j] == board[i + 1][j + 1] && board[i][j] != " ") { count++; } if (count == row-1) { return board[i][j]; } } //右斜行 int counts = 0; for (i = 0, j = row - 1; i < row - 1; i++, j--)//02=11&&02!="" 和 11=20&&11!=‘’ { if (board[i][j] == board[i + 1][j - 1] && board[i][j] != " ") { counts++; } if (counts == row - 1) { return board[i][j]; } } //平局 if (isfull(board, ROW, COL) == 1) { return "q";//平局 } return "c"; //繼續(xù)}
歡迎評(píng)論區(qū)交流哦
標(biāo)簽: 首先我們