扫雷游戏(进阶版)
目錄
掃雷(簡易版)
掃雷(進(jìn)階版)【加料】
掃雷(簡易版)
掃雷游戲都玩過吧,童年回憶了屬于是,今天我們就用代碼來實(shí)現(xiàn)一下。
首先創(chuàng)建3個(gè)文件,分別用來存放 游戲測試(test.c),游戲的頭(game.h) ,游戲具體內(nèi)容實(shí)現(xiàn)(game.c)。
游戲測試(test.c)
?在游戲測試(test.c)中設(shè)置游戲入口(具體過程和之前三子棋教程一樣CSDN,有興趣大家可以看看)。
代碼實(shí)現(xiàn):
#include"game.h"void menu() {printf("******************\n");printf("*****1. play *****\n");printf("*****0. exit *****\n");printf("******************\n"); } void game() {; } int main() {int input = 0;do{menu();printf("請選擇\n");scanf("%d", &input);switch (input){case 1:printf("進(jìn)入游戲\n");game();break;case 0:printf("退出游戲\n");break;default:printf("輸入有誤,請重試\n");break;}} while (input);return 0; }游戲入口設(shè)立好了,接下來就是實(shí)現(xiàn)掃雷游戲的函數(shù)。
界面分析:
先來看看掃雷游戲的界面:
?這是一個(gè)9*9的棋盤,上面布置了10個(gè)雷。我們設(shè)置有雷處為'1',無雷處為'0',(注意是字符1和0),布置完雷后我們需要排查,排查一個(gè)坐標(biāo)如果是雷就炸死了,不是雷會標(biāo)出周圍8個(gè)坐標(biāo)雷的個(gè)數(shù)。
?這里實(shí)現(xiàn)時(shí)有個(gè)問題,標(biāo)出周圍雷的數(shù)字時(shí),如果是1的話,就和前面"是不是雷" 產(chǎn)生沖突了,所以我們再創(chuàng)建一個(gè)棋盤,專門用來排查雷。
?還有個(gè)問題,像圖一這種排查沒什么問題,但是圖二這樣排查,就超出范圍越界了,所以我們創(chuàng)建數(shù)組時(shí),多給兩行兩列,創(chuàng)建成11*11的。展現(xiàn)時(shí)給出9*9的就行了。
下面來看代碼實(shí)現(xiàn):
char mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };這里的ROWS代表11*11數(shù)組的行,COLS代表列
在頭文件中定義常量ROW,COL(9*9數(shù)組的行和列),ROWS,COLS(11*11數(shù)組的行和列)
不寫死,方便后期修改。
#define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2定義棋盤:
然后我們定義棋盤board
void game() {char mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };Initboard(mine, ROWS, COLS, '0');//布置雷棋盤Initboard(show, ROWS, COLS, '*');//排查雷棋盤 }頭文件:
?game.c:
Initboard(char board[ROWS][COLS], int rows, int cols,char set) {int i, j;for (i = 0; i < rows; i++){for (j = 0; j < cols; j++){board[i][j] = set;}} }這里用一個(gè)函數(shù)InitBoard將兩種棋盤一起實(shí)現(xiàn)了,但是初始化的時(shí)候,布置雷棋盤初始為'0’ ,排查雷棋盤初始為'*' ,所以再將各自初始的東西傳參給InitBoard,就方便很多了。
打印棋盤:
接下來打印我們的棋盤來看一下:
寫一個(gè)Display函數(shù),為了好看,加上“掃雷游戲”的邊框,以及坐標(biāo)軸
?代碼實(shí)現(xiàn):
void DisplayBoard(char board[ROWS][COLS], int row, int col) {printf("----掃雷游戲----\n");int i, j;for (j = 0; j <= col; j++){printf("%d ", j);}printf("\n");for (i = 1; i <= row; i++){printf("%d ", i);for (j = 1; j <= col; j++){printf("%c ", board[i][j]);}printf("\n");}printf("----掃雷游戲----\n"); }布置雷:
棋盤有了接著該布置雷了。
寫一個(gè)SetMine函數(shù),用srand函數(shù)放進(jìn)隨機(jī)值。
代碼實(shí)現(xiàn):
void SetMine(char mine[ROWS][COLS], int row, int col) {int count = Count_mine;while (count){int x = rand() % 9 + 1;int y = rand() % 9 + 1;if (mine[x][y] == '0'){mine[x][y] = '1';count--;}} }Count_mine在頭文件中定義了
?注意調(diào)用rand時(shí),在test.c中包含srand函數(shù):
srand((unsigned int)time(NULL));打印一下棋盤看布置雷的效果:
?確實(shí)是隨機(jī)布置了10個(gè)雷。
排查雷:
布置完雷接下來就是排查雷了。
排查雷先要輸入坐標(biāo),那就要判斷坐標(biāo)的合法性。坐標(biāo)范圍是1~9,且不能輸入重復(fù)坐標(biāo)。
接著就是利用循環(huán)進(jìn)行排查了,如果碰到雷,那就被炸死。不是雷,就標(biāo)上周圍雷的個(gè)數(shù)。
那么這里需要計(jì)數(shù),可以用循環(huán)計(jì)算,也可以將周圍8個(gè)坐標(biāo)相加-'0'*8,就是雷的個(gè)數(shù)。
代碼實(shí)現(xiàn):
int count_round_mine(char mine[ROWS][COLS],int x,int y) {return mine[x - 1][y - 1] +mine[x - 1][y] +mine[x - 1][y + 1] +mine[x][y - 1] +mine[x][y + 1] +mine[x + 1][y - 1] +mine[x + 1][y] +mine[x + 1][y + 1]-'0'*8; //法二:循環(huán)/*int count = 0;int i, j;for (i = -1; i <= 1; i++){for (j = -1; j <= 1; j++){if (mine[x+i][y+j] == '1'){count++;}}}return count;*/ } void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) {while (1){int x, y;scanf("%d%d", &x, &y);int ret = 0;if (x > 0 && x <= row && y > 0 && y <= col){if (show[x][y] == '*'){if (mine[x][y] == '1'){printf("很遺憾,你被炸死了\n");DisplayBoard(show, ROW, COL);}else{ret = count_round_mine(mine, x, y);show[x][y] = '0' + ret;DisplayBoard(show, ROW, COL);}}elseprintf("坐標(biāo)已被占用,請重新輸入\n");}elseprintf("輸入無效坐標(biāo),請重試\n");} }但是這樣有個(gè)問題,我們無法結(jié)束游戲,所以需要判斷游戲結(jié)束的條件。
1、被炸死?????????? 2、排查完棋盤上所有非雷的位置
代碼實(shí)現(xiàn):
void SetMine(char mine[ROWS][COLS], int row, int col) {int count = Count_mine;while (count){int x = rand() % 9 + 1;int y = rand() % 9 + 1;if (mine[x][y] == '0'){mine[x][y] = '1';count--;}} }int count_round_mine(char mine[ROWS][COLS],int x,int y) {return mine[x - 1][y - 1] +mine[x - 1][y] +mine[x - 1][y + 1] +mine[x][y - 1] +mine[x][y + 1] +mine[x + 1][y - 1] +mine[x + 1][y] +mine[x + 1][y + 1]-'0'*8;} void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) {int win = row * col - Count_mine;while (win){int x, y;scanf("%d%d", &x, &y);int ret = 0;if (x > 0 && x <= row && y > 0 && y <= col){if (show[x][y] == '*'){if (mine[x][y] == '1'){printf("很遺憾,你被炸死了\n");DisplayBoard(mine, ROW, COL);}else{ret = count_round_mine(mine, x, y);show[x][y] = '0' + ret;DisplayBoard(show, ROW, COL);win--;}}elseprintf("坐標(biāo)已被占用,請重新輸入\n");}elseprintf("輸入無效坐標(biāo),請重試\n");}if (win == 0){printf("恭喜你,排雷成功\n");DisplayBoard(mine, ROW, COL);} }完整代碼(三部分):
game.h:
#define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2 #define Count_mine 10#include<stdio.h> #include<time.h> #include<stdlib.h>void Initboard(char board[ROWS][COLS],int rows,int cols,char set); void DisplayBoard(char board[ROWS][COLS],int row,int col); void SetMine(char mine[ROWS][COLS], int row, int col); void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);test.c:
#include"game.h"void menu() {printf("******************\n");printf("*****1. play *****\n");printf("*****0. exit *****\n");printf("******************\n"); } void game() {char mine[ROWS][COLS] = { 0 };char show[ROWS][COLS] = { 0 };Initboard(mine, ROWS, COLS, '0');//布置雷棋盤Initboard(show, ROWS, COLS, '*');//排查雷棋盤DisplayBoard(show, ROW, COL);SetMine(mine, ROW, COL);FindMine(mine, show, ROW, COL); } int main() {srand((unsigned int)time(NULL));int input = 0;do{menu();printf("請選擇\n");scanf("%d", &input);switch (input){case 1:printf("進(jìn)入游戲\n");game();break;case 0:printf("退出游戲\n");break;default:printf("輸入有誤,請重試\n");break;}} while (input);return 0; }game.c:
????????
#include"game.h"void Initboard(char board[ROWS][COLS], int rows, int cols,char set) {int i, j;for (i = 0; i < rows; i++){for (j = 0; j < cols; j++){board[i][j] = set;}} } void DisplayBoard(char board[ROWS][COLS], int row, int col) {printf("----掃雷游戲----\n");int i, j;for (j = 0; j <= col; j++){printf("%d ", j);}printf("\n");for (i = 1; i <= row; i++){printf("%d ", i);for (j = 1; j <= col; j++){printf("%c ", board[i][j]);}printf("\n");}printf("----掃雷游戲----\n"); }void SetMine(char mine[ROWS][COLS], int row, int col) {int count = Count_mine;while (count){int x = rand() % 9 + 1;int y = rand() % 9 + 1;if (mine[x][y] == '0'){mine[x][y] = '1';count--;}} }int count_round_mine(char mine[ROWS][COLS],int x,int y) {/*return mine[x - 1][y - 1] +mine[x - 1][y] +mine[x - 1][y + 1] +mine[x][y - 1] +mine[x][y + 1] +mine[x + 1][y - 1] +mine[x + 1][y] +mine[x + 1][y + 1]-'0'*8;*/int count = 0;int i, j;for (i = -1; i <= 1; i++){for (j = -1; j <= 1; j++){if (mine[x+i][y+j] == '1'){count++;}}}return count; } void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) {int win = row * col - Count_mine;while (win){int x, y;scanf("%d%d", &x, &y);int ret = 0;if (x > 0 && x <= row && y > 0 && y <= col){if (show[x][y] == '*'){if (mine[x][y] == '1'){printf("很遺憾,你被炸死了\n");DisplayBoard(mine, ROW, COL);}else{ret = count_round_mine(mine, x, y);show[x][y] = '0' + ret;DisplayBoard(show, ROW, COL);win--;}}elseprintf("坐標(biāo)已被占用,請重新輸入\n");}elseprintf("輸入無效坐標(biāo),請重試\n");}if (win == 0){printf("恭喜你,排雷成功\n");DisplayBoard(mine, ROW, COL);} }掃雷(進(jìn)階版)【加料】
?我們可以觀察到網(wǎng)頁版的掃雷較之我們上面寫的簡易版有兩個(gè)特點(diǎn):
1、有標(biāo)記功能,可以自行記錄埋藏雷的位置
2、有展開一片功能,如果點(diǎn)開位置附近一片都沒有雷,會自行展開。
下面進(jìn)階版主要實(shí)現(xiàn)這兩個(gè)功能。
1、標(biāo)記功能:
我們定義標(biāo)記符號為‘#’。
在排查雷函數(shù)中寫一個(gè)標(biāo)記雷函數(shù)SignMine,注意一定是在FindMine函數(shù)中寫。
SignMine代碼實(shí)現(xiàn)如下:
void SignMine(char show[ROWS][COLS], int row, int col) {int a = 0;printf("請輸入需要標(biāo)記的次數(shù)\n");scanf("%d", &a);while (a){printf("請輸入需要標(biāo)記的坐標(biāo)\n");int x = 0, y = 0;scanf("%d%d", &x, &y);if (x > 0 && x <= row && y > 0 && y <= col){if (show[x][y] == '*'){show[x][y] = '#';a--;}elseprintf("該坐標(biāo)已被占用,請重新輸入\n");}elseprintf("無效標(biāo)記,請重試\n");} }我們要標(biāo)記幾次,就輸入幾個(gè)標(biāo)記的坐標(biāo)。
2、展開一片功能:
分析:如果一個(gè)坐標(biāo)位置周圍一圈沒有雷,那么將其展開,再看它周圍一圈坐標(biāo)周圍的坐標(biāo)有沒有雷,沒有,繼續(xù)展開,直到碰到周圍有雷,標(biāo)記數(shù)字。
?可以想到用遞歸來實(shí)現(xiàn),但是注意一點(diǎn),1點(diǎn)判斷完判斷2點(diǎn)時(shí),要排除已經(jīng)判斷過的1點(diǎn),否則就死遞歸了。
代碼說明:
1、排查的坐標(biāo)(x,y)如果不是雷,,看他周圍8個(gè)坐標(biāo),如果沒有雷,將其標(biāo)記為空格' ? ' 。
2、遍歷坐標(biāo)周圍8個(gè)坐標(biāo),如果沒有被排查過,遞歸調(diào)用此函數(shù),在最里層表示show數(shù)組的值,就能實(shí)現(xiàn)展開。
代碼如下:
void OpenShow(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col,int x,int y) {int count = count_round_mine(mine, x, y);if (count == 0){show[x][y] == ' ';int i, j;for (i = -1; i <= 1; i++){for (j = -1; j <= 1; j++){if (show[x + i][y + j] == '*'){OpenShow(mine, show, row, col, x + i, y + j);}}}}else{show[x][y] = '0' + count;} }這樣就實(shí)現(xiàn)了展開棋盤。
后面就剩下組合代碼了。
總結(jié)
- 上一篇: H面试程序(29):求最大递增数
- 下一篇: 计算机怎样辅助英语听力教学方法有哪些,计