海那边的小房子

导航

基于树的迷宫算法

 

基于树的迷宫算法

完整代码

#include<iostream>
#include<ctime>

using namespace std;

class maze
{
  private:
  int rows;
  int cols;
  int start_x;
  int start_y;
  int end_x;
  int end_y;
  char **matrix;
  enum direction {UP = 0,LEFT = 1,DOWN = 2,RIGHT = 3};

  public:
  maze(int rows,int cols);
  ~maze();

  public:
  void print_maze(void);
  void create_maze(void);
  void find_exitance(int move_x,int move_y);
  bool vaild_move(int move_x,int move_y);
  int Get_Start_Point_X(void);
  int Get_Start_Point_Y(void);
};

maze::maze(const int rows,const int cols)
{
  cout << "create the maze structure" << endl;
  this->rows = rows;
  this->cols = cols;
  this->start_x = 0;
  this->start_y = 0;
  this->end_x = 0;
  this->end_y = 0;

  for(int x = 0; x < rows; x++) {
    this->matrix = new char *[cols];
    for(int y = 0; y < cols; y++) {
      this->matrix[y] = new char;
    }
  }
}

maze::~maze()
{
  cout << "destory the maze structure" << endl;
  delete this->matrix;
}

void maze::print_maze(void)
{
  for(int x = 0; x < this->rows; x++) {
    for(int y = 0; y < this->cols; y++) {
      cout << this->matrix[x][y];
    }
    cout << endl;
  }
  cout << endl;
}

void maze::create_maze(void)
{
  int Entry = 0, Exit = 0;

  //add rand seed aim to cause many different data
  srand((int)time(NULL));

  //(1)create the plane
  for(int x = 0; x < this->rows; x++) {
    for(int y = 0; y < this->cols; y++) {
      this->matrix[x][y] = '#';
    }
  }

  //(2)choose the direction of entrance and exitance
  do {
    Entry = rand() % 4;
    Exit = rand() % 4;
  } while(Entry == Exit);

  //(3)define the wall four direction about entrance
  if(Entry == this->UP) {
    this->start_x = 0;
    this->start_y = 1 + rand()%(this->cols - 2);
    this->matrix[this->start_x][this->start_y] = '0';
  } else if(Entry == this->LEFT) {
    this->start_x = 1 + rand()%(this->rows - 2);
    this->start_y = 0;
    this->matrix[this->start_x][this->start_y] = '0';
  } else if(Entry == this->RIGHT) {
    this->start_x = 1 + rand()%(this->rows - 2);
    this->start_y = this->cols - 1;
    this->matrix[this->start_x][this->start_y] = '0';
  } else { //down
    this->start_x = this->rows - 1;
    this->start_y = 1 + rand()%(this->cols - 2);
    this->matrix[this->start_x][this->start_y] = '0';
  }

  //(4)define the wall four direction about exitance
  if(Exit == this->UP) {
    this->end_x = 0;
    this->end_y = 1 + rand()%(this->cols - 2);
    this->matrix[this->end_x][this->end_y] = '0';
  } else if(Exit == this->LEFT) {
    this->end_x = 1 + rand()%(this->rows - 2);
    this->matrix[this->end_x][this->end_y] = '0';
    this->end_y = 0;
  } else if(Exit == this->RIGHT) {
    this->end_x = 1 + rand()%(this->rows - 2);
    this->end_y = this->cols - 1;
    this->matrix[this->end_x][this->end_y] = '0';
  } else { //down
    this->end_x = this->rows - 1;
    this->end_y = 1 + rand()%(this->cols - 2);
    this->matrix[this->end_x][this->end_y] = '0';
  }

  //(5)fill the step on the wall
  #if 0
  for(int x = 1; x <= this->rows - 2; x++) {
    for(int y = 1; y <= this->cols - 2; y++) {
      this->matrix[x][y] = rand()% 2 == 0 ? '0' : '#';
    }
  }
  #else
  int temp_x = 0;
  int temp_y = 0;
  for(int loop = 1;loop < (this->rows-2)*(this->cols-2); loop++) {
    temp_x = 1 + rand()%(this->rows-2);
    temp_y = 1 + rand()%(this->cols-2);
    this->matrix[temp_x][temp_y] = '0';
  }
  #endif

  this->print_maze();
}

void maze::find_exitance(int move_x,int move_y)
{
  static bool judge = false;
  static int succ = 0;

  this->matrix[move_x][move_y] = 'x';

  //cout << "move_x = " << move_x << ", move_y = " << move_y << endl; //debug the program

  if(move_x == this->end_x && move_y == this->end_y) {
    cout << "the exitance is finded" << endl;
    this->print_maze();
    succ++;
    return;
  }

  //(1)UP
  if(this->vaild_move(move_x - 1,move_y)) {
    judge = true;
    this->find_exitance(move_x - 1,move_y);
  }

  //(2)LEFT
  if(this->vaild_move(move_x,move_y - 1)) {
    judge = true;
    this->find_exitance(move_x,move_y - 1);
  }

  //(3)RIGHT
  if(this->vaild_move(move_x,move_y + 1)) {
    judge = true;
    this->find_exitance(move_x,move_y + 1);
   }

  //(4)DOWN
  if(this->vaild_move(move_x + 1,move_y)) {
    judge = true;
    this->find_exitance(move_x + 1,move_y);
  }

  //this->print_maze(); //debug the program

  if(judge == false) {
    cout << "the entrance is block" << endl;
    return;
  }

  if(judge == true && move_x == this->start_x && move_y == this->start_y && succ == 0) {
    cout << "try all prossiblilty,not chance to go home!" << endl;
    return;
  }
}

bool maze::vaild_move(int move_x, int move_y)
{
  #if 1
  return (move_x >= 0 && move_x <= this->rows - 1 && move_y >= 0 && move_y <= this->cols - 1 \
    && this->matrix[move_x][move_y] != 'x' && this->matrix[move_x][move_y] != '#');
  #else
  //optimize some calculate method
  return (move_x >= 0 && move_x < this->rows && move_y >= 0move_y < this->cols \
    && this->matrix[move_x][move_y] != 'x' && this->matrix[move_x][move_y] != '#');
  #endif
}

int maze::Get_Start_Point_X(void)
{
  return this->start_x;
}

int maze::Get_Start_Point_Y(void)
{
  return this->start_y;
}

int main(void)
{
  maze *my_maze = new maze(6,6);
  my_maze->create_maze();
  my_maze->find_exitance(my_maze->Get_Start_Point_X(),my_maze->Get_Start_Point_Y());
  free(my_maze);
}

 详细解释

以完整代码中6行6列的迷宫进行说明

create_maze函数说明

void maze::create_maze(void)
{
  int Entry = 0, Exit = 0;

  //add rand seed aim to cause many different data
  srand((int)time(NULL));

  //(1)create the plane
  for(int x = 0; x < this->rows; x++) {
    for(int y = 0; y < this->cols; y++) {
      this->matrix[x][y] = '#';
    }
  }

  //(2)choose the direction of entrance and exitance
  do {
    Entry = rand() % 4;
    Exit = rand() % 4;
  } while(Entry == Exit);

  //(3)define the wall four direction about entrance
  if(Entry == this->UP) {
    this->start_x = 0;
    this->start_y = 1 + rand()%(this->cols - 2);
    this->matrix[this->start_x][this->start_y] = '0';
  } else if(Entry == this->LEFT) {
    this->start_x = 1 + rand()%(this->rows - 2);
    this->start_y = 0;
    this->matrix[this->start_x][this->start_y] = '0';
  } else if(Entry == this->RIGHT) {
    this->start_x = 1 + rand()%(this->rows - 2);
    this->start_y = this->cols - 1;
    this->matrix[this->start_x][this->start_y] = '0';
  } else { //down
    this->start_x = this->rows - 1;
    this->start_y = 1 + rand()%(this->cols - 2);
    this->matrix[this->start_x][this->start_y] = '0';
  }

  //(4)define the wall four direction about exitance
  if(Exit == this->UP) {
    this->end_x = 0;
    this->end_y = 1 + rand()%(this->cols - 2);
    this->matrix[this->end_x][this->end_y] = '0';
  } else if(Exit == this->LEFT) {
    this->end_x = 1 + rand()%(this->rows - 2);
    this->matrix[this->end_x][this->end_y] = '0';
    this->end_y = 0;
  } else if(Exit == this->RIGHT) {
    this->end_x = 1 + rand()%(this->rows - 2);
    this->end_y = this->cols - 1;
    this->matrix[this->end_x][this->end_y] = '0';
  } else { //down
    this->end_x = this->rows - 1;
    this->end_y = 1 + rand()%(this->cols - 2);
    this->matrix[this->end_x][this->end_y] = '0';
  }

  //(5)fill the step on the wall
  #if 0
  for(int x = 1; x <= this->rows - 2; x++) {
    for(int y = 1; y <= this->cols - 2; y++) {
      this->matrix[x][y] = rand()% 2 == 0 ? '0' : '#';
    }
  }
  #else
  int temp_x = 0;
  int temp_y = 0;
  for(int loop = 1;loop < (this->rows-2)*(this->cols-2); loop++) {
    temp_x = 1 + rand()%(this->rows-2);
    temp_y = 1 + rand()%(this->cols-2);
    this->matrix[temp_x][temp_y] = '0';
  }
  #endif

  this->print_maze();
}

  create_maze的作用其实就是创建迷宫。创建迷宫有五个步骤,分别对应注释:

  (1)打好地基,建立一个6*6的'#'方阵

  (2)选择两堵墙,总共有四堵墙,我们规定入口和出口一定要在不同的墙壁上。也就是需要定义入口和出口在不同的墙壁上。这里只是定义方向而已

  (3)选择入口墙壁

      (4)选择出口墙壁

    (5)填满空区域,因为我们只定义了入口和出口,但是还没有内容

 

    下面,为了更好的理解笔者所述的话,笔者分别编辑了图片对这些步骤进行说明,也方便以后回顾的时候会有清晰的记忆^~^!!!

 

  对应(1)步骤

  

  对应(2)步骤,定义四个方向

  

    对应(3)步骤,选择一堵任意的墙作为入口

  我们现在选择黑色线方向作为入口,其对应y轴是固定的,即 (这里为1不是0是因为假如把0放到去左上角就会出现含义混乱,因为此时黑线和蓝线相交于一点,从代码的含义来看方向就不具有唯一性了)1 < x < 5(这里小于5和大于1的原理是一样的,都要保证各个墙壁方向的唯一性)y=0,对应代码的写法是x = 1+rand()%(rows-2),y = 0

  同理所得:

  假如以蓝色线方向作为入口,x = 01 < y < 5,对应代码的写法是x = 0,y = 1 + rand()%(cols-2)

  假如以绿色线方向作为入口,1 < x < 5y = 5(6-1,下标值),对应代码的写法是x = 1+rand()%(rows-2),y = cols-1

  假如以橙色线方向作为入口,x = 5(6-1,下标值)1 < y < 5, 对应代码的写法是x=rows-1,y = 1+rand()%(cols-2)

      

  对应(4)步骤,选择一堵任意的墙作为出口

  我们现在选择以绿色方向线的墙壁作为出口,根据(3)步骤的说明我们可以得出,此时绿色方向线作为出口的x,y的范围分别为1 < x < 5y = 5(6-1,下标值),对应代码为x=1+rand()%(rows-2)y=cols-1

  同理所得:

  假如以蓝色线方向作为出口,x = 01 < y < 5,对应代码的写法是x = 0,y = 1 + rand()%(cols-2)

  假如以橙色线方向作为出口,x = 5(6-1,下标值),1 < y < 5, 对应代码的写法是x=rows-1,y = 1+rand()%(cols-2)

  假如以黑色线方向作为出口,1 < x < 5y=0, 对应代码的写法是x = 1+rand()%(rows-2),y = 0

            

  对应(5)步骤,填满非墙壁的空区域

  对于我们现在所用的6*6矩阵我们可以通过任意的算法来把阴影空间补充满,我这边采用了两种算法:

  1.遍历阴影部分的区域一次,随机分配可通行区域(即'0'),对应被注释的部分

  2.对于此例子而言,把4*4个坑当作是16种分配的机会,每个坑每次被分配为'0'的机会都为1/16,对应未被注释的部分

  //(5)fill the step on the wall
  #if 0
  for(int x = 1; x <= this->rows - 2; x++) {
    for(int y = 1; y <= this->cols - 2; y++) {
      this->matrix[x][y] = rand()% 2 == 0 ? '0' : '#';
    }
  }
  #else
  int temp_x = 0;
  int temp_y = 0;
  for(int loop = 1;loop < (this->rows-2)*(this->cols-2); loop++) {
    temp_x = 1 + rand()%(this->rows-2);
    temp_y = 1 + rand()%(this->cols-2);
    this->matrix[temp_x][temp_y] = '0';
  }
  #endif

  

 

  通过了如上部分的图解,一个迷宫就自建好了,接着就是寻找出口了!!!

 

find_exitance函数说明

void maze::find_exitance(int move_x,int move_y)
{
  static bool judge = false;
  static int succ = 0;

  this->matrix[move_x][move_y] = 'x';

  //cout << "move_x = " << move_x << ", move_y = " << move_y << endl; //debug the program

  if(move_x == this->end_x && move_y == this->end_y) {
    cout << "the exitance is finded" << endl;
    this->print_maze();
    succ++;
    return;
  }

  //(1)UP
  if(this->vaild_move(move_x - 1,move_y)) {
    judge = true;
    this->find_exitance(move_x - 1,move_y);
  }

  //(2)LEFT
  if(this->vaild_move(move_x,move_y - 1)) {
    judge = true;
    this->find_exitance(move_x,move_y - 1);
  }

  //(3)RIGHT
  if(this->vaild_move(move_x,move_y + 1)) {
    judge = true;
    this->find_exitance(move_x,move_y + 1);
   }

  //(4)DOWN
  if(this->vaild_move(move_x + 1,move_y)) {
    judge = true;
    this->find_exitance(move_x + 1,move_y);
  }

  //this->print_maze(); //debug the program

  if(judge == false) {
    cout << "the entrance is block" << endl;
    return;
  }

  if(judge == true && move_x == this->start_x && move_y == this->start_y && succ == 0) {
    cout << "try all prossiblilty,not chance to go home!" << endl;
    return;
  }
}

 find_exitance函数的作用就是通过不断的循迹迷宫,找到最终的出口

 (1)先给定一个坐标,并将其置为'x',代表已经找过此路了,增加判断,假若当前坐标的(x,y)与终点坐标的(x,y)对应上了,我们则判定已经找到了迷宫的出口

 (2)寻找上边位置是否可通行,如若可以通行,则将坐标定为上边的位置,重新回到(1)步骤继续查找,如若不可以通行,则继续进行(3)步骤

 (3)寻找左边位置是否可通行,如若可以通行,则将坐标定为左边的位置,重新回到(1)步骤继续查找,如若不可以通行,则继续进行(4)步骤

 (4)寻找右边位置是否可通行,如若可以通行,则将坐标定为右边的位置,重新回到(1)步骤继续查找,如若不可以通行,则继续进行(5)步骤

 (5)寻找下边位置是否可通行,如若可以通行,则将坐标定为下边的位置,重新回到(1)步骤继续查找,如若不可以通行,则我们就要分析两种特殊的情况,我们将以生动的图像对两种特殊情况进行阐述

 第一种特殊情况,入口直接被封死(入口被标定为红色,出口被标定为绿色)

 第二种特殊情况,入口没被封死,但是走着走着发现无路可走了(入口被标定为红色,出口被标定为绿色)

 

 Note:为什么迷宫能够往回走,主要是基于入栈和弹栈的原理,栈的作用可以临时存储局部变量,故当有的路径发现走不通的时候,自然而然会弹栈,弹栈的过程就相当于回溯了,如果对栈有不理解的地方可以自行查阅栈的基本原理,笔者不才,就不在此篇章中展开论述了

 

 

   

  

 

posted on 2021-09-15 23:04  海那边的蓝精灵  阅读(70)  评论(0)    收藏  举报