@Override
  public void chooseMove() {
    long startTime = System.nanoTime();
    Move bestMove = null;
    double bestScore = 0;

    // We need to initialize alpha and beta -infinity and + infinity respectively.
    double alpha = Double.NEGATIVE_INFINITY;
    double beta = Double.POSITIVE_INFINITY;

    int maxDepth;
    for (maxDepth = 1; (System.nanoTime() - startTime) <= maxTime; maxDepth++) {
      List<Move> legalMoves = GameState2P.getLegalMoves(state, index);
      bestScore = 0;

      for (Move m : legalMoves) {
        // If we run out time we break out.
        if ((System.nanoTime() - startTime) >= maxTime) {
          break;
        }

        GameState2P next = m.doMove(state);
        double score = getMinScoreAlphaBeta(next, maxDepth, alpha, beta);

        if (bestMove == null || score >= bestScore) {
          bestMove = m;
          bestScore = score;
        }
      }
    }

    System.out.println("Depth: " + maxDepth + " trans score: " + bestScore);
    GameState2P newState = bestMove.doMove(state);
    game.doMove(index, newState);
  }
  /*
   * Consider all possible moves by our opponent
   */
  private double getMinScoreAlphaBeta(
      final GameState2P state, int depth, double alpha, double beta) {
    double res = Double.POSITIVE_INFINITY;
    double score;

    // We try to get the current opponent state from the transposition table.
    TranspositionEntry entry = minTable.getEntryFromGameState(state);

    // Get the opponent's moves.
    final List<Move> opponentMoves = GameState2P.getLegalMoves(state, indexOpponent);

    // Check if current opp state existed before in table and that the depth is less than the depth
    // stored in the entry. We need to check the states as well, as it is possible that two state
    // has the same hashcode.
    // Then return the previous best minimax score for this state.
    if (null != entry && state.equals(entry.getGameState2P()) && depth <= entry.getDepth()) {
      res = entry.getMinimax();
    }

    if (depth == 0 || state.isGameOver()) {
      res = state.evaluateState(index);
    } else {

      Comparator<Move> comparator =
          new Comparator<Move>() {
            @Override
            public int compare(Move move1, Move move2) {
              // Check if the current opponent moves exist in the transposition table. If it doesn't
              // set minimax
              // to positive infinity, in order words the worst result for the opponent.
              int lhs =
                  (null != minTable.getEntryFromGameState(move1.doMove(state)))
                      ? (int) minTable.getEntryFromGameState(move1.doMove(state)).getMinimax()
                      : (int) Double.POSITIVE_INFINITY;
              int rhs =
                  (null != minTable.getEntryFromGameState(move2.doMove(state)))
                      ? (int) minTable.getEntryFromGameState(move2.doMove(state)).getMinimax()
                      : (int) Double.POSITIVE_INFINITY;

              // If right is lower swap.
              if (lhs > rhs) {
                return 1;
              } else if (lhs == rhs) {
                return 0;
              } else {
                return -1;
              }
            }
          };

      // For the minimax score we need to sort the opponent's moves by their scores lowest first, in
      // order to optimise
      // the search.
      Collections.sort(opponentMoves, comparator);

      // The opponent will go through their moves and try to get the best minimax score for them.
      // Once a promising child move is found store it with the minimax value in the transposition
      // table.
      for (Move move : opponentMoves) {
        GameState2P next = move.doMove(state);
        score = getMaxScoreAlphaBeta(next, depth - 1, alpha, beta);
        res = Math.min(res, score);
        beta = Math.min(beta, score);
        if (beta <= alpha) {
          //
          minTable.addEntry(next, res, depth);
          break;
        }
      }
    }
    return res;
  }