/**
   * find a solution to the initial board (using the A* algorithm). Result will be stored in
   * searchNodeSolution queue;
   *
   * @param initial
   */
  public Solver(Board initial) {
    SearchNode initSearchNd = new SearchNode(initial, null);
    initialBoard = initial;
    pq.insert(initSearchNd);

    // output
    System.out.println("======Original SearchBoard==========");
    outputSN(initSearchNd);

    // find the Goal SearchNode
    while (!pq.min().board.isGoal()) {
      Stack<SearchNode> stackSNforNbrs = new Stack<SearchNode>();
      System.out.println("======NextLevel SearchBoard==========");

      // Insert all neighbors in the priority queue
      stackSNforNbrs = findNbrSearchNode(pq.delMin());
      while (stackSNforNbrs.size() != 0) {
        pq.insert(stackSNforNbrs.pop());
      }
    }

    // Trace back the search node
    SearchNode snInSolution = pq.min();
    Stack<SearchNode> stacksolution = new Stack<SearchNode>();
    while (snInSolution.prevNode != null) {
      stacksolution.push(snInSolution);
      snInSolution = snInSolution.prevNode;
    }
    stacksolution.push(initSearchNd);

    // Make it reverse order
    while (!stacksolution.isEmpty()) searchNodeSolution.enqueue(stacksolution.pop());
  }
 public Double median() {
   int left = max.size();
   int right = min.size();
   if (left == right) {
     return (max.max() + min.min()) * 0.5;
   }
   if (left > right) {
     return max.max().doubleValue();
   }
   return min.min().doubleValue();
 }