最近在学习面向对象的方法,强迫自己用面向对象的方法构建程序,于是便有了这个面向对象的迷宫。
在设计这个迷宫的初期,一共想到了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();
}