/// <summary> /// Find the best move for a player using alpha-beta for a given depth /// </summary> /// <param name="chessBoard"> Chess board</param> /// <param name="searchMode"> Search mode</param> /// <param name="ePlayerColor"> Color doing the move</param> /// <param name="moveList"> List of move to try</param> /// <param name="posInfoWhite"> Information about pieces attacks for the white</param> /// <param name="posInfoBlack"> Information about pieces attacks for the black</param> /// <param name="iTotalMoveCount"> Total list of moves</param> /// <param name="iDepth"> Maximum depth</param> /// <param name="iAlpha"> Alpha bound</param> /// <param name="iBeta"> Beta bound</param> /// <param name="transTable"> Transposition table or null if not using one</param> /// <param name="dtTimeOut"> Time limit (DateTime.MaxValue for no time limit)</param> /// <param name="iPermCount"> Total permutation evaluated</param> /// <param name="iBestMoveIndex"> Index of the best move</param> /// <param name="bTimeOut"> Return true if time out</param> /// <param name="arrPoints"> Returns point of each move in move list</param> /// <returns> /// Points /// </returns> private int FindBestMoveUsingAlphaBetaAtDepth(ChessBoard chessBoard, SearchMode searchMode, ChessBoard.PlayerColorE ePlayerColor, List<ChessBoard.MovePosS> moveList, ChessBoard.PosInfoS posInfoWhite, ChessBoard.PosInfoS posInfoBlack, int iTotalMoveCount, int iDepth, int iAlpha, int iBeta, TransTable transTable, DateTime dtTimeOut, out int iPermCount, out int iBestMoveIndex, out bool bTimeOut, out int[] arrPoints) { int iRetVal = -10000000; int iWhiteMoveCount; int iBlackMoveCount; int iMoveCount; int iIndex; int iPts; ChessBoard.MovePosS move; AlphaBetaInfo abInfo; ChessBoard.RepeatResultE eResult; bTimeOut = false; abInfo = new AlphaBetaInfo(); abInfo.m_arrMovePos = new ChessBoard.MovePosS[iDepth]; abInfo.m_iPermCount = 0; abInfo.m_dtTimeOut = dtTimeOut; abInfo.m_transTable = transTable; abInfo.m_iMaxDepth = iDepth; abInfo.m_searchMode = searchMode; abInfo.m_posInfoWhite = posInfoWhite; abInfo.m_posInfoBlack = posInfoBlack; iBestMoveIndex = -1; arrPoints = new int[moveList.Count]; if (ePlayerColor == ChessBoard.PlayerColorE.White) { iWhiteMoveCount = iTotalMoveCount; iBlackMoveCount = 0; } else { iWhiteMoveCount = 0; iBlackMoveCount = iTotalMoveCount; } iMoveCount = moveList.Count; iIndex = 0; iRetVal = iAlpha; while (iIndex < iMoveCount && !bTimeOut) { move = moveList[iIndex]; eResult = chessBoard.DoMoveNoLog(move); abInfo.m_arrMovePos[iDepth - 1] = move; if (eResult == ChessBoard.RepeatResultE.NoRepeat) { iPts = -AlphaBeta(chessBoard, (ePlayerColor == ChessBoard.PlayerColorE.Black) ? ChessBoard.PlayerColorE.White : ChessBoard.PlayerColorE.Black, iDepth - 1, -iBeta, -iRetVal, iWhiteMoveCount, iBlackMoveCount, abInfo); } else { iPts = 0; } arrPoints[iIndex] = iPts; chessBoard.UndoMoveNoLog(move); if (iPts == Int32.MinValue) { iRetVal = iPts; bTimeOut = true; } else { if (iPts > iRetVal) { TraceSearch(iDepth, ePlayerColor, move, iPts); iRetVal = iPts; iBestMoveIndex = iIndex; } } iIndex++; } iPermCount = abInfo.m_iPermCount; return(iRetVal); }
/// <summary> /// Find the best move for a player using minmax search /// </summary> /// <param name="chessBoard"> Chess board</param> /// <param name="searchMode"> Search mode</param> /// <param name="ePlayerColor"> Color doing the move</param> /// <param name="moveList"> Move list</param> /// <param name="arrIndex"> Order of evaluation of the moves</param> /// <param name="iDepth"> Maximum depth</param> /// <param name="moveBest"> Best move found</param> /// <param name="iPermCount"> Total permutation evaluated</param> /// <returns> /// true if a move has been found /// </returns> private bool FindBestMoveUsingMinMaxAtDepth(ChessBoard chessBoard, SearchMode searchMode, ChessBoard.PlayerColorE ePlayerColor, List<ChessBoard.MovePosS> moveList, int[] arrIndex, int iDepth, ref ChessBoard.MovePosS moveBest, out int iPermCount) { bool bRetVal = false; ChessBoard.MovePosS move; int iPts; int iWhiteMoveCount; int iBlackMoveCount; int iBestPts; ChessBoard.RepeatResultE eResult; iPermCount = 0; iBestPts = Int32.MinValue; if (ePlayerColor == ChessBoard.PlayerColorE.White) { iWhiteMoveCount = moveList.Count; iBlackMoveCount = 0; } else { iWhiteMoveCount = 0; iBlackMoveCount = moveList.Count; } foreach (int iIndex in arrIndex) { move = moveList[iIndex]; eResult = chessBoard.DoMoveNoLog(move); if (eResult == ChessBoard.RepeatResultE.NoRepeat) { iPts = -MinMax(chessBoard, searchMode, (ePlayerColor == ChessBoard.PlayerColorE.Black) ? ChessBoard.PlayerColorE.White : ChessBoard.PlayerColorE.Black, iDepth - 1, iWhiteMoveCount, iBlackMoveCount, ref iPermCount); } else { iPts = 0; } chessBoard.UndoMoveNoLog(move); if (iPts > iBestPts) { TraceSearch(iDepth, ePlayerColor, move, iPts); iBestPts = iPts; moveBest = move; bRetVal = true; } } return(bRetVal); }
/// <summary> /// Alpha Beta pruning function. /// </summary> /// <param name="chessBoard"> Chess board</param> /// <param name="ePlayerColor"> 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 chessBoard, ChessBoard.PlayerColorE ePlayerColor, int iDepth, int iAlpha, int iBeta, int iWhiteMoveCount, int iBlackMoveCount, AlphaBetaInfo abInfo) { int iRetVal; List<ChessBoard.MovePosS> 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 (chessBoard.IsEnoughPieceForCheckMate()) { eBoardExtraInfo = chessBoard.ComputeBoardExtraInfo(ePlayerColor, true); iRetVal = (abInfo.m_transTable != null) ? abInfo.m_transTable.ProbeEntry(chessBoard.CurrentZobristKey, eBoardExtraInfo, iDepth, iAlpha, iBeta) : Int32.MaxValue; if (iRetVal == Int32.MaxValue) { if (iDepth == 0 || m_bCancelSearch) { iRetVal = chessBoard.Points(abInfo.m_searchMode, ePlayerColor, abInfo.m_iMaxDepth - iDepth, iWhiteMoveCount - iBlackMoveCount, abInfo.m_posInfoWhite, abInfo.m_posInfoBlack); if (ePlayerColor == ChessBoard.PlayerColorE.Black) { iRetVal = -iRetVal; } abInfo.m_iPermCount++; if (abInfo.m_transTable != null) { abInfo.m_transTable.RecordEntry(chessBoard.CurrentZobristKey, eBoardExtraInfo, iDepth, iRetVal, TransEntryTypeE.Exact); } } else { moveList = chessBoard.EnumMoveList(ePlayerColor, true, out posInfo); iMoveCount = moveList.Count; if (ePlayerColor == ChessBoard.PlayerColorE.White) { iWhiteMoveCount = iMoveCount; abInfo.m_posInfoWhite = posInfo; } else { iBlackMoveCount = iMoveCount; abInfo.m_posInfoBlack = posInfo; } if (iMoveCount == 0) { if (chessBoard.IsCheck(ePlayerColor)) { iRetVal = -1000000 - iDepth; } else { iRetVal = 0; // Draw } if (abInfo.m_transTable != null) { abInfo.m_transTable.RecordEntry(chessBoard.CurrentZobristKey, eBoardExtraInfo, iDepth, iRetVal, TransEntryTypeE.Exact); } } else { iRetVal = iAlpha; foreach (ChessBoard.MovePosS move in moveList) { eResult = chessBoard.DoMoveNoLog(move); abInfo.m_arrMovePos[iDepth - 1] = move; if (eResult == ChessBoard.RepeatResultE.NoRepeat) { iPts = -AlphaBeta(chessBoard, (ePlayerColor == ChessBoard.PlayerColorE.Black) ? ChessBoard.PlayerColorE.White : ChessBoard.PlayerColorE.Black, iDepth - 1, -iBeta, -iRetVal, iWhiteMoveCount, iBlackMoveCount, abInfo); } else { iPts = 0; } chessBoard.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(chessBoard.CurrentZobristKey, eBoardExtraInfo, iDepth, iRetVal, eType); } } } } } else { iRetVal = 0; } return(iRetVal); }
/// <summary> /// Minimum/maximum depth first search /// </summary> /// <param name="chessBoard"> Chess board</param> /// <param name="searchMode"> Search mode</param> /// <param name="ePlayerColor"> Color doing the move</param> /// <param name="iDepth"> Actual search depth</param> /// <param name="iWhiteMoveCount"> Number of moves white can do</param> /// <param name="iBlackMoveCount"> Number of moves black can do</param> /// <param name="iPermCount"> Total permutation evaluated</param> /// <returns> /// Points to give for this move /// </returns> private int MinMax(ChessBoard chessBoard, SearchMode searchMode, ChessBoard.PlayerColorE ePlayerColor, int iDepth, int iWhiteMoveCount, int iBlackMoveCount, ref int iPermCount) { int iRetVal; int iMoveCount; int iPts; List<ChessBoard.MovePosS> moveList; ChessBoard.RepeatResultE eResult; if (chessBoard.IsEnoughPieceForCheckMate()) { if (iDepth == 0 || m_bCancelSearch) { iRetVal = (ePlayerColor == ChessBoard.PlayerColorE.Black) ? -chessBoard.Points(searchMode, ePlayerColor, 0, iWhiteMoveCount - iBlackMoveCount, ChessBoard.s_posInfoNull, ChessBoard.s_posInfoNull) : chessBoard.Points(searchMode, ePlayerColor, 0, iWhiteMoveCount - iBlackMoveCount, ChessBoard.s_posInfoNull, ChessBoard.s_posInfoNull); iPermCount++; } else { moveList = chessBoard.EnumMoveList(ePlayerColor); iMoveCount = moveList.Count; if (ePlayerColor == ChessBoard.PlayerColorE.White) { iWhiteMoveCount = iMoveCount; } else { iBlackMoveCount = iMoveCount; } if (iMoveCount == 0) { if (chessBoard.IsCheck(ePlayerColor)) { iRetVal = -1000000 - iDepth; } else { iRetVal = 0; // Draw } } else { iRetVal = Int32.MinValue; foreach (ChessBoard.MovePosS move in moveList) { eResult = chessBoard.DoMoveNoLog(move); if (eResult == ChessBoard.RepeatResultE.NoRepeat) { iPts = -MinMax(chessBoard, searchMode, (ePlayerColor == ChessBoard.PlayerColorE.Black) ? ChessBoard.PlayerColorE.White : ChessBoard.PlayerColorE.Black, iDepth - 1, iWhiteMoveCount, iBlackMoveCount, ref iPermCount); } else { iPts = 0; } chessBoard.UndoMoveNoLog(move); if (iPts > iRetVal) { iRetVal = iPts; } } } } } else { iRetVal = 0; } return(iRetVal); }