经典游戏扫雷详解--你也可以写出扫雷和玩好扫雷
掃雷小游戲
經典游戲掃雷,在學習C語言基礎后,今天試著用C語言去實現這個經典小游戲。
1.游戲介紹
掃雷想必大家都不陌生,但是,是不是還有很多人不知道怎么掃雷呢?是不是一點就踩雷被呢?別看了,說的就是你!那么,下面就給大家介紹一下這個游戲的玩法。
注意:(改圖截自掃雷游戲網頁版)
圖例:
左上角的數字 10–表示雷的個數(此時為8由于我已經手動標了兩處旗,表明我已經排除兩個雷了)
右上角的數字目前為 002–表示的是排查出雷的個數(圖中的兩個小旗)
2.掃雷代碼邏輯
1.創建數組
由上面玩游戲的過程可以體會到,我們需要兩個二維素組來分別存放雷和展示雷2.初始化素組
我們看到,一開始點開這個游戲界面的時候,只有小方塊,因此我們也需要將它進行一個初始化3.展示(打印)數組
存放好后的信息都已經放在了數組里,玩家進行游戲時,需要根據我們展示的信息來完成掃雷,因此我們需要將這個數組打印出來給玩家觀察4.設置雷(埋雷)
在進行掃雷之前,需要規定多大的棋盤里一共需要埋下多少顆雷來讓玩家進行掃雷5.掃雷
當上述準備過程都已經完成后,那接下來就是掃雷的過程啦,根據我們的玩法規則,結 合展示的信息完成掃雷6.展開該坐標周圍沒有雷的全部方塊
掃雷展開過程 效果展示
(該視頻錄制掃雷網頁版)
下面我們一起來觀察一下這個展開效果。視頻中可以觀察到,前幾次我點開的每一個方塊都只有這一個方塊沒了并且顯示了數字,根據我們的規則,以這個數字為中心的九宮格是有該數字個雷的,因此他的周圍沒有展開我的最后一步,點開了右下角的一個方塊,一下子周圍很多方塊都消失了,這就是展開的效果,根據規則我們可以知道,展開是需要一定前提的:1.這個坐標本身不是雷2.這個坐標九宮格內的其他坐標不能是雷7. 判斷輸贏
到最后,如果玩家找到了所有的雷,那么意味著排雷成功,若是中途觸雷,則直接判定失敗3.詳細步驟實現
1.創建數組
采取分模塊寫法:
1.test.c的主源文件中寫主體步驟
2.game.h 中申明掃雷游戲模塊相關的函數申明,自定義等
3.game.c 中實現函數定義
test.c 中代碼如下:
void game()//游戲函數實現 {char mine[ROWS][COLS] = { 0 };//存放雷的數組char show_mine[ROWS][COLS] = { 0 };//存放展示掃雷的素組}void menu() //菜單函數實現 {printf("****************\n");printf("**** 1.play ****\n");printf("**** 0.exit ****\n");printf("****************\n"); }int main() {int input = 0;srand((unsigned)time(NULL));do{menu(); //菜單printf("請選擇: \n");scanf("%d", &input);switch (input){case 1:game();break;case 0:printf("即將退出游戲\n");break;default:printf("選擇錯誤,請重新選擇\n");break;}} while (input);//玩家輸入的值來進行循環的判斷,可達到循環玩游戲的效果return 0; }game.h 中代碼如下:
#define ROW 9 //操作的行 #define COL 9 //操作的列 #define COLS COL+2 //防止數組越界 #define ROWS ROW+2 //防止素組越界由于我們看到的掃雷的棋盤是一個9*9的棋盤,因此我們操作的棋盤應該就是這個大小,但是當判斷內容時,我們是以一個數字為中心的九宮格,那么,在邊界上的數字(如上圖所示)的九宮格就會超過需要的棋盤大小,為了防止越界,我們將棋盤的行列均擴大,上下左右均需要擴大,因此行列擴大兩行。
2.初始化素組
test.c 中代碼如下:
void game() {char mine[ROWS][COLS] = { 0 };//存放雷的數組char show_mine[ROWS][COLS] = { 0 };//展示掃雷的素組--給玩家觀察的數組Initboard(mine, ROWS, COLS, '0'); //初始化為字符‘0’ Initboard(show_mine, ROWS, COLS, '*');//初始化為字符‘*’}game.h 中代碼如下:
//初始化數組中的內容 void Initboard(char board[ROWS][COLS], int rows, int cols ,char sz);game.c 中代碼如下:
game.c 中實現函數時所涉及的頭文件我們放在game.h中,可以防止重復引用
#define _CRT_SECURE_NO_WARNINGS 1#include"game.h"//用了game.h 中 ROWS COLS 等自定義的變量須應用頭文件 void Initboard(char board[ROWS][COLS], int rows, int cols,char sz) { //**傳入 sz 這個字符參數 方便我們一個函數可以解決 雷的棋盤和展示棋盤的初始化**int i = 0;int j = 0;for (i = 0; i < rows; i++){for (j = 0; j < cols; j++){board[i][j] = sz;}} }3.展示(打印)數組
test.c 中代碼如下:
void game() {char mine[ROWS][COLS] = { 0 };//存放雷的數組char show_mine[ROWS][COLS] = { 0 };//展示掃雷的數組--給玩家觀察的數組Initboard(mine, ROWS, COLS, '0'); //初始化為字符‘0’ Initboard(show_mine, ROWS, COLS, '*');//初始化為字符‘*’print_board(show_mine, ROW, COL);//展示掃雷的數組 //注意的是,我們操作的是展示的9*9的棋盤,因此我們傳入的棋盤行列大小也是9*9,即ROW,COL }game.h 中代碼如下:
#include<stdio.h>//打印初始化后的內容 void print_board(char board[ROWS][COLS], int row, int col);我們傳入的是show_mine 這個數組,因此這里的【ROWS】【COLS】也應當是和 show_mine創建的時候保持一直,但我們展示的卻是9*9的棋盤,因此傳入的行列是 row和colgame.c 中代碼如下:
void print_board(char board[ROWS][COLS], int row, int col) {printf("--------掃雷-------\n");//上分割線int i = 0;int j = 0;//打印橫坐標for (i = 0; i <= row; i++) {if (i == 0)printf(" ");elseprintf("%d ", i);}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");下分割線 }效果展示:
4. 設置雷(埋雷)
test.c 中代碼如下:
void game() {char mine[ROWS][COLS] = { 0 };//存放雷的數組char show_mine[ROWS][COLS] = { 0 };//展示掃雷的數組--給玩家觀察的數組Initboard(mine, ROWS, COLS, '0'); //初始化為字符‘0’ Initboard(show_mine, ROWS, COLS, '*');//初始化為字符‘*’print_board(show_mine, ROW, COL);//展示掃雷的數組Set_mine(mine, ROW, COL);//埋雷的過程,只操作我們存放雷的數組//print_board(mine, ROW, COL);//可以觀察設置的雷是否正確 }game.h 中代碼如下:
#define junior_mine 10 //雷的數目 #include<stdlib.h>//srand,rand 的頭文件 #include<time.h> //time 的頭文件 //設置雷 void Set_mine(char board[ROWS][COLS], int row, int col); 同上面展示雷的數組一樣,埋雷的這個數組操作的是創建的 mine這個數組 【ROWS】【COLS】需要保持一直,由于掃雷的方塊是9*9大小,所以我們傳 入的棋盤大小任然是row 和 colgame.c 中代碼如下:
void Set_mine(char board[ROWS][COLS], int row, int col) {int x = 0;int y = 0;int count = junior_mine;while (count) //雷的數量為0時跳出循環說明雷已經布置完了{//隨機產生雷的坐標在 1~9的范圍內x = rand() % row + 1;y = rand() % col + 1;if (board[x][y] == '0') //說明該坐標處沒有雷并且可以設置雷{board[x][y] = '1'; //埋雷成功 用 字符 1表示count--;}} }5.掃雷
test.c 中代碼如下:
void game() {char mine[ROWS][COLS] = { 0 };//存放雷的數組char show_mine[ROWS][COLS] = { 0 };//展示掃雷的數組--給玩家觀察的數組Initboard(mine, ROWS, COLS, '0'); //初始化為字符‘0’ Initboard(show_mine, ROWS, COLS, '*');//初始化為字符‘*’print_board(show_mine, ROW, COL);//展示掃雷的數組Set_mine(mine, ROW, COL);Find_mine(mine, show_mine, ROW, COL);}game.h 中代碼如下:
//排雷 void Find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);game.c 中代碼如下:
//統計該坐標周圍雷的個數 int sum_mine(char board[ROWS][COLS], int x, int y) {int sum = 0;int i = 0;int j = 0;for (i = x - 1; i <= x + 1; i++) {//產生以該坐標為中心的九宮格內的八個坐標for (j = y - 1; j <= y + 1; j++){sum+=board[i][j] - '0'; //注意數字和字符之間的轉換}}return sum; }void Find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) {printf("請輸入坐標進行排查:\n");int x = 0;int y = 0;//IsWin函數用于判斷是否勝利 下在一步具體實現while (IsWin(show,row,col)==0) {scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col)//判斷坐標合法性{if (mine[x][y] == '1'){printf("踩雷!\n");print_board(mine, ROW, COL);//踩雷后給玩家展示踩雷在哪里//和雷的全部坐標break;}else //沒有踩雷{int count = sum_mine(mine, x, y);//先統計該做標的周圍的雷show[x][y] = count + '0';//注意int類型和字符類型轉換Open_Not_mine(mine, show, x, y);//展開該坐標周圍沒有雷的方塊print_board(show, ROW, COL);//展示完以及雷的個數統計后,展示給玩家觀察}}elseprintf("輸入錯誤,請重新輸入\n");}6.展開該坐標周圍沒有雷的全部方塊
由于展開周圍坐標沒有雷的方塊這個函數不屬于游戲模塊test.c 中的game()里的函數,因此不需要寫在game.h中聲明
game.c 中代碼如下:
void Open_Not_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y) {int i = 0;int j = 0;int count = 0;//判斷坐標是否合法if (x >= 1 && x <= 9 && y >= 1 && y <= 9){ for (i = -1; i<= 1; i++){ //該坐標為中心的八個坐標的循環寫法for (j = -1; j<= 1; j++){//如果這個坐標不是雷的情況下if (mine[x + i][y + j] == '0'){ // 注意是 [x+i]和[y+i] 是改坐標周圍其他坐標//統計這個坐標周圍的雷count = sum_mine(mine, x + i, y + j);if (count == 0) //坐標周圍沒有雷,說明可以展開{if (show[x + i][y + j] == '*'){show[x + i][y + j] = ' ';Open_Not_mine(mine, show, x + i, y + j); //回去遞歸調用周圍坐標判斷}}else //周圍有雷 則這個坐標軸為中心的九宮格將不展開{show[i + x][j + y] = count + '0'; //統計這個坐標周圍有幾個雷并顯示在改坐標處}}}}} }7.判斷輸贏
同展開函數 Open_Not_mine 一樣, 判斷輸贏這個函數也不需要在game.h中進行聲明
game.c中代碼如下:
int IsWin(char show[ROWS][COLS], int row, int col) {int i = 0;int j = 0;int count = 0;for (i = 1; i <= row;i++){//判斷坐標范圍for (j = 1; j <= col; j++){if (show[i][j] == '*'){count++; //統計show數組在9*9中棋盤上一共有多少個不是雷的個數}}} //雷的個數return count == junior_mine;//相等返回1 不想動返回0//相等時說明 沒有雷的方塊都已經找到了,其余的位置都為雷--勝利//不相等的時候表明,不是雷的方塊還沒有全部找出來--未勝利 }總結
以上是生活随笔為你收集整理的经典游戏扫雷详解--你也可以写出扫雷和玩好扫雷的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java命名规范和代码风格
- 下一篇: Mvc 学习笔记(一)