前言
图结构在计算机科学及众多领域中具有极其重要的地位,说到图就不得不提起两种核心搜索算法-BFS和DFS,
DFS主要通过从一个顶点开始并一直深入直至尽头,然后再搜索另一个顶点,通常以递归和栈的方式实现;
BFS则主要通过队列的方式先搜查最先进入队列的点,以“先进先出”为原则。
立意
扫雷作为一款几乎人人玩过的小游戏,选择去做这个是想重温经典

问题描述
->未探索 0-8->附近的雷数 !->标记点 9->雷
输入:
生成雷的数量
1->扫雷,2->标记
横坐标x ,纵坐标Y
输出:
对应的图
开始的图

样例输入:1 2 1

实验思路
创建两个二维矩阵来存放两个地图:玩家视角的地图和地图的原图,可以通过地图的原图来为玩家视角地图做分析。
创建原图:用两个一位数组储存x,y的偏移量,通过BFS遍历计算原图中每个格子周围的地雷数(这里其实可以直接用双重循环来遍历每个格子,效率更高,只是想练习一下BFS);
双重循环:
void initMap(int map[MAX][MAX],int boomNum){
int i,j,z,x,y;
int a[8]={-1,-1,-1,0,1,1,1,0};
int b[8]={-1,0,1,1,1,0,-1,-1};
srand((unsigned int)time(NULL));
for(i=0;i<MAX;++i)
for(j=0;j<MAX;++j)
map[i][j]=0;
for(z=0;z<boomNum;++z){
i=rand()%MAX;
j=rand()%MAX;
if(map[i][j]==9)
++boomNum;
else
map[i][j]=9;
}
for(i=0;i<MAX;i++)
for(j=0;j<MAX;j++){
if(map[i][j]==9)
continue;
for(z=0;z<8;z++){
x=i+a[z];
y=j+b[z];
if(x>0&&x<MAX&&y>0&&y<MAX&&map[x][y]==9)
++map[i][j];
}
}
BFS:
void initMap(int map[MAX][MAX],int boomNum){
int i,j,z,x=0,y=0;
int visited[21][21];
memset(visited,0,sizeof(visited));
queue<pair<int,int>>que;
int a[8]={-1,-1,-1,0,1,1,1,0};
int b[8]={-1,0,1,1,1,0,-1,-1};
srand((unsigned int)time(NULL));
for(i=0;i<MAX;++i)
for(j=0;j<MAX;++j)
map[i][j]=0;
for(z=0;z<boomNum;++z){
i=rand()%MAX;
j=rand()%MAX;
if(map[i][j]==9)
++boomNum;
else
map[i][j]=9;
}
for(int i=0;i<MAX;++i)
for(int j=0;j<MAX;++j){
if(map[i][j]==0){
x=i;
y=j;
break;
}
}
visited[x][y]=1;
que.push(make_pair(x,y));
while(!que.empty()){
for(int i=0;i<8;i++){
int nx=que.front().first+a[i];
int ny=que.front().second+b[i];
if(nx>=0&&nx<MAX&&ny>=0&&ny<MAX&&visited[nx][ny]==0){
if(map[nx][ny]==9)
map[que.front().first][que.front().second]+=1;
else{
visited[nx][ny]=1;
que.push(make_pair(nx,ny));}
}
}
que.pop();
}
}
使用种子函数srand(),以时间为变量,通过伪随机对雷进行分布;
创建玩家视角地图:如果格子在原图中对应9,则输出‘#’,如果对应-1,则输出‘!’
DFS遍历格子的四个方向,如果对应格子数不为零,则赋值并返回,否则继续遍历。
最后判断胜利条件。
实验代码
#include<bits/stdc++.h>
#include<time.h>
#include<stdlib.h>
#define MAX 20
using namespace std;
void initMap(int map[MAX][MAX],int boomNum){
int i,j,z,x=0,y=0;
int visited[21][21];
memset(visited,0,sizeof(visited));
queue<pair<int,int>>que;
int a[8]={-1,-1,-1,0,1,1,1,0};
int b[8]={-1,0,1,1,1,0,-1,-1};
srand((unsigned int)time(NULL));
for(i=0;i<MAX;++i)
for(j=0;j<MAX;++j)
map[i][j]=0;
for(z=0;z<boomNum;++z){
i=rand()%MAX;
j=rand()%MAX;
if(map[i][j]==9)
++boomNum;
else
map[i][j]=9;
}
for(int i=0;i<MAX;++i)
for(int j=0;j<MAX;++j){
if(map[i][j]==0){
x=i;
y=j;
break;
}
}
visited[x][y]=1;
que.push(make_pair(x,y));
while(!que.empty()){
for(int i=0;i<8;i++){
int nx=que.front().first+a[i];
int ny=que.front().second+b[i];
if(nx>=0&&nx<MAX&&ny>=0&&ny<MAX&&visited[nx][ny]==0){
if(map[nx][ny]==9)
map[que.front().first][que.front().second]+=1;
else{
visited[nx][ny]=1;
que.push(make_pair(nx,ny));}
}
}
que.pop();
}
}
void initPlayerViewMap(int playerviewmap[MAX][MAX]){
int i,j;
for(i=0;i<MAX;i++)
for(j=0;j<MAX;j++){
playerviewmap[i][j]=9;
}
}
void printViewMap(int playerviewmap[MAX][MAX],int map[MAX][MAX]){
int i,j,a=0;
char ch='#',ch1='!';
printf("%6d",a);
for(i=1;i<MAX;i++){
printf("%4d",i);
}
cout<<endl;
for(i=0;i<MAX;++i){
printf("%2d",i);
for(j=0;j<MAX;++j){
if(playerviewmap[i][j]==9)
printf("%4c",ch);
else if(playerviewmap[i][j]==-1)
printf("%4c",ch1);
else
printf("%4d",map[i][j]);
}
cout<<endl;
}
cout<<"选项:1->扫雷 0->标记"<<endl;
}
void pathFinding(int i,int j,int playerviewmap[MAX][MAX],int map[MAX][MAX]){
if(i < 0 || i >= MAX || j < 0 || j >= MAX|| playerviewmap[i][j] == 0) return ;
playerviewmap[i][j] = map[i][j];
if(map[i][j] != 0) return ;
pathFinding(i-1,j,playerviewmap,map);
pathFinding(i,j+1,playerviewmap,map);
pathFinding(i+1,j,playerviewmap,map);
pathFinding(i,j-1,playerviewmap,map);
}
bool operate_1(int i,int j,int playerviewmap[MAX][MAX],int map[MAX][MAX]){
if(map[i][j]==9)
return true;
else if(map[i][j]>0&&map[i][j]<9)
playerviewmap[i][j]=map[i][j];
else if(map[i][j]==0)
pathFinding(i,j,playerviewmap,map);
return false;
}
void opearte_0(int i,int j,int playerviewmap[MAX][MAX]){
if(playerviewmap[i][j]==-1)
playerviewmap[i][j]=9;
else if(playerviewmap[i][j]==9)
playerviewmap[i][j]=-1;
}
bool isWin(int playerviewmap[MAX][MAX],int map[MAX][MAX]){
int i,j;
for(i=0;i<MAX;i++)
for(j=0;j<MAX;j++)
if(map[i][j]!=9&&(playerviewmap[i][j]==9||playerviewmap[i][j]==-1))
return false;
return true;
}
void printMap(int map[MAX][MAX]){
int i,j,a=0;
printf("%6d",a);
for(i=1;i<MAX;i++){
printf("%4d",i);
}
cout<<endl;
for(i=0;i<MAX;++i){
printf("%2d",i);
for(j=0;j<MAX;++j){
printf("%4d",map[i][j]);
}
cout<<endl;
}
}
int main(){
int map[MAX][MAX];
int playerviewmap[MAX][MAX];
int i,j,boomNum,operate;
bool lose=false;
cout<<"#->未探索 0-8->附近的雷数 !->标记点 9->雷"<<endl;
cout<<"请输入要生成的雷的数量:";
cin>>boomNum;
initMap(map,boomNum);
initPlayerViewMap(playerviewmap);
system("cls");
while(true){
printViewMap(playerviewmap,map);
cout<<"请输入序号以及要操作的点位坐标";
cin>>operate>>i>>j;
if(operate==1)
lose=operate_1(i,j,playerviewmap,map);
else if(operate==0)
opearte_0(i,j,playerviewmap);
if(lose)
break;
if(isWin(playerviewmap,map))
break;
system("cls");
}
system("cls");
printMap(map);
if(lose)
cout<<"你输了!"<<endl;
else
cout<<"你赢了!"<<endl;
system("pause");
return 0;
}
心得体会
做这样一个简单小应用需要了解许多相应的知识,开始可以先借鉴别人的思路,读懂代码的每一步,包括逻辑功能,函数功能,每一步是怎样实现的,一开始是比较困难的,但只要理解了代码的思路,学会了相应函数的应用,掌握了做这个游戏的基本知识,就会容易一些,这需要平时的多加练习,在他人的思路上建立起自己的思路,然后实现出来,每天必须抽出时间敲代码,只有这样代码水平才能逐渐提高,课堂上的一些算法必须手动敲出来才能理解到底是怎样进行的。
相关条目
- BFS经典题目
- DP动态规划
- 贪心算法