C ++中的迷宫求解算法

时间:2012-02-08 10:23:04

标签: c++

我正在编写一种算法,通过粘贴在墙上并按此顺序移动来找到通过迷宫的方法:向下 - 向右 - 向上 - 向左直到找到出口。但是,有时候,它会陷入无限循环而无法继续。我一直想弄清楚几个小时出了什么问题而我没有运气。这是代码

#include <iostream>
#include <windows.h>
const int MazeWidth = 30;
const int MazeHeight = 20;
const char MazeExit = '$';
const char Wall = '#';
const char Free = ' ';
const unsigned char SomeDude = 254;
COORD MazeExitCoords;
COORD StartingPoint;

using namespace std;
char Maze [MazeHeight][MazeWidth];




void FillDaMaze(){

    MazeExitCoords.X = MazeWidth - 20;
    MazeExitCoords.Y = 2;
    StartingPoint.X = 3;
    StartingPoint.Y = MazeHeight - 3;

    for(int i = 0; i < MazeHeight; i++){

        for(int ii = 0; ii < MazeWidth; ii++){

            if(i == 0 || i == MazeHeight - 1 || ii == 0 || ii == MazeWidth - 1){
                Maze[i][ii] = Wall;
            }
            else{
            Maze[i][ii] = Free;
            }

            if(i == MazeExitCoords.Y && ii == MazeExitCoords.X){
                    Maze[i][ii] = MazeExit;
            }
            else if(i == StartingPoint.Y && ii == StartingPoint.X){
                    Maze[i][ii] = SomeDude;
            }
        }
    }
}
void PrintDaMaze(int color){
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),color);

    for(int i = 0; i < MazeHeight; i++){

        for(int ii = 0; ii < MazeWidth;ii++){

            cout << Maze[i][ii];
        }
        cout << endl;
    }
}
void FindYourWayThroughTheMaze(){



        if(Maze[StartingPoint.Y + 1][StartingPoint.X] != Wall && Maze[StartingPoint.Y + 1][StartingPoint.X ] != SomeDude){
        StartingPoint.Y++;



        }
        else if(Maze[StartingPoint.Y][StartingPoint.X + 1] != Wall && Maze[StartingPoint.Y][StartingPoint.X + 1] != SomeDude){
            StartingPoint.X++;



        }
        else if(Maze[StartingPoint.Y - 1][StartingPoint.X] != Wall && Maze[StartingPoint.Y - 1][StartingPoint.X ] != SomeDude){
            StartingPoint.Y--;





        }
        else if(Maze[StartingPoint.Y][StartingPoint.X - 1] != Wall && Maze[StartingPoint.Y][StartingPoint.X - 1] != SomeDude){
            StartingPoint.X--;



        }


    Maze[StartingPoint.Y][StartingPoint.X] = SomeDude;

}
int main(){

FillDaMaze();
PrintDaMaze(10);
while(StartingPoint.X != MazeExitCoords.X || StartingPoint.Y != MazeExitCoords.Y){
    FindYourWayThroughTheMaze();
    system("CLS");
    PrintDaMaze(10);
    Sleep(50);
}


}

2 个答案:

答案 0 :(得分:20)

enter image description here

要有机会解决它,你必须:

  • 创建一个Solve()例程并递归调用自身:
    • 如果第1,第2,第3,......为真Solve已成功找到解决方案
    • 如果1st,2nd,3rd,...包含false,则必须回溯并找到另一种方式
  • 您需要构建一个缓冲区,以避免无限循环
    • 当你做出动作时,它需要密切关注它
    • 当我们走到死胡同时,我们需要消除不良行动
    • 我们可以通过猜测来实现上述操作,如果错误则将其删除

这是基于以上概念的粗略实现:

#include "stdafx.h"
#include <stdio.h>

const int MazeHeight = 9;
const int MazeWidth = 9;

char Maze[MazeHeight][MazeWidth + 1] =
{
    "# #######",
    "#   #   #",
    "# ### # #",
    "# #   # #",
    "# # # ###",
    "#   # # #",
    "# ### # #",
    "#   #   #",
    "####### #",
};

const char Wall = '#';
const char Free = ' ';
const char SomeDude = '*';

class COORD
{
public:
    int X;
    int Y;
    COORD(int x = 0, int y = 0) { X = x, Y = y; }
    COORD(const COORD &coord) { X = coord.X; Y = coord.Y; }
};

COORD StartingPoint(1, 0);
COORD EndingPoint(7, 8);

void PrintDaMaze()
{
    for (int Y = 0; Y < MazeHeight; Y++)
    {
        printf("%s\n", Maze[Y]);
    }
    printf("\n");
}

bool Solve(int X, int Y)
{
    // Make the move (if it's wrong, we will backtrack later.
    Maze[Y][X] = SomeDude;

    // If you want progressive update, uncomment these lines...
    //PrintDaMaze();
    //Sleep(50);

    // Check if we have reached our goal.
    if (X == EndingPoint.X && Y == EndingPoint.Y)
    {
        return true;
    }

    // Recursively search for our goal.
    if (X > 0 && Maze[Y][X - 1] == Free && Solve(X - 1, Y))
    {
        return true;
    }
    if (X < MazeWidth && Maze[Y][X + 1] == Free && Solve(X + 1, Y))
    {
        return true;
    }
    if (Y > 0 && Maze[Y - 1][X] == Free && Solve(X, Y - 1))
    {
        return true;
    }
    if (Y < MazeHeight && Maze[Y + 1][X] == Free && Solve(X, Y + 1))
    {
        return true;
    }

    // Otherwise we need to backtrack and find another solution.
    Maze[Y][X] = Free;

    // If you want progressive update, uncomment these lines...
    //PrintDaMaze();
    //Sleep(50);
    return false;
}

int _tmain(int argc, _TCHAR* argv[])
{
    if (Solve(StartingPoint.X, StartingPoint.Y))
    {
        PrintDaMaze();
    }
    else
    {
        printf("Damn\n");
    }

    return 0;
}

答案 1 :(得分:5)

正如Luchian已经发布的那样,算法(即使正确实施)也不适合找到各种迷宫中的方法:如果你的迷宫中有一些循环,你可能最终会绕着这个循环墙跑来跑去。

另外,看起来,你并没有真正产生一个迷宫,而是一个在边界处有墙壁并且在其内部某处有“出口”的大场。如果出口不靠近墙壁(目前只在“迷宫”的边界处),那么真正“贴墙”的算法将永远找不到出口。

由于你没有删除SomeDude s,即你已经去过的职位,并且你正在以SomeDude的方式对待Wall,你就是用某种“SomeDude-Wall”慢慢填满迷宫:你向下走直到你撞到边界,然后在场地周围大逆时针旋转,留下SomeDude s的痕迹。

根据您的起点和出口,您可以轻松地遇到所有四个方向被阻挡的情况,无论是通过“真实”墙还是您之前留下的SomeDude。然后,四个if - 语句中没有一个被执行,你只有一个无限循环(因为循环体内没有任何变化)。

对于一个算法,它会粘在一堵墙上(因而能够找到某种方法来解决某些类型的迷宫),我建议采取以下步骤:

  • 首先,朝一个方向走,直到你撞墙。
  • 设置当前的方向,使墙壁位于右侧。
  • 按照您当前的指示(不要忘记删除SomeDude - 跟踪),直到其中任何一个
    • 你找到了出口。
    • 右侧没有墙:在这种情况下,向右转,向前迈出一步。
    • 或者,在你面前有一面墙。在这种情况下,请转动 left ,直到你前方的路是免费的

通过这种方式,您确保右侧始终存在“相同”的墙壁,因此您“坚持”到该墙壁。

请记住,这个算法找不到出口,如果出口在一些自由空间内(因为它总是粘在墙上,出口也必须靠近墙壁才能找到)。

对于能够找到所有可能的迷宫的算法,你需要进行某种回溯:记住每个点,你有多个选择可以继续。选择一种方式,然后按照它。如果它是一个死胡同,请回到最后的决定点并采取下一个选择。如果没有办法通往出口,请转到上一个最后一点,依此类推。这是一种递归方法,在图论中被称为“深度优先搜索”(随意做一些谷歌搜索,我很自信,你会发现很多关于这个的材料:) ...)< / p>

HTH 马丁