【问题标题】:Maze Program Can't Finish迷宫程序无法完成
【发布时间】:2015-09-27 03:08:37
【问题描述】:

所以我正在编写一个生成然后解决迷宫的程序。除了这件小事,我什么都在工作。迷宫中的标记将到达完成迷宫的倒数第二个步骤,然后停止,然后移动到不同的方向。我已经为此工作了大约 2 个小时,一直在跟踪我的代码,但似乎无法找到它在最后一步中出现异常的位置或原因。

迷宫的规则是X 是墙,不能移动,O 是可以移动的可能区域,. 是起点。 - 是我已经移动到的路径。标记可以沿任何序数或基本方向(北、东北等)移动。

我有两个矩阵,一个称为mat,它使用X's 和O's 和-'s 显示给用户。我还有另一个矩阵visited,它的大小与mat 相同,是一种幕后矩阵,它跟踪我可以或不能移动到的坐标。它为墙壁存储W,为我已经访问过的坐标存储Y,为我可以访问的坐标存储N

我解决迷宫的方法是从北开始检查可能的移动,然后围绕指南针逆时针移动,直到找到可能的移动。标记无法移动以发现它已经移动。

如果我遇到具有多个可能移动的分割路径,我将该位置的坐标放在两个堆栈中,称为 splitx 用于行,splity 用于列,以便稍后我可以回到它。如果我遇到了一个死胡同,每个方块要么是一面墙,要么已经被访问过,我会回溯到我的分割路径堆栈中的最后一个坐标,关闭我刚刚移动到的路径,然后弹出堆栈的顶部值。

我还有另一个名为visitStack 的堆栈,它将我所做的每一个动作存储为N 用于North,NE 用于Northeast,等等。这让我可以回溯我的动作并转到我遇到的最后一条分割路径。这是代码,下面是一些选择的输出。如果您对代码或输出有任何疑问,或者只是一般性的澄清,请尽管提问。

import java.util.*;

public class MazeLab
{
    public static void main(String args[]) 
    {
        Scanner input = new Scanner(System.in);
        System.out.print("Enter random starting seed  ===>>  ");
        int seed = input.nextInt();

        Maze maze = new Maze(seed);
        maze.displayMaze();
        maze.solveMaze();
    }
}

class Maze
{

    private char mat[][];               // 2d character array that stores the maze display
    private char visited[][];           // 2d character array that works behind to scenes to let me know where I can or can't move
    private Stack<String> visitStack;           // stack that stores every move I make as N, NE, E, SE, etc
    private int nowR, nowC;                     // coordinates for current position in the matrix
    private int startRow, startCol;             // coordinates for the starting position
    private boolean done = false;               // not that important
    private Stack<Integer> splitx = new Stack<Integer>(); // row coord for split paths
    private Stack<Integer> splity = new Stack<Integer>(); // col coord for split paths
    Random random = new Random();

    public Maze(int seed)
    // constructor which generates the random maze, random starting location
    // and initializes Maze class values.  If the random value equals 0 the maze
    // store an 'X' otherwise it store an 'O' in the maze.
    {
        Random randomize = new Random(seed);
        mat = new char[12][12];
        visited = new char[12][12];
        for (int r = 0; r < 12; r++)
            for (int c = 0; c < 12; c++)
            {
                if (r == 0 || c == 0 || r == 11 || c == 11)
                    mat[r][c] = 'X';
                else
                {
                    int rndInt = randomize.nextInt(2);
                    if (rndInt == 0)
                        mat[r][c] = 'X';
                    else
                        mat[r][c] = 'O';
                }
            }
        mat[0][0] = 'O';
        startRow = randomize.nextInt(12);
        startCol = 11;
        nowR = startRow;
        nowC = startCol;
        mat[startRow][startCol] = '.';
        visitStack = new Stack<String>();

        for(int i = 0; i < mat.length; i++)
            for(int k = 0; k < mat[i].length; k++)
                if(mat[i][k] == 'X')
                    visited[i][k] = 'W';
                else
                    visited[i][k] = 'N';
//                                      Avoid going back to the starting point
        visited[nowR][nowC] = 'Y';
    }


    void displayMaze()
    // displays the current maze configuration
    {
        for (int r = 0; r < 12; r++)
        {
            for (int c = 0; c < 12; c++)
                System.out.print(mat[r][c] + "  ");
            System.out.println();
        }
        System.out.println();

        if(done == false)
            pause();
    }


    public void solveMaze()
    {
    // for testing purposes, this is not the real method
        for(int i = 0; i < 15; i++)
        {
            getMove();
            displayMaze();
        }
    }

    private int numMoves()
    // This method determines if a position has a valid move or not       
    {
        int moves = 0;
        if(nowR != 0 && visited[nowR-1][nowC] == 'N')
            moves++;
        if(nowR != 0 && nowC != 11 && visited[nowR-1][nowC+1] == 'N')
            moves++;
        if(nowC != 11 && visited[nowR][nowC+1] == 'N')
            moves++;
        if(nowR != 11 && nowC != 11 && visited[nowR+1][nowC+1] == 'N')
            moves++;
        if(nowR != 11 && visited[nowR+1][nowC] == 'N')
            moves++;
        if(nowR != 11 && nowC != 0 && visited[nowR+1][nowC-1] == 'N')
            moves++;
        if(nowC != 0 && visited[nowR][nowC-1] == 'N')
            moves++;
        if(nowR != 0 && nowC != 0 && visited[nowR-1][nowC-1] == 'N')
            moves++;
        return moves;
    }

    private void getMove()
    {
        if(numMoves() > 1)
        {
//                                      checks for split paths
//                                      north
            if(nowR != 0 && visited[nowR-1][nowC] == 'N')
            {
                splitx.push(nowR);
                splity.push(nowC);
            }
//                                      northwest
            if(nowR != 0 && nowC != 0 && visited[nowR-1][nowC-1] == 'N')
            {
                splitx.push(nowR);
                splity.push(nowC);
            }
//                                      west
            if(nowC != 0 && visited[nowR][nowC-1] == 'N')
            {
                splitx.push(nowR);
                splity.push(nowC);
            }
//                                      southwest
            if(nowR != 11 && nowC != 0 && visited[nowR+1][nowC-1] == 'N')
            {
                splitx.push(nowR);
                splity.push(nowC);
            }
//                                      south
            if(nowR != 11 && visited[nowR+1][nowC] == 'N')
            {
                splitx.push(nowR);
                splity.push(nowC);
            }
//                                      southeast
            if(nowR != 11 && nowC != 11 && visited[nowR+1][nowC+1] == 'N')
            {
                splitx.push(nowR);
                splity.push(nowC);
            }
//                                      east
            if(nowC != 11 && visited[nowR][nowC+1] == 'N')
            {
                splitx.push(nowR);
                splity.push(nowC);
            }
//                                      northeast
            if(nowR != 0 && nowC != 11 && visited[nowR-1][nowC+1] == 'N')
            {
                splitx.push(nowR);
                splity.push(nowC);
            }
        }
        if(numMoves() > 0)
        {
//                                      moves the marker, oriented to the right
//                                      north
            if(nowR != 0 && visited[nowR-1][nowC] == 'N')
            {
                nowR--;
                visited[nowR][nowC] = 'Y';
                visitStack.push("N");
                mat[nowR][nowC] = '-';
//              System.out.println("PUSHING ON NORTH");
            }
//                                      northwest
            else if(nowR != 0 && nowC != 0 && visited[nowR-1][nowC-1] == 'N')
            {
                nowR--;
                nowC--;
                visited[nowR][nowC] = 'Y';
                visitStack.push("NW");
                mat[nowR][nowC] = '-';
//              System.out.println("PUSHING ON NORTHWEST");
            }   
//                                      west
            else if(nowC != 0 && visited[nowR][nowC-1] == 'N')
            {
                nowC--;
                visited[nowR][nowC] = 'Y';
                visitStack.push("W");
                mat[nowR][nowC] = '-';
//              System.out.println("PUSHING ON WEST");
            }
//                                      southwest
            else if(nowR != 11 && nowC != 0 && visited[nowR+1][nowC-1] == 'N')
            {
                nowR++;
                nowC--;
                visited[nowR][nowC] = 'Y';
                visitStack.push("SW");
                mat[nowR][nowC] = '-';
//              System.out.println("PUSHING ON SOUTHWEST");
            }
//                                      south
            else if(nowR != 11 && visited[nowR+1][nowC] == 'N')
            {
                nowR++;
                visited[nowR][nowC] = 'Y';
                visitStack.push("S");
                mat[nowR][nowC] = '-';
//              System.out.println("PUSHING ON SOUTH");
            }
//                                      southeast
            else if(nowR != 11 && nowC != 11 && visited[nowR+1][nowC+1] == 'N')
            {
                nowR++;
                nowC++;
                visited[nowR][nowC] = 'Y';
                visitStack.push("SE");
                mat[nowR][nowC] = '-';
//              System.out.println("PUSHING ON SOUTHEAST");
            }
//                                      east
            else if(nowC != 11 && visited[nowR][nowC+1] == 'N')
            {
                nowC++;
                visited[nowR][nowC] = 'Y';
                visitStack.push("E");
                mat[nowR][nowC] = '-';
//              System.out.println("PUSHING ON EAST");
            }
//                                      northeast
            else if(nowR != 0 && nowC != 11 && visited[nowR-1][nowC+1] == 'N')
            {
                nowR--;
                nowC++;
                visited[nowR][nowC] = 'Y';
                visitStack.push("NE");
                mat[nowR][nowC] = '-';
//              System.out.println("PUSHING ON NORTHEAST");
            }
        }
        if(numMoves() == 0)
        {
            while(nowR != splitx.peek() && nowC != splity.peek())
            {
                switch(visitStack.pop())
                {
//                                  have to backtrack the opposite direction i previously went
                    case "N":   visited[nowR][nowC] = 'N';
                                mat[nowR][nowC] = 'O';
                                nowR++;
                                break;
                    case "NE":  visited[nowR][nowC] = 'N';
                                mat[nowR][nowC] = 'O';
                                nowR++;
                                nowC--;
                                break;
                    case "E":   visited[nowR][nowC] = 'N';
                                mat[nowR][nowC] = 'O';
                                nowC--;
                                break;
                    case "SE":  visited[nowR][nowC] = 'N';
                                mat[nowR][nowC] = 'O';
                                nowR--;
                                nowC--;
                                break;
                    case "S":   visited[nowR][nowC] = 'N';
                                mat[nowR][nowC] = 'O';
                                nowR--;
                                break;
                    case "SW":  visited[nowR][nowC] = 'N';
                                mat[nowR][nowC] = 'O';
                                nowR--;
                                nowC++;
                                break;
                    case "W":   visited[nowR][nowC] = 'N';
                                mat[nowR][nowC] = 'O';
                                nowC++;
                                break;
                    case "NW":  visited[nowR][nowC] = 'N';
                                mat[nowR][nowC] = 'O';
                                nowR++;
                                nowC++;
                                break;
                    default: System.out.println("SOMETHING WENT WRONG WITH BACKTRACKING");
                }
            }
//                                      blocks off dead ends
//                                      north
            if(nowR != 0 && visited[nowR-1][nowC] == 'N')
                visited[nowR-1][nowC] = 'Y';
//                                      northwest
            else if(nowR != 0 && nowC != 0 && visited[nowR-1][nowC-1] == 'N')
                visited[nowR-1][nowC-1] = 'Y';  
//                                      west
            else if(nowC != 0 && visited[nowR][nowC-1] == 'N')
                visited[nowR][nowC-1] = 'Y';
//                                      southwest
            else if(nowR != 11 && nowC != 0 && visited[nowR+1][nowC-1] == 'N')
                visited[nowR+1][nowC-1] = 'Y';
//                                      south
            else if(nowR != 11 && visited[nowR+1][nowC] == 'N')
                visited[nowR+1][nowC] = 'Y';
//                                      southeast
            else if(nowR != 11 && nowC != 11 && visited[nowR+1][nowC+1] == 'N')
                visited[nowR+1][nowC+1] = 'Y';
//                                      east
            else if(nowC != 11 && visited[nowR][nowC+1] == 'N')
                visited[nowR][nowC+1] = 'Y';
//                                      northeast
            else if(nowR != 0 && nowC != 11 && visited[nowR-1][nowC+1] == 'N')
                visited[nowR-1][nowC+1] = 'Y';

            splitx.pop();
            splity.pop();
        }
    }

    private void pause() 
    {   
        Scanner input = new Scanner(System.in); 
        String dummy;
        System.out.print("\nPress <Enter> to continue  ===>>  ");                       
        dummy = input.nextLine();                               
    }
}

这是标记通过之前的迷宫。

这是最后的迷宫。请注意,当标记应向西北移动以完成迷宫时,它会在下一个转弯处停留在同一位置,然后在转弯后向南移动。

【问题讨论】:

  • 你有没有试过调试它,单步调试代码看看发生了什么?
  • 是的,我追踪了好几次,不明白为什么它在最后一步没有向西北移动。我尝试在标记向西北移动时放置System.out.println 语句,并且它应该在最后一步移动时打印,但该位置仍然是“O”
  • @JonSnow,你做了什么?
  • 使用枚举而不是硬编码字符串来检测 N,S,W,E

标签: java algorithm maze


【解决方案1】:

所以,你在位置 (1,1) 并找到两个移动:NW 和 S。

if(numMoves() &gt; 1) 触发并将 both 推入堆栈。

if(numMoves() &gt; 0) 触发并应用 NW 移动,将你留在 (0,0)。

if(numMoves() == 0) 触发并开始回溯,因为 (0,0) 没有移动。

2 个问题:

  • 检测您找到出口的代码在哪里?
  • if(numMoves() == 0) 正在使用 new 坐标调用 numMoves()。将其更改为else

【讨论】:

  • 尝试回答+1
  • 哇,这让我觉得很傻,所需要的只是改变那些 if 语句的顺序。
  • 我仍在为退出条件/无解决方案编写代码,我无法继续处理这个错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多