繁体   English   中英

C++中的迷宫求解算法

[英]Maze Solving Algorithm in 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);
}


}

在此输入图像描述

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

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

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

#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;
}

为了说明,我在Javascript中有以上版本:

 const MazeWidth = 9 const MazeHeight = 9 let Maze = [ "# #######", "# # #", "# ### # #", "# # # #", "# # # ###", "# # # #", "# ### # #", "# # #", "####### #" ].map(line => line.split('')) const Wall = '#' const Free = ' ' const SomeDude = '*' const StartingPoint = [1, 0] const EndingPoint = [7, 8] function PrintDaMaze() { //Maze.forEach(line => console.log(line.join(''))) let txt = Maze.reduce((p, c) => p += c.join('') + '\\n', '') let html = txt.replace(/[*]/g, c => '<font color=red>*</font>') $('#mazeOutput').html(html) } async function Solve(X, 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() await sleep(100) // Check if we have reached our goal. if (X == EndingPoint[0] && Y == EndingPoint[1]) { return true } // Recursively search for our goal. if (X > 0 && Maze[Y][X - 1] == Free && await Solve(X - 1, Y)) { return true } if (X < MazeWidth && Maze[Y][X + 1] == Free && await Solve(X + 1, Y)) { return true } if (Y > 0 && Maze[Y - 1][X] == Free && await Solve(X, Y - 1)) { return true } if (Y < MazeHeight && Maze[Y + 1][X] == Free && await 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() await sleep(100) return false } function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)) } (async function() { if (await Solve(StartingPoint[0], StartingPoint[1])) { console.log("Solved!") PrintDaMaze() } else { console.log("Cannot solve. :-(") } })() 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <pre id="mazeOutput"> </pre> 

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

而且,看起来,你并没有真正产生一个迷宫,而是一个大的场地,边界有墙壁,里面有“出口”。 如果出口不在墙附近(目前只在你的“迷宫”的边界处),那么真正“贴墙”的算法永远不会找到出口。

既然你没有删除SomeDude s,即你已经去过的位置,并且你正在以与Wall相同的方式对待SomeDude ,那么你正慢慢地用某种“SomeDude-Wall”填满迷宫:你只是向下走,直到你撞到边界,然后围绕场地逆时针旋转,留下一些SomeDude的痕迹。

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

对于算法,它会粘在墙上(从而能够找到某种迷宫的方法 ),我建议采取以下步骤:

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

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

请记住,此算法无法找到出口,如果出口位于某个自由空间内(因为它始终贴在墙上,出口也必须靠近墙壁才能找到)。

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

HTH马丁

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM