Проблема с решением лабиринта по возврату с настройкой посещенных комнат - PullRequest
1 голос
/ 21 марта 2011

Я ищу, может ли кто-нибудь помочь мне с алгоритмом поиска в моей комнате
Я пытаюсь реализовать алгоритм обратного отслеживания для решения лабиринта.Я застрял в том месте, где я должен запомнить комнаты, которые я уже посетил.
Лабиринт состоит из комнат, каждая комната имеет 4 стороны - север, восток, юг и запад.Каждая комната связана с соседней комнатой, открывая дверь на желаемую сторону, то есть room1.createNorth(roomName), которая создает новую комнату на севере, а новая комната имеет южную дверь для связи с первой, как вы можете видеть в моем классе.

Вот мой класс порубленной комнаты, который представляет каждую комнату в лабиринте.Я удалил направления на юг, запад и восток, которые идентичны моим методам, касающимся северной стороны.

public class Room {

    private String name;
    private Room north;
    private Room east;
    private Room west;
    private Room south;
    private boolean isExit = false;
    private Maze maze;

    /**
     * @return name room
     */
    public String getName() {
        return this.name;
    }

    /**
     * Sets room name
     * 
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Gets northern room if any
     * 
     * @return pointer to northern room if any, otherwise <code>null</code>
     */
    public Room getNorth() {
        return this.north;
    }

    /**
     * Sets the door to the next room to the north in that room and in the other
     * room sets southern door as connecting back to that room
     * 
     * @param otherRoom
     */
    public void setNorth(Room otherRoom) {
        this.north = otherRoom;
        otherRoom.south = this;
    }

    /**
     * creates a new room to the north and connects back to this room
     * 
     * @param name
     *            of the room
     * @return created room
     */
    public Room createNorth(String name) {
        Room otherRoom = null;

        // create new room in that direction ONLY if there is no room yet
        if (this.getNorth() == null) { // get northern direction, if it's null,
                                        // then it's okay to create there
            otherRoom = new Room(); // create!
            this.setNorth(otherRoom); // set the door
            otherRoom.setName(name); // set the name

        } else { // there is a room in that direction, so don't create a new
                    // room and drop a warning
            System.out.println("There is already a room in northern direction");
        }

        return otherRoom;
    }

    /**
     * Asdf
     * 
     * @return maze
     */
    public Maze getMaze() {
        return this.maze;
    }

    /**
     * Set maze
     * 
     * @param maze
     */
    public void setMaze(Maze maze) {
        this.maze = maze;
    }

    /**
     * @param roomName path to this room must be found
     */
    public void findPathTo(String roomName) {
        Room soughtRoom = this.getMaze().getEntry();

        while (!(soughtRoom.getName().equalsIgnoreCase(roomName))) {

//          here should be also a method such as setRoomAsVisited()

            if (this.getWest() != null) {
                soughtRoom = this.getWest();
                this.getMaze().getPaths().push(soughtRoom);
            }
            else if (this.getNorth() != null) {
                soughtRoom = this.getNorth();
                this.getMaze().getPaths().push(soughtRoom);
            }
            else if (this.getEast() != null) {
                soughtRoom = this.getEast();
                this.getMaze().getPaths().push(soughtRoom);
            }
            else if (this.getSouth() != null) {
                soughtRoom = this.getSouth();
                this.getMaze().getPaths().push(soughtRoom);
            }
            else {
                if (this.getMaze().getPaths().isEmpty()) {
                    break; // no more path for backtracking, exit (no solution found)
                }
                // dead end, go back!
                soughtRoom = this.getMaze().getPaths().pop();
            }
            System.out.println(this.getMaze().getPaths().toString());
        }


    }

    @Override
    public String toString() {
        return "Room name is " + this.getName();
    }
}

Лабиринт выглядит так: http://i.stack.imgur.com/2KePs.jpg где S - начальная точка

Мой класс Лабиринта

public class Maze {

    Room room;

/**
 * helper collection path stack for findPathTo() method
 */
private Stack<Room> paths = new Stack<Room>();

/**
 * @return path for exit
 */
public Stack<Room> getPaths() {
    return this.paths;
}

    /**
     * Singleton method for first room in the maze which is entry room
     * 
     * @return room if no room is created then creates new, otherwise returns
     *         already created room
     */
    public Room getEntry() {
        if (this.room == null) {
            this.room = new Room();
            return this.room;
        }
        return this.room;
    }
}

Вот мой основной класс общего класса Main {

    public static void main(String[] args) {

        Maze maze = new Maze();
        maze.getEntry().setName("A4"); // set first room's name A4
        // labyrinth creation
        maze.getEntry().createEast("B4").createNorth("B3").createWest("A3");
        maze.getEntry().getEast().getNorth().createNorth("B2").createWest("A2")
                .createNorth("A1");
        maze.getEntry().getEast().getNorth().getNorth().createNorth("B1");
        maze.getEntry().getEast().getNorth().getNorth().createEast("C2")
                .createNorth("C1").createEast("D1");
        maze.getEntry().getEast().createEast("C4").createEast("D4");
        maze.getEntry().getEast().getEast().createNorth("C3").createEast("D3")
                .createNorth("D2").setExit(true);

        System.out.println("=====Test findPathTo method======");
        maze.getEntry().setMaze(maze); // set maze instance to our entrance room
        maze.getEntry().findPathTo("B4");

        System.out.println("=====End of testing findPathTo method======");

    }

}

Проблема в моем методе findPathTo(roomName), который находит маршрут к комнате.Если я вхожу в комнату D4, то мой алгоритм перемещается только один раз на восток в комнату «B4» из «A4», и там он просто зацикливается бесконечно, а стек только растет с комнатой «B4».Почему он не перемещается, например, в следующую комнату "B3" или "C4"?

РЕДАКТИРОВАТЬ: вот рабочий код

public void findPathTo(String roomName) {

        Room soughtRoom = this.getMaze().getEntry();

        while (!(soughtRoom.getName().equalsIgnoreCase(roomName))) {

            if (soughtRoom.getWest() != null && soughtRoom.getWest().isVisited != true) {
                this.getMaze().getPaths().push(soughtRoom);
                soughtRoom = soughtRoom.getWest();
                soughtRoom.isVisited = true;

            }
            else if (soughtRoom.getNorth() != null && soughtRoom.getNorth().isVisited != true) {
                this.getMaze().getPaths().push(soughtRoom);
                soughtRoom = soughtRoom.getNorth();
                soughtRoom.isVisited = true;

            }
            else if (soughtRoom.getEast() != null && soughtRoom.getEast().isVisited != true) {
                this.getMaze().getPaths().push(soughtRoom);
                soughtRoom = soughtRoom.getEast();
                soughtRoom.isVisited = true;

            }
            else if (soughtRoom.getSouth() != null && soughtRoom.getSouth().isVisited != true) {
                this.getMaze().getPaths().push(soughtRoom);
                soughtRoom = soughtRoom.getSouth();
                soughtRoom.isVisited = true;

            }
            else {
                if (this.getMaze().getPaths().isEmpty()) {
                    System.out.println("No solutions found :(");
                    break; // no more path for backtracking, exit (no solution found)
                }
                // dead end, go back!
                soughtRoom = this.getMaze().getPaths().pop();
            }
            System.out.println("Path rooms: " + this.getMaze().getPaths().toString());
        }
    }

Ответы [ 3 ]

1 голос
/ 21 марта 2011

Есть несколько способов сделать это.

Можно было бы сохранить логический флаг «isVisited» в каждом объекте комнаты, который вы устанавливаете / отменяете в процессе отслеживания и возврата.Это означает, что вы можете только один поток поиска в вашем лабиринте (это может или не может иметь значение).

Другой вариант - сохранить список посещенных комнат, с которыми вы сравниваете (преимущество здесь в том, что он должен бытьсравнительно легко просто «вставить» новую комнату в список и автоматически вытолкнуть ее, если вы используете стек вызовов для передачи этого списка).

Вы также можете использовать хеш-таблицу пространства для поиска для isVisible, это позволяет (возможно) быстрее выполнять поиск, чем поиск по списку, допускает многопоточность (как в случае, если несколько потоков могут искать влабиринт ", не" более одного потока могут участвовать в одном и том же поиске ").

Возможно, есть еще несколько вещей, о которых я не задумывался, но все три из них должны быть довольно простыми для реализации.

0 голосов
/ 21 марта 2011

Некоторые комментарии:

В вашем коде отсутствуют некоторые функции, которые вы используете.В вашем классе лабиринта нет метода getPaths ().Если вы публикуете код в Интернете, постарайтесь убедиться, что он легко компилируется и тестируется.В вашем случае я должен был бы предположить, что getPaths () возвращает какой-то стек, в котором вы пытаетесь сохранить возможные пути, которые нужно исследовать, но нет никакого способа быть уверенным, что он на самом деле делает.

Также попробуйте упростить код перед публикацией.Ваш лабиринт довольно сложен, и нужно было бы нарисовать его, чтобы увидеть, соответствует ли ваш построенный лабиринт тому, что на картинке.Попробуйте, если вы можете воспроизвести проблему с гораздо более простым лабиринтом (возможно, 2 или 3 комнаты).Кроме того, упрощение часто дает вам много подсказок относительно того, где может быть проблема.Пока вы упрощаете, будет момент, когда проблема внезапно исчезнет.Это многое говорит вам о фактической ошибке.

Некоторые идеи о том, что может быть не так с вашим кодом: На каждом направлении вы устанавливаете seekRoom на единицу в этом направлении.Я предполагаю, что seekRoom - это комната, в которой вы сейчас находитесь.Затем вы помещаете эту комнату в стек.Однако для возврата вам нужно хранить в каждом филиале всю информацию, которая возвращает вас в предыдущее состояние.Если сначала установить текущую комнату, а затем нажать ее, информация из предыдущего состояния будет потеряна.Попробуйте наоборот и посмотрите, что получится.

0 голосов
/ 21 марта 2011

Быстрый и крайне неоптимизированный подход:

Для каждой посещенной комнаты сохраните возможные направления (например, укажите enum Direction и Set<Direction>) и удалите то, которое выи направление, которое вы выбрали из предыдущей комнаты.Таким образом, переходя с A4 на B4, вы удаляете EAST с A4 и WEST с B4.Если вам нужно отследить, просто размотайте стопку, пока не найдете комнату с невидимым направлением (список возможных направлений не пуст) и попробуйте следующее.Если в этот момент стек становится пустым, вы перепробовали все возможности, не найдя целевой комнаты.

Как я уже сказал, это крайне неоптимизировано, но оно должно работать.

...