/// <summary> /// Alpha Beta pruning function. /// </summary> /// <param name="board"> Chess board</param> /// <param name="ePlayer"> Color doing the move</param> /// <param name="iDepth"> Actual search depth</param> /// <param name="iAlpha"> Alpha limit</param> /// <param name="iBeta"> Beta limit</param> /// <param name="iWhiteMoveCount"> Number of moves white can do</param> /// <param name="iBlackMoveCount"> Number of moves black can do</param> /// <param name="abInfo"> Supplemental information</param> /// <returns> /// Points to give for this move or Int32.MinValue for timed out /// </returns> private int AlphaBeta(ChessBoard board, ChessBoard.PlayerE ePlayer, int iDepth, int iAlpha, int iBeta, int iWhiteMoveCount, int iBlackMoveCount, AlphaBetaInfo abInfo) { int iRetVal; List <Move> moveList; int iPts; int iMoveCount; ChessBoard.PosInfoS posInfo; TransEntryTypeE eType = TransEntryTypeE.Alpha; ChessBoard.BoardStateMaskE eBoardExtraInfo; ChessBoard.RepeatResultE eResult; if (abInfo.m_dtTimeOut != DateTime.MaxValue && DateTime.Now >= abInfo.m_dtTimeOut) { iRetVal = Int32.MinValue; // Time out! } else if (board.IsEnoughPieceForCheckMate()) { eBoardExtraInfo = board.ComputeBoardExtraInfo(ePlayer, true); iRetVal = (abInfo.m_transTable != null) ? abInfo.m_transTable.ProbeEntry(board.CurrentZobristKey, eBoardExtraInfo, iDepth, iAlpha, iBeta) : Int32.MaxValue; if (iRetVal == Int32.MaxValue) { if (iDepth == 0 || m_bCancelSearch) { iRetVal = board.Points(abInfo.m_searchMode, ePlayer, abInfo.m_iMaxDepth - iDepth, iWhiteMoveCount - iBlackMoveCount, abInfo.m_posInfoWhite, abInfo.m_posInfoBlack); if (ePlayer == ChessBoard.PlayerE.Black) { iRetVal = -iRetVal; } abInfo.m_iPermCount++; if (abInfo.m_transTable != null) { abInfo.m_transTable.RecordEntry(board.CurrentZobristKey, eBoardExtraInfo, iDepth, iRetVal, TransEntryTypeE.Exact); } } else { moveList = board.EnumMoveList(ePlayer, true, out posInfo); iMoveCount = moveList.Count; if (ePlayer == ChessBoard.PlayerE.White) { iWhiteMoveCount = iMoveCount; abInfo.m_posInfoWhite = posInfo; } else { iBlackMoveCount = iMoveCount; abInfo.m_posInfoBlack = posInfo; } if (iMoveCount == 0) { if (board.IsCheck(ePlayer)) { iRetVal = -1000000 - iDepth; } else { iRetVal = 0; // Draw } if (abInfo.m_transTable != null) { abInfo.m_transTable.RecordEntry(board.CurrentZobristKey, eBoardExtraInfo, iDepth, iRetVal, TransEntryTypeE.Exact); } } else { iRetVal = iAlpha; foreach (Move move in moveList) { eResult = board.DoMoveNoLog(move); abInfo.m_arrMove[iDepth - 1] = move; if (eResult == ChessBoard.RepeatResultE.NoRepeat) { iPts = -AlphaBeta(board, (ePlayer == ChessBoard.PlayerE.Black) ? ChessBoard.PlayerE.White : ChessBoard.PlayerE.Black, iDepth - 1, -iBeta, -iRetVal, iWhiteMoveCount, iBlackMoveCount, abInfo); } else { iPts = 0; } board.UndoMoveNoLog(move); if (iPts == Int32.MinValue) { iRetVal = iPts; break; } else { if (iPts > iRetVal) { iRetVal = iPts; eType = TransEntryTypeE.Exact; } if (iRetVal >= iBeta) { iRetVal = iBeta; eType = TransEntryTypeE.Beta; break; } } } if (abInfo.m_transTable != null && iRetVal != Int32.MinValue) { abInfo.m_transTable.RecordEntry(board.CurrentZobristKey, eBoardExtraInfo, iDepth, iRetVal, eType); } } } } } else { iRetVal = 0; } return(iRetVal); }
/// <summary> /// Record a new entry in the table /// </summary> /// <param name="i64ZobristKey"> Zobrist key. Probably unique for this board position.</param> /// <param name="eExtraInfo"> Extra information about the board not contains in the Zobrist key</param> /// <param name="iDepth"> Current depth (reverse)</param> /// <param name="iValue"> Board evaluation</param> /// <param name="eType"> Type of the entry</param> public void RecordEntry(long i64ZobristKey, ChessBoard.BoardStateMaskE eExtraInfo, int iDepth, int iValue, TransEntryTypeE eType) { TransEntry entry; i64ZobristKey ^= (int)eExtraInfo; entry.m_i64Key = i64ZobristKey; entry.m_iGen = m_iGen; entry.m_eExtraInfo = eExtraInfo; entry.m_iDepth = iDepth; entry.m_iValue = iValue; entry.m_eType = eType; m_arrTransEntry[(UInt64)i64ZobristKey % (UInt64)m_arrTransEntry.Length] = entry; }