Java 一个*(星型)滑块式拼图有时会进入无限循环

Java 一个*(星型)滑块式拼图有时会进入无限循环,java,infinite-loop,a-star,Java,Infinite Loop,A Star,我不久前在Java中实现了A*算法,有时它会用比最初洗牌更多的步骤来解决我的滑块难题,有时甚至会进入无限循环。我注意到,当我增加洗牌因子时,它通常会进入无限循环。8字谜并不存在这个问题,但从4x3或15字谜开始,几乎1/3以上的游戏都失败了 为了清楚起见,我使用了一个洗牌功能来保证生成的游戏是可解的,并且每次应用洗牌动作时都会删除“后退”动作,以实现更好的随机化(尽管有时仍然会形成完整的圆圈) 使用的启发式函数是曼哈顿距离 我好像在什么地方搞砸了。有人能帮我理解为什么会发生这种情况吗 声明: @

我不久前在Java中实现了A*算法,有时它会用比最初洗牌更多的步骤来解决我的滑块难题,有时甚至会进入无限循环。我注意到,当我增加洗牌因子时,它通常会进入无限循环。8字谜并不存在这个问题,但从4x3或15字谜开始,几乎1/3以上的游戏都失败了

为了清楚起见,我使用了一个洗牌功能来保证生成的游戏是可解的,并且每次应用洗牌动作时都会删除“后退”动作,以实现更好的随机化(尽管有时仍然会形成完整的圆圈)

使用的启发式函数是曼哈顿距离

我好像在什么地方搞砸了。有人能帮我理解为什么会发生这种情况吗

声明:

@EqualsAndHashCode(of="board")
public class State{
    @Getter @Setter private int[] board;
    @Getter @Setter private int g;
    @Getter @Setter private int h;
    @Getter @Setter private State parent;

    public State(int[] board){
        this.board = board;
    }

    public int getF(){
        return this.g + this.h;
    }
}
游戏:

公共抽象类游戏{
@Getter@Setter private int dimX;
@Getter@Setter private int dimY;
@Getter@Setter private int[]门板;
@Getter@Setter私有int交换;
public int[]generateRandomGame(){
int[]board=Utils.cloneBoard(守门板);
列出可能的动作;
整数nextMove=null;
for(int i=0;i=findState(successorState,openedStates).getG()){
继续;
}
successorState.setG(g);
setH(calculateH(successorState));
successorState.setParent(当前状态);
}
}
返回解状态;
}
私有状态getStateWithMinF(){
状态bestState=null;
int minF=Integer.MAX_值;
for(状态:openedStates){
if(minF>state.getF()){
minF=state.getF();
最佳状态=状态;
}
}
返回最佳状态;
}
私人整数计算器(州){
int h=0;
int dimX=game.getDimX();
int length=state.getBoard().length;
int[]board=state.getBoard();
int[]hBoard=新的int[长度];

for(int i=0;a-star中的iInfinite循环表示您没有正确地将节点添加到闭合列表中。假设这是Java,我将仔细检查您是否实现了
equals()
,以便将具有不同父节点/状态的节点/状态视为相等。默认情况下,在计算
equals()时会比较对象中的所有字段
,这有时会导致问题。Equals已经由@EqualsAndHashCode(of=“board”)实现,这意味着它只计算board字段,这是int数组的深度散列,而忽略其余的State类字段。
public abstract class Game{

    @Getter @Setter private int dimX;
    @Getter @Setter private int dimY;
    @Getter @Setter private int[] goalBoard;
    @Getter @Setter private int swaps;

    public int[] generateRandomGame(){
        int[] board = Utils.cloneBoard(goalBoard);
        List<Integer> possibleMoves;
        Integer nextMove = null;
        for(int i=0; i<swaps; i++){
            possibleMoves = Utils.getPossibleMoves(board, dimX, dimY);
            if(nextMove != null){
                switch(EnumMoveDirection.getById(nextMove.intValue())){
                case UP:
                    possibleMoves.remove(EnumMoveDirection.DOWN.getIntegerId());
                    break;
                case RIGHT:
                    possibleMoves.remove(EnumMoveDirection.LEFT.getIntegerId());
                    break;
                case DOWN:
                    possibleMoves.remove(EnumMoveDirection.UP.getIntegerId());
                    break;
                case LEFT:
                    possibleMoves.remove(EnumMoveDirection.RIGHT.getIntegerId());
                    break;
                }
                possibleMoves.remove(nextMove);
            }
            nextMove = possibleMoves.get(new Random().nextInt(possibleMoves.size()));

            int startIndex = Utils.getStartPositionIndex(board);
            int tmp;
            switch(EnumMoveDirection.getById(nextMove.intValue())){
            case UP:
                tmp = board[startIndex];
                board[startIndex] = board[startIndex-dimX];
                board[startIndex-dimX] = tmp;
                break;
            case RIGHT:
                tmp = board[startIndex];
                board[startIndex] = board[startIndex+1];
                board[startIndex+1] = tmp;
                break;
            case DOWN:
                tmp = board[startIndex];
                board[startIndex] = board[startIndex+dimX];
                board[startIndex+dimX] = tmp;
                break;
            case LEFT:
                tmp = board[startIndex];
                board[startIndex] = board[startIndex-1];
                board[startIndex-1] = tmp;
                break;
            }
        }
        return board;
    }
}
public class AStar {
    private Game game;
    private List<State> openedStates = new ArrayList<>();
    private List<State> closedStates = new ArrayList<>();

    public AStar(Game game){
        this.game = game;
    }

    public List<State> solve(State startState){
        List<State> solutionStates = new LinkedList<>();
        State goalState = new State(game.getGoalBoard());

        startState.setG(0);
        startState.setH(calculateH(startState));
        openedStates.add(startState);

        State currentState = null;
        int g;
        while(!openedStates.isEmpty()){
            currentState = getStateWithMinF();

            if(currentState.equals(goalState)){
                State state = currentState;
                solutionStates.add(state);
                while(state.getParent() != null){
                    state = state.getParent();
                    solutionStates.add(cloneState(state));
                }
                break;
            }

            openedStates.remove(currentState);
            closedStates.add(currentState);

            for(State successorState : generateSuccessors(currentState)){
                if(closedStates.contains(successorState)){
                    continue;
                }

                g = currentState.getG()+1;

                if(!openedStates.contains(successorState)){
                    openedStates.add(successorState);
                }else if(g >= findState(successorState, openedStates).getG()){
                    continue;
                }

                successorState.setG(g);
                successorState.setH(calculateH(successorState));
                successorState.setParent(currentState);
            }
        }
        return solutionStates;
    }

    private State getStateWithMinF(){
        State bestState = null;
        int minF = Integer.MAX_VALUE;
        for(State state : openedStates){
            if(minF > state.getF()){
                minF = state.getF();
                bestState = state;
            }
        }
        return bestState;
    }

    private int calculateH(State state){
        int h = 0;
        int dimX = game.getDimX();
        int length = state.getBoard().length;
        int[] board = state.getBoard();
        int[] hBoard = new int[length];
        for(int i=0; i<length; i++){
            hBoard[i] = Math.abs(i/dimX-getGoalPosition(board[i])/dimX) + Math.abs(i%dimX-getGoalPosition(board[i])%dimX);
            h += hBoard[i];
        }
        return h;
    }

    private int getGoalPosition(int num){
        int[] goalBoard = game.getGoalBoard();
        int length = goalBoard.length;
        for(int i=0; i<length; i++){
            if(goalBoard[i] == num){
                return i;
            }
        }
        return 0;
    }

    private List<State> generateSuccessors(State state){
        List<State> successors = new ArrayList<>(4);
        int startIndex = Utils.getStartPositionIndex(state.getBoard());
        int tmp, dimX = game.getDimX();
        int[] board;
        for(Integer possibleMove : Utils.getPossibleMoves(state.getBoard(), dimX, game.getDimY())){
            board = Utils.cloneBoard(state.getBoard());
            switch(EnumMoveDirection.getById(possibleMove.intValue())){
            case UP:
                tmp = board[startIndex];
                board[startIndex] = board[startIndex-dimX];
                board[startIndex-dimX] = tmp;
                break;
            case RIGHT:
                tmp = board[startIndex];
                board[startIndex] = board[startIndex+1];
                board[startIndex+1] = tmp;
                break;
            case DOWN:
                tmp = board[startIndex];
                board[startIndex] = board[startIndex+dimX];
                board[startIndex+dimX] = tmp;
                break;
            case LEFT:
                tmp = board[startIndex];
                board[startIndex] = board[startIndex-1];
                board[startIndex-1] = tmp;
                break;
            }
            successors.add(new State(board));
        }
        return successors;
    }

    private static State findState(State state, List<State> states){
        for(State item : states){
            if(item.equals(state)){
                return item;
            }
        }
        return null;
    }

    private static State cloneState(State state){
        State clone = new State(Utils.cloneBoard(state.getBoard()));
        clone.setG(state.getG());
        clone.setH(state.getH());
        return clone;
    }
}