public int think(Board board, int depth) {

        // Initialization

        nodesSearched = 0;
        qsearched = 0;
        abortSearch = false;
        timeStarted = System.currentTimeMillis();
        useFixedDepth = (depth != 0);

        if (!useFixedDepth) {
            timeForThisMove = handler.getTimeForThisMove(board.sideToMove);
        }

        int iteration = 1;
        int bestMove = Move.MOVE_NONE;
        int alpha = -Value.INFINITY, beta = Value.INFINITY;

        while (iteration <= MAX_ITERATIONS) {

            // Resets the stop poll interval
            pollForStopInterval = TIME_CHECK_INTERVAL;

            // Does the search for this iteration
            int eval = searchRoot(board, iteration, alpha, beta, bestMove);

            // Checks to see if we should stop.
            if (abortSearch) break;

            // TODO: change as on page 20 in Yngvis thesis.
            // Check if aspiration window failed, and if so; search with a wider window
            if (eval <= alpha) {
                alpha = -Value.INFINITY;
                continue;
            } else if (eval >= beta) {
                beta = Value.INFINITY;
                continue;
            }

            // The aspiration window search did not fail.
            int[] pvArray = new int[MAX_PLY];
            int noOfMoves = transTable.extractPV(board, pvArray);

            // PV to string:
            StringBuilder sb = new StringBuilder();
            for (int c = 0; c < noOfMoves; c++) sb.append(Move.toLAN(pvArray[c])).append(" ");

            long timeUsed = System.currentTimeMillis() - timeStarted;
            double timeUsedPerSec = timeUsed / 1000d;
            int nps = (int) (timeUsedPerSec <= 1. ? nodesSearched : nodesSearched / timeUsedPerSec);

            // TODO: MATE BOUND: info depth 88 score mate 2 time 17 nodes 10107 nps 594529 pv h6h7 h8h7 h5g6

            String info = String.format(
                    "info score cp %d depth %d nodes %d nps %d time %d pv %s",
                    eval, iteration, nodesSearched, nps, timeUsed, sb.toString());
            handler.sendMessage(info);
            bestMove = pvArray[0];

            assert Move.isOk(bestMove) : "Invalid move: " + bestMove;

            // Adjusts the aspiration window size
            alpha = Math.max(eval - ASPIRATION_SIZE, -Value.INFINITY);
            beta = Math.min(eval + ASPIRATION_SIZE, Value.INFINITY);

            // Break if we are using fixed depth and we have searched to that specific depth
            if (useFixedDepth && iteration == depth) break;

            iteration++;
        }

        assert bestMove != Move.MOVE_NONE;
        return bestMove;
    }