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