C語(yǔ)言實(shí)現(xiàn)掃雷算法簡(jiǎn)易版
掃雷分析
從小到大你或許沒(méi)玩過(guò)但一定聽(tīng)過(guò)的游戲——掃雷
首先我們來(lái)分一下“掃雷”的功能
這是一個(gè)簡(jiǎn)單難度的掃雷,從外觀上,我們可以發(fā)現(xiàn)可供用戶操作的棋盤(pán)范圍是9×9的范圍,也就是我們建立的棋盤(pán)大小至少要為9,但是問(wèn)題也就來(lái)了,我們?nèi)绻唤?×9的棋盤(pán),那么在邊緣的格子要進(jìn)行提示操作的時(shí)候就會(huì)出現(xiàn)數(shù)據(jù)越界問(wèn)題。
為了解決數(shù)據(jù)越界的問(wèn)題,我們最好創(chuàng)建一個(gè)比可視界面大一圈的數(shù)組,即11×11的數(shù)組
但是在我們開(kāi)始做這個(gè)小游戲的時(shí)候發(fā)現(xiàn)了一個(gè)問(wèn)題——一個(gè)數(shù)組里面包含的數(shù)據(jù)太多了,可能會(huì)發(fā)生數(shù)據(jù)重疊的現(xiàn)象,而且一個(gè)數(shù)組里面又要放雷,又要存放排雷之后的信息,還要遮掩雷和其他位置,太過(guò)麻煩,因此我們可以創(chuàng)建兩個(gè)數(shù)組,一個(gè)數(shù)組專門(mén)用來(lái)放雷,一個(gè)數(shù)組用來(lái)存放排雷的信息,注意,這兩個(gè)數(shù)組一定要保證大小一樣。
所以我們不妨設(shè)置這樣兩個(gè)數(shù)組
mine[11][11] //存放雷的信息 show[11][11] //存放排除的雷的信息 /*如果我們直接用數(shù)字11來(lái)初始化數(shù)組,局限性太大了,我們后面如果想要 **進(jìn)行修改也不好改,所以我們可以引用一個(gè)全局變量來(lái)初始化數(shù)組,這樣 **即使我們以后想要玩更大的棋盤(pán)掃雷,就能夠做到一步更改??紤]到棋盤(pán) **數(shù)組的初始化要比棋盤(pán)大一圈,所以可以設(shè)置為下面這樣。 */ #define ROW 9 //可視化界面是9×9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2 mine[ROWS][COLS] show[ROWS][COLS] //為了和掃雷游戲保持一樣我們?cè)陲@示掃雷棋盤(pán)的時(shí)候用符號(hào)將它遮住,這里用的是“*”,所以數(shù)組類型就確定了 char mine[ROWS][COLS] char show[ROWS][COLS]
棋盤(pán)初始化
建立好數(shù)組之后,我們就開(kāi)始思考可視化界面的建立,根據(jù)前面的信息,我們要?jiǎng)?chuàng)建一個(gè)9×9的游戲空間時(shí)得擴(kuò)大一圈,因此創(chuàng)建的函數(shù)傳參用ROWS和COLS,并且我們對(duì)這兩個(gè)的數(shù)組初始化也要做出差異,那么要如何來(lái)保證一個(gè)函數(shù)能同時(shí)初始化2個(gè)數(shù)組呢?實(shí)現(xiàn)如下:
//將數(shù)組初始化的信息作為區(qū)分參數(shù),傳入函數(shù)即可 InitBoard(mine, ROWS, COLS, '0');//沒(méi)有雷的地方存放字符‘0' InitBoard(show, ROWS, COLS, '*');//‘*'遮掩掃雷棋盤(pán) //接收傳參的函數(shù) void InitBoard(char board[ROWS][COLS], int rows, int cols,char set) { int i = 0; int j = 0; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { board[i][j] = set ; } } }
棋盤(pán)顯示
初始化之后,是騾子是馬,拉出來(lái)溜溜,因?yàn)槲覀円WC數(shù)據(jù)不能越界所以可視化界面比實(shí)際數(shù)組小一圈
void DisplayBoard(char board[ROWS][COLS], int row, int col) { int i = 0; int j = 0; for (i = 1; i <= row; i++) { for (j = 1; j <= col; j++) { printf("%c ",board[i][j]); } printf("\n"); } }
這種顯示乍一看沒(méi)什么問(wèn)題,但是當(dāng)你要進(jìn)行輸入的時(shí)候,你就難受了,因?yàn)槟悴恢浪男泻土?,每次輸入都要去?shù)一次,所以,我們可以進(jìn)行優(yōu)化
void DisplayBoard(char board[ROWS][COLS], int row, int col) { int i = 0; int j = 0; for (i = 0; i <= col; i++) { printf("--");//將整個(gè)棋盤(pán)布局壓在下面,可以當(dāng)做分割線 } printf("\n"); for (i = 0; i <= col; i++) { printf("%d ", i);//顯示列的號(hào)數(shù) } printf("\n"); for (i = 1; i <= row; i++) { printf("%d ", i);//顯示行的號(hào)數(shù) for (j = 1; j <= col; j++) { printf("%c ",board[i][j]); } printf("\n"); } for (i = 0; i <= col; i++) { printf("--");//將整個(gè)棋盤(pán)布局頂在上面,可以當(dāng)做分割線 } printf("\n"); }
效果圖:
放雷
當(dāng)掃雷棋盤(pán)可以正常顯示出來(lái)之后,我們就可以開(kāi)始做設(shè)置雷了
在設(shè)置雷的時(shí)候我們需要考慮,設(shè)置多少個(gè)雷,來(lái)形成簡(jiǎn)單,普通,困難等難度
因此,雷的數(shù)量在以后可能會(huì)發(fā)生變化,我們也可以將它設(shè)置為全局變量
#define easy_count 10
后面我們?cè)诜胖美椎臅r(shí)候要確保它的隨機(jī)性,因此需要用到rand()函數(shù)和time()函數(shù)
void SetMine(char board[ROWS][COLS], int row, int col) { int count = EASY_COUNT; while (count) { int x = rand() % row + 1; int y = rand() % col + 1; if (board[x][y] != '1')/*確保了它只有在不是‘1'的空位上去放置雷,這樣一來(lái)就可以 *避免數(shù)據(jù)覆蓋而導(dǎo)致雷的數(shù)量不夠*/ { board[x][y] = '1'; count--; } } }
排雷和判定勝負(fù)
void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int win = 0; while (win<row*col-EASY_COUNT) { printf("請(qǐng)輸入要排查的坐標(biāo):>"); scanf("%d%d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col) { if (mine[x][y] == '1') { printf("很遺憾,你被炸死了!\n"); DisplayBoard(mine, ROW, COL); break; } else { int count = GetMineCount(mine, x, y); show[x][y] = count + '0'; DisplayBoard(show, ROW, COL); win++; } } else { printf("非法坐標(biāo),請(qǐng)重新輸入:>\n"); } } if (win == row * col - EASY_COUNT) { printf("恭喜你,排雷成功!\n"); } }
效果圖:
頭文件:
#pragma once #include<stdio.h> #include<stdlib.h> #include<time.h> #define ROW 9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2 #define EASY_COUNT 79 //初始化棋盤(pán) void InitBoard(char board[ROWS][COLS],int rows,int cols,char set); //顯示棋盤(pán) void DisplayBoard(char board[ROWS][COLS], int row, int col); //埋雷 void SetMine(char board[ROWS][COLS], int row, int col); //排雷 void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col);
游戲功能實(shí)現(xiàn):
#include"game.h" void InitBoard(char board[ROWS][COLS], int rows, int cols,char set) { int i = 0; int j = 0; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { board[i][j] = set ; } } } void DisplayBoard(char board[ROWS][COLS], int row, int col) { int i = 0; int j = 0; for (i = 0; i <= col; i++) { printf("--"); } printf("\n"); for (i = 0; i <= col; i++) { printf("%d ", i); } printf("\n"); for (i = 1; i <= row; i++) { printf("%d ", i); for (j = 1; j <= col; j++) { printf("%c ",board[i][j]); } printf("\n"); } for (i = 0; i <= col; i++) { printf("--"); } printf("\n"); } void SetMine(char board[ROWS][COLS], int row, int col) { int count = EASY_COUNT; while (count) { int x = rand() % row + 1; int y = rand() % col + 1; if (board[x][y] != '1') { board[x][y] = '1'; count--; } } } int GetMineCount(char mine[ROWS][COLS], int x, int y) { return mine[x - 1][y] + mine[x - 1][y - 1] + mine[x][y - 1] + mine[x + 1][y - 1] + mine[x + 1][y] + mine[x + 1][y + 1] + mine[x][y + 1] + mine[x - 1][y + 1] - 8 * '0'; } void FindMine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int win = 0; while (win<row*col-EASY_COUNT) { printf("請(qǐng)輸入要排查的坐標(biāo):>"); scanf("%d%d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col) { if (mine[x][y] == '1') { printf("很遺憾,你被炸死了!\n"); DisplayBoard(mine, ROW, COL); break; } else { int count = GetMineCount(mine, x, y); show[x][y] = count + '0'; DisplayBoard(show, ROW, COL); win++; } } else { printf("非法坐標(biāo),請(qǐng)重新輸入:>\n"); } } if (win == row * col - EASY_COUNT) { printf("恭喜你,排雷成功!\n"); } }
游戲主干和菜單:
#include"game.h" void menu() { printf("***********************************************\n"); printf("************ 1.play *************\n"); printf("************ 0.exit *************\n"); printf("***********************************************\n"); } void game() { printf(" >> >> >>>掃雷<<< << <<\n"); char mine[ROWS][COLS] = {0}; char show[ROWS][COLS] = {0}; InitBoard(mine, ROWS, COLS, '0'); InitBoard(show, ROWS, COLS, '*'); SetMine(mine,ROW,COL); DisplayBoard(mine, ROW, COL); DisplayBoard(show, ROW, COL); FindMine(mine,show,ROW,COL); } int main() { int input; srand((unsigned int)time(NULL)); do { menu(); printf("請(qǐng)做出選擇:>"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("您已退出游戲\n"); break; default: printf("輸入錯(cuò)誤,請(qǐng)重新輸入:>\n"); break; } } while (input); return 0; }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C++編寫(xiě)DLL動(dòng)態(tài)鏈接庫(kù)的步驟與實(shí)現(xiàn)方法
這篇文章主要介紹了C++編寫(xiě)DLL動(dòng)態(tài)鏈接庫(kù)的步驟與實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了C++導(dǎo)出類文件及生成與調(diào)用DLL動(dòng)態(tài)連接庫(kù)的相關(guān)操作技巧,需要的朋友可以參考下2016-08-08C語(yǔ)言實(shí)現(xiàn)銷售管理系統(tǒng)設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)銷售管理系統(tǒng)設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03C++ 先對(duì)數(shù)組排序,在進(jìn)行折半查找
以下小編就為大家介紹兩種實(shí)現(xiàn)方法。第一種方法是,選擇排序法+循環(huán)折半查找法。第二種方法是,冒泡排序法+遞歸折半查找法。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2013-10-10基于C語(yǔ)言實(shí)現(xiàn)的TCP服務(wù)器的流程分析
本文詳細(xì)介紹了如何使用C語(yǔ)言編寫(xiě)一個(gè)簡(jiǎn)單的TCP服務(wù)器,包括創(chuàng)建套接字、綁定IP和端口、監(jiān)聽(tīng)連接請(qǐng)求、接受客戶端連接、數(shù)據(jù)接收與發(fā)送以及關(guān)閉套接字等步驟,最后通過(guò)一個(gè)簡(jiǎn)單的示例展示了TCP服務(wù)器的基本實(shí)現(xiàn)過(guò)程2024-10-10C語(yǔ)言中動(dòng)態(tài)內(nèi)存管理初學(xué)者容易犯的6個(gè)錯(cuò)誤分享
本篇文章主要介紹了初學(xué)者使用C語(yǔ)言中動(dòng)態(tài)內(nèi)存管理的4個(gè)函數(shù)時(shí)最容易犯的6個(gè)錯(cuò)誤,以及如何避免這些錯(cuò)誤,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2023-04-04C++棧(stack)的模板類實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了C++棧(stack)的模板類實(shí)現(xiàn)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06