//*********************************************************     
        //
        /// <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;
            int                         iAttackedPos;
            int                         iAttackedPieces;
            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) {
                        if (ePlayerColor == ChessBoard.PlayerColorE.White) {
                            iAttackedPos    = abInfo.m_iAttackedPos;
                            iAttackedPieces = abInfo.m_iAttackedPieces;
                        } else {
                            iAttackedPos    = -abInfo.m_iAttackedPos;
                            iAttackedPieces = -abInfo.m_iAttackedPieces;
                        }
                        iRetVal = (ePlayerColor == ChessBoard.PlayerColorE.Black) ? -chessBoard.Points(abInfo.m_searchMode, ePlayerColor, iWhiteMoveCount - iBlackMoveCount, iAttackedPos, iAttackedPieces) : 
                                                                                     chessBoard.Points(abInfo.m_searchMode, ePlayerColor, iWhiteMoveCount - iBlackMoveCount, iAttackedPos, iAttackedPieces);
                        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 abInfo.m_iAttackedPos, out abInfo.m_iAttackedPieces);
                        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
                            }
                            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>
        /// 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>
 /// 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="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, 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_iAttackedPos       = 0;
     abInfo.m_iAttackedPieces    = 0;
     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 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);
        }