c語(yǔ)言實(shí)現(xiàn)含遞歸清場(chǎng)版掃雷游戲
一,設(shè)計(jì)思路
想必大家都玩過(guò)掃雷
?這便是一個(gè)標(biāo)準(zhǔn)的掃雷,換做代碼實(shí)現(xiàn),我們需要考慮以下幾點(diǎn):
1.棋盤的設(shè)計(jì)與初始化
2.在棋盤中放入雷
3.統(tǒng)計(jì)雷數(shù)
4.如何實(shí)現(xiàn)“一片”的效果
5.輸贏的判斷
接下來(lái)我們進(jìn)行具體操作。
二.實(shí)現(xiàn)方式
1.菜單的打印
對(duì)任意一個(gè)游戲,菜單是必不可少的,也是最簡(jiǎn)單的部分,直接上代碼
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是為了求隨機(jī)值,用來(lái)布置雷
2.game函數(shù)
主菜單完后進(jìn)入game函數(shù),在game函數(shù)里我們就要開始主要的游戲部分,如棋盤初始化與打印等,當(dāng)然這些步驟都依靠函數(shù)完成,game函數(shù)只相當(dāng)于集合了一系列的游戲模塊
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);//設(shè)置雷 //displayboard(mine, ROW, COL); find_mine(mine, show, ROWS, COLS);//排查雷 }
3.棋盤的初始化與打印
可以看到,我在game函數(shù)里初始了兩個(gè)棋盤,為什么要兩個(gè)呢?
其實(shí),一個(gè)是為了放置了雷,一個(gè)為了展示給玩家,為什么不用一個(gè)呢,我們要在放雷處用'1',表示不放雷處用‘0',這樣計(jì)算一個(gè)坐標(biāo)周圍雷的數(shù)量就會(huì)更簡(jiǎn)單,接下來(lái)看一段代碼:
#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
這里我們看到定義了一個(gè)ROWS和COLS這又是為何呢?
回歸棋盤
?掃雷時(shí)當(dāng)你確認(rèn)一個(gè)點(diǎn)時(shí),它會(huì)對(duì)此點(diǎn)周圍的八個(gè)點(diǎn)進(jìn)行排查看是否有淚,當(dāng)坐標(biāo)位于紅線處時(shí)沒有無(wú)法判斷八個(gè),因此有了ROWS與COLS,這時(shí),有人就會(huì)問了:那埋雷的地方用ROW COL就可以了,還不用擔(dān)心雷跑到外邊我們加的框,想法很好,但我們有兩個(gè)棋盤,必須對(duì)應(yīng),而且也不存在跑出雷的情況,往下分析你就會(huì)知道
void initeboard(char board[ROWS][COLS], int cols, int rows,char s)//棋盤初始化,此處用了個(gè)節(jié)省步驟的方法,不用兩個(gè)棋盤依次初始化 { 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對(duì)應(yīng) for (j = 0; j <=col; j++) { printf(" %d ", j); } printf("\n"); printf("-"); for (j = 1; j <= col + 1; j++) { printf("---"); printf("|"); } printf("\n");//列對(duì)應(yīng)打印完成 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");//行對(duì)應(yīng)嵌套在內(nèi)部 打印的數(shù)前加0是為了讓當(dāng)行數(shù)大于9時(shí)能夠?qū)?yīng) 如09與10 } }
棋盤的打印做了行列對(duì)應(yīng),所以可能有點(diǎn)不明顯
?4.雷的放置,雷的個(gè)數(shù)
雷的放置很簡(jiǎn)單,在棋盤‘0',處放置就行,因?yàn)槲覀儗?duì)隨機(jī)數(shù)的算式使隨機(jī)數(shù)只會(huì)出現(xiàn)在0-9沒有跑出的情況
mine_make(char mine[ROWS][COLS], int row, int col)//設(shè)置雷 { int count = 10; while (count) { int x = rand() % 10; int y = rand() % 10; if (mine[x][y] == '0') { mine[x][y] = '1'; count--; } } }
雷的個(gè)數(shù)就需要一定考慮了:
首先,我們需要把周圍八個(gè)位置是否有雷,有多少個(gè)雷判斷出來(lái),這時(shí)我們?cè)O(shè)計(jì)‘0' ‘1'類型就排上用場(chǎng)了,但是注意,這是字符,不是數(shù)字
?一張表 讓我們知道如何轉(zhuǎn)型
當(dāng)然返回的數(shù)字記得轉(zhuǎn)成字符類型
int get_mine(char mine[ROWS][COLS], int i, int j)//得到一個(gè)坐標(biāo)附近雷的個(gè)數(shù) { 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';//此處我們的數(shù)字其實(shí)是字符,用此方法可以轉(zhuǎn)為數(shù)字整形 }
5.遞歸實(shí)現(xiàn)一片效果
當(dāng)不為雷是會(huì)展開附近一片不為雷,提高游戲效率
void spread(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)//遞歸方法實(shí)現(xiàn)一大片 { show[x][y] = ' ';//先讓輸入金的坐標(biāo)處變?yōu)榭崭瘢驗(yàn)橐呀?jīng)判定過(guò)雷所以可以直接轉(zhuǎn)空格 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循環(huán)表示輸入坐標(biāo)包括自生及周圍八個(gè) { if (i > 0 && i <= ROW && j > 0 && j <= COL && mine[i][j] != '1' && show[i][j] == '*')//防止出現(xiàn)負(fù)坐標(biāo),避免有雷,避免輸入重復(fù) { ret = get_mine(mine, i, j);//判斷ret是0或非0,并得出周圍雷數(shù) if (!ret)//如果ret=0,!ret便是非0;為真 { spread(show, mine, i, j);//遞歸 } if (ret)//ret!=0時(shí)為真,便打印數(shù) { show[i][j] = ret + '0';//使數(shù)字轉(zhuǎn)成對(duì)應(yīng)字符 } } } } }
效果展示:
?6.排查雷
負(fù)責(zé)判斷是否被炸死及游戲勝利
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//排查雷 { printf("請(qǐng)輸入坐標(biāo)\n"); int i = 0; int j = 0; int win = 0; while (row*col-10)//因?yàn)槭鞘畟€(gè)雷,所以是—10,因?yàn)橄驴倲?shù)減10就贏了,所以可以以此跳出循環(huán),當(dāng)然要是雷部位10,定一個(gè)變量就行,此處就不改了 { 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)//棋盤初始化,此處用了個(gè)節(jié)省步驟的方法,不用兩個(gè)棋盤依次初始化 { 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對(duì)應(yīng) for (j = 0; j <=col; j++) { printf(" %d ", j); } printf("\n"); printf("-"); for (j = 1; j <= col + 1; j++) { printf("---"); printf("|"); } printf("\n");//列對(duì)應(yīng)打印完成 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");//行對(duì)應(yīng)嵌套在內(nèi)部 打印的數(shù)前加0是為了讓當(dāng)行數(shù)大于9時(shí)能夠?qū)?yīng) 如09與10 } } mine_make(char mine[ROWS][COLS], int row, int col)//設(shè)置雷 { 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)//得到一個(gè)坐標(biāo)附近雷的個(gè)數(shù) { 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';//此處我們的數(shù)字其實(shí)是字符,用此方法可以轉(zhuǎn)為數(shù)字整形 } void spread(char show[ROWS][COLS], char mine[ROWS][COLS], int x, int y)//遞歸方法實(shí)現(xiàn)一大片 { show[x][y] = ' ';//先讓輸入金的坐標(biāo)處變?yōu)榭崭瘢驗(yàn)橐呀?jīng)判定過(guò)雷所以可以直接轉(zhuǎn)空格 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循環(huán)表示輸入坐標(biāo)包括自生及周圍八個(gè) { if (i > 0 && i <= ROW && j > 0 && j <= COL && mine[i][j] != '1' && show[i][j] == '*')//防止出現(xiàn)負(fù)坐標(biāo),避免有雷,避免輸入重復(fù) { ret = get_mine(mine, i, j);//判斷ret是0或非0,并得出周圍雷數(shù) if (!ret)//如果ret=0,!ret便是非0;為真 { spread(show, mine, i, j);//遞歸 } if (ret)//ret!=0時(shí)為真,便打印數(shù) { show[i][j] = ret + '0';//使數(shù)字轉(zhuǎn)成對(duì)應(yīng)字符 } } } } } void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)//排查雷 { printf("請(qǐng)輸入坐標(biāo)\n"); int i = 0; int j = 0; int win = 0; while (row*col-10)//因?yàn)槭鞘畟€(gè)雷,所以是—10,因?yàn)橄驴倲?shù)減10就贏了,所以可以以此跳出循環(huán),當(dāng)然要是雷部位10,定一個(gè)變量就行,此處就不改了 { 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);//設(shè)置雷 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; }
總結(jié)
到此這篇關(guān)于c語(yǔ)言實(shí)現(xiàn)含遞歸清場(chǎng)版掃雷游戲的文章就介紹到這了,更多相關(guān)c語(yǔ)言實(shí)現(xiàn)掃雷內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C語(yǔ)言實(shí)現(xiàn)第一次防死版掃雷游戲
- C語(yǔ)言實(shí)現(xiàn)遞歸版掃雷游戲?qū)嵗?/a>
- C語(yǔ)言實(shí)現(xiàn)掃雷游戲詳解(附源碼)
- 基于C語(yǔ)言掃雷游戲的設(shè)計(jì)與實(shí)現(xiàn)
- C語(yǔ)言實(shí)現(xiàn)掃雷游戲小項(xiàng)目
- 基于C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的掃雷小游戲
- C語(yǔ)言掃雷游戲的簡(jiǎn)單實(shí)現(xiàn)
- C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易的掃雷游戲
- C語(yǔ)言掃雷詳細(xì)代碼分步實(shí)現(xiàn)流程
相關(guān)文章
C++ 實(shí)現(xiàn)優(yōu)先隊(duì)列的簡(jiǎn)單實(shí)例
這篇文章主要介紹了C++ 實(shí)現(xiàn)優(yōu)先隊(duì)列的簡(jiǎn)單實(shí)例的相關(guān)資料,希望通過(guò)本文能幫助大家實(shí)現(xiàn)優(yōu)先隊(duì)列,需要的朋友可以參考下2017-08-08用C語(yǔ)言舉例講解數(shù)據(jù)結(jié)構(gòu)中的算法復(fù)雜度結(jié)與順序表
這篇文章主要介紹了講解數(shù)據(jù)結(jié)構(gòu)中的算法復(fù)雜度結(jié)與順序表的C語(yǔ)言版示例,包括對(duì)時(shí)間復(fù)雜度和空間復(fù)雜度等概念的簡(jiǎn)單講解,需要的朋友可以參考下2016-02-02C++實(shí)現(xiàn)LeetCode(141.單鏈表中的環(huán))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(141.單鏈表中的環(huán)),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07基于C語(yǔ)言實(shí)現(xiàn)隨機(jī)點(diǎn)名器(附源碼)
這篇文章主要為大家詳細(xì)介紹如何基于C語(yǔ)言實(shí)現(xiàn)一個(gè)簡(jiǎn)單的隨機(jī)點(diǎn)名器,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起動(dòng)手嘗試一下2022-07-07嵌入式C實(shí)戰(zhàn)項(xiàng)目開發(fā)技巧:對(duì)一個(gè)有規(guī)律的數(shù)組表進(jìn)行位移操作的方法
今天小編就為大家分享一篇關(guān)于嵌入式C實(shí)戰(zhàn)項(xiàng)目開發(fā)技巧:對(duì)一個(gè)有規(guī)律的數(shù)組表進(jìn)行位移操作的方法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12Qt信號(hào)與槽知識(shí)點(diǎn)總結(jié)歸納
信號(hào)和槽是一種高級(jí)接口,應(yīng)用于對(duì)象之間的通信,它是QT的核心特性,下面這篇文章主要給大家介紹了關(guān)于Qt信號(hào)與槽知識(shí)點(diǎn)總結(jié)歸納的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12c++中vector<int>和vector<int*>的用法及區(qū)別
這篇文章主要介紹了c++中vector<int>和vector<int*>的用法及區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2013-10-10C++進(jìn)程共享數(shù)據(jù)封裝成類實(shí)例
這篇文章主要介紹了C++進(jìn)程共享數(shù)據(jù)封裝成類的方法,以實(shí)例形式講述了其封裝代碼與具體用法,具有一定的實(shí)用價(jià)值,需要的朋友可以參考下2014-10-10