2016-09-14 11 views
1

私は、JavaでRush Hourソルバーを書いています。これは設定hereを解くことを目的としています。しかし、そのページの最も単純なパズルであっても、ソルバーは無限に実行され、最終的にはメモリ不足になります。私は各ボード状態から発生する可能性のあるすべての動き(自分自身を繰り返さないことを保証するためにHashSetを使用して)、各状態をそこに持っている動きにマッピングするための幅広い最初の検索を使用しているので、後でそれらを通して。ラッシュアブソーバーが無限ループに陥っていても意味がありません

私は自分自身を思いついたより些細なパズルで試してみましたが、それを解決することはできますが(ゆっくりですが)。

私はこの問題にどのように近づいているのか、まったく間違っていますか?関連するクラスのコードも必要に応じて置くことができますが、かなり徹底的にテストしましたが、問題は次のコードのどこかにあると確信しています。私の腸は、それがハッシュセットと関係していると私は自分自身を繰り返さないことを確認している(キューのサイズは定期的に十万に達するので)と言います。

提案がありますか?ここでは、要求されたよう

// Start at the original configuration 
    queue.add(originalBoard); 

    // We add this to our map, but getting here did not require a move, so we use 
    // a dummy move as a placeholder move 
    previous.put(originalBoard, new Move(-1, -1, "up")); 

    // Breadth first search through all possible configurations 
    while(!queue.isEmpty()) { 
     // Dequeue next board and make sure it is unique 
     Board currentBoard = queue.poll(); 
     if (currentBoard == null)   continue; 
     if (seen.contains(currentBoard)) continue; 
     seen.add(currentBoard); 

     // Check if we've won 
     if (currentBoard.hasWon()) { 
      System.out.println("We won!"); 
      currentBoard.renderBoard(); 
      return solved(currentBoard); 
     } 

     // Get a list of all possible moves for the current board state 
     ArrayList<Move> possibleMoves = currentBoard.allPossibleMoves(); 

     // Check if one of these moves is the winning move 
     for (Move move : possibleMoves) { 
      Board newBoard = move.execute(currentBoard); 

      // We don't need to enqueue boards we've already seen 
      if (seen.contains(newBoard)) continue; 
      queue.add(newBoard); 

      // Map this board to the move that got it there 
      previous.put(newBoard, move); 
     } 
    } 

は(彼らはクラスレベルの変数です)HashSetの私のinitialisationsです:

private static HashSet<Board> seen = new HashSet<>(); 

そして、私のBoard.equals()メソッド:

@Override 
public boolean equals (Object b) { 
    Board otherBoard = (Board) b; 
    boolean equal = false; 
    if (this.M == otherBoard.getM() && this.N == otherBoard.getN()) { 
     equal = true; 

     // Each board has an ArrayList of Car objects, and boards are only 
     // considered equal if they contain the exact same cars 
     for (Car car : this.cars) { 
      if (otherBoard.getCar(car.getPosition()) == null) { 
       equal = false; 
      } 
     } 
    } 
    System.out.println(equal); 
    return equal; 
} 
+0

. =空きスペース * =一部 'queue'と' seen'の初期化を追加してください。 、 'Board.hashCode()'と 'Board.equals()'の実装です。それらは偶発的な非効率のための私の一番の容疑者です。 – Douglas

+0

BoardHashCode()の実装はありませんが、 – wimkeir

+0

ダグラスが書いたものか、私たちが見ることができないメソッドは予期せぬことがあります - move.execute()/ currentBoard .allPossibleMoves()/ currentBoard.hasWon()。ここでマップを使用しているので、hashCodeを実装する必要があります。 Moveクラスでも同様に、equalsとhashcodeの両方を行います。 – Shadov

答えて

1

ますデフォルトのObjectベースのバージョンをオーバーライドするには、Board.hashCode()を実装する必要があります。これにより、コントラクトごとに等しい2つの等しいBoardオブジェクトが同じハッシュコードを持つようになります。あなたがしない場合、あなたのseenセットは実際にあなたのために何かを達成するわけではありません。

別の問題では、ボードの車をチェックしている方法が完全ではないと思われます。それは、私はそれがないと思うように動作している場合、それは、これら二つのボードが等しくなるように検討する:車

...... 
.**.*. 
....*. 
.*.... 
.*.**. 
...... 

...... 
.*..** 
.*.... 
...... 
.**.*. 
....*. 
+0

私はCarオブジェクトとBoardオブジェクトの両方に対してhashCode関数を実装しました。助けてくれてありがとう:) – wimkeir

+0

Car.equals()メソッドで比較されるX座標とY座標が車にあるので、そうは思わないでしょうか? – wimkeir

+0

@WimKeir 'Board.equals()'が呼び出されない 'Car.equals()'メソッド? 'getCar()'がそれをチェックすることによって動作しない限り。とにかく、私のサンプルボードの違いはオリエンテーションです。 'Car.equals()'もそれをチェックしますか?また、まだ 'queue'の初期化を表示していません。 – Douglas

関連する問題