/** Generate optimal policy */
  private void generateOptimalPolicy() {
    double startTime, currentTime; // Timer things
    boolean alreadyRunThrough = false; // Record if we've already done one run
    Set<State> toLookup; // The states to lookup
    Map<Action, Double> differentValues =
        new HashMap<Action, Double>(); // The different values for the current state
    Map<State, Action> newPolicy = new HashMap<State, Action>(); // New policy
    State newState; // New state for new policy
    Action best; // The best action

    startTime = Global.currentTime();
    currentTime = Global.currentTime();
    while ((currentTime - startTime) <= this.timeRemaining) {
      if (alreadyRunThrough) {
        toLookup = this.policy.keySet();
      } else {
        toLookup = this.possibleStates;
      }
      for (State currentState : toLookup) {
        differentValues.clear(); // Reset different values
        for (Action currentAction : this.possibleActions) {
          if (!validAction(currentAction, currentState)) {
            continue;
          }
          differentValues.put(
              currentAction, valueGeneration(currentState, currentAction, toLookup));
        }
        best = maxArg(differentValues);
        if (isBetterPolicy(currentState, differentValues.get(best))) {
          newState = new State(currentState.getState());
          newState.setTemporaryCost(differentValues.get(best));
          newPolicy.put(newState, best);
        }
      }
      if (CheckDifference(0.1, newPolicy)) {
        copyPolicy(newPolicy);
        newPolicy.clear();
        alreadyRunThrough = true;
      } else {
        currentTime = Global.currentTime();
        break;
      }
    }
  }
  /** Generate all possible actions */
  private void generateAllPossibleActions() {
    double startTime, endTime; // Timer for generating states
    Map<Integer, Integer> action; // Action
    int maxSum = this.fridge.getMaxPurchase(); // The maximum amount we can purchase
    int maxIndex = this.fridge.getMaxTypes() - 1; // The maximum index of an action

    System.out.println("Generating all possible actions");
    startTime = endTime = Global.currentTime(); /* Set the time */
    action = new HashMap<Integer, Integer>();

    /* Generate zero case */
    for (int i = 0; i < (maxIndex + 1); ++i) {
      action.put(i, 0);
    }
    this.possibleActions.add(new Action(action));
    System.out.println("Size of action: " + action.size());

    while ((endTime - startTime) < this.MAX_GENERATION_TIME) {
      if (this.fridge.getMaxTypes() <= 0) {
        System.err.println("Invalid number of item types");
        System.exit(10);
      } else if (this.fridge.getMaxTypes() == 1) { // Only have 1 type of item
        break;
      } else { // Fridge has 2 or more types of items
        for (int i = maxSum; i >= 0; --i) {
          for (int j = 0; j < (maxIndex + 1); ++j) {
            recursiveGeneration(1, maxSum, i, j, action, this.fridge.getMaxPurchase());
            for (int k = 0; k < (maxIndex + 1); ++k) { // Reset list
              action.put(k, 0);
            }
          }
          endTime = Global.currentTime();
          if ((endTime - startTime) >= this.MAX_GENERATION_TIME) {
            break;
          }
        }
      }
      endTime = Global.currentTime(); // Get current time
      this.timeRemaining -= (endTime - startTime);
      System.out.println("Time remaining: " + this.timeRemaining);
      break;
    }
  }
  /** Generate all the possible states */
  private void generateAllPossibleStates() {
    double startTime, endTime; // Timer for generating states
    Map<Integer, Integer> state; // Action
    int maxSum = this.fridge.getCapacity(); // The maximum amount we can have in a state
    int maxIndex = this.fridge.getMaxTypes() - 1; // The maximum index of a state

    System.out.println("Generating all possible states");
    startTime = endTime = Global.currentTime(); /* Set the time */
    state = new HashMap<Integer, Integer>();

    /* Generate zero case */
    for (int i = 0; i < (maxIndex + 1); ++i) {
      state.put(i, 0);
    }
    this.possibleStates.add(new State(state));
    System.out.println("Size of state: " + state.size());

    while ((endTime - startTime) < this.MAX_GENERATION_TIME) {
      if (this.fridge.getMaxTypes() <= 0) {
        System.exit(10);
      } else if (this.fridge.getMaxTypes() == 1) { // Only have 1 type of item
        break;
      } else { // Fridge has 2 or more types of items
        for (int i = maxSum; i >= 0; --i) {
          for (int j = 0; j < (maxIndex + 1); ++j) {
            recursiveGeneration(0, maxSum, i, j, state, this.fridge.getMaxItemsPerType());
            for (int k = 0; k < (maxIndex + 1); ++k) { // Reset list
              state.put(k, 0);
            }
          }
          endTime = Global.currentTime();
          if ((endTime - startTime) >= this.MAX_GENERATION_TIME) {
            break;
          }
        }
      }
      endTime = Global.currentTime(); // Get current time
      this.timeRemaining -= (endTime - startTime);
      System.out.println("Time remaining: " + this.timeRemaining);
      break;
    }
  }