拼图解算器方法

时间:2013-05-07 20:38:35

标签: java algorithm puzzle

好的,所以我正在编写一个3 x 3跳汰机益智游戏,我坚持使用解决方法。

public Piece[][] solve(int r, int c) {
    if (isSolved())
        return board;
    board[r][c] = null;
    for (Piece p : pieces) {
        if (tryInsert(p, r, c)) {
            pieces.remove(p);
            break;
        }
    }
    if (getPieceAt(r, c) != null)
        return solve(nextLoc(r, c).x, nextLoc(r, c).y);
    else {
        pieces.add(getPieceAt(prevLoc(r, c).x, prevLoc(r, c).y));
        return solve(prevLoc(r, c).x, prevLoc(r, c).y);
    }
}

我知道我没有提供有关这个谜题的更多信息,但我的算法无论具体细节如何都应该有效。我已经测试了所有辅助方法,片段是所有未使用的片段的列表,tryInsert尝试以所有可能的方向插入片段,如果片段可以插入,它将是。不幸的是,当我测试它时,我得到StackOverflow Error。

3 个答案:

答案 0 :(得分:3)

您的DFS样式解算法算法永远不会将Piece对象重新添加到pieces变量中。这不是合理的,很容易导致无限递归。

例如,假设您有一个简单的两件式拼图,一个2x1网格,其中唯一有效的拼图排列是[2,1]。这就是你的算法所做的:

1)将第1件放入插槽1中   2)它适合!删除这件,现在件= {2}。解决nextLoc()问题      3)现在尝试将第2件装入插槽2中......不起作用      4)解决prevLoc()
        5)将件2放入槽1中         6)它适合!删除这件,件现在是空的。解决nextLoc()问题            7)没有尝试,所以我们失败了。解决prevLoc()
              8)没有尝试的东西,所以我们失败了。解决prevLoc()
                9)没有尝试,所以我们失败了。解决prevLoc()
                   无限重复广告...

正如评论者提到的那样,这可能只是问题的一部分。您的帖子中缺少很多关键代码,也可能是错误。

答案 1 :(得分:2)

我认为你需要以不同的方式构建递归。我也不确定从列表的不同位置添加和删除件是安全的;就像我宁愿避免在递归中分配一样,创建列表副本或扫描电路板可能是最安全的 到目前为止,同一件事件的例子,以避免重复使用。

public Piece[][] solve(int r, int c, List<Piece> piecesLeft) {
    // Note that this check is equivalent to
    // 'have r and c gone past the last square on the board?'
    // or 'are there no pieces left?'
    if (isSolved())
        return board;

    // Try each remaining piece in this square
    for (Piece p : piecesLeft) {
        // in each rotation
        for(int orientation = 0; orientation < 4; ++orientation) {
            if (tryInsert(p, r, c, orientation)) {
                // It fits: recurse to try the next square
                // Create the new list of pieces left
                List<Piece> piecesLeft2 = new ArrayList<Piece>(piecesLeft);
                piecesLeft2.remove(p);
                // (can stop here and return success if piecesLeft2 is empty)
                // Find the next point
                Point next = nextLoc(r, c);
                // (could also stop here if this is past end of board)

                // Recurse to try next square
                Piece[][] solution = solve(next.x, next.y, piecesLeft2);
                if (solution != null) {
                    // This sequence worked - success!
                    return solution;
                }
            }
        }
    }

    // no solution with this piece
    return null;
}

答案 2 :(得分:1)

具有递归函数的

StackOverflowError意味着您要么缺少有效的递归停止条件,要么尝试解决太大的问题,而应该尝试使用迭代算法。包含9件的拼图不是太大问题所以首先必须是这样的。

结束递归的条件是完成董事会。你只是试图在for循环中插入一个片段,所以问题可能是tryInsert()方法没有插入片段或者它没有被调用。由于您确定此方法正常,我建议您从

中删除break;
if (p.equals(prev[r][c])) 
{
    System.out.println("Hello");
    break;
}

因为它是唯一可能阻止插入该部件的东西。我仍然不确定我是否理解prev角色。