C语言实现扫雷完整算法详解~(附完整代码~)
掃雷是一個常見小游戲,那么如何用C語言實現掃雷呢?學習了二維數組之后,我們可將掃雷的網格區域存儲為二維數組,從而使用C語言實現掃雷。
目錄
1.算法基本思路
2.算法詳解
1.初始化數組與打印數組
2.設置雷
3.排查與標記
4.CountMine函數計算周圍雷的個數
?5.ExpandMine函數遞歸展開周圍所有安全區域
3.完整代碼!!!
1.test.c源文件
2.game.h頭文件
3.game.c源文件
完結撒花!!!
1.算法基本思路
首先,用一個二維數組存儲雷的分布,雷的分布在游戲期間從始至終不變,下文稱為mine數組。用另一個二維數組存儲排查出的雷的信息,在游戲期間展示給玩家,下文稱為show數組。程序所要實現的幾個主要功能是:1.初始化數組。2.打印數組。3.隨機設置雷。4.排查雷。5.計算某個坐標周圍雷的個數。6.玩家選擇一個坐標后,展開周圍坐標直至周圍有雷的坐標。
?由于計算一個坐標周圍雷的個數時,會計算周圍八個坐標中雷的個數之和。因此,為了防止當坐標在邊角時,計算周圍雷的個數時發生數組越界的現象,mine數組和show數組都應在掃雷盤面的大小基礎上各增加兩行或兩列。
因此,常量定義為:
#define ROW 9//可自由設置,掃雷盤面的行數 #define COL 9//可自由設置,掃雷盤面的列數#define ROWS ROW+2//數組的行數 #define COLS COL+2//數組的列數#define MINE 10//地雷個數,可以自由設置2.算法詳解
1.初始化數組與打印數組
將mine數組中的各元素均初始化為‘0’,將show數組中的各元素均初始化為‘*’,初始化與打印均可以由簡單的遍歷二維數組實現。
2.設置雷
設置雷可由rand()函數隨機生成。
別忘了!使用rand()之前需要調用srand()生成時間戳,使用系統時間初始化!
注意!srand()不能寫在隨機數生成的循環中,因此可以將srand()放在主函數中,生成一次隨機數種子即可。
int x = rand() % row + 1;//rand()取模row范圍在0-row-1之間,+1則范圍為1-row int y = rand() % col + 1;//rand()取模row范圍在0-col-1之間,+1則范圍為1-col3.排查與標記
在掃雷游戲中,可以通過插小旗標記雷(再次點擊取消標記),也可以通過點擊方格翻開周圍沒有雷的區域。接受用戶輸入,通過分支選擇進入標記(若想進入標記,則輸入1)或是排查(若想排查,則輸入0)。
而標記是有上限的,玩家最多標記個數即為該局游戲中雷的個數。若標記達到上限,玩家只有取消之前的標記才能繼續添加標記。
玩家開始游戲時,則進入循環,游戲結束可以跳出循環。跳出循環時,要么是玩家已經展開除雷外的所有區域,游戲成功;要么是玩家踩到了雷,游戲結束。
玩家每排除一個坐標,則會翻開周圍所有的安全區域(展開周圍坐標直至周圍有雷的坐標),這個功能可以由遞歸實現(ExpandBoard函數),后續講解。
若坐標的周圍有雷,則坐標會顯示周圍雷的個數,由CountMine函數實現,后續講解。
4.CountMine函數計算周圍雷的個數
一個坐標周圍的坐標由八個坐標組成。因此,若該坐標周圍有雷,排查該坐標后,該坐標應該顯示周圍八個坐標中雷的個數之和。
int CountMine(char board[ROWS][COLS], int row, int col) {int num = 0;num = board[row - 1][col + 1] + board[row - 1][col] + board[row - 1][col - 1] + board[row][col - 1] +board[row + 1][col - 1] + board[row + 1][col] + board[row + 1][col + 1] + board[row][col + 1] - 8 * '0';/*注意:二維數組中所存的值是字符型,通過將周圍的八個字符型加起來后減去八個‘0’的ARC2碼值將其轉換為整型*/return num; }?5.ExpandMine函數遞歸展開周圍所有安全區域
傳統的掃雷游戲中,當你點擊一個坐標,若該坐標沒有雷,則會展開該坐標周圍所有的安全區域,直到周圍有雷的坐標,上述過程可由遞歸實現。
1.若該坐標沒有雷,則賦值為空格。之后,判斷周圍八個坐標的周圍是否有雷,周圍沒有雷的坐標同樣賦值為空格,周圍沒有雷的坐標則繼續向外展開,直到遇到周圍有雷的坐標或達到了掃雷盤面的邊緣,則停止遞歸。
2.若該坐標有雷,則直接賦值為周圍雷的個數。
因此,該函數代碼如下:
void ExpandBoard(char mine[ROWS][COLS], char show[ROWS][COLS],int x, int y,int *win) {int count = CountMine(mine, x, y);if (count == 0){show[x][y] = ' ';//沒有雷的坐標賦值為空格(*win)++;//遞歸周圍的八個格子if (show[x - 1][y - 1] == '*' && x - 1 > 0 && x - 1 < ROWS && y - 1 > 0 && y - 1 < COLS)ExpandBoard(mine, show, x - 1, y - 1,win);if (show[x - 1][y] == '*' && x - 1 > 0 && x - 1 < ROWS && y > 0 && y < COLS)ExpandBoard(mine, show, x - 1, y,win);if (show[x - 1][y + 1] == '*' && x - 1 > 0 && x - 1 < ROWS && y + 1 > 0 && y + 1 < COLS)ExpandBoard(mine, show, x - 1, y + 1,win);if (show[x][y - 1] == '*' && x > 0 && x < ROWS && y - 1 > 0 && y - 1 < COLS)ExpandBoard(mine, show, x, y - 1,win);if (show[x][y + 1] == '*' && x > 0 && x < ROWS && y + 1 > 0 && y + 1 < COLS)ExpandBoard(mine, show, x, y + 1,win);if (show[x + 1][y - 1] == '*' && x + 1 > 0 && x + 1 < ROWS && y - 1 > 0 && y - 1 < COLS)ExpandBoard(mine, show, x + 1, y - 1,win);if (show[x + 1][y] == '*' && x + 1 > 0 && x + 1 < ROWS && y > 0 && y < COLS)ExpandBoard(mine, show, x + 1, y,win);if (show[x + 1][y + 1] == '*' && x + 1 > 0 && x + 1 < ROWS && y + 1 > 0 && y + 1 < COLS)ExpandBoard(mine, show, x + 1, y + 1,win);}else{show[x][y] = count + '0';} }3.完整代碼!!!
由于代碼很多,為了讓代碼更加易讀、邏輯性更強,將代碼分為test.c,game.c,game.h三個文件編寫。
1.test.c源文件
#define _CRT_SECURE_NO_WARNINGS#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 };//排查雷的信息//初始化數組,沒有布置雷時,mine均為0,show均為*InitBoard(mine, ROWS, COLS,'0');InitBoard(show, ROWS, COLS, '*');//打印數組SetMine(mine, ROW, COL);//DisplayBoard(mine, ROW, COL);DisplayBoard(show, ROW, COL);FindMine(mine, show, ROW, COL); } int main() {int input = 0;srand((unsigned int)time(NULL));do{menu();printf("請選擇——>");scanf("%d", &input);switch(input){case 1:game();break;case 0:printf("祝您天天開心\n");break;default:printf("輸入不合法,請重新輸入!\n");break;}} while (input);return 0; }2.game.h頭文件
#pragma once#include <stdio.h> #include <time.h> #include <stdlib.h>#define ROW 9//可自由設置 #define COL 9//可自由設置#define ROWS ROW+2 #define COLS COL+2#define MINE 10//地雷個數,可以自由設置void InitBoard(char board[ROWS][COLS], int row, int col,char set); void DisplayBoard(char board[ROWS][COLS], int row, int col); void SetMine(char board[ROWS][COLS], int row, int col); void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col); int CountMine(char board[ROWS][COLS], int row, int col); void ExpandBoard(char mine[ROWS][COLS], char show[ROWS][COLS],int x, int y,int *win);3.game.c源文件
#define _CRT_SECURE_NO_WARNINGS#include "game.h"void InitBoard(char board[ROWS][COLS], int row, int col, char set) {int i = 0;int j = 0;for (i = 0; i < row; i++){for (j = 0; j < col; j++){board[i][j] = set;}} }void DisplayBoard(char board[ROWS][COLS], int row, int col) {int i = 0;int j = 0;printf("--------分割線-------\n");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 board[ROWS][COLS], int row, int col) {int count = MINE;while (count){int x = rand() % row + 1;//rand()取模row范圍在0-row-1之間,+1則范圍為1-rowint y = rand() % col + 1;//rand()取模row范圍在0-col-1之間,+1則范圍為1-colif (board[x][y] == '0'){board[x][y] = '1';count--;}} }void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) {int x = 0;int y = 0;int input = 0;int win = 0;int i = 1;//判斷是否踩到了雷int mark = 0;//標記的次數,標記次數最多為雷的個數。while ((win < row * col - MINE)&&i){printf("**** 1.標記 ****\n");printf("**** 0.排查 ****\n");printf("請選擇->");scanf("%1d", &input);switch (input){case 1:{printf("請輸入想要標記的坐標:(選擇已標記的坐標則會取消標記)\n");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if (show[x][y] == '?'){printf("該坐標已標記過!將取消該坐標的標記!\n");mark--;show[x][y] = '*';DisplayBoard(show, ROW, COL);}else{if (mark < MINE)//標記個數小于雷的個數時,才可以繼續標記{printf("已標記該坐標!\n");show[x][y] = '?';DisplayBoard(show, ROW, COL);mark++;}else{printf("標記個數已達上限!只有取消之前標記,才可以繼續標記!\n");break;}}}elseprintf("輸入不合法,請重新輸入!\n");break;}case 0:{printf("請輸入想要排查的坐標:\n");scanf("%d %d", &x, &y);if (x >= 1 && x <= row && y >= 1 && y <= col){if ((show[x][y] != '*')&& (show[x][y] != '?')){printf("該坐標已排查過!\n");}else{if (mine[x][y] == '1'){i = 0;}else{win++;ExpandBoard(mine,show,x,y,&win);DisplayBoard(show, ROW, COL);}}}elseprintf("輸入不合法,請重新輸入!\n");break;}default:{printf("輸入不合法,請重新輸入!\n");break;}}} if (win == row * col - MINE){printf("恭喜你!排雷成功!你可真是個排雷小天才!\n\n");}else{printf("很不幸,您踩到了地雷!游戲結束!\n\n");}DisplayBoard(mine, ROW, COL);//展示設置的雷 }int CountMine(char board[ROWS][COLS], int row, int col) {int num = 0;num = board[row - 1][col + 1] + board[row - 1][col] + board[row - 1][col - 1] + board[row][col - 1] +board[row + 1][col - 1] + board[row + 1][col] + board[row + 1][col + 1] + board[row][col + 1] - 8 * '0';/*注意:二維數組中所存的值是字符型,通過將周圍的八個字符型加起來后減去八個‘0’的ARC2碼值將其轉換為整型*/return num; }void ExpandBoard(char mine[ROWS][COLS], char show[ROWS][COLS],int x, int y,int *win) {int count = CountMine(mine, x, y);if (count == 0){show[x][y] = ' ';//沒有雷的坐標賦值為空格(*win)++;//遞歸周圍的八個格子if (show[x - 1][y - 1] == '*' && x - 1 > 0 && x - 1 < ROWS && y - 1 > 0 && y - 1 < COLS)ExpandBoard(mine, show, x - 1, y - 1,win);if (show[x - 1][y] == '*' && x - 1 > 0 && x - 1 < ROWS && y > 0 && y < COLS)ExpandBoard(mine, show, x - 1, y,win);if (show[x - 1][y + 1] == '*' && x - 1 > 0 && x - 1 < ROWS && y + 1 > 0 && y + 1 < COLS)ExpandBoard(mine, show, x - 1, y + 1,win);if (show[x][y - 1] == '*' && x > 0 && x < ROWS && y - 1 > 0 && y - 1 < COLS)ExpandBoard(mine, show, x, y - 1,win);if (show[x][y + 1] == '*' && x > 0 && x < ROWS && y + 1 > 0 && y + 1 < COLS)ExpandBoard(mine, show, x, y + 1,win);if (show[x + 1][y - 1] == '*' && x + 1 > 0 && x + 1 < ROWS && y - 1 > 0 && y - 1 < COLS)ExpandBoard(mine, show, x + 1, y - 1,win);if (show[x + 1][y] == '*' && x + 1 > 0 && x + 1 < ROWS && y > 0 && y < COLS)ExpandBoard(mine, show, x + 1, y,win);if (show[x + 1][y + 1] == '*' && x + 1 > 0 && x + 1 < ROWS && y + 1 > 0 && y + 1 < COLS)ExpandBoard(mine, show, x + 1, y + 1,win);}else{show[x][y] = count + '0';} }完結撒花!!!
總結
以上是生活随笔為你收集整理的C语言实现扫雷完整算法详解~(附完整代码~)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++头文件防卫式声明
- 下一篇: 企业微信被别人登录了怎么办?有风险吗?