Program: 17195
Project: 17195
Buggy source:
public static void main(String[] args){
  final Puzzle initialState=new Puzzle(new int[]{0,8,7,6,5,4,3,2,1});
  final Puzzle goalState=new Puzzle(new int[]{0,1,2,3,4,5,6,7,8});
  ActionFunction<PuzzleMove,Puzzle> af=new ActionFunction<PuzzleMove,Puzzle>(){
    @Override public Iterable<PuzzleMove> actionsFor(    Puzzle state){
      LinkedList<PuzzleMove> movements=new LinkedList<PuzzleMove>();
      Point gap=state.getTile(0);
      int boardSize=state.getMatrixBoard().length;
      if (gap.getX() > 0 && gap.getX() < boardSize) {
        movements.add(PuzzleMove.UP);
      }
      if (gap.getX() >= 0 && gap.getX() < boardSize - 1) {
        movements.add(PuzzleMove.DOWN);
      }
      if (gap.getY() >= 0 && gap.getY() < boardSize - 1) {
        movements.add(PuzzleMove.RIGHT);
      }
      if (gap.getY() > 0 && gap.getY() < boardSize) {
        movements.add(PuzzleMove.LEFT);
      }
      return movements;
    }
  }
;
  ActionStateTransitionFunction<PuzzleMove,Puzzle> atf=new ActionStateTransitionFunction<PuzzleMove,Puzzle>(){
    @Override public Puzzle apply(    PuzzleMove action,    Puzzle state){
      Point gap=state.getTile(0);
      int[][] board=state.copyBoard();
switch (action) {
case UP:
        board[gap.x][gap.y]=state.getMatrixBoard()[gap.x - 1][gap.y];
      board[gap.x - 1][gap.y]=0;
    break;
case DOWN:
  board[gap.x][gap.y]=state.getMatrixBoard()[gap.x + 1][gap.y];
board[gap.x + 1][gap.y]=0;
break;
case LEFT:
board[gap.x][gap.y]=state.getMatrixBoard()[gap.x][gap.y - 1];
board[gap.x][gap.y - 1]=0;
break;
case RIGHT:
board[gap.x][gap.y]=state.getMatrixBoard()[gap.x][gap.y + 1];
board[gap.x][gap.y + 1]=0;
break;
}
Puzzle successor=new Puzzle(board);
return successor;
}
}
;
CostFunction<PuzzleMove,Puzzle,Double> cf=new CostFunction<PuzzleMove,Puzzle,Double>(){
@Override public Double evaluate(Transition<PuzzleMove,Puzzle> transition){
return 1d;
}
}
;
HeuristicFunction<Puzzle,Double> hf=new HeuristicFunction<Puzzle,Double>(){
@Override public Double estimate(Puzzle state){
int mdistance=0;
int[][] board=state.getMatrixBoard();
int size=board.length;
for (int x=0; x < size; x++) for (int y=0; y < size; y++) {
int value=board[x][y];
Point goalTile=goalState.getTile(value);
if (value != 0) {
int dx=x - goalTile.x;
int dy=y - goalTile.y;
mdistance+=Math.abs(dx) + Math.abs(dy);
}
}
return (double)mdistance;
}
}
;
Hipster.SearchProblem<PuzzleMove,Puzzle,WeightedNode<PuzzleMove,Puzzle,Double>> p=ProblemBuilder.create().initialState(initialState).goalState(goalState).defineProblemWithExplicitActions().useActionFunction(af).useTransitionFunction(atf).useCostFunction(cf).useHeuristicFunction(hf).build();
System.out.println(Hipster.createAStar(p).search());
}

Fixed version (ground truth):
public static void main(String[] args){
  final Puzzle initialState=new Puzzle(new int[]{0,8,7,6,5,4,3,2,1});
  final Puzzle goalState=new Puzzle(new int[]{0,1,2,3,4,5,6,7,8});
  ActionFunction<PuzzleMove,Puzzle> af=new ActionFunction<PuzzleMove,Puzzle>(){
    @Override public Iterable<PuzzleMove> actionsFor(    Puzzle state){
      LinkedList<PuzzleMove> movements=new LinkedList<PuzzleMove>();
      Point gap=state.getTile(0);
      int boardSize=state.getMatrixBoard().length;
      if (gap.getX() > 0 && gap.getX() < boardSize) {
        movements.add(PuzzleMove.UP);
      }
      if (gap.getX() >= 0 && gap.getX() < boardSize - 1) {
        movements.add(PuzzleMove.DOWN);
      }
      if (gap.getY() >= 0 && gap.getY() < boardSize - 1) {
        movements.add(PuzzleMove.RIGHT);
      }
      if (gap.getY() > 0 && gap.getY() < boardSize) {
        movements.add(PuzzleMove.LEFT);
      }
      return movements;
    }
  }
;
  ActionStateTransitionFunction<PuzzleMove,Puzzle> atf=new ActionStateTransitionFunction<PuzzleMove,Puzzle>(){
    @Override public Puzzle apply(    PuzzleMove action,    Puzzle state){
      Point gap=state.getTile(0);
      int[][] board=state.copyBoard();
switch (action) {
case UP:
        board[gap.x][gap.y]=state.getMatrixBoard()[gap.x - 1][gap.y];
      board[gap.x - 1][gap.y]=0;
    break;
case DOWN:
  board[gap.x][gap.y]=state.getMatrixBoard()[gap.x + 1][gap.y];
board[gap.x + 1][gap.y]=0;
break;
case LEFT:
board[gap.x][gap.y]=state.getMatrixBoard()[gap.x][gap.y - 1];
board[gap.x][gap.y - 1]=0;
break;
case RIGHT:
board[gap.x][gap.y]=state.getMatrixBoard()[gap.x][gap.y + 1];
board[gap.x][gap.y + 1]=0;
break;
}
Puzzle successor=new Puzzle(board);
return successor;
}
}
;
CostFunction<PuzzleMove,Puzzle,Double> cf=new CostFunction<PuzzleMove,Puzzle,Double>(){
@Override public Double evaluate(Transition<PuzzleMove,Puzzle> transition){
return 1d;
}
}
;
HeuristicFunction<Puzzle,Double> hf=new HeuristicFunction<Puzzle,Double>(){
@Override public Double estimate(Puzzle state){
int mdistance=0;
int[][] board=state.getMatrixBoard();
int size=board.length;
for (int x=0; x < size; x++) for (int y=0; y < size; y++) {
int value=board[x][y];
Point goalTile=goalState.getTile(value);
if (value != 0) {
int dx=x - goalTile.x;
int dy=y - goalTile.y;
mdistance+=Math.abs(dx) + Math.abs(dy);
}
}
return (double)mdistance;
}
}
;
Hipster.SearchProblem<PuzzleMove,Puzzle,WeightedNode<PuzzleMove,Puzzle,Double>> p=ProblemBuilder.create().initialState(initialState).defineProblemWithExplicitActions().useActionFunction(af).useTransitionFunction(atf).useCostFunction(cf).useHeuristicFunction(hf).build();
System.out.println(Hipster.createAStar(p).search(goalState));
}