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