Esempio n. 1
0
 /// <summary>
 /// Gets one of the static translation table
 /// </summary>
 /// <param name="iIndex">           Index of the table (0..ProcessorCount-1)</param>
 /// <returns>
 /// Translation table
 /// </returns>
 static public TransTable GetTransTable(int iIndex)
 {
     if (s_arrTransTable[iIndex] == null)
     {
         s_arrTransTable[iIndex] = new TransTable(TranslationTableSize);
     }
     return(s_arrTransTable[iIndex]);
 }
        /// <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);
        }
        /// <summary>
        /// Find the best move for a player using alpha-beta
        /// </summary>
        /// <param name="board">        Chess board</param>
        /// <param name="searchMode">   Search mode</param>
        /// <param name="ePlayer">      Player doing the move</param>
        /// <param name="moveList">     Move list</param>
        /// <param name="arrIndex">     Order of evaluation of the moves</param>
        /// <param name="posInfo">      Information about pieces attacks</param>
        /// <param name="moveBest">     Best move found</param>
        /// <param name="iPermCount">   Total permutation evaluated</param>
        /// <param name="iCacheHit">    Number of moves found in the translation table cache</param>
        /// <param name="iMaxDepth">    Maximum depth to use</param>
        /// <returns>
        /// true if a move has been found
        /// </returns>
        protected override bool FindBestMove(ChessBoard board,
                                             SearchMode searchMode,
                                             ChessBoard.PlayerE ePlayer,
                                             List <Move> moveList,
                                             int[]                  arrIndex,
                                             ChessBoard.PosInfoS posInfo,
                                             ref Move moveBest,
                                             out int iPermCount,
                                             out int iCacheHit,
                                             out int iMaxDepth)
        {
            bool bRetVal = false;
            bool bMultipleThread;
            bool bUseTransTable;

            ChessBoard[]             arrBoard;
            Task <AlphaBetaResult>[] taskArray;
            List <Move>[]            arrMoveList;
            AlphaBetaResult          alphaBetaRes;

            ChessBoard.PosInfoS posInfoWhite;
            ChessBoard.PosInfoS posInfoBlack;
            int iAlpha;
            int iBeta;
            int iThreadCount;

            //TODO Enable transposition table when bug on 3 repetition move draw will be found.
            if (ePlayer == ChessBoard.PlayerE.White)
            {
                posInfoWhite = posInfo;
                posInfoBlack = ChessBoard.s_posInfoNull;
            }
            else
            {
                posInfoWhite = ChessBoard.s_posInfoNull;
                posInfoBlack = posInfo;
            }
            searchMode.m_eOption &= ~SearchMode.OptionE.UseTransTable;
            bUseTransTable        = (searchMode.m_eOption.HasFlag(SearchMode.OptionE.UseTransTable));
            iCacheHit             = 0;
            iMaxDepth             = 0;
            iPermCount            = 0;
            iAlpha          = -10000000;
            iBeta           = +10000000;
            bMultipleThread = (searchMode.m_eThreadingMode == SearchMode.ThreadingModeE.OnePerProcessorForSearch);
            iThreadCount    = System.Environment.ProcessorCount;
            if (bMultipleThread && iThreadCount < 2)
            {
                bMultipleThread = false;    // No reason to go with multi-threading if only one processor
            }
            if (bMultipleThread)
            {
                arrBoard    = new ChessBoard[iThreadCount];
                arrMoveList = new List <Move> [iThreadCount];
                taskArray   = new Task <AlphaBetaResult> [iThreadCount];
                for (int iIndex = 0; iIndex < iThreadCount; iIndex++)
                {
                    arrBoard[iIndex]    = board.Clone();
                    arrMoveList[iIndex] = new List <Move>(moveList.Count / iThreadCount + 1);
                    for (int iStep = iIndex; iStep < moveList.Count; iStep += iThreadCount)
                    {
                        arrMoveList[iIndex].Add(moveList[arrIndex[iStep]]);
                    }
                }
                for (int iIndex = 0; iIndex < iThreadCount; iIndex++)
                {
                    taskArray[iIndex] = Task <AlphaBetaResult> .Factory.StartNew((param) => {
                        int iStep = (int)param;
                        return(FindBestMoveUsingAlphaBetaAsync(arrBoard[iStep],
                                                               searchMode,
                                                               ePlayer,
                                                               iStep,
                                                               arrMoveList[iStep],
                                                               posInfoWhite,
                                                               posInfoBlack,
                                                               moveList.Count,
                                                               iAlpha,
                                                               iBeta));
                    }, iIndex);
                }
                iMaxDepth = 999;
                for (int iStep = 0; iStep < iThreadCount; iStep++)
                {
                    alphaBetaRes = taskArray[iStep].Result;
                    if (alphaBetaRes.movePosBest.StartPos != 255)
                    {
                        iPermCount += alphaBetaRes.iPermCount;
                        iMaxDepth   = Math.Min(iMaxDepth, alphaBetaRes.iMaxDepth);
                        if (bUseTransTable)
                        {
                            iCacheHit += TransTable.GetTransTable(iStep).CacheHit;
                        }
                        if (alphaBetaRes.iPts > iAlpha)
                        {
                            iAlpha   = alphaBetaRes.iPts;
                            moveBest = alphaBetaRes.movePosBest;
                            bRetVal  = true;
                        }
                    }
                }
                if (iMaxDepth == 999)
                {
                    iMaxDepth = -1;
                }
            }
            else
            {
                ChessBoard  chessBoardTmp;
                List <Move> moveListTmp;

                chessBoardTmp = board.Clone();
                moveListTmp   = new List <Move>(moveList.Count);
                for (int iIndex = 0; iIndex < moveList.Count; iIndex++)
                {
                    moveListTmp.Add(moveList[arrIndex[iIndex]]);
                }
                alphaBetaRes = FindBestMoveUsingAlphaBetaAsync(chessBoardTmp,
                                                               searchMode,
                                                               ePlayer,
                                                               0,  // ThreadId
                                                               moveListTmp,
                                                               posInfoWhite,
                                                               posInfoBlack,
                                                               moveList.Count,
                                                               iAlpha,
                                                               iBeta);
                iPermCount = alphaBetaRes.iPermCount;
                iMaxDepth  = alphaBetaRes.iMaxDepth;
                if (alphaBetaRes.movePosBest.StartPos != 255)
                {
                    if (bUseTransTable)
                    {
                        iCacheHit += TransTable.GetTransTable(0).CacheHit;
                    }
                    moveBest = alphaBetaRes.movePosBest;
                    bRetVal  = true;
                }
            }
            return(bRetVal);
        }
        /// <summary>
        /// Find the best move for a player using alpha-beta for a given depth
        /// </summary>
        /// <param name="board">            Chess board</param>
        /// <param name="searchMode">       Search mode</param>
        /// <param name="ePlayer">          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 board,
                                                      SearchMode searchMode,
                                                      ChessBoard.PlayerE ePlayer,
                                                      List <Move> 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;
            Move          move;
            AlphaBetaInfo abInfo;

            ChessBoard.RepeatResultE eResult;

            bTimeOut              = false;
            abInfo                = new AlphaBetaInfo();
            abInfo.m_arrMove      = new Move[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 (ePlayer == ChessBoard.PlayerE.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 = 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;
                }
                arrPoints[iIndex] = iPts;
                board.UndoMoveNoLog(move);
                if (iPts == Int32.MinValue)
                {
                    iRetVal  = iPts;
                    bTimeOut = true;
                }
                else
                {
                    if (iPts > iRetVal)
                    {
                        TraceSearch(iDepth, ePlayer, move, iPts);
                        iRetVal        = iPts;
                        iBestMoveIndex = iIndex;
                    }
                }
                iIndex++;
            }
            iPermCount = abInfo.m_iPermCount;
            return(iRetVal);
        }