@Override
  public SimplePlan call() throws Exception {

    int MAX_SAMPLES = 10;
    boolean foundPlan = false;

    long start = System.currentTimeMillis();
    List<SimplePlan> plans = new ArrayList<SimplePlan>();
    int planSize = 0;
    while (planSize < MAX_SAMPLES || !foundPlan) {
      SimplePlan plan = null;
      try {
        plan = solve(goal);
        if (plan != null) {
          planSize++;
          foundPlan = true;
          setMaxDepth(plan.actions.size());
          plans.add(plan);
          Debug.print(plan.actions.size());
        }
      } catch (InterruptedException e) {
        return null;
      } catch (Exception e) {
        planSize++;
      }
    }
    long elapsed = System.currentTimeMillis() - start;
    Debug.print(this + ": Plan solved in: " + elapsed + " ms.");
    return getShortestPlan(plans);
  }
 private static SimplePlan getShortestPlan(List<SimplePlan> plans) {
   if (plans == null || plans.isEmpty()) {
     return null;
   }
   SimplePlan shortestPlan = plans.remove(0);
   for (SimplePlan p : plans) {
     if (p.actions.isEmpty()) {
       continue;
     }
     if (p.actions.size() < shortestPlan.actions.size()) {
       shortestPlan = p;
     }
   }
   Debug.print("Picked the shortest plan: " + shortestPlan);
   return shortestPlan;
 }
  private SimplePlan solve(Goal goal) throws PlannerException, InterruptedException {
    State startState = new State(world, heldEntity);

    if (!ConstraintCheck.isValidWorld(world)) {
      Debug.print("World is not valid!");
      Debug.print(world);
      throw new PlannerException(this + ": World is not valid!");
    }

    int size = 0;
    State prePickedState = null;
    int prePickedActionSize = 0;
    int rollbackAttempts = 0;
    for (List<Entity> column : world) {
      rollbackAttempts += column.size() * 100;
    }
    SimplePlan plan = new SimplePlan(startState, new ArrayList<Action>(), goal);
    while (true) {
      count++;
      if (hasReachedGoal(goal, plan.currentState)) {
        Debug.print(this + ": " + plan + " reached the goal state " + goal);
        Debug.print(this + ": Planning finished!");
        Debug.print(this + ": Actions: " + plan.actions);
        Debug.print(this + ": Total iteration count: " + count);
        return plan;
      }
      if (Thread.interrupted()) {
        throw new InterruptedException();
      }

      /*
       * Fill a list of possible actions to take. We only pick the actions
       * that make sense to try. (Hopefully!)
       */
      // Small optimization. No point in dropping in the same location
      // we last picked, or picking in the same location we last
      // dropped.
      int i = ran.nextInt(world.size());
      Action newAction;
      while (plan.actions.size() != 0 && plan.actions.get(plan.actions.size() - 1).column == i) {
        i = ran.nextInt(world.size());
      }
      if (plan.currentState.isHolding()) {
        newAction = new Action(Action.COMMAND.DROP, i);
      } else {
        // Big optimization. No need to try to pick something
        // from
        // an empty column.
        while (plan.currentState.world.get(i).isEmpty()) {
          i = ran.nextInt(world.size());
        }
        newAction = new Action(Action.COMMAND.PICK, i);
        prePickedState = new State(plan.currentState);
        prePickedActionSize = plan.actions.size();
      }

      plan.actions.add(newAction);

      if (plan.actions.size() > maxDepth) {
        size = plan.actions.size();
        throw new PlannerException(
            this + ": interrupted, my plan is too long: " + size + " > " + maxDepth);
      }

      try {
        plan.currentState = plan.currentState.takeAction(newAction);

        if (newAction.command == Action.COMMAND.DROP) {
          if (!ConstraintCheck.isValidColumn(plan.currentState.world.get(newAction.column))) {
            if (prePickedState != null) {
              if (rollbackAttempts > 0) {
                plan.currentState = new State(prePickedState);
                plan.actions.subList(prePickedActionSize, plan.actions.size()).clear();
                rollbackAttempts--;
              } else {
                return null;
              }
            }
          }
        }
      } catch (Exception e) {
        Debug.print(e);
        return null;
        // The action was rejected, so we do nothing.
      }
    }
  }