c語言實現含遞歸清場版掃雷遊戲
一,設計思路
想必大傢都玩過掃雷
這便是一個標準的掃雷,換做代碼實現,我們需要考慮以下幾點:
1.棋盤的設計與初始化
2.在棋盤中放入雷
3.統計雷數
4.如何實現“一片”的效果
5.輸贏的判斷
接下來我們進行具體操作。
二.實現方式
1.菜單的打印
對任意一個遊戲,菜單是必不可少的,也是最簡單的部分,直接上代碼
void menu() { printf("------------------掃雷------------------\n"); printf("---------------1.開始遊戲---------------\n"); printf("---------------0.退出遊戲---------------\n"); } int main() { srand((unsigned int)time(NULL)); int a = 0; do { menu(); scanf("%d", &a); if (a == 0) { break; } game(); } while (a); return 0; }
其中srand是為瞭求隨機值,用來佈置雷
2.game函數
主菜單完後進入game函數,在game函數裡我們就要開始主要的遊戲部分,如棋盤初始化與打印等,當然這些步驟都依靠函數完成,game函數隻相當於集合瞭一系列的遊戲模塊
void game() { char mine[ROWS][COLS]; char show[ROWS][COLS]; initeboard(mine, ROWS, COLS, '0'); initeboard(show, ROWS, COLS, '*');//初始棋盤 displayboard(show, ROW, COL);//打印棋盤 mine_make(mine, ROW, COL);//設置雷 //displayboard(mine, ROW, COL); find_mine(mine, show, ROWS, COLS);//排查雷 }
3.棋盤的初始化與打印
可以看到,我在game函數裡初始瞭兩個棋盤,為什麼要兩個呢?
其實,一個是為瞭放置瞭雷,一個為瞭展示給玩傢,為什麼不用一個呢,我們要在放雷處用’1′,表示不放雷處用‘0’,這樣計算一個坐標周圍雷的數量就會更簡單,接下來看一段代碼:
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <time.h> #define ROW 10 #define COL 10 #define ROWS ROW+2 #define COLS COL+2
這裡我們看到定義瞭一個ROWS和COLS這又是為何呢?
回歸棋盤
掃雷時當你確認一個點時,它會對此點周圍的八個點進行排查看是否有淚,當坐標位於紅線處時沒有無法判斷八個,因此有瞭ROWS與COLS,這時,有人就會問瞭:那埋雷的地方用ROW COL就可以瞭,還不用擔心雷跑到外邊我們加的框,想法很好,但我們有兩個棋盤,必須對應,而且也不存在跑出雷的情況,往下分析你就會知道
void initeboard(char board[ROWS][COLS], int cols, int rows,char s)//棋盤初始化,此處用瞭個節省步驟的方法,不用兩個棋盤依次初始化 { int i = 0; int j = 0; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { board[i][j] = s; } } } void displayboard(char board[ROWS][COLS], int row, int col)//棋盤打印 { int i = 0; int j = 0; printf(" ");//與行中打印的0%d對應 for (j = 0; j <=col; j++) { printf(" %d ", j); } printf("\n"); printf("-"); for (j = 1; j <= col + 1; j++) { printf("---"); printf("|"); } printf("\n");//列對應打印完成 for (i = 1; i <= row; i++) { if (i <= 9) { printf(" 0%d ", i); } else printf(" %d ", i); printf("|"); for (j = 1; j <= col; j++) { printf(" %c ", board[i][j]); printf("|"); } printf("\n"); printf("-"); for (j = 1; j <= col+1; j++) { printf("---"); printf("|"); } printf("\n");//行對應嵌套在內部 打印的數前加0是為瞭讓當行數大於9時能夠對應 如09與10 } }
棋盤的打印做瞭行列對應,所以可能有點不明顯
4.雷的放置,雷的個數
雷的放置很簡單,在棋盤‘0’,處放置就行,因為我們對隨機數的算式使隨機數隻會出現在0-9沒有跑出的情況
mine_make(char mine[ROWS][COLS], int row, int col)//設置雷 { int count = 10; while (count) { int x = rand() % 10; int y = rand() % 10; if (mine[x][y] == '0') { mine[x][y] = '1'; count--; } } }
雷的個數就需要一定考慮瞭:
首先,我們需要把周圍八個位置是否有雷,有多少個雷判斷出來,這時我們設計‘0′ ‘1’類型就排上用場瞭,但是註意,這是字符,不是數字
一張表 讓我們知道如何轉型
當然返回的數字記得轉成字符類型
int get_mine(char mine[ROWS][COLS], int i, int j)//得到一個坐標附近雷的個數 { return mine[i - 1][j - 1] + mine[i - 1][j] + mine[i - 1][j + 1] + mine[i][j - 1] + mine[i][j + 1] + mine[i + 1][j - 1] + mine[i +1 ][j] + mine[i + 1][j + 1] - 8 * '0';//此處我們的數字其實是字符,用此方法可以轉為數字整形 }
5.遞歸實現一片效果
當不為雷是會展開附近一片不為雷,提高遊戲效率
void spread(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)//遞歸方法實現一大片 { show[x][y] = ' ';//先讓輸入金的坐標處變為空格,因為已經判定過雷所以可以直接轉空格 int i = 0; int j = 0; int ret = 0; for (i = x - 1; i <= x + 1; i++) { for (j = y - 1; j <= y + 1; j++)//嵌套for循環表示輸入坐標包括自生及周圍八個 { if (i > 0 && i <= ROW && j > 0 && j <= COL && mine[i][j] != '1' && show[i][j] == '*')//防止出現負坐標,避免有雷,避免輸入重復 { ret = get_mine(mine, i, j);//判斷ret是0或非0,並得出周圍雷數 if (!ret)//如果ret=0,!ret便是非0;為真 { spread(show, mine, i, j);//遞歸 } if (ret)//ret!=0時為真,便打印數 { show[i][j] = ret + '0';//使數字轉成對應字符 } } } } }
效果展示:
6.排查雷
負責判斷是否被炸死及遊戲勝利
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//排查雷 { printf("請輸入坐標\n"); int i = 0; int j = 0; int win = 0; while (row*col-10)//因為是十個雷,所以是—10,因為下總數減10就贏瞭,所以可以以此跳出循環,當然要是雷部位10,定一個變量就行,此處就不改瞭 { scanf("%d %d", &i, &j); if (mine[i][j] == '1') { printf("你掛瞭\n"); displayboard(mine, ROW, COL); break; } else { show[i][j] = get_mine(mine, i, j)+'0'; spread(show,mine, i, j); displayboard(show, ROW, COL); win++; } } if (win ==row * col - 10) { printf("恭喜你,成功瞭\n"); displayboard(mine, ROW, COL); } }
具體註釋都在代碼裡瞭
正常情況把打印雷盤註釋就行,就可以正常遊戲瞭
三.完整代碼
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <time.h> #define ROW 10 #define COL 10 #define ROWS ROW+2 #define COLS COL+2 void menu() { printf("------------------掃雷------------------\n"); printf("---------------1.開始遊戲---------------\n"); printf("---------------0.退出遊戲---------------\n"); } void initeboard(char board[ROWS][COLS], int cols, int rows,char s)//棋盤初始化,此處用瞭個節省步驟的方法,不用兩個棋盤依次初始化 { int i = 0; int j = 0; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { board[i][j] = s; } } } void displayboard(char board[ROWS][COLS], int row, int col)//棋盤打印 { int i = 0; int j = 0; printf(" ");//與行中打印的0%d對應 for (j = 0; j <=col; j++) { printf(" %d ", j); } printf("\n"); printf("-"); for (j = 1; j <= col + 1; j++) { printf("---"); printf("|"); } printf("\n");//列對應打印完成 for (i = 1; i <= row; i++) { if (i <= 9) { printf(" 0%d ", i); } else printf(" %d ", i); printf("|"); for (j = 1; j <= col; j++) { printf(" %c ", board[i][j]); printf("|"); } printf("\n"); printf("-"); for (j = 1; j <= col+1; j++) { printf("---"); printf("|"); } printf("\n");//行對應嵌套在內部 打印的數前加0是為瞭讓當行數大於9時能夠對應 如09與10 } } mine_make(char mine[ROWS][COLS], int row, int col)//設置雷 { int count = 10; while (count) { int x = rand() % 10; int y = rand() % 10; if (mine[x][y] == '0') { mine[x][y] = '1'; count--; } } } int get_mine(char mine[ROWS][COLS], int i, int j)//得到一個坐標附近雷的個數 { return mine[i - 1][j - 1] + mine[i - 1][j] + mine[i - 1][j + 1] + mine[i][j - 1] + mine[i][j + 1] + mine[i + 1][j - 1] + mine[i +1 ][j] + mine[i + 1][j + 1] - 8 * '0';//此處我們的數字其實是字符,用此方法可以轉為數字整形 } void spread(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)//遞歸方法實現一大片 { show[x][y] = ' ';//先讓輸入金的坐標處變為空格,因為已經判定過雷所以可以直接轉空格 int i = 0; int j = 0; int ret = 0; for (i = x - 1; i <= x + 1; i++) { for (j = y - 1; j <= y + 1; j++)//嵌套for循環表示輸入坐標包括自生及周圍八個 { if (i > 0 && i <= ROW && j > 0 && j <= COL && mine[i][j] != '1' && show[i][j] == '*')//防止出現負坐標,避免有雷,避免輸入重復 { ret = get_mine(mine, i, j);//判斷ret是0或非0,並得出周圍雷數 if (!ret)//如果ret=0,!ret便是非0;為真 { spread(show, mine, i, j);//遞歸 } if (ret)//ret!=0時為真,便打印數 { show[i][j] = ret + '0';//使數字轉成對應字符 } } } } } void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//排查雷 { printf("請輸入坐標\n"); int i = 0; int j = 0; int win = 0; while (row*col-10)//因為是十個雷,所以是—10,因為下總數減10就贏瞭,所以可以以此跳出循環,當然要是雷部位10,定一個變量就行,此處就不改瞭 { scanf("%d %d", &i, &j); if (mine[i][j] == '1') { printf("你掛瞭\n"); displayboard(mine, ROW, COL); break; } else { show[i][j] = get_mine(mine, i, j)+'0'; spread(show,mine, i, j); displayboard(show, ROW, COL); win++; } } if (win ==row * col - 10) { printf("恭喜你,成功瞭\n"); displayboard(mine, ROW, COL); } } void game() { char mine[ROWS][COLS]; char show[ROWS][COLS]; initeboard(mine, ROWS, COLS, '0'); initeboard(show, ROWS, COLS, '*');//初始棋盤 displayboard(show, ROW, COL);//打印棋盤 mine_make(mine, ROW, COL);//設置雷 displayboard(mine, ROW, COL); find_mine(mine, show, ROWS, COLS);//排查雷 } int main() { srand((unsigned int)time(NULL)); int a = 0; do { menu(); scanf("%d", &a); if (a == 0) { break; } game(); } while (a); return 0; }
總結
到此這篇關於c語言實現含遞歸清場版掃雷遊戲的文章就介紹到這瞭,更多相關c語言實現掃雷內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!