private AlphaBetaResult AlphaBeta(BoardState state, int alpha, int beta, GameState parent) { var result = new AlphaBetaResult(state.StartEstimate, alpha, beta); var estimatedCells = EstimateCells(state); //double enumeration doesn't happen - we parallelize only non-terminal states if (state.AllowParallelize(estimatedCells) && !AnalyzeModeOn) { Parallel.ForEach(estimatedCells, (estimatedCell, parallelLoopState) => { if (ProcessCell(state, parent, estimatedCell, result)) { parallelLoopState.Stop(); } }); } else { foreach (var estimatedCell in estimatedCells) { if (ProcessCell(state, parent, estimatedCell, result)) { break; } } } return(result); }
/// <summary> /// Find the best move for a player using alpha-beta in a secondary thread /// </summary> /// <param name="board"> Chess board</param> /// <param name="searchMode"> Search mode</param> /// <param name="ePlayer"> Color doing the move</param> /// <param name="iThreadId"> Thread Id (0-n)</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 number of moves</param> /// <param name="iAlpha"> Alpha bound</param> /// <param name="iBeta"> Beta bound</param> /// <returns> /// Points /// </returns> private AlphaBetaResult FindBestMoveUsingAlphaBetaAsync(ChessBoard board, SearchMode searchMode, ChessBoard.PlayerE ePlayer, int iThreadId, List <Move> moveList, ChessBoard.PosInfoS posInfoWhite, ChessBoard.PosInfoS posInfoBlack, int iTotalMoveCount, int iAlpha, int iBeta) { AlphaBetaResult resRetVal; DateTime dtTimeOut; int iDepth; int iPermCountAtLevel; int iPoint; int iBestMoveIndex; int iDepthLimit; int[] arrPoints; System.Threading.ThreadPriority eThreadPriority; TransTable transTable; bool bTimeOut; bool bIterativeDepthFirst; resRetVal = new AlphaBetaResult(); eThreadPriority = System.Threading.Thread.CurrentThread.Priority; System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.BelowNormal; if ((searchMode.m_eOption & SearchMode.OptionE.UseTransTable) != 0) { transTable = TransTable.GetTransTable(iThreadId); transTable.Reset(); } else { transTable = null; } bIterativeDepthFirst = (searchMode.m_eOption.HasFlag(SearchMode.OptionE.UseIterativeDepthSearch)); resRetVal.movePosBest.StartPos = 255; resRetVal.movePosBest.EndPos = 255; resRetVal.movePosBest.OriginalPiece = ChessBoard.PieceE.None; resRetVal.movePosBest.Type = Move.TypeE.Normal; try { resRetVal.iPermCount = 0; if (searchMode.m_iSearchDepth == 0 || bIterativeDepthFirst) { dtTimeOut = (bIterativeDepthFirst) ? DateTime.MaxValue : DateTime.Now + TimeSpan.FromSeconds(searchMode.m_iTimeOutInSec); iDepthLimit = (bIterativeDepthFirst) ? searchMode.m_iSearchDepth : 999; iDepth = 1; resRetVal.iPts = FindBestMoveUsingAlphaBetaAtDepth(board, searchMode, ePlayer, moveList, posInfoWhite, posInfoBlack, iTotalMoveCount, iDepth, iAlpha, iBeta, transTable, DateTime.MaxValue, out iPermCountAtLevel, out iBestMoveIndex, out bTimeOut, out arrPoints); if (iBestMoveIndex != -1) { resRetVal.movePosBest = moveList[iBestMoveIndex]; } resRetVal.iPermCount += iPermCountAtLevel; resRetVal.iMaxDepth = iDepth; while (DateTime.Now < dtTimeOut && !m_bCancelSearch && !bTimeOut && iDepth < iDepthLimit) { moveList = SortMoveList(moveList, arrPoints); iDepth++; iPoint = FindBestMoveUsingAlphaBetaAtDepth(board, searchMode, ePlayer, moveList, posInfoWhite, posInfoBlack, iTotalMoveCount, iDepth, iAlpha, iBeta, transTable, dtTimeOut, out iPermCountAtLevel, out iBestMoveIndex, out bTimeOut, out arrPoints); if (!bTimeOut) { if (iBestMoveIndex != -1) { resRetVal.movePosBest = moveList[iBestMoveIndex]; } resRetVal.iPermCount += iPermCountAtLevel; resRetVal.iMaxDepth = iDepth; resRetVal.iPts = iPoint; } } } else { resRetVal.iMaxDepth = searchMode.m_iSearchDepth; resRetVal.iPts = FindBestMoveUsingAlphaBetaAtDepth(board, searchMode, ePlayer, moveList, posInfoWhite, posInfoBlack, iTotalMoveCount, resRetVal.iMaxDepth, iAlpha, iBeta, transTable, DateTime.MaxValue, out resRetVal.iPermCount, out iBestMoveIndex, out bTimeOut, out arrPoints); if (iBestMoveIndex != -1) { resRetVal.movePosBest = moveList[iBestMoveIndex]; } } } finally { System.Threading.Thread.CurrentThread.Priority = eThreadPriority; } return(resRetVal); }
private static bool ShouldBreak(BoardState state, AlphaBetaResult res, int minMax) { return(BreakOnDoubleThreat(state.ItIsFirstsTurn, minMax) || res.Beta <= res.Alpha); }
private bool ProcessCell(BoardState state, GameState parent, EstimatedCell estimatedCell, AlphaBetaResult res) { var cell = estimatedCell.Cell; var currEstim = estimatedCell.Estimate * state.Multiplier; var gameState = new GameState(estimatedCell); OnStateChanged(gameState, parent); var cellResult = ShoudNotGoDeeper(state, estimatedCell) ? new AlphaBetaResult(currEstim) : AlphaBeta(state.GetNextState(estimatedCell.BoardState), res.Alpha, res.Beta, gameState); gameState.Estimate = cellResult.MinMax; if (state.ItIsFirstsTurn && cellResult.MinMax > res.MinMax) { res.MinMax = cellResult.MinMax; res.Alpha = cellResult.MinMax; res.Move = cell; } if (!state.ItIsFirstsTurn && cellResult.MinMax < res.MinMax) { res.MinMax = cellResult.MinMax; res.Beta = cellResult.MinMax; res.Move = cell; } return(ShouldBreak(state, res, cellResult.MinMax)); }
/// <summary> /// Find the best move for a player using alpha-beta in a secondary thread /// </summary> /// <param name="chessBoard"> Chess board</param> /// <param name="searchMode"> Search mode</param> /// <param name="ePlayerColor"> Color doing the move</param> /// <param name="iThreadId"> Thread Id (0-n)</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 number of moves</param> /// <param name="iAlpha"> Alpha bound</param> /// <param name="iBeta"> Beta bound</param> /// <returns> /// Points /// </returns> private AlphaBetaResult FindBestMoveUsingAlphaBetaAsync(ChessBoard chessBoard, SearchMode searchMode, ChessBoard.PlayerColorE ePlayerColor, int iThreadId, List<ChessBoard.MovePosS> moveList, ChessBoard.PosInfoS posInfoWhite, ChessBoard.PosInfoS posInfoBlack, int iTotalMoveCount, int iAlpha, int iBeta) { AlphaBetaResult resRetVal; DateTime dtTimeOut; int iDepth; int iPermCountAtLevel; int iPoint; int iBestMoveIndex; int iDepthLimit; int[] arrPoints; System.Threading.ThreadPriority eThreadPriority; TransTable transTable; bool bTimeOut; bool bIterativeDepthFirst; resRetVal = new AlphaBetaResult(); eThreadPriority = System.Threading.Thread.CurrentThread.Priority; System.Threading.Thread.CurrentThread.Priority = System.Threading.ThreadPriority.BelowNormal; if ((searchMode.m_eOption & SearchMode.OptionE.UseTransTable) != 0) { transTable = TransTable.GetTransTable(iThreadId); transTable.Reset(); } else { transTable = null; } bIterativeDepthFirst = ((searchMode.m_eOption & SearchMode.OptionE.UseIterativeDepthSearch) == SearchMode.OptionE.UseIterativeDepthSearch); resRetVal.movePosBest.StartPos = 255; resRetVal.movePosBest.EndPos = 255; resRetVal.movePosBest.OriginalPiece = ChessBoard.PieceE.None; resRetVal.movePosBest.Type = ChessBoard.MoveTypeE.Normal; try { resRetVal.iPermCount = 0; if (searchMode.m_iSearchDepth == 0 || bIterativeDepthFirst) { dtTimeOut = (bIterativeDepthFirst) ? DateTime.MaxValue : DateTime.Now + TimeSpan.FromSeconds(searchMode.m_iTimeOutInSec); iDepthLimit = (bIterativeDepthFirst) ? searchMode.m_iSearchDepth : 999; iDepth = 1; resRetVal.iPts = FindBestMoveUsingAlphaBetaAtDepth(chessBoard, searchMode, ePlayerColor, moveList, posInfoWhite, posInfoBlack, iTotalMoveCount, iDepth, iAlpha, iBeta, transTable, DateTime.MaxValue, out iPermCountAtLevel, out iBestMoveIndex, out bTimeOut, out arrPoints); if (iBestMoveIndex != -1) { resRetVal.movePosBest = moveList[iBestMoveIndex]; } resRetVal.iPermCount += iPermCountAtLevel; resRetVal.iMaxDepth = iDepth; while (DateTime.Now < dtTimeOut && !m_bCancelSearch && !bTimeOut && iDepth < iDepthLimit) { moveList = SortMoveList(moveList, arrPoints); iDepth++; iPoint = FindBestMoveUsingAlphaBetaAtDepth(chessBoard, searchMode, ePlayerColor, moveList, posInfoWhite, posInfoBlack, iTotalMoveCount, iDepth, iAlpha, iBeta, transTable, dtTimeOut, out iPermCountAtLevel, out iBestMoveIndex, out bTimeOut, out arrPoints); if (!bTimeOut) { if (iBestMoveIndex != -1) { resRetVal.movePosBest = moveList[iBestMoveIndex]; } resRetVal.iPermCount += iPermCountAtLevel; resRetVal.iMaxDepth = iDepth; resRetVal.iPts = iPoint; } } } else { resRetVal.iMaxDepth = searchMode.m_iSearchDepth; resRetVal.iPts = FindBestMoveUsingAlphaBetaAtDepth(chessBoard, searchMode, ePlayerColor, moveList, posInfoWhite, posInfoBlack, iTotalMoveCount, resRetVal.iMaxDepth, iAlpha, iBeta, transTable, DateTime.MaxValue, out resRetVal.iPermCount, out iBestMoveIndex, out bTimeOut, out arrPoints); if (iBestMoveIndex != -1) { resRetVal.movePosBest = moveList[iBestMoveIndex]; } } } finally { System.Threading.Thread.CurrentThread.Priority = eThreadPriority; } return(resRetVal); }