Need a practical solution for creating pattern database(5-5-5) for 15-Puzzle

我是研究僧i 提交于 2019-12-01 13:20:21

It seems that you are moving the blocks to get all the permutations. Then, checking each permutation to be present in DB; if yes then updating the number of moves if necessary.

It would generate a tree. You are generating it in DFS style (by recursive calls). If you do it in BFS style, then you will always get the smallest number of moves. The duplicate states generated later would always have larger moves required. So, you don't have to compare it in the DB.

In the following examples, we will shift 6 and then we see the number of moves.

Priority: Left, Right, Up, Down (as you gave)

DFS Style

1 2 3 4    1 2 3 4
0 6 0 0    6 0 0 0
0 0 0 0    0 0 0 0
0 0 0 0    0 0 0 0
  (0)        (1)

Left most position reached. Now, check to move to it right (from where it came from). That position is already there in the DB, so carry on. Moreover, it can't even go up. So going down.

1 2 3 4    1 2 3 4
0 0 0 0    0 0 0 0
6 0 0 0    0 0 0 0
0 0 0 0    6 0 0 0
  (2)        (3)

Now, go right

           State-1    State-2    State-3
1 2 3 4    1 2 3 4    1 2 3 4    1 2 3 4
0 0 0 0    0 0 0 0    0 0 0 0    0 0 0 0
0 0 0 0    0 0 0 0    0 0 0 0    0 0 0 0
6 0 0 0    0 6 0 0    0 0 6 0    0 0 0 6
  (3)        (4)        (5)        (6)

Here you can see that, State-1 can be reached in just 2 (not 4) moves. But that will be revealed later and we'd have to update the DB. So, clearly its a waste of effort.

BFS Style

1 2 3 4    1 2 3 4
0 6 0 0    6 0 0 0
0 0 0 0    0 0 0 0
0 0 0 0    0 0 0 0
  (0)        (1)

Leftmost position reached, now go right

1 2 3 4    1 2 3 4
0 0 6 0    0 0 0 0
0 0 0 0    0 6 0 0
0 0 0 0    0 0 0 0
  (1)        (1)

You can consider this as 6 spreading all the sides equally. Here also, we would have duplicate states but those would have larger min moves required than the first entry of the DB.

You can use a simple queue to implement this.

Pseudocode:

Initialize no_of_moves by 0
enqueue(startingPosition)
insertIntoDB(startingPattern, no_of_moves)
while((currentPattern = dequeue()) is not null)
    if(currentPattern is not already traversed)
        insertIntoDB(currentPattern);
        list<Pattern> allPatterns = patterns which can be reached from currentPattern in just 1 move
        no_of_moves++
        enqueue(allPatterns, no_of_moves)
    end if
end while

There can be many ways to check if a state has already been traversed besides checking it from the DB. I was thinking of hashing but not able to come up.

You can maintain a boolean list mapped from the pattern string (say traversed["1234060000000000"] = true or false). I don't think storing 524160 entries in the main memory would create any problem.

The important part is the first line: java.lang.StackOverflowError. Recursion is stack-demanding.

Try doing only the algorithm part recursively, while putting the DB access in an extra method.

You should not call recursive. Doing so will put another address on the stack in your memory and if this happens too often you run out of memory, which happens in your case: StackOverflowError
Try to make a mothod that lets you input data once and then call that method in a loop until all data is saved in your database.

You are creating new PreparedStatement objects in each method call, which is here a recursive method. ex. ps=connection.prepareStatement(read_statement); and ps=connection.prepareStatement(insert_statement);. Create two seperate PreparedStatement object for both and move them out of the method and call ps.clearParameters(); at the start of the method (for both the objects). With that you have to deal with only two objects where as here you are creating thousands of objects. And then take care of closing resources when no longer needed. (ie., before FifteenPuzzle temp=new FifteenPuzzle(sub.puzzle.clone(),2,sub.g_n); )

I would guess that your problem has to do with resource mis-management rather than recursion itself. Also, you're trying to complicate your implementation more than you need to. I would suggest the following:

  • Create a method that would insert/update data to your database. Manage your resources over here. This need not be recursive.
  • From your recursive method, call this method to insert/update data to your database.

This is cleaner because you know that the database specific method would close all the resources before it gets back to your recursion. However, I would suggest that you should reuse your connection object while calling this method.

Also, make sure to close your statements, resultset or even your connection as part of finally block. One issue that I can see, for starters is this:

  • You're trying to close your preparedstatement in a try-block or a if-block. What if you don't hit the if-block and you hit an exception before you get a chance to close the resources? Your PreparedStatement and other resources will never be closed.
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!