/// <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); }