1


迷路を解くためのバックトラッキングアルゴリズムを実装しようとしている部屋検索アルゴリズムを誰かが手伝ってくれるかどうかを探しています。すでに訪れた部屋を覚えておかなければならない場所で立ち往生しています。
迷路は部屋で構成されており、各部屋には北、東、南、西の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に入ると、アルゴリズムは「A4」から「B4」の部屋に東に1回だけ移動し、そこで無限にループし、スタックは部屋「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());
        }
    }
4

3 に答える 3

1

これを行うにはいくつかの方法があります。

1つは、トラッキングとバックトラッキングが進むにつれて、設定/設定解除した各部屋オブジェクトに「isVisited」ブールフラグを保持することです。これは、迷路をシングルスレッドで検索することしかできないことを意味します(これは重要な場合とそうでない場合があります)。

もう1つは、比較対象の訪問済みの部屋のリストを保持することです(ここでの利点は、新しい部屋をリストに「プッシュ」して、コールスタックを使用してこれを渡すと自動的にポップされるようにするのが比較的簡単なことです。リスト)。

isVisibleに対して検索ごとの部屋のハッシュテーブルを使用することもできます。これにより、リストの検索よりも(おそらく)高速なルックアップが可能になり、マルチスレッドが可能になります(「複数のスレッドが迷路を検索できる」のように、「もっと複数のスレッドが同じ検索に参加できます」)。

おそらく私が考えていないことがいくつかありますが、これら3つすべてを実装するのは非常に簡単です。

于 2011-03-21T15:37:11.440 に答える
0

迅速で高度に最適化されていないアプローチ:

訪問した部屋ごとに、可能な方向を保存し(たとえば、enum Directionとを作成Set<Direction>)、前の部屋からの方向だけでなく、元の方向も削除します。したがって、A4からB4に移動すると、A4からEASTが削除され、B4からWESTが削除されます。追跡する必要がある場合は、方向性のない部屋が見つかるまでスタックを巻き戻し(可能な方向のリストは空ではありません)、次の方向を試してください。この時点でスタックが空になった場合は、ターゲットルームを見つけることなくすべての可能性を試しました。

私が言ったように、これは非常に最適化されていませんが、動作するはずです。

于 2011-03-21T15:09:28.253 に答える
0

いくつかのコメント:

使用している関数の一部がコードに含まれていません。mazeクラスにはgetPaths()メソッドはありません。オンラインでコードを投稿する場合は、コードが簡単にコンパイルおよびテストできることを確認してください。あなたの場合、getPaths()は、探索される可能性のあるパスを格納しようとするある種のスタックを返すと推測する必要がありますが、実際に何をするのかを確認する方法はありません。

また、投稿する前にコードを単純化してみてください。あなたの迷路はかなり複雑であり、あなたが構築した迷路が写真のものと一致するかどうかを確認するために、それを描く必要があります。はるかに単純な迷路(おそらく2つまたは3つの部屋)で問題を再現できるかどうか試してください。また、単純化すると、問題がどこにあるかについて多くのヒントが得られることがよくあります。単純化している間、問題が突然消えるポイントがあります。これにより、実際のバグについて多くのことがわかります。

コードのどこが間違っているかについてのいくつかのアイデア:各方向で、soughtRoomをその方向の1つに設定します。soughtRoomは、現在検索している部屋だと思います。次に、その部屋をスタックにプッシュします。ただし、バックトラックの場合は、各ブランチに、以前の状態に戻すためのすべての情報を保存する必要があります。最初に現在の部屋を設定してからプッシュすると、前の状態の情報が失われます。逆に試して、何が起こるかを確認してください。

于 2011-03-21T15:19:01.217 に答える