简体   繁体   English

Java学习迷宫求解器

[英]Java learning maze solver

I have been working on some code to guide a 'robot' through a maze with multiple dead ends and 1 correct path to the goal like this: 我一直在研究一些代码,以引导“机器人”穿过迷宫,迷宫中有多个死角,并且有一条通往目标的正确路径,如下所示:

I have used a stack to record the direction the robot is facing the first time it reaches a square with 3 or 4 possible exits and if all adjacent squares have already been visited, used pop() to make the robot return from the direction it first came from (opposite to direction arrived). 我已经使用堆栈记录了机器人第一次到达具有3个或4个可能出口的正方形时所面对的方向,如果已经访问了所有相邻的正方形,请使用pop()使机器人从其第一个方向返回来自(与到达方向相反)。 At the end of the run the stack contains the direction arrived at all squares on the route to the target. 在运行结束时,堆栈包含到达目标路线上所有正方形的方向。 Following the opposite directions of the stack would take the robot from the goal back to the start point. 沿着堆栈的相反方向将机器人从目标带回到起点。 I am struggling to find out how to use this stack so that on the next run the robot will take the optimal path to reach the goal. 我正在努力寻找如何使用该堆栈的方法,以便在下一次运行时,机器人将采用最佳路径来达到目标​​。

Some of my code: 我的一些代码:

private int pollRun = 0; // Incremented after each pass
private int explorerMode; // 1 = explore, 0 = backtrack

public void exploreControl(IRobot robot) {

  byte exits = nonwallExits(robot);
  int direction;

  switch (exits) { //passes control to respective method
    case 1: direction = deadEnd(robot);   break;
    case 2: direction = corridor(robot); break;
    case 3: direction = junction(robot); break;
    default: direction = crossroads(robot); break;
  }

  if (exits == 1) {explorerMode = 0;}

  robot.face(direction); 

  pollRun++;

}

public void backtrackControl(IRobot robot) {

  byte exits = nonwallExits(robot);
  int direction = IRobot.CENTRE;

  switch (exits) { //passes control to respective method
    case 1: direction = deadEnd(robot);   break;
    case 2: direction = corridor(robot); break;
    default: direction = junction(robot); break; // do nothing
  }

  if (exits > 2) {
    if (passageExits(robot) > 0){
      exploreControl(robot);
      explorerMode = 1;
      pollRun++;
      return;
    } else {
      robot.setHeading(st.pop());
      robot.face(IRobot.BEHIND);
      pollRun++;
      return;
    }

  }

    robot.face(direction); 

  pollRun++;

}

public void optimal(IRobot robot) {

  byte exits = nonwallExits(robot);
  int direction;
  int heading;

  for(int i = 0; i < st.size(); i++) {
    stNew.push(st.pop());
  }

  if (exits < 3) {

    switch (exits) { //passes control to respective method
      case 1: direction = deadEnd(robot);   break;
      default: direction = corridor(robot); break;
    }

    robot.face(direction);

  } else {
    robot.setHeading(stNew.pop());
  }

}

public void controlRobot(IRobot robot) {

  if ((robot.getRuns() == 0) && (pollRun == 0)) {
    robotData = new RobotData(); //reset the data store
    explorerMode = 1;
  }

  if (robot.getRuns() = 1) {
    optimal(robot);
    return;
  }

  if (robot.getRuns() <= 0 && (nonwallExits(robot) >= 3)
      && (beenbeforeExits(robot) <= 0)) {
    st.push(robot.getHeading());
  }

  if (explorerMode == 1) {
    exploreControl(robot);
  } else {backtrackControl(robot);}

}

The optimal method shows my attempt at solving it, however all it does is cause the robot to head straight at every junction 最佳方法表明了我为解决该问题所做的尝试,但是它所做的只是使机器人在每个路口直行

For example this maze, 例如这个迷宫

在此处输入图片说明

Would leave me with the stack: EAST, EAST, SOUTH, SOUTH, EAST, SOUTH, SOUTH, EAST, EAST, SOUTH, SOUTH, EAST, EAST, EAST, SOUTH, EAST, SOUTH 会让我失望的是:东,东,南,南,东,南,南,东,东,东,南,南,东,东,东,东,南,东,南

It is true that this problem can be solved using a stack and an exhaustive search of the maze. 确实可以使用堆栈和对迷宫的详尽搜索来解决此问题。 There are more efficient methods but this one will work. 有更有效的方法,但是这种方法可以工作。

It's fairly difficult to know how your code is intended to function because you've only given a part of it. 知道代码的意图是相当困难的,因为您只给出了一部分。 However in general these sorts of exhaustive searches make heavy use of recursion - which is a very common use case for stacks. 但是,总的来说,这类穷举搜索大量使用了递归-这是堆栈的一种非常常见的用例。 I assume yours does the same though I can't see that code in the sample you've provided. 我假设您的代码也一样,尽管在您提供的示例中看不到该代码。

Here is some sample psuedo code for an exhaustive 'depth first' search. 这是一些示例性伪代码,用于详尽的“深度优先”搜索。 This code will end up with all possible solutions rather than just one. 该代码将以所有可能的解决方案而不仅仅是一种解决方案。 You should have a method that looks something like this in your code. 您应该有一个在代码中看起来像这样的方法。

void findPath(Stack currentPath) {
    if (currentPath.peek() == goal) {
        solutions.add(currentPath);
    } else {
        for (Position next: currentPath.openPositions()) {
            currentPath.push(next);
            findPath(currentPath);
            currentPath.pop();
        }
    }
}

The 'openPositions' method needs to explicitly stop any doubling back by looking at the current path - in other words it shouldn't return any positions that are already in the currentPath stack or you will end up with infinite recursion. 'openPositions'方法需要通过查看当前路径来显式停止任何加倍操作-换句话说,它不应返回currentPath堆栈中已经存在的任何位置,否则您将得到无限递归。

Because this finds all possible solutions you would then need to find the one with the shortest length as the optimal path. 由于找到了所有可能的解决方案,因此您将需要找到长度最短的解决方案作为最佳路径。 In your case it seems the mazes only have one path so you can exit as soon as you have found a path. 在您的情况下,迷宫似乎只有一条路径,因此一旦找到路径就可以退出。

A final note: you've tried to mix the task of setting the direction the robot needs to turn with the task of finding a path through the maze. 最后一点:您已经尝试将设置机器人需要转向的任务与寻找穿过迷宫的路径的任务混合在一起。 I recommend keeping these separate. 我建议将它们分开。 Use the algorithm above to find a path (or a more efficient one such as a*) and then once you have paths walk through it to determine the list of directions for the robot. 使用上面的算法查找路径(或更有效的路径,例如a *),然后一旦路径通过,就可以确定机器人的方向列表。

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

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