目錄
引言:
三個新功能實現
? ? ? ? 1.可以選擇難度或自定義
? ? ? ?
? ? ? ? 實現難點解析
? ? ? ? 代碼實現(附源碼)
?
????????掃雷.c
? ? ? ? game.h
? ? ? ? game.c
????????2.對選擇位置進行標記或取消標記
? ? ? ? 一.框架
? ? ? ? 我們先理一下思路
? ? ? ? 如何構造框架
? ? ? ? 二.取消標記函數
? ? ? ? 三.標記函數
????????四.加入清屏,進行優化
? ? ? ? 源碼
? ? ? ? game.c
? ? ? ? 3.點的鋪開(相比其他較難)
拓展版源碼
game.h
game.c
掃雷.c
結語:
?
引言:
? ? ? ? 那么,本篇我們來對之前的基礎版掃雷進行拓展,來實現一個相比于網頁版的掃雷,只少了一個計時功能的掃雷游戲。總代碼量約為450行左右,并不會很多
? ? ? ? 那么,沒看過掃雷基礎篇的請移步C語言制作掃雷游戲(基礎版賦源碼)-CSDN博客看完再來看這篇,因為該篇代碼是基于基礎版掃雷代碼改編而來
? ? ? ? 那么,接下來,我們進入正文(紅色部分是老代碼,綠色為更改后代碼,后面就不強調啦)
????????????????????????
三個新功能實現
? ? ? ? 我推薦從上往下依次看這四個功能如何實現,因為一開始是基礎版的源碼,然后呢,我會按著一步步的順序將基礎版的源碼進行優化與功能實現,可以把基礎版的三個文件的源碼復制到你的編譯器中,然后跟著我的思路進行更改時,對比也比較清晰,從上往下看就不會遺漏有些代碼的更改與變化,最后的完整代碼是一步一步改下來的,那么我們開始? ? ? ??
?
? ? ? ? 1.可以選擇難度或自定義
? ? ? ? 首先,我們先進行最簡單的一個功能的實現,那就是選擇難度與自定義難度,那我們把它拆分成選擇難度和自定義難度倆個塊來進行處理
? ? ? ?
? ? ? ? 實現難點解析
? ? ? ? 首先是選擇難度,這個十分簡單,我們先來確定一個各個難度的長寬與雷的數量
? ? ? ? 在基礎篇中,我們是只有一個9*9的格子,然后雷的數量是10個,那么,我們就當這個是easy難度,我是這么設置難度劃分的
? ? ? ? 簡單:9*9的格子,10個雷
? ? ? ? 中等:16*16的格子,40個雷
? ? ? ? 困難:30*16的格子,99個雷
? ? ? ? 那么,我們先看變量
????????在基礎版中因為只有一個9*9的格子,所以我們只用了下圖中紅色區域的代碼,用Chang來表示棋盤的長,用Kuan來表示棋盤的寬,Changs和Kuans表示數組的大小,然后用Leisum來表示棋盤中雷的個數
? ? ? ? 因為有了不同難度的選擇,所以我們可以將宏定義把簡單,中等,困難的長度,寬度和雷數都進行定義,然后在之后的程序中因為選擇的不同來使用不用的宏名(宏定義定義的變量)即可,為了方便理解,可以像我這樣在前面加上一個前綴E表示簡單,M表示中等,H表示困難,如圖
? ? ? ? 那么,大小方面搞定了,那么數組應該怎么創建呢,如果像基礎版那個樣子寫的話,那數組創建又是個大問題了,這里就有2種方案了,我是用的第二種方案
? ? ? ? 一.根據輸入的值,選擇出難度后,然后創建一個數組,數組中的數字用宏名來頂替,就跟之前基礎版的一樣,但是,因為有第四種情況,就是自定義的情況,變量可創不了數組(后面傳遞數組時難以接收,因為你不知道接收時的形參函數部分的列里該寫什么,但列又不能省略),所以又要為了第四段專門再寫一段代碼,而且最主要的是,若創建的數組大小不一,那么在調用函數傳遞數組時候,就需要寫多個函數了,會使代碼及其冗雜,這就很影響代碼的可讀性了,而且因為自定義的存在,之后還是會創建第二種方法的數組,所以我選擇的是第二種方法,當然,如果想要用第一種方法的話也可以嘗試一下,就是game.c里的代碼長度可能會很長
? ? ? ? 二.在選擇前,先創建100*100的二維數組,這樣不管選擇哪個難度,都可以進行操作(因為自定義范圍肯定會限制,太大不利于游玩,一般都限制在50*16左右)
? ? ? ? 如圖,即可
????????
? ? ? ? 那么問題都解決了,我們來進行代碼實現
?
? ? ? ? 代碼實現(附源碼)
????????掃雷.c
? ? ? ? 我們先對掃雷.c進行操作,對基礎版掃雷的框架進行更改,因為有難度選擇了,那我們先自定義一個Level函數用于輸出選擇難度的菜單,如圖
? ? ? ? 菜單創建完后,接下來就是?game函數內部的更改了,代碼如下,首先我們先創建四個變量
? ? ? ? input? ? 用于選擇難度特判
? ? ? ? chang和kuan? 用于自定義難度時輸入長和寬
? ? ? ? lei? ? ? ? 用于自定義難度時雷數量的輸入
? ? ? ? 1.接下來我們先使用do while語句,讓用戶根據提示輸入信息,若輸入有問題就其實用戶重新輸入,直到按要求輸入位置
? ? ? ? 2.而后,我們創建倆個數組,只是數組的范圍變化了一下,變為了100*100,代表的意思依舊如基礎版一樣,cun表示暗盤,show表示明盤
? ? ? ? 3.接下來再通過switch語句,根據input的值跳轉到對應的情況中,case 1,2,3都是同樣的情況,只需要將函數中的參數變一下就可以了,這部分如何操作以及函數里每個參數分別代表什么在基礎版里已經講過了,就不過多贅述了,case 4的自定義也是如此,只是需要多加上一步輸入雷盤的長與寬與雷的個數,并根據輸入情況進行反饋,直至符合要求后跳出do while循環,然后再進行同樣的操作即可
? ? ? ? 下面就是掃雷.c的源碼,其余部分不用變動
void Lelve()
{printf("************************\n");printf("*** 1.easy(9*9 10) ***\n");printf("*** 2.mid(16*16 40) ***\n");printf("*** 3.hard(30*16 99) ***\n");printf("*** 4.自定義 ***\n");printf("************************\n");
}void game()
{int input = 0;int chang = 0, kuan = 0, lei = 0;Lelve();printf("請選擇:");do {scanf("%d", &input);if (input < 1 || input>4){printf("輸入有誤,請重新輸入:");continue;}break;} while (1);char cun[100][100] = { 0 };char show[100][100] = { 0 };switch (input){case 1:chu(cun, EKuans, EChangs, '0');chu(show, EKuans, EChangs, '*');//布置雷set(cun, EKuan, EChang, ELeisum);//打印棋盤print(show, EKuan, EChang);//排查雷Findlei(cun, show, EKuan, EChang, ELeisum);break;case 2:chu(cun, MKuans, MChangs, '0');chu(show, MKuans, MChangs, '*');//布置雷set(cun, MKuan, MChang, MLeisum);//打印棋盤print(show, MKuan, MChang);//排查雷Findlei(cun, show, MKuan, MChang, MLeisum);break;case 3:chu(cun, HKuans, HChangs, '0');chu(show, HKuans, HChangs, '*');//布置雷set(cun, HKuan, HChang, HLeisum);//打印棋盤print(show, HKuan, HChang);//排查雷Findlei(cun, show, HKuan, HChang, HLeisum);break;case 4:printf("請輸入長度 寬度 雷的個數(長<=50 寬<=16 雷數<長*寬)\n");//過大控制臺太小,屏幕會亂跳,不好操控do{scanf("%d %d %d", &chang, &kuan, &lei);if (chang > 50 || chang < 1 || kuan>50 || kuan < 1 || chang * kuan <= lei){printf("輸入有誤,請重新輸入:");continue;}break;} while (1);chu(cun, kuan+2, chang+2, '0');chu(show, kuan+2, chang+2, '*');//布置雷set(cun, kuan, chang, lei);//打印棋盤print(show, kuan, chang);//排查雷Findlei(cun, show, kuan, chang, lei);break;}
}
? ? ? ? 那么掃雷.c里的更改已經完成了,接下來就是通過更改game,h和game.c中的函數來實現即可,那么這邊就只是改個參數的事情了,這邊就直接放代碼啦(只有Findlie函數部分略有變化,多了一個參數,里面也變了一點點,但很明了,看一眼就知道了,就不多贅述啦),自己比對一下函數部分喲
?
? ? ? ? game.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>#define EChang 9//好處是,想更改棋盤大小時候直接改這里就好了,不用在程序里一個個改,方便很多
#define EKuan 9#define MChang 16
#define MKuan 16#define HChang 30
#define HKuan 16#define EChangs EChang+2
#define EKuans EKuan+2#define MChangs MChang+2
#define MKuans MKuan+2#define HChangs HChang+2
#define HKuans HKuan+2#define ELeisum 10
#define MLeisum 40
#define HLeisum 99void chu(char arr[][100], int hang, int lie, char fu);void print(char arr[][100], int lie, int hang);void set(char arr[][100], int hang, int lie, int ge);void Findlei(char yin[][100], char xian[][100], int lie, int hang, int leisum);
?
? ? ? ? game.c
? ? ? ? game.c中,除了game.h的變化,就只有print函數(改了輸出格式,因為有多位數了,不該輸出格式會使打印出來的對不齊)和FIndlie函數里面發生了略微變化,但因為變化目的很明顯,也很易懂,就直接放源碼啦
#define _CRT_SECURE_NO_WARNINGS#include "game.h"//初始化棋盤
void chu(char arr[][100],int hang,int lie,char fu)
{for (int i = 0; i < hang; i++){for (int j = 0; j < lie; j++)arr[i][j] = fu;}
}//打印棋盤
void print(char arr[][100], int hang, int lie)
{for (int i = 0; i <= lie; i++)printf("%d ", i);printf("%2d ", i);printf("\n");for (int i = 1; i <= hang; i++){printf("%d ", i);printf("%2d ", i);for (int j = 1; j <= lie; j++)printf("%c ", arr[i][j]);printf("%2c ", arr[i][j]);printf("\n");}
}//布置雷
void set(char arr[][100],int hang,int lie,int ge)
{while (ge--){int h = 1 + rand() % hang;int l = 1 + rand() % lie;if (arr[h][l] == '0'){arr[h][l] = '1';}elsege++;}
}void Findlei(char yin[][100], char xian[][100], int hang, int lie,int leisum)
{int x = 0, y = 0;int ge = 0;while (1){printf("請輸入要排查的坐標(行 列):");scanf("%d %d", &x, &y);if (x<1 || x>hang || y<1 || y>lie)printf("輸入的坐標有誤,請重新輸入:");else if (xian[x][y] != '*')printf("該坐標已排查過,請重新輸入:");else{if (yin[x][y] == '1'){system("cls");printf("很遺憾,你被炸死了,游戲結束\n");print(yin, hang, lie);break;}else{int fang[8][2] = { {0,1},{0,-1},{-1,0},{1,0},{1,1},{1,-1},{-1,1},{-1,-1} };xian[x][y] = '0';for (int i = 0; i < 8; i++){if (yin[x + fang[i][0]][y + fang[i][1]] == '1')xian[x][y]++;}ge++;system("cls");if (ge + Leisum == Kuan * Chang)print(xian, hang, lie);if (ge + leisum == hang * lie){printf("恭喜你,排雷成功\n");break;}}}}
}
? ? ? ? 那么這部分完成后,現在的代碼就多出可以選擇難度和自定義的功能啦,那么,網頁版有插旗子標記,我們也不能少,接下來,我們來講對棋盤進行標記與取消標記
????????????????????????????????
????????2.對選擇位置進行標記或取消標記
? ? ? ? 這一部分在game.c里實現
? ? ? ? 那么這部分開始就比較要吃點邏輯了,我打算分三步來講,先把框架講清楚后,再分別講標記與取消標記這倆個函數
? ? ? ? 一.框架
? ? ? ? 我們先理一下思路
? ? ? ? 總所周知,在我們原先的代碼里,我們不管進不進行模式選擇,到最后都會輸出一次棋盤,然后再進入Findlei函數之中,
????????那么我們想要在排查雷之前,先詢問一下意向,是排雷,還是標點,還是取消標點,這塊部分,就可以在Findlei函數中實現,只需要放在排雷的前面執行即可;
????????然后因為在網頁游戲中,玩掃雷標點是想標就標,想把標的點去掉就去掉,然后或者進行掃雷,掃雷前可以無限次的進行標點或者取消標點,只要標點的數量不超過雷的數量即可
? ? ? ? 那么大致要求已經說完了,我們來看看怎么打,首先來看下我的代碼,如圖,我們結合代碼來分析(紅綠代碼更有辨識度,就用圖片了)
? ? ? ? 如何構造框架
? ? ? ? 我們多創建2個變量
? ? ? ? biaoji? ? ? ? 代表目前盤上標記的個數
? ? ? ? input? ? ? ? 用于特判標記還是取消標記還是排雷
? ? ? ? 首先,依舊是跟一樣的while語句,知識要在排雷前進行選擇的操作,那么,我們就要給他菜單,即代碼中的Choose函數
? ? ? ? 然后因為要進行提示,并且判斷輸入是否合理,合理的話就進行對應的操作,這個時候我們就用到了我們的do while循環來判斷輸入的合理性和我們的switch語句來進入要執行對應操作的分支語句,以及通過biaoji的值的變化來判斷是否符合要求。
??
? ? ? ? 執行完這些操作后,代碼的框架就基本構筑完成了,代碼中的Biaolei函數便是標記雷函數的具體實現,Clearlei函數便是取消標記雷的具體實現,因為取消標記雷更好實現,那我們先講取消標記函數
? ? ? ? 二.取消標記函數
? ? ? ? 取消標記函數我們只需要做到在這個函數中先命名倆個變量
? ? ? ? 我就命名了x,y來表示坐標
? ? ? ? 然后進入while循環,提示輸入取消標記的坐標,直至輸入的坐標符合要求,就跳出循環,將對應的那個點位賦值為 ' * '即可,最后在進行一次打印就可以了,因為若進入了這個語句,就不會去排雷的部分,自然就不會打印了,所以需要在這邊寫上print函數來打印暗盤
? ? ? ?代碼如下,十分簡單? ? ? ? ?
?
? ? ? ? 三.標記函數
? ? ? ? 如果取消標記函數弄懂了,再看這個就會簡單很多,這個函數就是需要多一層操作
? ? ? ? 先給代碼,然后我來圍繞代碼來講,應該更容易懂
? ? ? ? 首先,先創建三個變量
????????一個x,一個y,用來表示想要標記的坐標
? ? ? ? 還有一個type??用來表示判斷想要標記的坐標類型是?還是!? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? 然后套一層while循環,若輸入不滿足要求,就反饋相應信息要求重新輸入,直到滿足要求為止,跳出循環
? ? ? ? 跳出循環后,進入menubiao函數,給出提示,然后依舊與往常一樣,用while循環套上,進行輸入,直到輸入滿足條件跳出
? ? ? ? 然后用switch語句進行跳轉,進入想要執行的語句中,然后通過x,y的坐標,將那個位置的明盤上的‘*’賦值成對應符號
? ? ? ? 最后再進行一次輸出,即可,至于為什么要輸出一次明盤,原因和取消標記函數里一樣
????????
?
????????四.加入清屏,進行優化
? ? ? ? 這個功能到這里來說就已經實現完畢了,但我們在運行時,會發現輸出會很亂,這時候,就要稍稍改變一下代碼的順序,再插入清屏,實現運行代碼時的那種清爽感了,這里就不細講啦,跟著下面的代碼看,很容易就理解啦
?
那么,對選擇位置進行標記或取消標記的這個功能也實現啦,我把實現這個功能后的源碼發出來
? ? ? ? 源碼
? ? ? ? 因為這個功能并沒有改動game.c與掃雷.c,那倆個的碼就不發啦
? ? ? ? game.c
#define _CRT_SECURE_NO_WARNINGS#include "game.h"//初始化棋盤
void chu(char arr[][100], int hang, int lie, char fu)
{for (int i = 0; i < hang; i++){for (int j = 0; j < lie; j++)arr[i][j] = fu;}
}//打印棋盤
void print(char arr[][100], int hang, int lie)
{for (int i = 0; i <= lie; i++)printf("%2d ", i);printf("\n");for (int i = 1; i <= hang; i++){printf("%2d ", i);for (int j = 1; j <= lie; j++)printf("%2c ", arr[i][j]);printf("\n");}
}//布置雷
void set(char arr[][100], int hang, int lie, int ge)
{while (ge--){int h = 1 + rand() % hang;int l = 1 + rand() % lie;if (arr[h][l] == '0'){arr[h][l] = '1';}elsege++;}
}static void Choose()
{printf("******************\n");printf("*** 1.標記 ***\n");printf("*** 2.取消標記 ***\n");printf("*** 0.排雷 ***\n");printf("******************\n");
}static void menubiao()
{printf("*********************\n");printf("**** 1.?(不確定) ****\n");printf("**** 2.!(肯定) ****\n");printf("*********************\n");
}//標記雷
void Biaolei(char arr[][100], int hang, int lie)
{int x = 0, y = 0;int type = 0;while (1){printf("請輸入要標記的坐標:");scanf("%d %d", &x, &y);if (x<1 || x>hang || y<1 || y>lie){printf("輸入的坐標有誤,請重新輸入\n");continue;}else if (arr[x][y] == '?' || arr[x][y] == '!'){printf("該位置已被標記,請重新輸入\n");continue;}else if (arr[x][y] != '*'){printf("該坐標已被排查,無法標記,請重新輸入\n");continue;}break;}menubiao();do{printf("請輸入要標記的類型:");scanf("%d", &type);if (type != 1 && type != 2){printf("不存在該選項,請重新輸入\n");continue;}break;} while (1);switch (type){case 1:arr[x][y] = '?';print(arr, hang, lie);break;case 2:arr[x][y] = '!';print(arr, hang, lie);break;}
}//取消標記雷
void Clearlei(char arr[][100], int hang, int lie)
{int x = 0, y = 0;int type = 0;while (1){printf("請輸入要取消標記的坐標:");scanf("%d %d", &x, &y);if (x<1 || x>hang || y<1 || y>lie){printf("輸入的坐標有誤,請重新輸入\n");continue;}else if (arr[x][y] != '?' && arr[x][y] != '!'){printf("該位置未被標記,請重新輸入\n");continue;}break;}arr[x][y] = '*';print(arr, hang, lie);
}//排查,標記雷
void Findlei(char yin[][100], char xian[][100], int hang, int lie, int leisum)
{int x = 0, y = 0;int ge = 0;int biaoji = 0;int input = 0;while (1){do{system("cls");print(xian, hang, lie);Choose();printf("請選擇:");scanf("%d", &input);if (input != 1 && input != 2 && input != 0){printf("輸入有誤,請重新輸入\n");}if (biaoji >= leisum && input == 1){printf("標記個數已超出雷數,請重新選擇\n");continue;}if (biaoji <= 0 && input == 2){printf("已經沒有可以取消標記的點了,請重新選擇\n");continue;}switch (input){case 1:Biaolei(xian, hang, lie);biaoji++;break;case 2:Clearlei(xian, hang, lie);biaoji--;break;default:break;}} while (input);do{printf("請輸入要排查的坐標(行 列):");scanf("%d %d", &x, &y);if (x<1 || x>hang || y<1 || y>lie){printf("輸入的坐標有誤,請重新輸入\n");continue;}else if (xian[x][y] == '?' || xian[x][y] == '!'){printf("該位置已被標記,請重新輸入\n");continue;}else if (xian[x][y] != '*'){printf("該坐標已排查過,請重新輸入\n");continue;}break;} while (1);if (yin[x][y] == '1'){system("cls");printf("很遺憾,你被炸死了,游戲結束\n");print(yin, hang, lie);break;}else{int fang[8][2] = { {0,1},{0,-1},{-1,0},{1,0},{1,1},{1,-1},{-1,1},{-1,-1} };xian[x][y] = '0';for (int i = 0; i < 8; i++){if (yin[x + fang[i][0]][y + fang[i][1]] == '1')xian[x][y]++;}ge++;system("cls");print(xian, hang, lie);if (ge + leisum == hang * lie){printf("恭喜你,排雷成功\n");break;}}}
}
? ? ? ?
那么,這個功能也結束啦,最后一個功能,也是最難的一個功能,那便是實現像網頁版那樣的點一個點,鋪開一片。
????????????????????????????????????????
? ? ? ? 3.點的鋪開(相比其他較難)
? ? ? ? 這個部分的實現用到了函數的遞歸,也涉及一點的算法,與前倆個部分相比,這個功能的實現呈指數型上升,因為搜索這個知識具體來講的話在這篇文章里很難講清楚,所以這里我主要是講思路,然后dfs,bfs這種搜索有空我會專門出一篇來講解,所以,如果初學者代碼沒看懂也沒關系,我用的是深度搜索(即dfs)來實現這個功能的
? ? ? ? 首先,因為我們實現這個為了使內存損耗小,需要用到bool類型的數組,所以我們需要先在game.h的頭文件內加入#include <stdbool.h>這一行代碼
? ? ? ? ok,說回正題,這個部分,雖然是這三個功能中最難實現的,但代碼卻是最簡短的,如圖,上圖是自定義函數,下圖是Findlei函數中略微改變的部分。
? ? ? ? 那么,我來簡單說下這部分的思路,首先將方位數組(就那個fang數組)放在全局變量中,這樣可以保證進入zhanlei函數時也可以使用,然后將當前坐標的訪問標記成1,然后算出當前坐標附近有沒有雷,如果有雷,就不進入函數,如果沒雷,就進入zhanlei函數,然后通過八個方位來進行深搜,然后深搜過程中也不能忘了排雷個數的++,然后當程序運行完后,就展開一片了,函數功能也就實現了
當然,如果直接這樣就結束,肯定也會有bug,就比如如果雷的個數在展開的那個函數中加到了排雷要求數,他判斷排雷成功后,會直接輸出明盤,但其實明盤那時候還并不是掃雷的最終結果,所以要輸出暗盤,所以只需要再補上這么一行就可以啦
? ? ? ? ?那么,到此,掃雷的所有功能講解就全部講完啦,接下來,最終版源碼附上
????????????????????????
?
拓展版源碼
?
game.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#define EChang 9//好處是,想更改棋盤大小時候直接改這里就好了,不用在程序里一個個改,方便很多
#define EKuan 9#define MChang 16
#define MKuan 16#define HChang 30
#define HKuan 16#define EChangs EChang+2
#define EKuans EKuan+2#define MChangs MChang+2
#define MKuans MKuan+2#define HChangs HChang+2
#define HKuans HKuan+2#define ELeisum 10
#define MLeisum 40
#define HLeisum 99void chu(char arr[][100], int hang, int lie, char fu);void print(char arr[][100], int lie, int hang);void set(char arr[][100], int hang, int lie, int ge);void Findlei(char yin[][100], char xian[][100], int lie, int hang, int leisum);
?
game.c
#define _CRT_SECURE_NO_WARNINGS#include "game.h"//初始化棋盤
void chu(char arr[][100],int hang,int lie,char fu)
{for (int i = 0; i < hang; i++){for (int j = 0; j < lie; j++)arr[i][j] = fu;}
}//打印棋盤
void print(char arr[][100], int hang, int lie)
{for (int i = 0; i <= lie; i++)printf("%2d ", i);printf("\n");for (int i = 1; i <= hang; i++){printf("%2d ", i);for (int j = 1; j <= lie; j++)printf("%2c ", arr[i][j]);printf("\n");}
}//布置雷
void set(char arr[][100],int hang,int lie,int ge)
{while (ge--){int h = 1 + rand() % hang;int l = 1 + rand() % lie;if (arr[h][l] == '0'){arr[h][l] = '1';}elsege++;}
}static void Choose()
{printf("******************\n");printf("*** 1.標記 ***\n");printf("*** 2.取消標記 ***\n");printf("*** 0.排雷 ***\n");printf("******************\n");
}static void menubiao()
{printf("*********************\n");printf("**** 1.?(不確定) ****\n");printf("**** 2.!(肯定) ****\n");printf("*********************\n");
}//標記雷
void Biaolei(char arr[][100],int hang,int lie)
{int x = 0, y = 0;int type = 0;while (1){printf("請輸入要標記的坐標:");scanf("%d %d", &x, &y);if (x<1 || x>hang || y<1 || y>lie){printf("輸入的坐標有誤,請重新輸入\n");continue;}else if (arr[x][y] == '?' || arr[x][y] == '!'){printf("該位置已被標記,請重新輸入\n");continue;}else if (arr[x][y] != '*'){printf("該坐標已被排查,無法標記,請重新輸入\n");continue;}break;}menubiao();do{printf("請輸入要標記的類型:");scanf("%d", &type);if (type != 1 && type != 2){printf("不存在該選項,請重新輸入\n");continue;}break;} while (1);switch (type){case 1:arr[x][y] = '?';print(arr, hang, lie);break;case 2:arr[x][y] = '!';print(arr, hang, lie);break;}
}//取消標記雷
void Clearlei(char arr[][100], int hang, int lie)
{int x = 0, y = 0;int type = 0;while (1){printf("請輸入要取消標記的坐標:");scanf("%d %d", &x, &y);if (x<1 || x>hang || y<1 || y>lie){printf("輸入的坐標有誤,請重新輸入\n");continue;}else if (arr[x][y] != '?' && arr[x][y] != '!'){printf("該位置未被標記,請重新輸入\n");continue;}break;}arr[x][y] = '*';print(arr, hang, lie);
}//展開
bool vis[100][100];
int fang[8][2] = { {0,1},{0,-1},{-1,0},{1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
void zhanlei(char yin[][100], char xian[][100], int hang, int lie, int x, int y, int* ge)
{if (xian[x][y] != '0')return;for (int i = 0; i < 8; i++){int x1 = x + fang[i][0];int y1 = y + fang[i][1];if (!vis[x1][y1] && yin[x1][y1] != '1' && x1 >= 1 && x1 <= hang && y1 >= 1 && y1 <= lie){(*ge)++;xian[x1][y1] = '0';vis[x1][y1] = 1;for (int i = 0; i < 8; i++){if (yin[x1 + fang[i][0]][y1 + fang[i][1]] == '1')xian[x1][y1]++;}zhanlei(yin, xian, hang, lie, x1, y1, ge);}}
}//排查雷
void Findlei(char yin[][100], char xian[][100], int hang, int lie,int leisum)
{int x = 0, y = 0;int ge = 0;int biaoji = 0;int input = 0;while (1){do{system("cls");print(xian, hang, lie);Choose();printf("請選擇:");scanf("%d", &input);if (input != 1 && input != 2 && input != 0){printf("輸入有誤,請重新輸入\n");}if (biaoji >= leisum && input == 1){printf("標記個數已超出雷數,請重新選擇\n");continue;}if (biaoji <= 0 && input == 2){printf("已經沒有可以取消標記的點了,請重新選擇\n");continue;}switch (input){case 1:Biaolei(xian, hang, lie);biaoji++;break;case 2:Clearlei(xian, hang, lie);biaoji--;break;default:break;}} while (input);do{printf("請輸入要排查的坐標(行 列):");scanf("%d %d", &x, &y);if (x<1 || x>hang || y<1 || y>lie){printf("輸入的坐標有誤,請重新輸入\n");continue;}else if (xian[x][y] == '?' || xian[x][y] == '!'){printf("該位置已被標記,請重新輸入\n");continue;}else if (xian[x][y] != '*'){printf("該坐標已排查過,請重新輸入\n");continue;}break;} while (1);if (yin[x][y] == '1'){system("cls");printf("很遺憾,你被炸死了,游戲結束\n");print(yin, hang, lie);break;}else{xian[x][y] = '0';vis[x][y] = 1;for (int i = 0; i < 8; i++){if (yin[x + fang[i][0]][y + fang[i][1]] == '1')xian[x][y]++;}ge++;if(xian[x][y]=='0')zhanlei(yin, xian, hang, lie, x, y, &ge);system("cls");print(xian, hang, lie);if (ge + leisum == hang * lie){system("cls");print(yin, hang, lie);printf("恭喜你,排雷成功\n");break;}}}
}
?
掃雷.c
#define _CRT_SECURE_NO_WARNINGS#include "game.h"
void menu()
{printf("********************\n");printf("***** 1.play *****\n");printf("***** 0.exit *****\n");printf("********************\n");
}void Lelve()
{printf("************************\n");printf("*** 1.easy(9*9 10) ***\n");printf("*** 2.mid(16*16 40) ***\n");printf("*** 3.hard(30*16 99) ***\n");printf("*** 4.自定義 ***\n");printf("************************\n");
}void game()
{//初始化函數int input = 0;int chang = 0, kuan = 0, lei = 0;Lelve();printf("請選擇:");do {scanf("%d", &input);if (input < 1 || input>4){printf("輸入有誤,請重新輸入:");continue;}break;} while (1);char cun[100][100] = { 0 };char show[100][100] = { 0 };switch (input){case 1:chu(cun, EKuans, EChangs, '0');chu(show, EKuans, EChangs, '*');//布置雷set(cun, EKuan, EChang, ELeisum);//打印棋盤print(show, EKuan, EChang);//排查雷,標記雷Findlei(cun, show, EKuan, EChang, ELeisum);break;case 2:chu(cun, MKuans, MChangs, '0');chu(show, MKuans, MChangs, '*');//布置雷set(cun, MKuan, MChang, MLeisum);//打印棋盤print(show, MKuan, MChang);//排查雷Findlei(cun, show, MKuan, MChang, MLeisum);break;case 3:chu(cun, HKuans, HChangs, '0');chu(show, HKuans, HChangs, '*');//布置雷set(cun, HKuan, HChang, HLeisum);//打印棋盤print(show, HKuan, HChang);//排查雷Findlei(cun, show, HKuan, HChang, HLeisum);break;case 4:printf("請輸入長度 寬度 雷的個數(長<=50 寬<=16 雷數<長*寬)\n");//過大控制臺太小,屏幕會亂跳,不好操控do{scanf("%d %d %d", &chang, &kuan, &lei);if (chang > 50 || chang < 1 || kuan>50 || kuan < 1 || chang * kuan <= lei){printf("輸入有誤,請重新輸入:");continue;}break;} while (1);chu(cun, kuan+2, chang+2, '0');chu(show, kuan+2, chang+2, '*');//布置雷set(cun, kuan, chang, lei);//打印棋盤print(show, kuan, chang);//排查雷Findlei(cun, show, kuan, chang, lei);break;}
}void test()
{srand((unsigned int)time(NULL));int input = 0;do{menu();printf("請選擇:");scanf("%d", &input);switch (input){case 1:system("cls");printf("游戲開始\n");game();break;case 0:system("cls");printf("歡迎下次游玩\n");break;default:printf("輸入錯誤,請重新輸入\n");break;}} while (input);
}int main()
{test();return 0;
}
?
結語:
? ? ? ? 那么本篇文章的內容就到此為止啦,希望對你有所幫助,謝謝觀看啦,如果覺得有幫助可以轉發給朋友一起看喲,畢竟一個人走的快,一群人走的遠嘛,有競爭對手才有動力嘛
?