public static int AlphaBetaTT(Board board, int alpha, int beta, byte depthLeft, sbyte side, UInt16[] killers, int level) { int score; TranspositionTableEntry entry = transpositionTable.Retrieve(board.ZobristHash); if (entry.IsValid() && (TranspositionTableEntryHelper.GetDepthSearched(entry.Data) >= depthLeft)) { if (TranspositionTableEntryHelper.GetEntryType(entry.Data) == TranspositionTableEntryHelper.EntryTypeExactValue) { return TranspositionTableEntryHelper.GetScore(entry.Data); } if ((TranspositionTableEntryHelper.GetEntryType(entry.Data) == TranspositionTableEntryHelper.EntryTypeLowerBound) && (TranspositionTableEntryHelper.GetScore(entry.Data) > alpha)) { alpha = TranspositionTableEntryHelper.GetScore(entry.Data); } else if ((TranspositionTableEntryHelper.GetEntryType(entry.Data) == TranspositionTableEntryHelper.EntryTypeUpperBound) && (TranspositionTableEntryHelper.GetScore(entry.Data) < beta)) { beta = TranspositionTableEntryHelper.GetScore(entry.Data); } if (alpha >= beta) { return TranspositionTableEntryHelper.GetScore(entry.Data); } } if (depthLeft == 0) { score = Quiescence_Limited(board, side, alpha, beta, (level + 1) % 2); // the last arg ensures that quiescence evaluates opponent's move as the last one. // Quiescence(board, side, alpha, beta); // Evaluation2.EvaluateFromPerspectiveOf(board, side); if (score <= alpha) { transpositionTable.Add(new TranspositionTableEntry(board.ZobristHash, TranspositionTableEntryHelper.ComposeData(score, TranspositionTableEntryHelper.InvalidMove, depthLeft, TranspositionTableEntryHelper.EntryTypeLowerBound))); } else if (score >= beta) { transpositionTable.Add(new TranspositionTableEntry(board.ZobristHash, TranspositionTableEntryHelper.ComposeData(score, TranspositionTableEntryHelper.InvalidMove, depthLeft, TranspositionTableEntryHelper.EntryTypeUpperBound))); } else { transpositionTable.Add(new TranspositionTableEntry(board.ZobristHash, TranspositionTableEntryHelper.ComposeData(score, TranspositionTableEntryHelper.InvalidMove, depthLeft, TranspositionTableEntryHelper.EntryTypeExactValue))); } return score; } int movesCount; UInt16[] moves = board.GenerateMoves(out movesCount); #region Move Ordering // this is the index with which a good move will be swapped with... int indexToSwapWith = 0; /*************** Transposition Table Reordering **************/ // NOTE (17 Jul 2013): There appears to be no gain from transposition table re-ordering, therefore // commenting it out. //if (entry.IsValid()) //{ // UInt16 bestMoveFromTable = TranspositionTableEntryHelper.GetBestMove(entry.Data); // if (bestMoveFromTable != TranspositionTableEntryHelper.InvalidMove) // { // for (int i = 0; i < movesCount; i++) // { // if (moves[i] == bestMoveFromTable) // { // // swap... // UInt16 temp = moves[i]; // moves[i] = moves[indexToSwapWith]; // moves[indexToSwapWith] = temp; // indexToSwapWith++; // break; // } // } // } //} /*************** End of Transposition Table Reordering **************/ /*************** Killer Heuristic Reordering *****************/ if (killers[level] != 0) { for (int i = 0; i < movesCount; i++) { if (killers[level] == moves[i]) { // if killer move found then swap that with the first move. UInt16 temp = moves[i]; moves[i] = moves[indexToSwapWith]; moves[indexToSwapWith] = temp; indexToSwapWith++; break; } } } // set killer for next level to 0 killers[level + 1] = 0; /*************** End of Killer Heuristic Reordering *****************/ #endregion // NOTE: diluting negative infinity by level so that the farther away the checkmate is from current // board position the lower will be the score. this is to get the engine to checkmate opponent // as soon as possible rather than wasting time in capture or other moves which ultimately lead to // checkmate but are not the fastest route to checkmakte. int bestScore = Constants.NegativeInfinity + level; UInt16 bestMove = TranspositionTableEntryHelper.InvalidMove; BoardState state; sbyte oppositeSide = (sbyte)(-1 * side); for (int i = 0; i < movesCount; i++) { state = board.GetBoardState(); if (!board.MakeMove(moves[i])) { continue; } score = -AlphaBetaTT(board, -beta, -alpha, (byte)(depthLeft - 1), oppositeSide, killers, level + 1); board.RestoreState(state); if (score > bestScore) { bestScore = score; bestMove = moves[i]; } if (bestScore > alpha) { alpha = bestScore; } if (bestScore >= beta) { // beta-cutoff, therefore update killer for this level killers[level] = moves[i]; break; } } // following nested ifs check for stalemate. if (bestScore == (Constants.NegativeInfinity + level)) { if (!board.IsInCheck(side)) { bestScore = Constants.DrawScore; } } if (bestScore <= alpha) // lower bound value { transpositionTable.Add(new TranspositionTableEntry(board.ZobristHash, TranspositionTableEntryHelper.ComposeData(bestScore, bestMove, depthLeft, TranspositionTableEntryHelper.EntryTypeLowerBound))); } else if (bestScore >= beta) // upper bound value { transpositionTable.Add(new TranspositionTableEntry(board.ZobristHash, TranspositionTableEntryHelper.ComposeData(bestScore, bestMove, depthLeft, TranspositionTableEntryHelper.EntryTypeUpperBound))); } else // true minimax value { transpositionTable.Add(new TranspositionTableEntry(board.ZobristHash, TranspositionTableEntryHelper.ComposeData(bestScore, bestMove, depthLeft, TranspositionTableEntryHelper.EntryTypeExactValue))); } return bestScore; }