C語(yǔ)言代碼實(shí)現(xiàn)簡(jiǎn)單掃雷小游戲
用C語(yǔ)言寫一個(gè)簡(jiǎn)單的掃雷,供大家參考,具體內(nèi)容如下
1.所需要的知識(shí)
c語(yǔ)言的基本語(yǔ)法,簡(jiǎn)單的二維數(shù)組,一點(diǎn)簡(jiǎn)單的遞歸知識(shí)。
2.總體思路
掃雷游戲主要由3個(gè)部分組成,埋雷子,掃雷,判斷輸贏。
掃雷游戲的主體是兩個(gè)個(gè)字符類型的二維數(shù)組。一個(gè)是mine[][]它的構(gòu)成是'0'和‘1',其中'0'表示無(wú)雷,'1'表示有雷。一個(gè)是show[][]它的構(gòu)成是'*'和'數(shù)字'。星號(hào)表示未開啟的地方,數(shù)字表示周圍的雷數(shù)。這里要注意的是:mine和show的實(shí)際大小是11x11,但是展示的效果是 9x9。這樣做的優(yōu)點(diǎn)將在Find()中體現(xiàn)。藍(lán)色部分是可見(jiàn)的9x9,實(shí)際的類似紅色 11x11。
下面是我用到的一些函數(shù)。
//game.h #pragma once #ifndef __GAME_H__ #define __GAME_H__ #include<stdio.h> #include<stdlib.h> #include<process.h> #include<string.h> #include<time.h> #define ROW 9 // 9行 #define COL 9 // 9列 #define ROWS ROW+2 //實(shí)際行 #define COLS COL+2 //實(shí)際列 #define MineNum 10 //雷子數(shù)量 //菜單信息 void menu(); //執(zhí)行菜單 void test(char mine[ROWS][COLS], int row1, int col1, char show[ROWS][COLS], int row2, int col2); //游戲主體 void game(char mine[ROWS][COLS], int row1, int col1, char show[ROWS][COLS], int row2, int col2); //打印雷陣 void InitBoard(char arr[ROWS][COLS], int row, int col); //埋雷子 void SetMine(char mine[ROWS][COLS], int row, int col); //找雷子 int FindMine(char mine[ROWS][COLS], int row1, int col1, char show[ROWS][COLS], int row2, int col2); //空白算法 void Find(char mine[ROWS][COLS], int row1, int col1, char show[ROWS][COLS], int row2, int col2,int x, int y,int exam[ROWS][COLS]); #endif//__GAME_H__
下面是主函數(shù)內(nèi)容
#include"game.h" int main() { char mine[ROWS][COLS]; char show[ROWS][COLS]; srand ((unsigned int)time(NULL)); //生成隨機(jī)數(shù),用于隨機(jī)埋雷 int i = 0, j = 0; test(mine, ROWS, COLS, show, ROWS, COLS); //測(cè)試函數(shù) system("pause"); return 0; }
3.詳細(xì)實(shí)現(xiàn)
菜單函數(shù)
void menu() { printf("******************\n"); printf("******1.play *****\n"); printf("******0.exit *****\n"); printf("******************\n"); }
這個(gè)函數(shù)是用來(lái)打印信息的,打印一個(gè)簡(jiǎn)單的菜單。
執(zhí)行菜單
void test(char mine[ROWS][COLS], int row1, int col1,char show[ROWS][COLS],int row2,int col2) { int m = 0; do { menu(); scanf_s("%d", &m); switch (m) { case 1: game(mine, row1, col1, show, row2, col2); break; case 0: exit(0); default: printf("輸入錯(cuò)誤!\n"); } } while (m); }
這個(gè)函數(shù)是用來(lái)執(zhí)行用戶選項(xiàng)的。1.進(jìn)行游戲 0.退出游戲。
游戲主體函數(shù)
void game(char mine[ROWS][COLS], int row1, int col1, char show[ROWS][COLS], int row2, int col2) { int i = 0, j = 0; int flag = 0; int count = 0; for (i = 0; i < row1; i++) { for (j = 0; j < col1; j++) { mine[i][j] = '0'; } } for (i = 0; i < row2; i++) { for (j = 0; j < col2; j++) { show[i][j] = '*'; } } SetMine(mine, row1, col1); while (1) { InitBoard(mine, row1 - 1, col1 - 1); printf("------------------------\n"); InitBoard(show, row2 - 1, col2 - 1); flag = FindMine(mine, row1, col1, show, row2, col2); if (flag == 0) { printf("恭喜你,你被炸死了!\n"); InitBoard(mine, row1 - 1, col1 - 1); break; } else if (flag == 1 ) { for (i = 1; i < row2 - 1; i++) { for (j = 1; j < col2 - 1; j++) { if (show[i][j] == '*') { count++; } } } printf("count == %d\n", count); if (count == MineNum) { printf("很遺憾,游戲結(jié)束\n"); break; } else { count = 0; } } } }
這個(gè)函數(shù)是游戲的主體部分。在一開始定義了一個(gè)標(biāo)志變量flag和一個(gè)計(jì)數(shù)變量count。之后,使用了兩個(gè)兩個(gè)for循環(huán)對(duì)二維數(shù)組進(jìn)行了初始化,mine被初始化為全'0',show被初始化了全'*'。然后,使用了SetMine()函數(shù)對(duì)mine進(jìn)行了埋雷活動(dòng)。最后使用個(gè)一個(gè)while死循環(huán),開始進(jìn)行掃雷游戲。
在while循環(huán)里首先是兩個(gè)InitBoard()函數(shù)對(duì)mine和show進(jìn)行打印。
FindMine函數(shù)是掃雷函數(shù)。它會(huì)返回一個(gè)值,如果被雷炸死了,他會(huì)返回0,如果點(diǎn)開區(qū)域沒(méi)有觸發(fā)雷的話,它會(huì)返回1。
接下來(lái)如果flag==1時(shí),開始進(jìn)行掃描,看看show中還剩下幾個(gè)星號(hào),如果剩下10個(gè)星號(hào),那么就證明掃完了,此時(shí)打印獲勝信息,并break跳出循環(huán)。如果沒(méi)有剩下10個(gè)星號(hào),那么將已有的count信息清除,繼續(xù)進(jìn)行以上步驟。
打印面板函數(shù)
void InitBoard(char arr[ROWS][COLS], int row, int col) { int i = 0; int j = 0; for (i = 0; i < row; i++) { printf("%d ", i); } printf("\n"); for (i = 1; i < row; i++) { printf("%d ", i); for (j = 1; j < col; j++) { printf("%c ", arr[i][j]); } printf("\n"); } }
這是一個(gè)簡(jiǎn)單的打印函數(shù),show和mine都可以公共使用。第一個(gè)for循環(huán)打印的是列坐標(biāo)。第二個(gè)for循環(huán)中,第一個(gè)printf函數(shù)打印的是行坐標(biāo)。
埋雷函數(shù)
void SetMine(char mine[ROWS][COLS], int row, int col) { int m = 0, n = 0; int count = 0; while (count < MineNum) { m = rand() % 9 + 1; n = rand() % 9 + 1; if (mine[m][n] == '0') { mine[m][n] = '1'; count++; } } }
這是一個(gè)埋雷函數(shù)。埋雷需要用到隨機(jī)數(shù),我使用m和n來(lái)存放隨機(jī)數(shù)。while循環(huán)的終止條件是埋雷數(shù) count 達(dá)到預(yù)設(shè)雷數(shù) MineNum 。rand()%9+1是為了產(chǎn)生1~9的隨機(jī)數(shù)。if語(yǔ)句保證設(shè)雷地區(qū)不重復(fù)。
掃雷函數(shù)
int FindMine(char mine[ROWS][COLS], int row1, int col1, char show[ROWS][COLS], int row2, int col2) { int m = 0, n = 0; int flag = 0; static int fflag = 0; int a1 = 0, a2 = 0; int exam[ROWS][COLS] = { 0 }; while (1) { scanf_s("%d %d", &m, &n); if ((m >= 1 && m <= 9) && (n >= 1 && n <= 9)) { break; } else { printf("輸錯(cuò)了吧?\n"); } } if (mine[m][n] == '0') { Find(mine, row1, col1, show, row2, col2, m, n, exam); flag = 1; } if (mine[m][n] == '1' && fflag > 0) { flag = 0; } if (mine[m][n] == '1' && fflag == 0) { mine[m][n] = '0'; a1 = m; a2 = n; while (1) { m = rand() % 9 + 1; n = rand() % 9 + 1; if (mine[m][n] == '0'&& m != a1 && n != a2) { mine[m][n] = '1'; flag = 1; break; } } fflag = 1; } return flag; }
這是一個(gè)掃雷函數(shù)。m和n是用來(lái)保存位置,flag 是標(biāo)志變量,fflag也是踩雷標(biāo)志變量。a1和a2是暫存m和n的位置的。exam是一個(gè)標(biāo)志數(shù)組,它將在Find函數(shù)發(fā)揮作用。
第一個(gè)while死循環(huán)它的作用是確保輸入正確的坐標(biāo)信息。在確保輸入的m和n的數(shù)據(jù)是正確的后。開始處理數(shù)據(jù),第一個(gè)if語(yǔ)句,如果第一下沒(méi)有踩雷,那么將執(zhí)行Find空白的算法,結(jié)果是產(chǎn)生周圍雷數(shù)。第二個(gè)if語(yǔ)句中,如果不是第一下踩雷,那么將會(huì)反饋爆炸信息flag == 0。第三個(gè)if語(yǔ)句中,如果第一下踩雷了,那么將這顆雷移動(dòng)到別的地方去。
移動(dòng)的方法是將踩雷地點(diǎn)先用a1和a2記錄下來(lái),然后生成隨機(jī)數(shù),該隨機(jī)數(shù)必須在 無(wú)雷 并且 不同于 m和n的坐標(biāo)的地方。
空白算法函數(shù)
void Find(char mine[ROWS][COLS], int row1, int col1, char show[ROWS][COLS], int row2, int col2, int x, int y,int exam[ROWS][COLS]) { int count = 0; if (x <= 0 || y <= 0 || x >= row1-1||y >= col1-1) { return; } count = mine[x - 1][y - 1] + mine[x - 1][y] + mine[x - 1][y + 1] + mine[x][y - 1] + mine[x][y + 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] - 8 * '0'; show[x][y] = '0' + count; if (show[x][y] == '0' && exam[x][y] == 0) { if (show[x][y] == '0') { exam[x][y] = 1; } Find(mine, row1, col1, show, row2, col2, x - 1, y - 1,exam); Find(mine, row1, col1, show, row2, col2, x - 1, y, exam); Find(mine, row1, col1, show, row2, col2, x - 1, y + 1, exam); Find(mine, row1, col1, show, row2, col2, x , y - 1, exam); Find(mine, row1, col1, show, row2, col2, x , y + 1, exam); Find(mine, row1, col1, show, row2, col2, x + 1, y - 1, exam); Find(mine, row1, col1, show, row2, col2, x + 1, y, exam); Find(mine, row1, col1, show, row2, col2, x + 1, y + 1, exam); } else { return; } }
這個(gè)函數(shù)是用來(lái)實(shí)現(xiàn)空白算法的。具體效果類似下圖。
從圖中可以發(fā)現(xiàn),點(diǎn)開一個(gè)空白產(chǎn)生了連鎖效果。
在Find函數(shù)中第一個(gè)if判斷條件,是看看有沒(méi)有觸底或者觸頂,如果有,那么將返回到上個(gè)函數(shù)中去。
接下來(lái)count是為了計(jì)算該點(diǎn)周圍的雷數(shù)量。如下圖:
當(dāng)計(jì)算好后,將計(jì)算的數(shù)據(jù)填入到show中。由于'0'+數(shù)字 = ‘?dāng)?shù)字',相當(dāng)于把整形的count轉(zhuǎn)成了char填入到 show。
然后使用遞歸算法。
假設(shè)我們首先點(diǎn)開了棕色區(qū)域中心點(diǎn),那么接下來(lái) 從x-1,y-1以順時(shí)針?lè)较蜷_始探索。此時(shí)我們進(jìn)入到第一個(gè)if中,檢查條件,exam該點(diǎn)默認(rèn)為0,表示我們沒(méi)有操作過(guò)它。
接下來(lái)將該點(diǎn)exam相對(duì)應(yīng)的地方改成1。然后進(jìn)入第一個(gè)Find()探索,也就是x - 1, y - 1。由于該點(diǎn)是‘ 1 ',所以return,返回到上層。此時(shí)按次序執(zhí)行第二個(gè)Find(),也就是 x - 1, y。由于該點(diǎn)是‘ 0 ',所以以這個(gè)點(diǎn)為中心,進(jìn)行探索(以紅色為標(biāo)記的九宮格)。探索前將這個(gè)點(diǎn)的標(biāo)記位改為‘ 1 ',表示我們已經(jīng)進(jìn)行了該點(diǎn)的探索。以該點(diǎn) 為 x,y,它的x-1, y-1是' 0 ‘,所以以黃色九宮格探索。以此類推直到觸頂、觸底停止,或者是周圍有不為 ‘ 0 '的數(shù)字停止。
這里為了防止兩個(gè)九宮格相互循環(huán),所以添加了exam標(biāo)志位。當(dāng)子九宮格再次探索到上個(gè)函數(shù)‘ 0 '時(shí),發(fā)現(xiàn)其對(duì)應(yīng)的exam標(biāo)志為1,不跳越至上個(gè)函數(shù)‘ 0 '繼續(xù)進(jìn)行探索或返回。
4.程序運(yùn)行效果
開局踩一顆雷,沒(méi)事;再踩一顆雷死了。
點(diǎn)開一大片空白。
游戲初始化面
游戲勝利!
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
VC自定義消息響應(yīng)函數(shù)postmessage用法示例
這篇文章主要介紹了VC自定義消息響應(yīng)函數(shù)postmessage用法示例,并對(duì)比說(shuō)明了postmessage與sendmessage的用法區(qū)別,需要的朋友可以參考下2014-10-10Microsoft Visual Studio 2022的安裝與使用詳細(xì)教程
Microsoft Visual Studio 2022是Microsoft Visual Studio軟件的一個(gè)高版本,能夠編寫和執(zhí)行C/C++代碼,具有強(qiáng)大的功能,是開發(fā)C/C++程序的主流軟件,這篇文章主要介紹了Microsoft Visual Studio 2022的安裝與使用詳細(xì)教程2024-01-01C++實(shí)現(xiàn)softmax函數(shù)的面試經(jīng)驗(yàn)
這篇文章主要為大家介紹了C++實(shí)現(xiàn)softmax函數(shù)的面試經(jīng)驗(yàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05詳解C++中OpenSSL動(dòng)態(tài)鏈接庫(kù)的使用
這篇文章主要介紹了OpenSSL動(dòng)態(tài)鏈接庫(kù)的使用,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-11-11C++中的繼承問(wèn)題(繼承基本概念、菱形虛擬繼承的對(duì)象模型)
這篇文章主要介紹了C++中的繼承問(wèn)題(繼承基本概念、菱形虛擬繼承的對(duì)象模型),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02C++實(shí)現(xiàn)英文句子中的單詞逆序輸出的方法
這篇文章主要介紹了C++實(shí)現(xiàn)英文句子中的單詞逆序輸出的方法,涉及C++字符串遍歷、分割、截取、輸出等相關(guān)操作技巧,需要的朋友可以參考下2018-01-01C++11 學(xué)習(xí)筆記之std::function和bind綁定器
這篇文章主要介紹了C++11 學(xué)習(xí)筆記之std::function和bind綁定器,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07