public int searchTree(final int levelsToTop, int alpha, final int beta) {

    if (board.isDraw()) {
      return scorer.drawValue();
    }

    if (levelsToTop == iterativeDepth) {
      return scorer.staticScore(board);
    }

    final MoveContainer moves = moveContainers[levelsToTop];
    final BoardHashEntry hashEntry = hashTable.get(board.getHashCode());

    prioritizeHashEntry(hashEntry, moves);

    board.makeNullMove();
    board.generateValidMoves(moves);

    if (moves.isEmpty()) {
      return scorer.endOfGameValue(board.isInCheck(), levelsToTop);
    }

    for (int m = 0; m < moves.size(); m++) {

      final Move move = moves.get(m);

      board.makeMove(move);

      final int childScore = -searchTree(levelsToTop + 1, -beta, -alpha);

      board.undoMove();

      if (childScore > alpha) {
        // narrowing alpha beta window
        alpha = childScore;

        movePath.markMove(levelsToTop, iterativeDepth, m);

        if (alpha >= beta) {
          // pruned!
          break;
        }
      }
    }

    unprioritizeHashEntry(hashEntry, moves);

    hashTable.set(
        board.getHashCode(),
        alpha,
        0,
        movePath.getRaw(levelsToTop),
        board.getMoveNumber(),
        BoardHashEntry.ValueBounds.PV);

    return alpha;
  }
 private static void unprioritizeHashEntry(
     final BoardHashEntry entry, final MoveContainer moveContainer) {
   if (entry != null) {
     moveContainer.unprioritizeMove(entry.getBestMove());
   }
 }