威老的迷宫探险

最近在学习面向对象的方法,强迫自己用面向对象的方法构建程序,于是便有了这个面向对象的迷宫。

在设计这个迷宫的初期,一共想到了4对象:点(Point)、组成迷宫的格子(Square)、迷宫(Maze)、探险者(Exploer)。

后来发现前两个类有点鸡肋了,删掉。剩下两个对象迷宫(Maze)、探险者(Exploer),这样写起来轻松些。

代码量约有300行,总耗时7、8个小时的样子吧。

 

好了,现在我们有两个类,开始设计。

迷宫(Maze):

首先,迷宫有许多个格子,每个格子不是墙壁就是可行走。我们约定 '0'为可走,'1'为墙壁。

为了方便,我定死了迷宫的最大长宽。(⊙o⊙)…别揍我啊。。。

迷宫应该有出入口,一开始我想到了我用数组entrance[2]以及exit[2]来表示,下标为0就是x坐标,下标为1是y坐标。但是这样做的话,语义上相对难理解,所以最终我还是选择了entrance_x,entrance_y,exit_x,exit_y这样的形式。

接下来是代码,头文件。

/*maze.h*/

#include<iostream>
#include
<fstream>
using namespace std;

/*迷宫*/
class Maze
{
private:
int height,width; //迷宫的高和宽
char board[50][50]; //迷宫体,'0'为可走,'1'为墙壁

int entrance_x,entrance_y; //入口
int exit_x,exit_y; //出口

public:
Maze();
//默认的构造,随机创建迷宫
Maze(char txtFileName[]); //从文件流读入(文件必须为文本文档)
display(); //显示迷宫
int getSquareType(int x, int y); //根据位置获取格子类型

int setEntrance(int x, int y){entrance_x = x; entrance_y = y;};//设置入口
int getEntrance_x();
int getEntrance_y();

int setExit(int x, int y){exit_x = x; exit_y = y;}; //设置出口
int getexit_x();
int getexit_y();
void mark(int x, int y, char mk);//标记的位置(x,y) ,标记的符号
};

 

 

其中的mark()是为了允许探险者标记迷宫提供的。

接下来maze.cpp

Maze()随机建立迷宫还没有实现(日后再说了)。

约定迷宫以ascii码存储,Maze()动态读取文本的内容。

/*maze.cpp*/

 

#include<iostream>
#include
<fstream>
#include
<string>
#include
"maze.h"
using namespace std;



Maze::Maze(
char txtFileName[])
{
ifstream
in(txtFileName);
char str[50];
int i,j;
for(i=0; in>>str; i++) //读入一行
{
for(j=0; str[j]!='\0'; j++) //判断是否已经读到行末
{
board[i][j]
=str[j]; //每一个字符存进一个格子
}
}
height
= i; //设置迷宫的高
width = j; //设置迷宫的宽
entrance_x = 1; //设置迷宫的入口x坐标(默认值)
entrance_y = 1; //设置迷宫的入口y坐标(默认值)
exit_x = width - 2; //设置迷宫的出口x坐标(默认值)
exit_y = height - 2; //设置迷宫的出口y坐标(默认值)
}


Maze::display()
{
for(int i=0; i < height; i++)
{
for(int j=0; j < width; j++)
cout
<<board[i][j];
cout
<<endl;
}
}

int Maze::getSquareType(int x, int y)
{
return board[y][x];
/*
这里的x,y位置应该相反。
因为坐标轴上(x,y)的位置在数组中为第y行第x列
*/
}

int Maze::getEntrance_x()
{
return entrance_x;
}

int Maze::getEntrance_y()
{
return entrance_y;
}

int Maze::getexit_x()
{
return exit_x;
}

int Maze::getexit_y()
{
return exit_y;
}

void Maze::mark(int x, int y, char mk)
{
board[y][x]
= mk;
}

 

 

迷宫构建完毕!

接下来就是造访这座迷宫的探险者了。

功能分得十分细,连检查某个方向都单独做了类,但是对外部只提供了一个函数:goAhead()。我的意思是你只能叫这个人去探险,而不能命令他做其他事情。

/*explorer.h*/

 

#include<iostream>
#include
"maze.h"
#include
<stack>
using namespace std;

/*探险家*/
class Explorer
{
private:
int current_x,current_y;//当前位置。
Maze * explored_Maze;//被探访的迷宫在探险者大脑里的反映。board中标记为' '(空格)表示走过
stack<int> memory;//存储自己的行走路线的栈,我这里只记录每次行走的方向。

bool IsInExit(); //检查是否已经到达终点
int searchAround(); //搜索四周,以寻找下一个路径点。四个方向东、南、西、北。
                  //分别返回1、2、3、4,无路可走返回-1,到达终点返回0。
bool IsEastWalkable(); //检查东面是否可行走
bool IsSouthWalkable(); //检查南面是否可行走
bool IsWestWalkable(); //检查西面是否可行走
bool IsNorthWalkable(); //检查北面是否可行走
bool checkWalkable(int x, int y); //检查指定位置是否可行走
void walkTowards(int direction); //往某个方向行走,direction为方向
int walkToNext(); //找到下一个点并移动到下一个点去。
void walkTo(int x, int y); //行走到某个位置,direction为方向
void mark(char mark); //在原地做个标记
bool goBack(); //往回走,返回值表示 往回走 成功或者失败。

public:
Explorer(Maze
* explored_maze)
{
explored_Maze
= explored_maze;
memory.push(
0);
current_x
= explored_Maze->getEntrance_x();
current_y
= explored_Maze->getEntrance_y();
};
//构造函数
int goAhead(); //一路寻路到尽头

int getPosition_x();
int getPosition_y();
};

 

 

功能分得这么细,我想也不需要太多啰嗦啦。

/*explorer.cpp*/

 

#include<iostream>
#include
"explorer.h"

bool Explorer::IsInExit()
{
if(current_x == explored_Maze->getexit_x() && current_y==explored_Maze->getexit_y())
return true;
else
return false;
}

int Explorer::searchAround()
{
if(IsInExit())//已经到出口了
{
// cout<<"InExit"<<endl;
return 0;
}

if(IsEastWalkable())
{
// cout<<"→";
return 1;
}
else if(IsSouthWalkable())
{
// cout<<"↓";
return 2;}
else if(IsWestWalkable())
{
// cout<<"←";
return 3;
}
else if(IsNorthWalkable())
{
// cout<<"↑";
return 4;
}
return -1;
}

bool Explorer::IsEastWalkable()
{
if(checkWalkable(current_x+1, current_y))
{
return true;
}
else
return false;
}

bool Explorer::IsSouthWalkable()
{
if(checkWalkable(current_x,current_y+1))
{
return true;
}
else
return false;
}

bool Explorer::IsWestWalkable()
{
if(checkWalkable(current_x - 1,current_y))
{
return true;
}
else
return false;
}

bool Explorer::IsNorthWalkable()
{
if(checkWalkable(current_x,current_y-1))
{
return true;
}
else
return false;
}

bool Explorer::checkWalkable(int x, int y)
{
if(explored_Maze->getSquareType(x, y) == '0')
return true;
else
return false;
}

void Explorer::walkTowards(int direction)
{
int next_x=current_x;
int next_y=current_y;
switch(direction)
{
case 1: next_x++; break;//
case 2: next_y++; break;//
case 3: next_x--; break; //西
case 4: next_y--; break; //
}
walkTo(next_x, next_y);
//走到下一点
memory.push(direction);//记住自己走的方向
}

void Explorer::walkTo(int next_x, int next_y)
{
mark(
' '); //做上“走过”(空格)标记
current_x = next_x;
current_y
= next_y;
mark(
'c'); //做上“当前位置”(字母c)标记,以代表探险者当前位置
}

int Explorer::walkToNext()
{
int nextDirection = searchAround();
if(nextDirection == -1)
{
if(goBack())
return 0;//可以往后退
else
return -1;//已经退回起点了,迷宫无解
} //无路可走
if(nextDirection == 0) return 1; //到达终点
walkTowards(nextDirection);
return 0;//移动到下一点
}

int Explorer::getPosition_x()
{
return current_x;
}

int Explorer::getPosition_y()
{
return current_y;
}

int Explorer::goAhead()
{
int walkResult;
for(int i=0;; i++)
{
walkResult
= walkToNext();
if( walkResult == 1)
{
return 1;//到达终点
}
if( walkResult == -1)
{
return -1;//找不到出口
}
system(
"pause"); //按任意键继续
system("cls"); //清屏
explored_Maze->display(); //重画迷宫
// cout<<current_x<<' '<<current_y<<endl;
}
return 1;
}

void Explorer::mark(char mk)
{
explored_Maze
->mark(current_x, current_y, mk);
}

bool Explorer::goBack()//可以后退返回true,无法后退,即已经回到起点,则返回false
{
// cout<<memory.top();
if(memory.top() == 3)//若来的时候是从东边来,返回东边的那一格。
walkTo(current_x + 1, current_y);
else if(memory.top() == 2)
walkTo(current_x, current_y
- 1);
else if(memory.top() == 1)
walkTo(current_x
- 1, current_y);
else if(memory.top() == 4)
walkTo(current_x, current_y
+ 1);
else if(memory.top() == 0)
{
return false;
}
memory.pop();
//把自己记录的路线做一下修改。
return true;
}

最后,再次感受一下面向对象的强大魅力。

简洁明了的main.cpp,都不知道什么还有地方需要解说了。

ps:yy无罪。

/*main.cpp*/

#include"explorer.h"
void main()
{
char filename[30] = "maze.data";
Maze mz(filename);
//创建迷宫
cout<<"据乾陵《述圣纪》碑记载,唐高宗临终遗言,要求将他生前所珍爱的书籍、字画等全部埋入陵中。武则天营建乾陵的目的是为了报答唐高宗的知遇之恩,因此,陪葬入乾陵的稀世珍宝一定不少。这是一个满藏无价瑰宝的地宫。\n古往今来,多少歹人绞尽脑汁,费尽心思找不到的乾陵地宫墓道口,在上个世纪50年代末被几个农民意外发现。"<<endl;
mz.display();
//打印迷宫
Maze weilaosMz = mz;
Explorer weilao(
&weilaosMz);//创建探险者
cout<<"现在weilao,一个特别牛X的考古学家来到了这里,一场惊心动魄的探险开始了……"<<endl;
int weilaosExplorResult = weilao.goAhead();//探险者走迷宫
if(weilaosExplorResult == 1) cout<<"weilao找到了大量宝藏!"<<endl;
if(weilaosExplorResult == -1) cout<<"weilao空手而归。。。"<<endl;
cin
>>weilaosExplorResult;
// weilaosMz.display();
}

原文地址:https://www.cnblogs.com/weilao/p/obj_maze.html