2011-03-21 87 views
1

我尋求有人可以幫助我與我的房間搜索算法
我試圖實現一個回溯算法解決迷宮。我被困在應該記住我已經去過的房間的地方。
迷宮由房間組成,每個房間都有四面 - 北面,東面,南面和西面。每個房間都連接到下一個房間,通過將門打開到所需的一側,即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; 
    } 
} 

這裏是我的主類 公共類主要{

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)方法,其中f指明通往房間的路線。 如果我進入房間D4,那麼我的算法只從「A4」向東移動到「B4」房間,在那裏它只是無限地循環,而棧僅隨着房間「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()); 
     } 
    } 
+0

添加您訪問該房間時設置爲true的「visited」布爾標誌。在您的回溯過程中,您只能穿過尚未嘗試過的房間。 – 2011-03-21 14:41:31

+0

嗨,謝謝。我這樣做,那是最簡單的方法。 – Skyzer 2011-03-27 12:52:12

回答

1

有幾種方法可以做到這一點。

一個會保持每個房間對象的「isVisited」布爾標誌,您設置/取消設置作爲您的跟蹤和回溯收益。這意味着你只能單線搜索你的迷宮(這可能不重要)。

另一種方法是保留您比較過的訪問過的房間的列表(這裏的優點是,只需將新房間「推」到列表中並使其自動彈出(如果您使用呼叫)堆棧來傳遞這個列表)。

你也可以使用每個搜索哈希表的空間到isVisible,這允許(可能)更快的查找比搜索列表,允許多線程(如「多個線程可以搜索迷宮」 ,而不是「多個線程可以參與相同的搜索」)。

也可能有一些我沒有想到的事情,但所有這三個應該是非常直接的實施。

+0

謝謝。這是我的錯誤,我從我的存儲庫複製了比我的筆記本電腦更老版本的代碼。現在我有了getPaths()方法的迷宮類,它確實返回一堆Room對象。 明天我會尋找我的回溯算法 – Skyzer 2011-03-21 18:33:22

0

快速和高度沒有優化的方法:

對於每個參觀室,存儲可能方向(做出enum DirectionSet<Direction>爲例如),並刪除你來自的一個以及你從前一個房間的方向。因此,從A4移動到B4,您將從A4移除EAST並從B4移除WEST。如果你必須追溯,只需展開堆棧,直到找到一個未訪問方向的房間(可能方向列表不爲空)並嘗試下一個方向。如果此時堆棧變空,則嘗試所有可能性而不查找目標房間。

正如我所說這是高度未優化,但它應該工作。

0

一些意見:

您的代碼缺少您正在使用的一些功能。迷宮課中沒有getPaths()方法。如果您在線發佈代碼,請嘗試確保它易於編譯和測試。在你的情況下,我將不得不猜測,getPaths()返回某種堆棧,你試圖存儲可能的路徑進行探索,但沒有辦法確定,它實際上做了什麼。

也嘗試在發佈之前簡化代碼。你的迷宮比較複雜,你必須畫出它,看看你製作的迷宮是否與圖片上的一致。試試如果你能用更簡單的迷宮(2或3個房間)重現問題。簡化通常會給你許多提示問題的可能性。當你簡化時,問題會突然消失。這告訴你很多關於實際的錯誤。

關於您的代碼可能出錯的一些想法: 在每個方向上,您將seekRoom設置爲該方向上的一個。我假設搜索房間是您搜索目前所在的房間。然後你把那個房間推到棧上。但是,對於回溯,您需要在每個分支中存儲所有將您帶回以前狀態的信息。如果您首先設置當前房間然後按下它,則以前狀態的信息將丟失。反過來試一試,看看會發生什麼。

+0

謝謝。我從不是最新版本的存儲庫複製了迷宮類。無論如何現在getPaths()方法在我的代碼在這裏。 – Skyzer 2011-03-21 18:32:12