【问题标题】:Recursive searching for a path in an Arraylist of rooms递归搜索房间数组列表中的路径
【发布时间】:2019-04-30 11:53:49
【问题描述】:

我正在尝试在有房间的地牢中找到一条路径,这些房间由门相连。 从一个房间到另一个房间总是只有一种方法。 有人可以帮我建造一条路径吗?我已经研究过路径搜索算法,但对于这个例子来说它们太复杂了,因为只有一个可能的路径,因此不需要给房间增加权重。

这是我正在使用的 Room 对象:

public Room(int id, Tile centerTile, ArrayList<Room> neighbours, ArrayList<Door> doors) 

  id = unique room id

  centerTile = center of the room.

  neighbours = list of neighbouring rooms

  doors = list of doors leading to the neighbouring rooms

房间被存储在一个称为探索房间的 Arraylist 中。

这是我目前得到的,但它不起作用。

package pathing;

import room.Room;
import room.RoomUtils;

import java.util.ArrayList;
import java.util.Iterator;

public class Path {

public static ArrayList<Room> findPath(Room start, Room target) {

    ArrayList<Room> frontier = new ArrayList<>();
    ArrayList<Node> visited = new ArrayList<>();
    ArrayList<Room> path = new ArrayList<>();

    frontier.add(RoomUtils.getRoomById(start.getId()));
    visited.add(new Node(RoomUtils.getRoomById(start.getId()), null));

    if (start.equals(target)) {
        path.add(RoomUtils.getRoomById(start.getId()));
    } else {
        Iterator frontierIterator = frontier.listIterator();
        while (frontierIterator.hasNext()) {
            Room front = (Room) frontierIterator.next();
            front = RoomUtils.getRoomById(front.getId());
            if (front.getNeighbours().size() > 0) {
                for (Room room : front.getNeighbours()) {
                    if (room.equals(target)) {
                        frontier.clear();
                        visited.add(new Node(RoomUtils.getRoomById(room.getId()), RoomUtils.getRoomById(front.getId())));
                        frontierIterator = frontier.listIterator();
                    } else {
                        frontier.remove(RoomUtils.getRoomById(front.getId()));
                        visited.add(new Node(RoomUtils.getRoomById(room.getId()), RoomUtils.getRoomById(front.getId())));
                        frontierIterator = frontier.listIterator();
                    }
                }
            }
        }

        Node startNode = visited.get(0);
        Node backtrackNode = getFrom(visited, target);

        if (backtrackNode != null && backtrackNode.getCurrent() != null) {
            path.add(backtrackNode.getCurrent());
        }

        while (backtrackNode != null && backtrackNode.getFrom() != null && !backtrackNode.equals(startNode)) {
            path.add(backtrackNode.getFrom());
            backtrackNode = getFrom(visited, backtrackNode.getFrom());
        }
    }
    return path;
}

private static Node getFrom(ArrayList<Node> nodes, Room from) {
    for (Node node : nodes) {
        if (node.getCurrent().equals(from)) {
            return node;
        }
    }
    return null;
}

private static class Node {
    private final Room current;
    private final Room from;

    public Node(Room current, Room from) {
        this.current = current;
        this.from = from;
    }

    public Room getCurrent() {
        return current;
    }

    public Room getFrom() {
        return from;
    }
}

}

【问题讨论】:

  • 我们需要您的 RoomDoor 课程代码。也欢迎您尝试解决此问题的代码。
  • 每一种可能的方式都是一条路径。如果您找到您正在搜索的路径,您的判断标准是什么?
  • @michalk 我用我目前得到的代码更新了这个问题。
  • @Conffusion 我需要一条从房间 A 到房间 B 的路径,但 A 和 B 之间的每个房间都可以有房间,所以它并不总是一条笔直的路径

标签: java arraylist path-finding


【解决方案1】:

您问题的标题包含“递归”,因此我寻找了递归解决方案。 对于每个房间,您可以说:如果我的相邻房间之一通向目标房间,那么我也是路径的一部分。如果您的邻居都没有通向目标,那么您也不是路径的一部分。

为了使其递归,我创建了一个从当前房间开始的新方法。 访问房间的整体路径和列表被定义为类变量,因此在所有调用 checkRoom 后它们仍然可用。

package pathing;

import java.util.ArrayList;
import java.util.List;

import room.Room;

public class Path {

    // list of all visited rooms to detect loops
    List<Room> visited = new ArrayList<>();
    // path from start to the current room
    List<Room> path = new ArrayList<>();
    Room target;
    boolean pathFound=false;

    public void checkRoom(Room current) {
        if(pathFound) {
            return;
        }
        if(visited.contains(current))
        {
            // we've been here before, we have detected a loop
            return;
        }
        path.add(current);
        visited.add(current);
        if (current.equals(target)) {
            pathFound=true;
        } else {
            // there are always neighbours (at least the room we come from
            for (Room room : current.getNeighbours()) {
                checkRoom(room);
                if(pathFound) {
                    return;
                }
            }
            // all neighbours processed without success
            path.remove(current);
        }
    }

    public static List<Room> findPath(Room start, Room target) {
        Path p=new Path();
        p.target=target;
        p.checkRoom(start);
        return p.path;
    }

    public static void main (String args[])
    {
        //      2 - 3 - 4
        //      |   |
        //      1 - 5
        //      |
        //      6 - 7 - 9
        //          |
        //          8
        Room room1=new Room(1,new ArrayList<Room>());
        Room room2=new Room(2,new ArrayList<Room>());
        Room room3=new Room(3,new ArrayList<Room>());
        Room room4=new Room(4,new ArrayList<Room>());
        Room room5=new Room(5,new ArrayList<Room>());
        Room room6=new Room(6,new ArrayList<Room>());
        Room room7=new Room(7,new ArrayList<Room>());
        Room room8=new Room(8,new ArrayList<Room>());
        Room room9=new Room(9,new ArrayList<Room>());
        room1.getNeighbours().add(room2);
        room1.getNeighbours().add(room5);
        room1.getNeighbours().add(room6);
        room2.getNeighbours().add(room1);
        room2.getNeighbours().add(room3);
        room3.getNeighbours().add(room2);
        room3.getNeighbours().add(room4);
        room4.getNeighbours().add(room3);
        room5.getNeighbours().add(room3);
        room5.getNeighbours().add(room1);
        room6.getNeighbours().add(room1);
        room6.getNeighbours().add(room7);
        room7.getNeighbours().add(room6);
        room7.getNeighbours().add(room9);
        room7.getNeighbours().add(room8);
        List<Room> path=Path.findPath(room1, room9);
        for(Room room:path)
            System.out.println("Room:"+room.getId());
        }
}

编辑:小优化:每个房间总是至少有一个邻居,即我们来自的房间,因此无需检查是否有邻居。当迷宫只有一个房间但在这种情况下 start 和 target 与之前已经测试过的相同时,可能会出现一种例外情况。

【讨论】:

  • 非常感谢,我回家后马上测试一下。
猜你喜欢
  • 2015-10-19
  • 1970-01-01
  • 2023-03-27
  • 2010-12-31
  • 1970-01-01
  • 2015-04-12
  • 1970-01-01
  • 1970-01-01
  • 2011-04-27
相关资源
最近更新 更多