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