C語言實(shí)現(xiàn)掃雷算法簡易版
掃雷分析
從小到大你或許沒玩過但一定聽過的游戲——掃雷
首先我們來分一下“掃雷”的功能

這是一個(gè)簡單難度的掃雷,從外觀上,我們可以發(fā)現(xiàn)可供用戶操作的棋盤范圍是9×9的范圍,也就是我們建立的棋盤大小至少要為9,但是問題也就來了,我們?nèi)绻唤?×9的棋盤,那么在邊緣的格子要進(jìn)行提示操作的時(shí)候就會(huì)出現(xiàn)數(shù)據(jù)越界問題。

為了解決數(shù)據(jù)越界的問題,我們最好創(chuàng)建一個(gè)比可視界面大一圈的數(shù)組,即11×11的數(shù)組
但是在我們開始做這個(gè)小游戲的時(shí)候發(fā)現(xiàn)了一個(gè)問題——一個(gè)數(shù)組里面包含的數(shù)據(jù)太多了,可能會(huì)發(fā)生數(shù)據(jù)重疊的現(xiàn)象,而且一個(gè)數(shù)組里面又要放雷,又要存放排雷之后的信息,還要遮掩雷和其他位置,太過麻煩,因此我們可以創(chuàng)建兩個(gè)數(shù)組,一個(gè)數(shù)組專門用來放雷,一個(gè)數(shù)組用來存放排雷的信息,注意,這兩個(gè)數(shù)組一定要保證大小一樣。
所以我們不妨設(shè)置這樣兩個(gè)數(shù)組
mine[11][11] //存放雷的信息 show[11][11] //存放排除的雷的信息 /*如果我們直接用數(shù)字11來初始化數(shù)組,局限性太大了,我們后面如果想要 **進(jìn)行修改也不好改,所以我們可以引用一個(gè)全局變量來初始化數(shù)組,這樣 **即使我們以后想要玩更大的棋盤掃雷,就能夠做到一步更改??紤]到棋盤 **數(shù)組的初始化要比棋盤大一圈,所以可以設(shè)置為下面這樣。 */ #define ROW 9 //可視化界面是9×9 #define COL 9 #define ROWS ROW+2 #define COLS COL+2 mine[ROWS][COLS] show[ROWS][COLS] //為了和掃雷游戲保持一樣我們在顯示掃雷棋盤的時(shí)候用符號(hào)將它遮住,這里用的是“*”,所以數(shù)組類型就確定了 char mine[ROWS][COLS] char show[ROWS][COLS]
棋盤初始化
建立好數(shù)組之后,我們就開始思考可視化界面的建立,根據(jù)前面的信息,我們要?jiǎng)?chuàng)建一個(gè)9×9的游戲空間時(shí)得擴(kuò)大一圈,因此創(chuàng)建的函數(shù)傳參用ROWS和COLS,并且我們對(duì)這兩個(gè)的數(shù)組初始化也要做出差異,那么要如何來保證一個(gè)函數(shù)能同時(shí)初始化2個(gè)數(shù)組呢?實(shí)現(xiàn)如下:
//將數(shù)組初始化的信息作為區(qū)分參數(shù),傳入函數(shù)即可
InitBoard(mine, ROWS, COLS, '0');//沒有雷的地方存放字符‘0'
InitBoard(show, ROWS, COLS, '*');//‘*'遮掩掃雷棋盤
//接收傳參的函數(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 ;
}
}
}
棋盤顯示
初始化之后,是騾子是馬,拉出來溜溜,因?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");
}
}
這種顯示乍一看沒什么問題,但是當(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è)棋盤布局壓在下面,可以當(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è)棋盤布局頂在上面,可以當(dāng)做分割線
}
printf("\n");
}
效果圖:

放雷
當(dāng)掃雷棋盤可以正常顯示出來之后,我們就可以開始做設(shè)置雷了
在設(shè)置雷的時(shí)候我們需要考慮,設(shè)置多少個(gè)雷,來形成簡單,普通,困難等難度
因此,雷的數(shù)量在以后可能會(huì)發(fā)生變化,我們也可以將它設(shè)置為全局變量
#define easy_count 10
后面我們在放置雷的時(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'的空位上去放置雷,這樣一來就可以
*避免數(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 //初始化棋盤 void InitBoard(char board[ROWS][COLS],int rows,int cols,char set); //顯示棋盤 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;
}
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C++編寫DLL動(dòng)態(tài)鏈接庫的步驟與實(shí)現(xiàn)方法
這篇文章主要介紹了C++編寫DLL動(dòng)態(tài)鏈接庫的步驟與實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了C++導(dǎo)出類文件及生成與調(diào)用DLL動(dòng)態(tài)連接庫的相關(guān)操作技巧,需要的朋友可以參考下2016-08-08
C語言實(shí)現(xiàn)銷售管理系統(tǒng)設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)銷售管理系統(tǒng)設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
C++ 先對(duì)數(shù)組排序,在進(jìn)行折半查找
以下小編就為大家介紹兩種實(shí)現(xiàn)方法。第一種方法是,選擇排序法+循環(huán)折半查找法。第二種方法是,冒泡排序法+遞歸折半查找法。需要的朋友可以過來參考下,希望對(duì)大家有所幫助2013-10-10
基于C語言實(shí)現(xiàn)的TCP服務(wù)器的流程分析
本文詳細(xì)介紹了如何使用C語言編寫一個(gè)簡單的TCP服務(wù)器,包括創(chuàng)建套接字、綁定IP和端口、監(jiān)聽連接請(qǐng)求、接受客戶端連接、數(shù)據(jù)接收與發(fā)送以及關(guān)閉套接字等步驟,最后通過一個(gè)簡單的示例展示了TCP服務(wù)器的基本實(shí)現(xiàn)過程2024-10-10
C語言中動(dòng)態(tài)內(nèi)存管理初學(xué)者容易犯的6個(gè)錯(cuò)誤分享
本篇文章主要介紹了初學(xué)者使用C語言中動(dòng)態(tài)內(nèi)存管理的4個(gè)函數(shù)時(shí)最容易犯的6個(gè)錯(cuò)誤,以及如何避免這些錯(cuò)誤,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2023-04-04
C++棧(stack)的模板類實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了C++棧(stack)的模板類實(shí)現(xiàn)代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06

