迷宫游戏的实现是运用了栈的“后进先出”的原理,究竟如何实现的呢?下来简单的分析一下。
比如:下图是一个小迷宫
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1 1
1 1 0 1 1 1 1 1 1 1 //0---表示通路
1 1 0 1 1 1 1 0 0 0 //1----表示墙
1 1 0 1 1 1 1 0 1 1
1 1 0 0 0 0 0 0 1 1
1 1 0 1 1 1 1 0 1 1
1 1 0 1 1 1 1 0 1 1
1 1 1 1 1 1 1 1 1 1
我们实现迷宫的步骤:
1.利用栈来解决此问题,首先得有个栈,可以自己实现也可以用库里的.
栈只允许在末端进行插入和删除的线性表,具有“后进先出”的特点;
如下图,data10后push进的,却先被pop.
2.首先得开辟一个二维数组并将迷宫代表数据读入;
1)开辟该数组有两种方式:
void InitMaze(int arr[][N]) //二维数组形式
void InitMaze(int* arr) //一维数组形式
其实,二维数组在
计算机中存储时依然是线性的,以一维数组的形式更能模拟二维数组的开辟。
2)从文本文件中读取数据时需注意:
*读出来的是字符‘0’,‘1’,要进行转化(字符-'0'转化为数字);
*控制列时,将空格跳过.
3.下来就是如何得到一条通路(这里就要用栈的原理了):
1)首先我们将入口push进去,然后对现在位置的四个方向进行检测(试探法),哪个方向是通的就继续往下走,如果走到边界仍然通的那么恭喜你找到迷宫出的路线了(可以做个标记),假如走入死胡同,那么必须就得返回继续找通路;
2)每往下走一步,push进一个数据,并加以标记;每返回一步,就pop掉一个数据,再做个标记,这一点就体现了回溯法。
下来先看一下栈的代码实现:
#include<assert.h>
#include<ostream>
using namespace std;
struct Istruetype
{
bool get()
{
return true;
}
};
struct Isfalsetype
{
bool get()
{
return false;
}
};
template<typename T>
struct TypeTraits
{
typedef Isfalsetype Ispodtype; //自定义类型
};
template<>
struct TypeTraits<int>
{
typedef Istruetype Ispodtype; //内置类型
};
template<>
struct TypeTraits<char>
{
typedef Istruetype Ispodtype; //内置类型
};
template<class T>
class Stack
{
public:
Stack():_data(0)
,_sz(0)
,_capacity(0)
{}
~Stack()
{
if(_data!=NULL)
{
delete[] _data;
_data=NULL;
}
_sz=0;
_capacity=0;
}
public:
void Push(const T& x)
{
CheckCapacity();
_data[_sz++]=x;
}
void Pop()
{
assert(_sz>0);
--_sz;
}
bool Empty()
{
return _sz==0;
}
size_t Size()
{
return _sz;
}
T& Top()
{
return _data[_sz-1];
}
void PrintStack()
{
if(_sz==0)
{
cout<<"顺序表已空"<<endl;
}
for(size_t i=0;i<_sz;++i)
{
cout<<_data[i]<<" ";
}
cout<<endl;
}
protected:
void CheckCapacity()
{
if(_sz==_capacity)
{
size_t newcapacity=_capacity*2+2;
T* tmp=new T[newcapacity];
if(TypeTraits<T>::Ispodtype().get())
{
memcpy(tmp,_data,sizeof(T)*_sz);
}
else
{
for(size_t i=0;i<_sz;++i)
{
tmp[i]=_data[i];
}
}
delete[] _data;
_data=tmp;
_capacity=newcapacity;
}
}
private:
T* _data;
size_t _sz;
size_t _capacity;
};
然后就是迷宫实现的主体部分:
#include<iostream>
using namespace std;
#include<assert.h>
#include"Stack.h"
const int N=10;
//void InitMaze(int arr[][N]); //二维数组形式
void InitMaze(int* arr) //一维数组形式
{
FILE* file=fopen("MazeMap.txt","r");
assert(file);
for(size_t i=0;i<N;++i)
{
for(size_t j=0;j<N;)
{
char value=fgetc(file);
if(value=='0'||value=='1')
{
arr[i*N+j]=value-'0'; //以一维数组的形式
++j; //跳过空格
}
}
}
fclose(file);
}
struct pos
{
int _row;
int _col;
pos(int row=2,int col=0)
:_row(row),_col(col)
{}
};
bool CheckCross(int* arr,pos next) //检查下一位置是否有效
{
if((next._row>=0) && (next._row<N ) //不能越界且值为0才通过
&& (next._col>=0 )&& (next._col<N)
&& (arr[next._row*N+next._col]==0))
{
return true;
}
else
{
return false;
}
}
bool GetPath(Stack<pos> path,pos& entry,int* arr)
{
path.Push(entry);
arr[entry._row*N+entry._col]=2;
while(!path.Empty())
{
pos cur=path.Top(); //每次cur为栈顶元素
pos next=cur;
if(next._row == N-1 ||next._row==0 || next._col==N-1) //走到边界就返回
{
return true;
}
//上
next._row--;
if(CheckCross(arr,next))
{
path.Push(next);
arr[next._row*N+next._col]=2;
continue;
}
next._row++;
//下
next._row++;
if(CheckCross(arr,next))
{
path.Push(next);
arr[next._row*N+next._col]=2;
continue;
}
next._row--;
//左
next._col--;
if(CheckCross(arr,next))
{
path.Push(next);
arr[next._row*N+next._col]=2;
continue;
}
next._col++;
//右
next._col++;
if(CheckCross(arr,next))
{
path.Push(next);
arr[next._row*N+next._col]=2;
continue;
}
next._col--;
path.Pop(); //找不到通路就返回
arr[cur._row*N+cur._col]=3; //标记回溯路线
}
return false;
}
void PrintMaze(int* arr)
{
for(size_t i=0;i<N;++i)
{
for(size_t j=0;j<N;++j)
{
cout<<arr[i*N+j]<<" ";
}
cout<< endl;
}
}
void PrintPath(int* arr)
{
Stack<pos> path;
pos entry;
GetPath(path,entry,arr);
for(size_t i=0;i<N;++i)
{
for(size_t j=0;j<N;++j)
{
cout<<arr[i*N+j]<<" ";
}
cout<< endl;
}
}
int main()
{
int arr[N][N];
InitMaze((int*)arr);
PrintMaze((int*) arr);
cout<<endl;
PrintPath((int*) arr);
system("pause");
return 0;
}
根据试探法的检测方向的顺序不同,回溯标记就会不同.对于迷宫游戏的优化,比如找出最优通路等暂时还没想出来,继续努力!