/// <summary>
 /// Class Ctor
 /// </summary>
 /// <param name="boardEvalUtil">        Board evaluation utility class</param>
 /// <param name="searchModeTemplate">   Search mode template</param>
 public frmTestBoardEval(BoardEvaluationUtil boardEvalUtil, SearchEngine.SearchMode searchModeTemplate) : this()
 {
     m_searchMode = new SearchEngine.SearchMode(boardEvalUtil.BoardEvaluators[0],
                                                boardEvalUtil.BoardEvaluators[0],
                                                SearchEngine.SearchMode.OptionE.UseAlphaBeta,
                                                searchModeTemplate.m_eThreadingMode,
                                                4,
                                                0,
                                                searchModeTemplate.m_eRandomMode);
     foreach (IBoardEvaluation boardEval in boardEvalUtil.BoardEvaluators)
     {
         comboBoxWhiteBEval.Items.Add(boardEval.Name);
         comboBoxBlackBEval.Items.Add(boardEval.Name);
     }
     comboBoxWhiteBEval.SelectedIndex = 0;
     comboBoxBlackBEval.SelectedIndex = (comboBoxBlackBEval.Items.Count == 0) ? 0 : 1;
     m_boardEvalUtil         = boardEvalUtil;
     plyCount2.Content       = plyCount.Value.ToString();
     gameCount2.Content      = gameCount.Value.ToString();
     plyCount.ValueChanged  += new RoutedPropertyChangedEventHandler <double>(plyCount_ValueChanged);
     gameCount.ValueChanged += new RoutedPropertyChangedEventHandler <double>(gameCount_ValueChanged);
 }
        /// <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="posInfo">          Information about pieces attacks</param>
        /// <param name="moveBest">         Best move found</param>
        /// <param name="iPermCount">       Nb of permutations evaluated</param>
        /// <param name="iCacheHit">        Nb of cache hit</param>
        /// <param name="iMaxDepth">        Maximum depth evaluated</param>
        /// <returns>
        /// true if a move has been found
        /// </returns>
        protected override bool FindBestMove(ChessBoard chessBoard,
                                             SearchEngine.SearchMode searchMode,
                                             ChessBoard.PlayerColorE ePlayerColor,
                                             List <ChessBoard.MovePosS> moveList,
                                             int[]                      arrIndex,
                                             ChessBoard.PosInfoS posInfo,
                                             ref ChessBoard.MovePosS moveBest,
                                             out int iPermCount,
                                             out int iCacheHit,
                                             out int iMaxDepth)
        {
            bool     bRetVal = false;
            DateTime dtTimeOut;
            int      iDepth;
            int      iPermCountAtLevel;

            iPermCount = 0;
            iCacheHit  = 0;
            if (searchMode.m_iSearchDepth == 0)
            {
                dtTimeOut = DateTime.Now + TimeSpan.FromSeconds(searchMode.m_iTimeOutInSec);
                iDepth    = 0;
                do
                {
                    bRetVal     = FindBestMoveUsingMinMaxAtDepth(chessBoard, searchMode, ePlayerColor, moveList, arrIndex, iDepth + 1, ref moveBest, out iPermCountAtLevel);
                    iPermCount += iPermCountAtLevel;
                    iDepth++;
                } while (DateTime.Now < dtTimeOut);
                iMaxDepth = iDepth;
            }
            else
            {
                iMaxDepth = searchMode.m_iSearchDepth;
                bRetVal   = FindBestMoveUsingMinMaxAtDepth(chessBoard, searchMode, ePlayerColor, moveList, arrIndex, iMaxDepth, ref moveBest, out iPermCount);
            }
            return(bRetVal);
        }
        /// <summary>
        /// Class constructor
        /// </summary>
        /// <param name="searchMode">       Actual search mode</param>
        /// <param name="boardEvalUtil">    Board Evaluation list</param>
        public frmSearchMode(SearchEngine.SearchMode searchMode, BoardEvaluationUtil boardEvalUtil) : this()
        {
            int iPos;

            m_searchMode    = searchMode;
            m_boardEvalUtil = boardEvalUtil;
            foreach (IBoardEvaluation boardEval in m_boardEvalUtil.BoardEvaluators)
            {
                iPos = comboBoxWhiteBEval.Items.Add(boardEval.Name);
                if (searchMode.m_boardEvaluationWhite == boardEval)
                {
                    comboBoxWhiteBEval.SelectedIndex = iPos;
                }
                iPos = comboBoxBlackBEval.Items.Add(boardEval.Name);
                if (searchMode.m_boardEvaluationBlack == boardEval)
                {
                    comboBoxBlackBEval.SelectedIndex = iPos;
                }
            }
            checkBoxTransTable.IsChecked = ((searchMode.m_eOption & SearchEngine.SearchMode.OptionE.UseTransTable) != 0);
            if (searchMode.m_eThreadingMode == SearchEngine.SearchMode.ThreadingModeE.OnePerProcessorForSearch)
            {
                radioButtonOnePerProc.IsChecked = true;
            }
            else if (searchMode.m_eThreadingMode == SearchEngine.SearchMode.ThreadingModeE.DifferentThreadForSearch)
            {
                radioButtonOneForUI.IsChecked = true;
            }
            else
            {
                radioButtonNoThread.IsChecked = true;
            }
            checkBoxBookOpening.IsChecked = ((searchMode.m_eOption & SearchEngine.SearchMode.OptionE.UseBook) != 0);
            if ((searchMode.m_eOption & SearchEngine.SearchMode.OptionE.UseAlphaBeta) != 0)
            {
                radioButtonAlphaBeta.IsChecked = true;
            }
            else
            {
                radioButtonMinMax.IsChecked  = true;
                checkBoxTransTable.IsEnabled = false;
            }
            if (searchMode.m_iSearchDepth == 0)
            {
                radioButtonAvgTime.IsChecked = true;
                textBoxTimeInSec.Text        = searchMode.m_iTimeOutInSec.ToString();
                plyCount.Value = 6;
            }
            else
            {
                if ((searchMode.m_eOption & SearchEngine.SearchMode.OptionE.UseIterativeDepthSearch) == SearchEngine.SearchMode.OptionE.UseIterativeDepthSearch)
                {
                    radioButtonFixDepthIterative.IsChecked = true;
                }
                else
                {
                    radioButtonFixDepth.IsChecked = true;
                }
                plyCount.Value        = searchMode.m_iSearchDepth;
                textBoxTimeInSec.Text = "15";
            }
            plyCount2.Content = plyCount.Value.ToString();
            switch (searchMode.m_eRandomMode)
            {
            case SearchEngine.SearchMode.RandomModeE.Off:
                radioButtonRndOff.IsChecked = true;
                break;

            case SearchEngine.SearchMode.RandomModeE.OnRepetitive:
                radioButtonRndOnRep.IsChecked = true;
                break;

            default:
                radioButtonRndOn.IsChecked = true;
                break;
            }
            textBoxTransSize.Text  = (TransTable.TranslationTableSize / 1000000 * 32).ToString();   // Roughly 32 bytes / entry
            plyCount.ValueChanged += new RoutedPropertyChangedEventHandler <double>(plyCount_ValueChanged);
        }
        /// <summary>
        /// Find the best move for a player using alpha-beta
        /// </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="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 chessBoard,
                                             SearchEngine.SearchMode searchMode,
                                             ChessBoard.PlayerColorE ePlayerColor,
                                             List <ChessBoard.MovePosS> moveList,
                                             int[]                      arrIndex,
                                             ChessBoard.PosInfoS posInfo,
                                             ref ChessBoard.MovePosS moveBest,
                                             out int iPermCount,
                                             out int iCacheHit,
                                             out int iMaxDepth)
        {
            bool bRetVal = false;
            bool bMultipleThread;
            bool bUseTransTable;

            ChessBoard[]                 arrChessBoard;
            Task <AlphaBetaResult>[]     taskArray;
            List <ChessBoard.MovePosS>[] 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 (ePlayerColor == ChessBoard.PlayerColorE.White)
            {
                posInfoWhite = posInfo;
                posInfoBlack = ChessBoard.s_posInfoNull;
            }
            else
            {
                posInfoWhite = ChessBoard.s_posInfoNull;
                posInfoBlack = posInfo;
            }
            searchMode.m_eOption &= ~SearchMode.OptionE.UseTransTable;
            bUseTransTable        = ((searchMode.m_eOption & SearchMode.OptionE.UseTransTable) != 0);
            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)
            {
                arrChessBoard = new ChessBoard[iThreadCount];
                arrMoveList   = new List <ChessBoard.MovePosS> [iThreadCount];
                taskArray     = new Task <AlphaBetaResult> [iThreadCount];
                for (int iIndex = 0; iIndex < iThreadCount; iIndex++)
                {
                    arrChessBoard[iIndex] = chessBoard.Clone();
                    arrMoveList[iIndex]   = new List <ChessBoard.MovePosS>(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(arrChessBoard[iStep],
                                                               searchMode,
                                                               ePlayerColor,
                                                               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 <ChessBoard.MovePosS> moveListTmp;

                chessBoardTmp = chessBoard.Clone();
                moveListTmp   = new List <ChessBoard.MovePosS>(moveList.Count);
                for (int iIndex = 0; iIndex < moveList.Count; iIndex++)
                {
                    moveListTmp.Add(moveList[arrIndex[iIndex]]);
                }
                alphaBetaRes = FindBestMoveUsingAlphaBetaAsync(chessBoardTmp,
                                                               searchMode,
                                                               ePlayerColor,
                                                               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);
        }