Solving puzzle NxN with IDA* and Manhattan

Viewed 196

Given the game http://mypuzzle.org/sliding, which starts with square grid containing tiles with numbers from 1 to N and one empty block represented with X.The goal is to put the tiles according to their numbers.The moving is done by moving a tile from left,right,top,bottom to the position of the empty tile.I have to solve this problem using IDA* and Manhattan approach

My goal is to output

1.On the first row output the length of the "optimal" path from the start to the destination state

2.The steps which solve the problem in order to reach our final state. The steps are left,right,up,down

Here is my current code working on solution for 3x3 :


/**
 *
 * Problem Name: Eight Algorithm: IDA* (Iterative deepening A*) using Manhattan Distance Heuristic
 * Source: AI: A Modern Approach
 *
 */

// Beware my messy code follows!

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 *
 *
 *
 *
 * @class used to keep State Machine of Eight Puzzle with f,g,h along with board
 *
 */

class StateEightPuzzle {

  private int f, g, h;
  private StringBuilder stateofBoard;
  private int xEmptyTile, yEmptyTile;
  private int pre;

  public void setStateofBoard(StringBuilder stateofBoard) {
    this.stateofBoard = stateofBoard;

  }

  public void setPre(int pre) {

    this.pre = pre;

  }

  public void setXEmptyTile(int xEmptyTile) {

    this.xEmptyTile = xEmptyTile;
  }

  public void setYEmptyTile(int yEmptyTile) {

    this.yEmptyTile = yEmptyTile;
  }

  public void setF(int f) {

    this.f = f;
  }

  public void setG(int g) {

    this.g = g;
  }

  public void setH(int h) {

    this.h = h;

  }

  public int getPre() {

    return pre;

  }

  public int getXEmptyTile() {

    return xEmptyTile;
  }

  public int getYEmptyTile() {

    return yEmptyTile;
  }

  public StringBuilder getStateofBoard() {

    return stateofBoard;

  }

  public int getF() {

    return f;
  }

  public int getG() {

    return g;
  }

  public int getH() {

    return h;
  }

}


/**
 *
 * @class used as return type where flimit is used as current flimit and sol indicates whether
 *        solution is found
 *
 */

class ReturnResult {

  int flimit;
  StateEightPuzzle sol;

}


public class Main {

  /**
   * @param args
   */

  static int flag;
  static int[] tracePath;
  static private int ROWSIZE = 3;
  static private int BOARDSIZE = 9;

  /*
   *
   * function used to see whether the current Eight puzzle can be solvable that is can we subjugate
   * our beloved using inversion permutation
   */

  public static boolean isSolvable(String dpState) {

    int inversion = 0;
    for (int i = 0; i < BOARDSIZE; i++)
      for (int j = i + 1; j < BOARDSIZE; j++)
        if (dpState.charAt(i) > '0' && dpState.charAt(j) > '0'
            && dpState.charAt(i) > dpState.charAt(j))
          inversion++;

    if (inversion % 2 == 1)
      return false;
    else
      return true;

  }

  /*
   *
   * getManhattanDistance returns Manhattan distance between current Node of Eight puzzle State
   * Machine and Goal State(Final Destination)
   */

  public static int getManhattanDistance(StringBuilder knightBoard) {

    int manhattanVal = 0;

    for (int i = 0; i < ROWSIZE; i++)
      for (int j = 0; j < ROWSIZE; j++) {
        int pos = i * ROWSIZE + j;
        int val = (knightBoard.charAt(pos) - '0') - 1;
        if (val == -1)
          continue;

        manhattanVal = manhattanVal + Math.abs((val / ROWSIZE) - i) + Math.abs((val % ROWSIZE) - j);

      }

    return manhattanVal;
  }

  /**
   *
   *
   *
   * @param stat
   * @param x
   * @param y
   * @return
   *
   *         function used to generate next State Machine of Eight Puzzle aka Successor Node(Child
   *         Node) of Current State(Father Node)
   *
   */

  public static StateEightPuzzle findSuccessor(StateEightPuzzle fatherNode, int x, int y, int pre) {

    int nextXCordiante, nextYCordiante;
    nextXCordiante = fatherNode.getXEmptyTile();
    nextYCordiante = fatherNode.getYEmptyTile();

    StateEightPuzzle childNode = new StateEightPuzzle();

    if ((nextXCordiante + x) < 0 || (nextYCordiante + y) < 0 || (nextXCordiante + x) > (ROWSIZE - 1)
        || (nextYCordiante + y) > (ROWSIZE - 1)) {
      flag = 0;
      return childNode;

    }

    int nextEmptyTile = (nextXCordiante + x) * ROWSIZE + (nextYCordiante + y);

    StringBuilder s1 = new StringBuilder(fatherNode.getStateofBoard());
    char ch = s1.charAt(nextEmptyTile);
    s1.setCharAt(nextEmptyTile, '0');
    s1.setCharAt(ROWSIZE * nextXCordiante + nextYCordiante, ch);

    childNode.setStateofBoard(s1);
    childNode.setXEmptyTile(nextXCordiante + x);
    childNode.setYEmptyTile(nextYCordiante + y);
    childNode.setG(fatherNode.getG() + 1);
    childNode.setH(getManhattanDistance(s1));
    childNode.setPre(pre);

    int maxfValue = (fatherNode.getF()) > (childNode.getG() + childNode.getH()) ? fatherNode.getF()
        : (childNode.getG() + childNode.getH());
    childNode.setF(maxfValue);
    flag = 1;
    return childNode;

  }

  /**
   *
   * @param init
   * @param flimit
   * @param res
   * @return function known as Iterative Deepening DFS for A* which uses f-cost for limiting it
   *         search depth. Once the search inside a given contour has been completed , a new
   *         iteration is started with new f-cost for the next DFS-CONTOUR.pls consult Artificial
   *         Intelligence A Modern Approach, 1st edition by Approach By Russell
   *
   */

  public static ReturnResult DFS_CONTOUR(StateEightPuzzle Node, int flimit, ReturnResult res) {

    int newf = Integer.MAX_VALUE;

    ReturnResult resTemp = new ReturnResult();
    StateEightPuzzle stat;
    tracePath[Node.getG()] = Node.getPre();

    // distance matrix for Eight Puzzle which helps to get successor
    int dist[][] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};

    // if current node exceeds flimit return it as flimit

    if (Node.getF() > flimit) {

      resTemp.flimit = Node.getF();
      resTemp.sol = null;

      return resTemp;
    }

    // I see : IDA* is going to give me juicy cool!
    if (Node.getH() == 0) {

      resTemp.flimit = flimit;
      resTemp.sol = Node;
      String sol = "uldr";
      for (int i = 1; i <= Node.getG(); i++)
        System.out.print(sol.charAt(tracePath[i]));
      System.out.println("");

      return resTemp;
    }

    // create next valid successor

    for (int i = 0; i < 4; i++) {

      if (Math.abs(i - Node.getPre()) == 2)
        continue;
      stat = findSuccessor(Node, dist[i][0], dist[i][1], i);
      if (flag == 0)
        continue;
      resTemp = DFS_CONTOUR(stat, flimit, res);
      if (resTemp.sol != null) {

        resTemp.flimit = res.flimit;
        return resTemp;
      }

      newf = resTemp.flimit < newf ? resTemp.flimit : newf;
    }

    resTemp.flimit = newf;
    resTemp.sol = null;
    return resTemp;

  }

  public static void main(String[] args) throws IOException {

    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

    String s_2;

    while ((s_2 = in.readLine()) != null) {

      String str = "";
      tracePath = new int[1000];

      int emptySquare = 0;
      String[] s2 = s_2.split("\\s+");

      for (int i = 0; i < s2.length; i++) {
        if (s2[i].equals("x") == false)
          str += s2[i];
        else
          str += "0";
      }

      if (isSolvable(str) == false) {

        System.out.println("unsolvable");

      } else {

        StringBuilder str_bld = new StringBuilder(str);
        for (int i = 0; i < str_bld.length(); i++)
          if (str_bld.charAt(i) == '0') {
            emptySquare += i;
            break;
          }

        // Create Initial Eight puzzle State Machine and let him dance
        // with
        // prima donna :-)

        StateEightPuzzle init = new StateEightPuzzle();
        init.setStateofBoard(str_bld);
        init.setG(0);

        init.setH(getManhattanDistance(str_bld));
        init.setF(init.getH() + init.getG());
        init.setXEmptyTile(emptySquare / ROWSIZE);
        init.setYEmptyTile(emptySquare % ROWSIZE);
        init.setPre(5);
        int flimit = init.getF();
        ReturnResult result = new ReturnResult();
        result.flimit = flimit;
        result.sol = init;

        // loop loop i m a strange loop living a mundane life with hopes
        for (;;) {

          ReturnResult resTemp = DFS_CONTOUR(init, flimit, result);
          if (resTemp.sol != null) {
            break;

          }
          flimit = resTemp.flimit;

        }
      }
    }
  }
}

The problem I find is for example for the puzzle when inputed 1 2 3 4 5 6 x 7 8 , it should input just "ll" moving the "x" tile to the right two times however it inputs "urdlurdlurdr" any ideas where the problem can be?

0 Answers
Related