/// <summary>
 /// Show the test result of a computer playing against a computer
 /// </summary>
 /// <param name="iGameCount">       Number of games played.</param>
 /// <param name="searchMode">       Search mode</param>
 /// <param name="stat">             Statistic.</param>
 /// <param name="iMethod1Win">      Number of games won by method #1</param>
 /// <param name="iMethod2Win">      Number of games won by method #2</param>
 private void TestShowResult(int iGameCount, SearchEngine.SearchMode searchMode, ComputerPlayingStat stat, int iMethod1Win, int iMethod2Win) {
     string  strMsg;
     string  strMethod1;
     string  strMethod2;
     int     iTimeMethod1;
     int     iTimeMethod2;
     
     strMethod1      = searchMode.m_boardEvaluationWhite.Name;
     strMethod2      = searchMode.m_boardEvaluationBlack.Name;
     
     iTimeMethod1    = (stat.m_iMethod1MoveCount == 0) ? 0 : stat.m_timeSpanMethod1.Milliseconds / stat.m_iMethod1MoveCount;
     iTimeMethod2    = (stat.m_iMethod2MoveCount == 0) ? 0 : stat.m_timeSpanMethod2.Milliseconds / stat.m_iMethod2MoveCount;
     strMsg          = iGameCount.ToString() + " game(s) played.\r\n" +
                       iMethod1Win.ToString() + " win(s) for method #1 (" + strMethod1 + "). Average time = " + iMethod1Win.ToString() + " ms per move.\r\n" + 
                       iMethod2Win.ToString() + " win(s) for method #2 (" + strMethod2 + "). Average time = " + iMethod2Win.ToString() + " ms per move.\r\n" + 
                       (iGameCount - iMethod1Win - iMethod2Win).ToString() + " draw(s).";
     MessageBox.Show(strMsg);
 }
        /// <summary>
        /// Tests the computer playing against itself. Can be called asynchronously by a secondary thread.
        /// </summary>
        /// <param name="iGameCount">       Number of games to play.</param>
        /// <param name="searchMode">       Search mode</param>
        private void TestComputerAgainstComputerAsync(int iGameCount, SearchEngine.SearchMode searchMode) {
            int                                                             iCount;
            Func<ChessBoard.MovePosS,int,int,int,ComputerPlayingStat,bool>  delPlayComputerMove = null;
            Action                                                          delResetBoard = null;
            Action                                                          delUnlockBoard;
            Action                                                          delSetPlayingMode;
            Action                                                          delShowResultDel;
            ChessBoard                                                      chessBoard;
            ChessBoard.MovePosS                                             move;
            int                                                             iPermCount;
            int                                                             iCacheHit;
            int                                                             iMaxDepth;
            int                                                             iGameIndex;
            int                                                             iMethod1Win = 0;
            int                                                             iMethod2Win = 0;
            DateTime                                                        dateTime;
            bool                                                            bMoveFound;
            bool                                                            bMultipleThread;
            bool                                                            bEven;
            bool                                                            bEndOfGame;
            IBoardEvaluation                                                boardEvaluation1;
            IBoardEvaluation                                                boardEvaluation2;
            ComputerPlayingStat                                             stat;

            stat             = new ComputerPlayingStat();
            bMultipleThread  = (searchMode.m_eThreadingMode == SearchEngine.SearchMode.ThreadingModeE.DifferentThreadForSearch ||
                                searchMode.m_eThreadingMode == SearchEngine.SearchMode.ThreadingModeE.OnePerProcessorForSearch);
            boardEvaluation1 = searchMode.m_boardEvaluationWhite;
            boardEvaluation2 = searchMode.m_boardEvaluationBlack;
            if (bMultipleThread) {
                delPlayComputerMove = (a1, a2, a3, a4, a5) => PlayComputerMove(false, MessageModeE.Silent, a1, a2, a3, a4, a5);
                delResetBoard       = () => ResetBoard();
            }
            iGameIndex = 0;
            while (iGameIndex < iGameCount && !stat.m_bUserCancel) {
                bEven = ((iGameIndex & 1) == 0);
                searchMode.m_boardEvaluationWhite   = bEven ? boardEvaluation1 : boardEvaluation2;
                searchMode.m_boardEvaluationBlack   = bEven ? boardEvaluation2 : boardEvaluation1;
                if (bMultipleThread) {
                    Dispatcher.Invoke(delResetBoard);
                } else {
                    ResetBoard();
                }
                iCount = 0;
                do {
                    chessBoard  = m_chessCtl.ChessBoard.Clone();
                    dateTime    = DateTime.Now;
                    bMoveFound  = m_chessCtl.FindBestMove(searchMode,
                                                          chessBoard,
                                                          out move,
                                                          out iPermCount,
                                                          out iCacheHit,
                                                          out iMaxDepth);
                    if (bMoveFound) {
                        if ((m_chessCtl.NextMoveColor == ChessBoard.PlayerColorE.White && bEven) ||
                            (m_chessCtl.NextMoveColor == ChessBoard.PlayerColorE.Black && !bEven)) {
                            stat.m_timeSpanMethod1 += DateTime.Now - dateTime;
                            stat.m_iMethod1MoveCount++;
                        } else {
                            stat.m_timeSpanMethod2 += DateTime.Now - dateTime;
                            stat.m_iMethod2MoveCount++;
                        }
                        if (bMultipleThread) {
                            bEndOfGame = (bool)Dispatcher.Invoke(delPlayComputerMove, new object[] { move, iPermCount, iMaxDepth, iCacheHit, stat } );
                        } else {
                            bEndOfGame = PlayComputerMove(false, MessageModeE.Silent, move, iPermCount, iMaxDepth, iCacheHit, stat);
                        }
                    } else {
                        bEndOfGame = true;
                    }
                    iCount++;
                } while (!bEndOfGame && PlayingMode == PlayingModeE.ComputerAgainstComputer && iCount < 250);
                if (PlayingMode != PlayingModeE.ComputerAgainstComputer) {
                    stat.m_bUserCancel = true;
                } else if (iCount < 250) {
                    if (stat.m_eResult == ChessBoard.MoveResultE.Mate) {
                        if ((m_chessCtl.NextMoveColor == ChessBoard.PlayerColorE.Black && bEven) ||
                            (m_chessCtl.NextMoveColor == ChessBoard.PlayerColorE.White && !bEven)) {
                            iMethod1Win++;
                        } else {
                            iMethod2Win++;
                        }
                    }
                }
                iGameIndex++;
            }
            searchMode.m_boardEvaluationWhite = boardEvaluation1;
            searchMode.m_boardEvaluationBlack = boardEvaluation2;
            if (bMultipleThread) {
                delSetPlayingMode   = () => SetPlayingMode(PlayingModeE.PlayerAgainstPlayer);
                delUnlockBoard      = () => UnlockBoard();
                delShowResultDel    = () => TestShowResult(iGameIndex, searchMode, stat, iMethod1Win, iMethod2Win);
                Dispatcher.Invoke(delShowResultDel);
                Dispatcher.Invoke(delSetPlayingMode);
                Dispatcher.Invoke(delUnlockBoard);
            } else {
                TestShowResult(iGameIndex, searchMode, stat, iMethod1Win, iMethod2Win);
                SetPlayingMode(PlayingModeE.PlayerAgainstPlayer);
                UnlockBoard();
            }
        }
 /// <summary>
 /// Play the computer move found by the search.
 /// </summary>
 /// <param name="bFlash">       true to flash moving position</param>
 /// <param name="eMessageMode"> Which message to show</param>
 /// <param name="move">         Best move</param>
 /// <param name="iPermCount">   Permutation count</param>
 /// <param name="iDepth">       Depth of the search</param>
 /// <param name="iCacheHit">    Number of moves found in the translation table cache</param>
 /// <param name="stat">         Playing stat. Can be null</param>
 /// <returns>
 /// true if end of game, false if not
 /// </returns>
 private bool PlayComputerMove(bool bFlash, MessageModeE eMessageMode, ChessBoard.MovePosS move, int iPermCount, int iDepth, int iCacheHit, ComputerPlayingStat stat) {
     bool                        bRetVal;
     ChessBoard.MoveResultE      eResult;
     ChessBoard.PlayerColorE     eColorToPlay;
                                 
     eColorToPlay    = m_chessCtl.NextMoveColor;
     eResult         = m_chessCtl.DoMove(move,
                                         bFlash,
                                         iPermCount,
                                         iDepth,
                                         iCacheHit);
     if (stat != null) {
         stat.m_eResult = eResult;
     }
     bRetVal = DisplayMessage(eResult, eMessageMode);
     return(bRetVal);
 }