C語言制作掃雷游戲(拓展版賦源碼)

目錄

引言:

三個新功能實現

? ? ? ? 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;
}

?

結語:

? ? ? ? 那么本篇文章的內容就到此為止啦,希望對你有所幫助,謝謝觀看啦,如果覺得有幫助可以轉發給朋友一起看喲,畢竟一個人走的快,一群人走的遠嘛,有競爭對手才有動力嘛

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/95754.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/95754.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/95754.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python快速入門專業版(十):字符串特殊操作:去除空格、判斷類型與編碼轉換

目錄引1.去除空格&#xff1a;清理字符串的實用技巧1.1 三類去空格方法&#xff1a;strip()、lstrip()、rstrip()1.2 實戰案例&#xff1a;處理用戶輸入的空格問題2.判斷類型&#xff1a;驗證字符串內容的特性2.1 常用類型判斷方法2.2 實戰案例&#xff1a;驗證用戶輸入的合法性…

Gamma AI:AI演示文稿制作工具,高效解決PPT框架搭建難與排版耗時問題

你做 PPT 的時候是不是也常陷入 “兩難”&#xff1f;要么對著空白幻燈片發呆&#xff0c;不知道怎么搭框架 —— 比如要做 “產品季度迭代復盤”&#xff0c;既想放數據又想講問題&#xff0c;結果頁面堆得像亂燉&#xff1b;要么好不容易湊完內容&#xff0c;又花兩小時調排版…

【應用案例】AI 給醫用過濾器 “找茬”:3 大難點 + 全流程解決方案

【應用案例】AI 給醫用過濾器 “找茬”&#xff1a;3 大難點 全流程解決方案&#x1f3af;醫用過濾器進行醫療AI檢測&#x1f3af;先看痛點&#xff1a;醫用過濾器檢測難在哪&#xff1f;&#x1f3af;AI檢測方案&#xff1a;3步實現“零漏檢”1. 硬件定制&#xff1a;讓缺陷“…

【數據庫相關】TxSQL新增數據庫節點步驟

TxSQL新增數據庫節點步驟準備工作與注意事項具體操作步驟第 1 步&#xff1a;在主庫上創建復制專用賬號第 2 步&#xff1a;對主庫進行鎖表并獲取二進制日志坐標第 3 步&#xff1a;備份主庫數據并傳輸到新從庫第 4 步&#xff1a;主庫解鎖第 5 步&#xff1a;在新從庫服務器上…

Jmeter快速安裝配置全指南

1、JDK安裝(Java Development Kit) 1.1.JDK下載 JDK下載址&#xff1a; Java Downloads | Oracle &#xff08;jdk-8u211-windows-x64.exe&#xff09; Android 基于 Java 語言開發&#xff0c;所以必須安裝Java環境&#xff0c;Java 環境分JDK 和JRE &#xff0c;JDK提…

設計模式最佳實踐 - 模板模式 + 責任鏈模式

廢話不多說&#xff0c;直接切入正題&#xff0c;本篇要講的是 模板模式 責任鏈模式 實踐。該最佳實踐本身就是一種對 責任鏈模式的增強&#xff0c;模板模式通過 父類 強耦合&#xff0c;預定義好 責任鏈 next 方法 的前后一些切面行為&#xff0c;優雅簡潔。先上示例&#x…

Python快速入門專業版(十一):布爾值與None:Python中的“真假”與“空值”(附邏輯判斷案例)

目錄引言&#xff1a;為什么“真假”與“空值”是編程的核心邏輯1.布爾值&#xff08;bool&#xff09;&#xff1a;Python中的“真”與“假”1.1 布爾值的基礎特性1.2 布爾運算&#xff1a;and、or、not的邏輯規則代碼示例&#xff1a;基礎布爾運算進階特性&#xff1a;短路求…

C++學習知識小結

1. 什么是類&#xff1f;什么是對象&#xff1f;兩者之間什么關系&#xff1f; 類是一類事物的共同特征的抽象描述&#xff0c;它定義這類所有的屬性和方法 可以理解為模版類本身不占用空間&#xff0c;它只是一種定義&#xff0c;描述了對象一個是什么樣子、能做什么 對象是根…

9. Mono項目與Unity的關系

1.Mono項目簡介 2.Mono項目與Unity是如何結合的 3.從Mono到IL2CPP演變過程1.Mono項目簡介 1).定義Mono是一個自由、開源的項目, 由Xamarin現屬于微軟主導開發; 它的目標是創建一個一套兼容于微軟.NET Framework 的跨平臺工具2).核心功能a.C#編譯器能將你寫的C#代碼編譯成IL(中間…

谷歌Genie 3:讓你的照片變成可以玩的游戲世界

你是否曾凝視著一張完美的旅行照片&#xff0c;想象著如果能走進那個畫面&#xff0c;自由探索會是怎樣一種體驗&#xff1f;或者&#xff0c;你是否曾被一幅畫的奇幻氛圍所吸引&#xff0c;渴望能在那片色彩斑斕的世界里奔跑跳躍&#xff1f;過去&#xff0c;這只是白日夢。而…

Cursor 提示詞探索——如何打造真正懂自己的Agent

最近看到魚皮的Cursor提示詞分享&#xff08;微信公眾平臺)&#xff0c;剛好之前也在做Agent開發&#xff0c;跟提示詞打交道的多&#xff0c;也經常發現 ai 蠢蠢的&#xff0c;一點不會根據提示詞設計的來&#xff0c;按魚皮的分享研究了一下&#xff0c;寫了這篇博客。 Curs…

C++ 內存模型:用生活中的例子理解并發編程

C 內存模型&#xff1a;用生活中的例子理解并發編程 文章目錄C 內存模型&#xff1a;用生活中的例子理解并發編程引言&#xff1a;為什么需要內存模型&#xff1f;核心概念&#xff1a;改動序列原子類型&#xff1a;不可分割的操作內存次序&#xff1a;不同的同步級別1. 寬松次…

AI急速搭建網站:Gemini、Bolt或Jules、GitHub、Cloudflare Pages實戰全流程!

文章目錄AI急速搭建網站&#xff1a;Gemini、Bolt或Jules、GitHub、Cloudflare Pages實戰全流程&#xff01;&#x1f680; 極速建站新范式&#xff1a;Gemini、Bolt.new、GitHub & Cloudflare Pages 全流程實戰&#xff01;第一步&#xff1a;創意可視化與代碼生成 — Goo…

Qwen2.5-VL實現本地GPTQ量化

本文不生產技術,只做技術的搬運工!! 前言 公開的Qwen2.5-VL模型雖然功能非常強大,但有時面對專業垂直領域的問題往往會出現一些莫名其妙的回復,這時候大家一版選擇對模型進行微調,而微調后的模型如果直接部署則顯存開銷過大,這時就需要執行量化,下面將介紹執行本地GPT…

【Redis】常用數據結構之Hash篇:從常用命令到使用場景詳解

目錄 1.前言 插播一條消息~ 2.正文 2.1Hash與String對比 2.2常用命令 2.2.1HSET 2.2.2HGET 2.2.3HEXISTS 2.2.4HDEL 2.2.5HKEYS 2.2.6HVALS 2.2.7HGETALL 2.2.8HMGET 2.2.9HLEN 2.2.10HSETNX 2.2.11HINCRBY 2.2.12HINCRBYFLOAT 2.3內部編碼 2.3.1. ziplist&…

OSPF基礎部分知識點

OSPF基礎 前言 路由器 根據 路由表 轉發數據包&#xff0c;路由表項 可通過手動配置 和動態路由協議 生成。&#xff08;兩種生成方式&#xff09;靜態路由比動態路由使用更少的帶寬&#xff0c;并且不占用CPU資源來計算和分析路由更新。當網絡結構比較簡單時&#xff0c;只需配…

Flutter 真 3D 游戲引擎來了,flame_3d 了解一下

在剛剛結束的 FlutterNFriends 大會上&#xff0c;Flame 展示了它們關于 3D 游戲的支持&#xff1a;flame_3d &#xff0c;Flame 是一個以組件系統&#xff08;Flame Component System, FCS&#xff09;、游戲循環、碰撞檢測和輸入處理為核心的 Flutter 游戲框架&#xff0c;而…

無需公網IP,電腦隨時與異地飛牛同步互聯保持數據一致性

最近小白有這樣一個煩惱&#xff1a;隨身帶著的電腦每天都在更新內容&#xff0c;于是就會有很多很多的存稿。電腦的空間開始變得不夠用了。各式各樣的圖片、視頻、文稿等內容&#xff0c;如果要整理到飛牛NAS上&#xff0c;好像很麻煩&#xff0c;而且每次都是需要回到家里才能…

數據庫中間件ShardingSphere v5.2.1

數據庫中間件ShardingSphere v5.2.1 文章目錄數據庫中間件ShardingSphere v5.2.1一 概述1 數據庫的瓶頸2 優化的手段3 主從復制4 讀寫分離5 分庫分表5.1 背景5.2 垂直分片5.3 水平分片6 ShardingSphere簡介二 ShardingSphere-JDBC講解1 讀寫分離實現1.1 基于Docker搭建MySQL主從…

[Upscayl圖像增強] Electron主進程命令 | 進程間通信IPC

第三章&#xff1a;Electron主進程命令 歡迎回來&#x1f43b;??? 在第一章&#xff1a;渲染器用戶界面&#xff08;前端&#xff09;中&#xff0c;我們探索了您與之交互的按鈕和菜單。然后在第二章&#xff1a;AI模型中&#xff0c;我們了解了讓您的圖像看起來更棒的&qu…