/// <summary> /// Reset the timer of both player /// </summary> /// <param name="ePlayerColor"> Playing color</param> /// <param name="lWhiteTicks"> White Ticks</param> /// <param name="lBlackTicks"> Black Ticks</param> public void ResetTo(ChessBoard.PlayerColorE ePlayerColor, long lWhiteTicks, long lBlackTicks) { m_ePlayerColor = ePlayerColor; m_timeSpanCommitedWhite = new TimeSpan(lWhiteTicks); m_timeSpanCommitedBlack = new TimeSpan(lBlackTicks); m_timerStart = DateTime.Now; }
//********************************************************* // /// <summary> /// Default constructor /// </summary> // //********************************************************* public frmPGNGamePicker() { InitializeComponent(); m_pgnUtil = new PgnUtil(); m_strSelectedGame = null; m_eStartingColor = ChessBoard.PlayerColorE.White; m_chessBoardStarting = null; }
/// <summary> /// Find a castle move /// </summary> /// <param name="ePlayerColor"> Color moving</param> /// <param name="bShortCastling"> true for short, false for long</param> /// <param name="iTruncated"> Truncated count</param> /// <param name="strMove"> Move</param> /// <param name="movePos"> Returned moved if found</param> /// <returns> /// Moving position or -1 if error /// </returns> private int FindCastling(ChessBoard.PlayerColorE ePlayerColor, bool bShortCastling, ref int iTruncated, string strMove, ref ChessBoard.MovePosS movePos) { int iRetVal = -1; int iWantedDelta; int iDelta; List <ChessBoard.MovePosS> arrMovePos; arrMovePos = m_chessBoard.EnumMoveList(ePlayerColor); iWantedDelta = bShortCastling ? 2 : -2; foreach (ChessBoard.MovePosS move in arrMovePos) { if ((move.Type & ChessBoard.MoveTypeE.MoveTypeMask) == ChessBoard.MoveTypeE.Castle) { iDelta = ((int)move.StartPos & 7) - ((int)move.EndPos & 7); if (iDelta == iWantedDelta) { iRetVal = (int)move.StartPos + ((int)move.EndPos << 8); movePos = move; m_chessBoard.DoMove(move); } } } if (iRetVal == -1) { if (m_bDiagnose) { throw new PgnParserException("Unable to find compatible move - " + strMove, GetCodeInError()); } iTruncated++; } return(iRetVal); }
/// <summary> /// Debugging routine /// </summary> /// <param name="iDepth"> Actual search depth</param> /// <param name="ePlayerColor"> Color doing the move</param> /// <param name="move"> Move</param> /// <param name="iPts"> Points for this move</param> protected void TraceSearch(int iDepth, ChessBoard.PlayerColorE ePlayerColor, ChessBoard.MovePosS move, int iPts) { if (m_trace != null) { m_trace.TraceSearch(iDepth, ePlayerColor, move, iPts); } }
/// <summary> /// Parse a single PGN/FEN game /// </summary> /// <param name="strText"> PGN Text</param> /// <param name="bIgnoreMoveListIfFEN"> Ignore the move list if FEN is found</param> /// <param name="listMovePos"> Returned the list of move if not null</param> /// <param name="iSkip"> Number of games skipped</param> /// <param name="iTruncated"> Number of games truncated</param> /// <param name="chessBoardStarting"> Starting board setting. If null, standard board used.</param> /// <param name="eStartingColor"> Starting color</param> /// <param name="strWhitePlayerName"> White pieces player name</param> /// <param name="strBlackPlayerName"> Black pieces player name</param> /// <param name="eWhitePlayerType"> White pieces player type</param> /// <param name="eBlackPlayerType"> Black pieces player type</param> /// <param name="spanWhitePlayer"> Time span for white player</param> /// <param name="spanBlackPlayer"> Time span for black player</param> /// <returns> /// false if the board specified by FEN is invalid. /// </returns> public bool ParseSingle(string strText, bool bIgnoreMoveListIfFEN, List <ChessBoard.MovePosS> listMovePos, out int iSkip, out int iTruncated, out ChessBoard chessBoardStarting, out ChessBoard.PlayerColorE eStartingColor, out string strWhitePlayerName, out string strBlackPlayerName, out PlayerTypeE eWhitePlayerType, out PlayerTypeE eBlackPlayerType, out TimeSpan spanWhitePlayer, out TimeSpan spanBlackPlayer) { bool bRetVal = true; int[] piMoveList; Dictionary <string, string> attrs; listMovePos.Clear(); chessBoardStarting = null; eStartingColor = ChessBoard.PlayerColorE.White; strWhitePlayerName = "Player 1"; strBlackPlayerName = "Player 2"; eWhitePlayerType = PlayerTypeE.Human; eBlackPlayerType = PlayerTypeE.Human; spanWhitePlayer = TimeSpan.Zero; spanBlackPlayer = TimeSpan.Zero; m_strText = strText; m_iPos = 0; m_iSize = strText.Length; iSkip = 0; iTruncated = 0; if (!ParseIfFENLine(strText, out eStartingColor, out chessBoardStarting)) { SkipAltMoveAndRemark(); if (PeekChr() != '\0') { m_iStartPos = m_iPos; bRetVal = ParseNextMoveList(bIgnoreMoveListIfFEN, out piMoveList, out attrs, listMovePos, ref iSkip, ref iTruncated, out chessBoardStarting, out eStartingColor, out strWhitePlayerName, out strBlackPlayerName, out eWhitePlayerType, out eBlackPlayerType, out spanWhitePlayer, out spanBlackPlayer); } } return(bRetVal); }
/// <summary> /// Parse if its a FEN line. FEN have only one line and must have 7 '/' which is highly improbable for a PGN text /// </summary> /// <param name="strText"> Text</param> /// <param name="eStartingColor"> Return the color to move</param> /// <param name="chessBoard"> Return the chessboard represent by this FEN</param> /// <returns> /// true if its a FEN text, false if not /// </returns> private bool ParseIfFENLine(string strText, out ChessBoard.PlayerColorE eStartingColor, out ChessBoard chessBoard) { bool bRetVal = false; eStartingColor = ChessBoard.PlayerColorE.White; chessBoard = null; strText = strText.TrimEnd('\r', '\n').Trim(); if (strText.Split('\r').Length == 1) { bRetVal = ParseFEN(strText, out eStartingColor, out chessBoard); } return(bRetVal); }
/// <summary> /// Parse FEN definition into a board representation /// </summary> /// <param name="strFEN"> FEN</param> /// <param name="eStartingColor"> Return the color to move</param> /// <param name="chessBoard"> Return the chess board represented by this FEN</param> /// <returns> /// true if succeed, false if failed /// </returns> private bool ParseFEN(string strFEN, out ChessBoard.PlayerColorE eStartingColor, out ChessBoard chessBoard) { bool bRetVal; ChessBoard.BoardStateMaskE eBoardMask; int iEnPassant; m_chessBoard.OpenDesignMode(); bRetVal = ParseFEN(strFEN, out eStartingColor, out eBoardMask, out iEnPassant); m_chessBoard.CloseDesignMode(eStartingColor, eBoardMask, iEnPassant); chessBoard = bRetVal ? m_chessBoard.Clone() : null; return(bRetVal); }
/// <summary> /// Convert a list of PGN positions into a moving positions /// </summary> /// <param name="eColorToPlay"> Color to play</param> /// <param name="arrRawMove"> Array of PGN moves</param> /// <param name="piMoveList"> Returned array of moving position</param> /// <param name="listMovePos"> Returned the list of move if not null</param> /// <param name="iSkip"> Skipped count</param> /// <param name="iTruncated"> Truncated count</param> private void CnvRawMoveToPosMove(ChessBoard.PlayerColorE eColorToPlay, List <string> arrRawMove, out int[] piMoveList, List <ChessBoard.MovePosS> listMovePos, ref int iSkip, ref int iTruncated) { List <int> arrMoveList; ChessBoard.MovePosS movePos; int iPos; movePos = new ChessBoard.MovePosS(); movePos.StartPos = 0; movePos.EndPos = 0; movePos.Type = ChessBoard.MoveTypeE.Normal; arrMoveList = new List <int>(256); try { foreach (string strMove in arrRawMove) { if (strMove == "1-0" || strMove == "0-1" || strMove == "1/2-1/2" || strMove == "*" || strMove[0] == '(') { break; } else if (strMove == "..") { iSkip++; break; } CnvRawMoveToPosMove(eColorToPlay, strMove, out iPos, ref iTruncated, ref movePos); if (iPos != -1) { arrMoveList.Add(iPos); if (listMovePos != null) { listMovePos.Add(movePos); } eColorToPlay = (eColorToPlay == ChessBoard.PlayerColorE.Black) ? ChessBoard.PlayerColorE.White : ChessBoard.PlayerColorE.Black; } else { break; } } } catch (PgnParserException ex) { ex.MoveList = arrMoveList.ToArray(); MessageBox.Show(ex.ToString()); throw; } piMoveList = arrMoveList.ToArray(); }
public void PointsTest() { ChessBoard target = new ChessBoard(); // TODO: инициализация подходящего значения SearchEngine.SearchMode searchMode = null; // TODO: инициализация подходящего значения ChessBoard.PlayerColorE ePlayerToPlay = new ChessBoard.PlayerColorE(); // TODO: инициализация подходящего значения int iDepth = 0; // TODO: инициализация подходящего значения int iMoveCountDelta = 0; // TODO: инициализация подходящего значения ChessBoard.PosInfoS posInfoWhite = new ChessBoard.PosInfoS(); // TODO: инициализация подходящего значения ChessBoard.PosInfoS posInfoBlack = new ChessBoard.PosInfoS(); // TODO: инициализация подходящего значения int expected = 0; // TODO: инициализация подходящего значения int actual; actual = target.Points(searchMode, ePlayerToPlay, iDepth, iMoveCountDelta, posInfoWhite, posInfoBlack); Assert.AreEqual(expected, actual); Assert.Inconclusive("Проверьте правильность этого метода теста."); }
/// <summary> /// Create a new game using the specified list of moves /// </summary> /// <param name="chessBoardStarting"> Starting board or null if standard board</param> /// <param name="listMove"> List of moves</param> /// <param name="eNextMoveColor"> Color starting to play</param> /// <param name="strWhitePlayerName"> Name of the player playing white pieces</param> /// <param name="strBlackPlayerName"> Name of the player playing black pieces</param> /// <param name="eWhitePlayerType"> Type of player playing white pieces</param> /// <param name="eBlackPlayerType"> Type of player playing black pieces</param> /// <param name="spanPlayerWhite"> Timer for white</param> /// <param name="spanPlayerBlack"> Timer for black</param> public override void CreateGameFromMove(ChessBoard chessBoardStarting, List <ChessBoard.MovePosS> listMove, ChessBoard.PlayerColorE eNextMoveColor, string strWhitePlayerName, string strBlackPlayerName, PgnParser.PlayerTypeE eWhitePlayerType, PgnParser.PlayerTypeE eBlackPlayerType, TimeSpan spanPlayerWhite, TimeSpan spanPlayerBlack) { base.CreateGameFromMove(chessBoardStarting, listMove, eNextMoveColor, strWhitePlayerName, strBlackPlayerName, eWhitePlayerType, eBlackPlayerType, spanPlayerWhite, spanPlayerBlack); if (eWhitePlayerType == PgnParser.PlayerTypeE.Program) { if (eBlackPlayerType == PgnParser.PlayerTypeE.Program) { Father.PlayingMode = MainWindow.PlayingModeE.ComputerAgainstComputer; } else { Father.PlayingMode = MainWindow.PlayingModeE.PlayerAgainstComputer; Father.m_eComputerPlayingColor = ChessBoard.PlayerColorE.White; } } else if (eBlackPlayerType == PgnParser.PlayerTypeE.Program) { Father.PlayingMode = MainWindow.PlayingModeE.PlayerAgainstComputer; Father.m_eComputerPlayingColor = ChessBoard.PlayerColorE.Black; } else { Father.PlayingMode = MainWindow.PlayingModeE.PlayerAgainstPlayer; } Father.SetCmdState(); Father.m_chessCtl.CommentBoard.SetPlayers(strWhitePlayerName + " [White] - " + strBlackPlayerName + " [Black]"); }
public void ParseFENTest() { PgnParser_Accessor target = new PgnParser_Accessor(); string strFEN = ""; ChessBoard.PlayerColorE eColorToMove; ChessBoard.BoardStateMaskE eBoardStateMask; int iEnPassant; bool bexpected = true; ChessBoard.PlayerColorE coloExpected = ChessBoard.PlayerColorE.Black; ChessBoard.BoardStateMaskE MaskoExpected = ChessBoard.BoardStateMaskE.BlackToMove; int iExpected = 0; bool bactual = target.ParseFEN(strFEN, out eColorToMove, out eBoardStateMask, out iEnPassant); // Сбой при создании частного метода доступа для "Microsoft.VisualStudio.TestTools.TypesAndSymbols.Assembly" Assert.Inconclusive("Сбой при создании частного метода доступа для \"Microsoft.VisualStudio.TestTools.T" + "ypesAndSymbols.Assembly\""); }
/// <summary> /// Find a move using the specification /// </summary> /// <param name="ePlayerColor"> Color moving</param> /// <param name="ePiece"> Piece moving</param> /// <param name="iStartCol"> Starting column of the move or -1 if not specified</param> /// <param name="iStartRow"> Starting row of the move or -1 if not specified</param> /// <param name="iEndPos"> Ending position of the move</param> /// <param name="eMoveType"> Type of move. Use for discriminating between different pawn promotion.</param> /// <param name="strMove"> Move</param> /// <param name="iTruncated"> Truncated count</param> /// <param name="movePos"> Move position</param> /// <returns> /// Moving position or -1 if error /// </returns> private int FindPieceMove(ChessBoard.PlayerColorE ePlayerColor, ChessBoard.PieceE ePiece, int iStartCol, int iStartRow, int iEndPos, ChessBoard.MoveTypeE eMoveType, string strMove, ref int iTruncated, ref ChessBoard.MovePosS movePos) { int iRetVal = -1; List <ChessBoard.MovePosS> arrMovePos; int iCol; int iRow; ePiece = ePiece | ((ePlayerColor == ChessBoard.PlayerColorE.Black) ? ChessBoard.PieceE.Black : ChessBoard.PieceE.White); arrMovePos = m_chessBoard.EnumMoveList(ePlayerColor); foreach (ChessBoard.MovePosS move in arrMovePos) { if ((int)move.EndPos == iEndPos && m_chessBoard[(int)move.StartPos] == ePiece) { if (eMoveType == ChessBoard.MoveTypeE.Normal || (move.Type & ChessBoard.MoveTypeE.MoveTypeMask) == eMoveType) { iCol = (int)move.StartPos & 7; iRow = (int)move.StartPos >> 3; if ((iStartCol == -1 || iStartCol == iCol) && (iStartRow == -1 || iStartRow == iRow)) { if (iRetVal != -1) { throw new PgnParserException("More then one piece found for this move - " + strMove, GetCodeInError()); } movePos = move; iRetVal = (int)move.StartPos + ((int)move.EndPos << 8); m_chessBoard.DoMove(move); } } } } if (iRetVal == -1) { if (m_bDiagnose) { throw new PgnParserException("Unable to find compatible move - " + strMove, GetCodeInError()); } iTruncated++; } return(iRetVal); }
/// <summary> /// Find the best move for a player using a specific method /// </summary> /// <param name="chessBoard"> Chess board</param> /// <param name="searchMode"> Search mode</param> /// <param name="ePlayerColor"> Color doing the move</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 reached</param> /// <returns> /// true if a move has been found /// </returns> public bool FindBestMove(ChessBoard chessBoard, SearchMode searchMode, ChessBoard.PlayerColorE ePlayerColor, out ChessBoard.MovePosS moveBest, out int iPermCount, out int iCacheHit, out int iMaxDepth) { bool bRetVal = false; List <ChessBoard.MovePosS> moveList; int[] arrIndex; int iSwapIndex; int iTmp; Random rnd; ChessBoard.PosInfoS posInfo; iCacheHit = 0; moveList = chessBoard.EnumMoveList(ePlayerColor, true, out posInfo); arrIndex = new int[moveList.Count]; m_bCancelSearch = false; for (int iIndex = 0; iIndex < moveList.Count; iIndex++) { arrIndex[iIndex] = iIndex; } if (searchMode.m_eRandomMode != SearchMode.RandomModeE.Off) { rnd = (searchMode.m_eRandomMode == SearchMode.RandomModeE.OnRepetitive) ? m_rndRep : m_rnd; for (int iIndex = 0; iIndex < moveList.Count; iIndex++) { iSwapIndex = rnd.Next(moveList.Count); iTmp = arrIndex[iIndex]; arrIndex[iIndex] = arrIndex[iSwapIndex]; arrIndex[iSwapIndex] = iTmp; } } moveBest.StartPos = 0; moveBest.EndPos = 0; moveBest.OriginalPiece = ChessBoard.PieceE.None; moveBest.Type = ChessBoard.MoveTypeE.Normal; bRetVal = FindBestMove(chessBoard, searchMode, ePlayerColor, moveList, arrIndex, posInfo, ref moveBest, out iPermCount, out iCacheHit, out iMaxDepth); return(bRetVal); }
/// <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> /// Reset the timer of both player /// </summary> /// <param name="ePlayerColor"> Playing color</param> /// <param name="lWhiteTicks"> White Ticks</param> /// <param name="lBlackTicks"> Black Ticks</param> // //********************************************************* public void ResetTo(ChessBoard.PlayerColorE ePlayerColor, long lWhiteTicks, long lBlackTicks) { m_ePlayerColor = ePlayerColor; m_timeSpanCommitedWhite = new TimeSpan(lWhiteTicks); m_timeSpanCommitedBlack = new TimeSpan(lBlackTicks); m_timerStart = DateTime.Now; }
/// <summary> /// Class Ctor /// </summary> public MainWindow() { SrcChess2.Properties.Settings settings; ExecutedRoutedEventHandler onExecutedCmd; CanExecuteRoutedEventHandler onCanExecuteCmd; PieceSet pieceSet; InitializeComponent(); settings = SrcChess2.Properties.Settings.Default; m_listPieceSet = PieceSetStandard.LoadPieceSetFromResource(); pieceSet = m_listPieceSet[settings.PieceSet]; m_chessCtl.Father = this; m_chessCtl.LiteCellColor = NameToColor(settings.LiteCellColor); m_chessCtl.DarkCellColor = NameToColor(settings.DarkCellColor); m_chessCtl.WhitePieceColor = NameToColor(settings.WhitePieceColor); m_chessCtl.BlackPieceColor = NameToColor(settings.BlackPieceColor); m_colorBackground = NameToColor(settings.BackgroundColor); Background = new SolidColorBrush(m_colorBackground); m_boardEvalUtil = new BoardEvaluationUtil(); SetSearchModeFromSetting(settings); m_chessCtl.UpdateCmdState += new EventHandler(m_chessCtl_UpdateCmdState); PlayingMode = PlayingModeE.PlayerAgainstComputer; m_eComputerPlayingColor = ChessBoard.PlayerColorE.Black; m_lostPieceBlack.ChessBoardControl = m_chessCtl; m_lostPieceBlack.Color = true; m_lostPieceWhite.ChessBoardControl = m_chessCtl; m_lostPieceWhite.Color = false; m_moveViewer.NewMoveSelected += new MoveViewer.NewMoveSelectedHandler(m_moveViewer_NewMoveSelected); m_moveViewer.DisplayMode = (settings.MoveNotation == 0) ? MoveViewer.DisplayModeE.MovePos : MoveViewer.DisplayModeE.PGN; m_chessCtl.MoveListUI = this; m_chessCtl.MoveSelected += new ChessBoardControl.MoveSelectedEventHandler(m_chessCtl_MoveSelected); m_chessCtl.QueryPiece += new ChessBoardControl.QueryPieceEventHandler(m_chessCtl_QueryPiece); m_chessCtl.QueryPawnPromotionType += new ChessBoardControl.QueryPawnPromotionTypeEventHandler(m_chessCtl_QueryPawnPromotionType); m_bSecondThreadBusy = false; m_dispatcherTimer = new DispatcherTimer(TimeSpan.FromSeconds(1), DispatcherPriority.Normal, new EventHandler(dispatcherTimer_Tick), Dispatcher); m_dispatcherTimer.Start(); SetCmdState(); ShowSearchMode(); mnuOptionFlashPiece.IsChecked = settings.FlashPiece; mnuOptionPGNNotation.IsChecked = (m_moveViewer.DisplayMode == MoveViewer.DisplayModeE.PGN); PieceSet = pieceSet; onExecutedCmd = new ExecutedRoutedEventHandler(OnExecutedCmd); onCanExecuteCmd = new CanExecuteRoutedEventHandler(OnCanExecuteCmd); foreach (RoutedUICommand cmd in m_arrCommands) { CommandBindings.Add(new CommandBinding(cmd, onExecutedCmd, onCanExecuteCmd)); } }
/// <summary> /// Minimum/maximum depth first search /// </summary> /// <param name="chessBoard"> Chess board</param> /// <param name="searchMode"> Search mode</param> /// <param name="ePlayerColor"> Color doing the move</param> /// <param name="iDepth"> Actual search depth</param> /// <param name="iWhiteMoveCount"> Number of moves white can do</param> /// <param name="iBlackMoveCount"> Number of moves black can do</param> /// <param name="iPermCount"> Total permutation evaluated</param> /// <returns> /// Points to give for this move /// </returns> private int MinMax(ChessBoard chessBoard, SearchMode searchMode, ChessBoard.PlayerColorE ePlayerColor, int iDepth, int iWhiteMoveCount, int iBlackMoveCount, ref int iPermCount) { int iRetVal; int iMoveCount; int iPts; List <ChessBoard.MovePosS> moveList; ChessBoard.RepeatResultE eResult; if (chessBoard.IsEnoughPieceForCheckMate()) { if (iDepth == 0 || m_bCancelSearch) { iRetVal = (ePlayerColor == ChessBoard.PlayerColorE.Black) ? -chessBoard.Points(searchMode, ePlayerColor, 0, iWhiteMoveCount - iBlackMoveCount, ChessBoard.s_posInfoNull, ChessBoard.s_posInfoNull) : chessBoard.Points(searchMode, ePlayerColor, 0, iWhiteMoveCount - iBlackMoveCount, ChessBoard.s_posInfoNull, ChessBoard.s_posInfoNull); iPermCount++; } else { moveList = chessBoard.EnumMoveList(ePlayerColor); 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 } } else { iRetVal = Int32.MinValue; foreach (ChessBoard.MovePosS move in moveList) { eResult = chessBoard.DoMoveNoLog(move); if (eResult == ChessBoard.RepeatResultE.NoRepeat) { iPts = -MinMax(chessBoard, searchMode, (ePlayerColor == ChessBoard.PlayerColorE.Black) ? ChessBoard.PlayerColorE.White : ChessBoard.PlayerColorE.Black, iDepth - 1, iWhiteMoveCount, iBlackMoveCount, ref iPermCount); } else { iPts = 0; } chessBoard.UndoMoveNoLog(move); if (iPts > iRetVal) { iRetVal = iPts; } } } } } else { iRetVal = 0; } return(iRetVal); }
/// <summary> /// Parse FEN definition into a board representation /// </summary> /// <param name="strFEN"> FEN</param> /// <param name="eColorToMove"> Return the color to move</param> /// <param name="eBoardStateMask"> Return the mask of castling info</param> /// <param name="iEnPassant"> Return the en passant position or 0 if none</param> /// <returns> /// true if succeed, false if failed /// </returns> private bool ParseFEN(string strFEN, out ChessBoard.PlayerColorE eColorToMove, out ChessBoard.BoardStateMaskE eBoardStateMask, out int iEnPassant) { bool bRetVal = true; string[] arrCmd; string[] arrRow; string strCmd; int iPos; int iLinePos; int iBlankCount; ChessBoard.PieceE ePiece; eBoardStateMask = (ChessBoard.BoardStateMaskE) 0; iEnPassant = 0; eColorToMove = ChessBoard.PlayerColorE.White; arrCmd = strFEN.Split(' '); if (arrCmd.Length != 6) { bRetVal = false; } else { arrRow = arrCmd[0].Split('/'); if (arrRow.Length != 8) { bRetVal = false; } else { iPos = 63; foreach (string strRow in arrRow) { iLinePos = 0; foreach (char cChr in strRow) { ePiece = ChessBoard.PieceE.None; switch (cChr) { case 'P': ePiece = ChessBoard.PieceE.Pawn | ChessBoard.PieceE.White; break; case 'N': ePiece = ChessBoard.PieceE.Knight | ChessBoard.PieceE.White; break; case 'B': ePiece = ChessBoard.PieceE.Bishop | ChessBoard.PieceE.White; break; case 'R': ePiece = ChessBoard.PieceE.Rook | ChessBoard.PieceE.White; break; case 'Q': ePiece = ChessBoard.PieceE.Queen | ChessBoard.PieceE.White; break; case 'K': ePiece = ChessBoard.PieceE.King | ChessBoard.PieceE.White; break; case 'p': ePiece = ChessBoard.PieceE.Pawn | ChessBoard.PieceE.Black; break; case 'n': ePiece = ChessBoard.PieceE.Knight | ChessBoard.PieceE.Black; break; case 'b': ePiece = ChessBoard.PieceE.Bishop | ChessBoard.PieceE.Black; break; case 'r': ePiece = ChessBoard.PieceE.Rook | ChessBoard.PieceE.Black; break; case 'q': ePiece = ChessBoard.PieceE.Queen | ChessBoard.PieceE.Black; break; case 'k': ePiece = ChessBoard.PieceE.King | ChessBoard.PieceE.Black; break; default: if (cChr >= '1' && cChr <= '8') { iBlankCount = Int32.Parse(cChr.ToString()); if (iBlankCount + iLinePos <= 8) { for (int iIndex = 0; iIndex < iBlankCount; iIndex++) { m_chessBoard[iPos--] = ChessBoard.PieceE.None; } iLinePos += iBlankCount; } } else { bRetVal = false; } break; } if (bRetVal && ePiece != ChessBoard.PieceE.None) { if (iLinePos < 8) { m_chessBoard[iPos--] = ePiece; iLinePos++; } else { bRetVal = false; } } } if (iLinePos != 8) { bRetVal = false; } } if (bRetVal) { strCmd = arrCmd[1]; if (strCmd == "w") { eColorToMove = ChessBoard.PlayerColorE.White; } else if (strCmd == "b") { eColorToMove = ChessBoard.PlayerColorE.Black; } else { bRetVal = false; } strCmd = arrCmd[2]; if (strCmd != "-") { for (int iIndex = 0; iIndex < strCmd.Length; iIndex++) { switch (strCmd[iIndex]) { case 'K': eBoardStateMask |= ChessBoard.BoardStateMaskE.WRCastling; break; case 'Q': eBoardStateMask |= ChessBoard.BoardStateMaskE.WLCastling; break; case 'k': eBoardStateMask |= ChessBoard.BoardStateMaskE.BRCastling; break; case 'q': eBoardStateMask |= ChessBoard.BoardStateMaskE.BLCastling; break; } } } strCmd = arrCmd[3]; if (strCmd == "-") { iEnPassant = 0; } else { iEnPassant = PgnUtil.GetSquareIDFromPGN(strCmd); if (iEnPassant == -1) { iEnPassant = 0; } } } } } return(bRetVal); }
//********************************************************* // /// <summary> /// Form constructor /// </summary> // //********************************************************* public frmChessBoard() { SrcChess.Properties.Settings settings; SearchEngine.SearchMode.OptionE eOption; SearchEngine.SearchMode.ThreadingModeE eThreadingMode; int iTransTableSize; IBoardEvaluation boardEvalWhite; IBoardEvaluation boardEvalBlack; ChessControl.ChessControlColorInfo colorInfo; InitializeComponent(); settings = SrcChess.Properties.Settings.Default; colorInfo.m_colBlackPiece = NameToColor(settings.BlackPieceColor); colorInfo.m_colWhitePiece = NameToColor(settings.WhitePieceColor); colorInfo.m_colLiteCase = NameToColor(settings.LiteCaseColor); colorInfo.m_colDarkCase = NameToColor(settings.DarkCaseColor); iTransTableSize = (settings.TransTableSize < 5 || settings.TransTableSize > 256) ? 32 : settings.TransTableSize; TransTable.TranslationTableSize = iTransTableSize / 32 * 1000000; eOption = settings.UseAlphaBeta ? SearchEngine.SearchMode.OptionE.UseAlphaBeta : SearchEngine.SearchMode.OptionE.UseMinMax; if (settings.UseBook) { eOption |= SearchEngine.SearchMode.OptionE.UseBook; } if (settings.UseTransTable) { eOption |= SearchEngine.SearchMode.OptionE.UseTransTable; } if (settings.UsePlyCountIterative) { eOption |= SearchEngine.SearchMode.OptionE.UseIterativeDepthSearch; } switch(settings.UseThread) { case 0: eThreadingMode = SearchEngine.SearchMode.ThreadingModeE.Off; break; case 1: eThreadingMode = SearchEngine.SearchMode.ThreadingModeE.DifferentThreadForSearch; break; default: eThreadingMode = SearchEngine.SearchMode.ThreadingModeE.OnePerProcessorForSearch; break; } m_boardEvalUtil = new BoardEvaluationUtil(); boardEvalWhite = m_boardEvalUtil.FindBoardEvaluator(settings.WhiteBoardEval); if (boardEvalWhite == null) { boardEvalWhite = m_boardEvalUtil.BoardEvaluators[0]; } boardEvalBlack = m_boardEvalUtil.FindBoardEvaluator(settings.BlackBoardEval); if (boardEvalBlack == null) { boardEvalBlack = m_boardEvalUtil.BoardEvaluators[0]; } m_searchMode = new SearchEngine.SearchMode(boardEvalWhite, boardEvalBlack, eOption, eThreadingMode, settings.UsePlyCount | settings.UsePlyCountIterative ? ((settings.PlyCount > 1 && settings.PlyCount < 9) ? settings.PlyCount : 6) : 0, // Maximum depth settings.UsePlyCount | settings.UsePlyCountIterative ? 0 : (settings.AverageTime > 0 && settings.AverageTime < 1000) ? settings.AverageTime : 15, (settings.RandomMode >= 0 && settings.RandomMode <= 2) ? (SearchEngine.SearchMode.RandomModeE)settings.RandomMode : SearchEngine.SearchMode.RandomModeE.On); // Average time m_chessCtl = new LocalChessControl(); m_chessCtl.Location = new Point(0, 0); m_chessCtl.Size = new Size(60 * 9, 60 * 9); m_chessCtl.UpdateCmdState += new EventHandler(m_chessCtl_UpdateCmdState); m_chessCtl.Father = this; m_chessCtl.ColorInfo = colorInfo; panelBoard.Controls.Add(m_chessCtl); PlayingMode = PlayingModeE.PlayerAgainstComputer; m_eComputerPlayingColor = ChessBoard.PlayerColorE.Black; m_lostPieceBlack = new LostPiecesControl(); m_lostPieceBlack.Location = new Point(0,0); m_lostPieceBlack.Size = new Size(200, 200); m_lostPieceBlack.Dock = DockStyle.Fill; m_lostPieceBlack.ChessControl = m_chessCtl; m_lostPieceBlack.Color = true; panelBlackLostPiece.Controls.Add(m_lostPieceBlack); m_lostPieceWhite = new LostPiecesControl(); m_lostPieceWhite.Location = new Point(0,0); m_lostPieceWhite.Size = new Size(200, 200); m_lostPieceWhite.Dock = DockStyle.Fill; m_lostPieceWhite.ChessControl = m_chessCtl; m_lostPieceWhite.Color = false; panelWhiteLostPiece.Controls.Add(m_lostPieceWhite); m_moveViewer = new MoveViewer(); m_moveViewer.Location = new Point(0,0); m_moveViewer.Size = panelMoveList.Size; m_moveViewer.Dock = DockStyle.Fill; m_moveViewer.NewMoveSelected += new MoveViewer.NewMoveSelectedHandler(m_moveViewer_NewMoveSelected); m_moveViewer.DisplayMode = (settings.MoveNotation == 0) ? MoveViewer.DisplayModeE.MovePos : MoveViewer.DisplayModeE.PGN; panelMoveList.Controls.Add(m_moveViewer); m_chessCtl.MoveListUI = this; m_chessCtl.MoveSelected += new ChessControl.MoveSelectedEventHandler(m_chessCtl_MoveSelected); m_chessCtl.QueryPiece += new ChessControl.QueryPieceEventHandler(m_chessCtl_QueryPiece); m_chessCtl.QueryPawnPromotionType += new ChessControl.QueryPawnPromotionTypeEventHandler(m_chessCtl_QueryPawnPromotionType); m_bSecondThreadBusy = false; timer1.Tick += new EventHandler(timer1_Tick); timer1.Start(); ResizeChessCtl(); SetCmdState(); ShowSearchMode(); flashPieceToolStripMenuItem.Checked = settings.FlashPiece; pgnNotationToolStripMenuItem.Checked = (m_moveViewer.DisplayMode == MoveViewer.DisplayModeE.PGN); }
//********************************************************* // /// <summary> /// Revert the board so the computer play the actual user pieces /// </summary> /// <param name="sender"> Sender object</param> /// <param name="e"> Event handler</param> // //********************************************************* private void revertBoardToolStripMenuItem_Click(object sender, EventArgs e) { m_eComputerPlayingColor = (m_eComputerPlayingColor == ChessBoard.PlayerColorE.Black) ? ChessBoard.PlayerColorE.White : ChessBoard.PlayerColorE.Black; CheckIfComputerMustPlay(); }
/// <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="iDepth"> Maximum depth</param> /// <param name="moveBest"> Best move found</param> /// <param name="iPermCount"> Total permutation evaluated</param> /// <returns> /// true if a move has been found /// </returns> private bool FindBestMoveUsingMinMaxAtDepth(ChessBoard chessBoard, SearchMode searchMode, ChessBoard.PlayerColorE ePlayerColor, List <ChessBoard.MovePosS> moveList, int[] arrIndex, int iDepth, ref ChessBoard.MovePosS moveBest, out int iPermCount) { bool bRetVal = false; ChessBoard.MovePosS move; int iPts; int iWhiteMoveCount; int iBlackMoveCount; int iBestPts; ChessBoard.RepeatResultE eResult; iPermCount = 0; iBestPts = Int32.MinValue; if (ePlayerColor == ChessBoard.PlayerColorE.White) { iWhiteMoveCount = moveList.Count; iBlackMoveCount = 0; } else { iWhiteMoveCount = 0; iBlackMoveCount = moveList.Count; } foreach (int iIndex in arrIndex) { move = moveList[iIndex]; eResult = chessBoard.DoMoveNoLog(move); if (eResult == ChessBoard.RepeatResultE.NoRepeat) { iPts = -MinMax(chessBoard, searchMode, (ePlayerColor == ChessBoard.PlayerColorE.Black) ? ChessBoard.PlayerColorE.White : ChessBoard.PlayerColorE.Black, iDepth - 1, iWhiteMoveCount, iBlackMoveCount, ref iPermCount); } else { iPts = 0; } chessBoard.UndoMoveNoLog(move); if (iPts > iBestPts) { TraceSearch(iDepth, ePlayerColor, move, iPts); iBestPts = iPts; moveBest = move; bRetVal = true; } } return(bRetVal); }
/// <summary> /// Parse one game in PGN /// </summary> /// <param name="bIgnoreMoveListIfFEN"> Ignore the move list if FEN is found</param> /// <param name="piMoveList"> Returned move list</param> /// <param name="attrs"> Returned list of attributes for this game</param> /// <param name="listMovePos"> Returned the list of move if not null</param> /// <param name="iSkip"> Number of games skipped</param> /// <param name="iTruncated"> Number of games truncated</param> /// <param name="chessBoardStarting"> Starting board setting. If null, standard board used.</param> /// <param name="eStartingColor"> Starting color</param> /// <param name="strWhitePlayerName"> White pieces player name</param> /// <param name="strBlackPlayerName"> Black pieces player name</param> /// <param name="eWhitePlayerType"> White pieces player type</param> /// <param name="eBlackPlayerType"> Black pieces player type</param> /// <param name="spanWhitePlayer"> Time span for white player</param> /// <param name="spanBlackPlayer"> Time span for black player</param> /// <returns> /// false if invalid board /// </returns> /// <remarks> /// /// The parser understand an extended version of the [TimeControl] tag: /// /// [TimeControl "?:123:456"] where 123 = white tick count, 456 = black tick count (100 nano-sec unit) /// /// The parser also understand the following standard tags: /// /// [White] [Black] [FEN] [WhiteType] [BlackType] /// /// </remarks> private bool ParseNextMoveList(bool bIgnoreMoveListIfFEN, out int[] piMoveList, out Dictionary <string, string> attrs, List <ChessBoard.MovePosS> listMovePos, ref int iSkip, ref int iTruncated, out ChessBoard chessBoardStarting, out ChessBoard.PlayerColorE eStartingColor, out string strWhitePlayerName, out string strBlackPlayerName, out PlayerTypeE eWhitePlayerType, out PlayerTypeE eBlackPlayerType, out TimeSpan spanWhitePlayer, out TimeSpan spanBlackPlayer) { bool bRetVal = true; bool bEndOfMove; bool bFENFound; List <string> arrRawMove; int iMoveIndex; string strMove; string strFEN; string[] arrStr; string[] arrTimeControl; int iTick1; int iTick2; attrs = new Dictionary <string, string>(10); chessBoardStarting = null; eStartingColor = ChessBoard.PlayerColorE.White; piMoveList = null; arrRawMove = new List <string>(256); SkipAltMoveAndRemark(); while (PeekChr() == '[') { ParseAttr(attrs); SkipAltMoveAndRemark(); } strWhitePlayerName = (attrs.ContainsKey("WHITE")) ? attrs["WHITE"] : "Player 1"; strBlackPlayerName = (attrs.ContainsKey("BLACK")) ? attrs["BLACK"] : "Player 2"; if (attrs.ContainsKey("WHITETYPE")) { eWhitePlayerType = (attrs["WHITETYPE"].ToLower() == "program") ? PlayerTypeE.Program : PlayerTypeE.Human; } else { eWhitePlayerType = PlayerTypeE.Human; } if (attrs.ContainsKey("BLACKTYPE")) { eBlackPlayerType = (attrs["BLACKTYPE"].ToLower() == "program") ? PlayerTypeE.Program : PlayerTypeE.Human; } else { eBlackPlayerType = PlayerTypeE.Human; } arrTimeControl = (attrs.ContainsKey("TIMECONTROL")) ? attrs["TIMECONTROL"].Split(':') : null; if (arrTimeControl != null && arrTimeControl.Length == 3 && arrTimeControl[0] == "?" && Int32.TryParse(arrTimeControl[1], out iTick1) && Int32.TryParse(arrTimeControl[2], out iTick2)) { spanWhitePlayer = new TimeSpan(iTick1); spanBlackPlayer = new TimeSpan(iTick2); } else { spanWhitePlayer = TimeSpan.Zero; spanBlackPlayer = TimeSpan.Zero; } bFENFound = attrs.ContainsKey("FEN"); m_chessBoard.ResetBoard(); if (bFENFound) { strFEN = attrs["FEN"]; bRetVal = ParseFEN(strFEN, out eStartingColor, out chessBoardStarting); } if (bRetVal && !(bFENFound && bIgnoreMoveListIfFEN)) { iMoveIndex = 1; bEndOfMove = false; while (!bEndOfMove && ParseRawMove(iMoveIndex, out strMove)) { arrStr = strMove.Split(' '); if (arrStr.Length == 2) { arrRawMove.Add(arrStr[0]); arrRawMove.Add(arrStr[1]); } else if (arrStr.Length == 1) { arrRawMove.Add(arrStr[0]); } else { bEndOfMove = true; } iMoveIndex++; } if (arrRawMove.Count == 0) { if (m_bDiagnose) { throw new PgnParserException("Syntax error", GetCodeInError()); } iSkip++; } CnvRawMoveToPosMove(eStartingColor, arrRawMove, out piMoveList, listMovePos, ref iSkip, ref iTruncated); } return(bRetVal); }
/// <summary> /// Find the best move for a player using alpha-beta in a secondary thread /// </summary> /// <param name="chessBoard"> Chess board</param> /// <param name="searchMode"> Search mode</param> /// <param name="ePlayerColor"> 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 chessBoard, SearchMode searchMode, ChessBoard.PlayerColorE ePlayerColor, int iThreadId, List <ChessBoard.MovePosS> 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 & SearchMode.OptionE.UseIterativeDepthSearch) == SearchMode.OptionE.UseIterativeDepthSearch); resRetVal.movePosBest.StartPos = 255; resRetVal.movePosBest.EndPos = 255; resRetVal.movePosBest.OriginalPiece = ChessBoard.PieceE.None; resRetVal.movePosBest.Type = ChessBoard.MoveTypeE.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(chessBoard, searchMode, ePlayerColor, 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(chessBoard, searchMode, ePlayerColor, 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(chessBoard, searchMode, ePlayerColor, 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 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="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 chessBoard, SearchMode searchMode, ChessBoard.PlayerColorE ePlayerColor, List <ChessBoard.MovePosS> 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; 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_posInfoWhite = posInfoWhite; abInfo.m_posInfoBlack = posInfoBlack; 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> /// Convert a PGN position into a moving position /// </summary> /// <param name="ePlayerColor"> Color moving</param> /// <param name="strMove"> Move</param> /// <param name="iPos"> Returned moving position</param> /// <param name="iTruncated"> Truncated count</param> /// <param name="movePos"> Move position</param> private void CnvRawMoveToPosMove(ChessBoard.PlayerColorE ePlayerColor, string strMove, out int iPos, ref int iTruncated, ref ChessBoard.MovePosS movePos) { string strPureMove; int iIndex; int iStartCol; int iStartRow; int iEndPos; int iOfs; ChessBoard.PieceE ePiece; ChessBoard.MoveTypeE eMoveType; eMoveType = ChessBoard.MoveTypeE.Normal; iPos = 0; strPureMove = strMove.Replace("x", "").Replace("#", "").Replace("ep", "").Replace("+", ""); iIndex = strPureMove.IndexOf('='); if (iIndex != -1) { if (strPureMove.Length > iIndex + 1) { switch (strPureMove[iIndex + 1]) { case 'Q': eMoveType = ChessBoard.MoveTypeE.PawnPromotionToQueen; break; case 'R': eMoveType = ChessBoard.MoveTypeE.PawnPromotionToRook; break; case 'B': eMoveType = ChessBoard.MoveTypeE.PawnPromotionToBishop; break; case 'N': eMoveType = ChessBoard.MoveTypeE.PawnPromotionToKnight; break; case 'P': eMoveType = ChessBoard.MoveTypeE.PawnPromotionToPawn; break; default: iPos = -1; iTruncated++; break; } if (iPos != -1) { strPureMove = strPureMove.Substring(0, iIndex); } } else { iPos = -1; iTruncated++; } } if (iPos == 0) { if (strPureMove == "O-O") { iPos = FindCastling(ePlayerColor, true, ref iTruncated, strMove, ref movePos); } else if (strPureMove == "O-O-O") { iPos = FindCastling(ePlayerColor, false, ref iTruncated, strMove, ref movePos); } else { iOfs = 1; switch (strPureMove[0]) { case 'K': // King ePiece = ChessBoard.PieceE.King; break; case 'N': // Knight ePiece = ChessBoard.PieceE.Knight; break; case 'B': // Bishop ePiece = ChessBoard.PieceE.Bishop; break; case 'R': // Rook ePiece = ChessBoard.PieceE.Rook; break; case 'Q': // Queen ePiece = ChessBoard.PieceE.Queen; break; default: // Pawn ePiece = ChessBoard.PieceE.Pawn; iOfs = 0; break; } DecodeMove(strPureMove.Substring(iOfs), out iStartCol, out iStartRow, out iEndPos); iPos = FindPieceMove(ePlayerColor, ePiece, iStartCol, iStartRow, iEndPos, eMoveType, strMove, ref iTruncated, ref movePos); } } }
/// <summary> /// Find the best move using a specific search method /// </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"> Position information</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 abstract bool FindBestMove(ChessBoard chessBoard, 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);
/// <summary> /// Reset the timer of both player /// </summary> /// <param name="ePlayerColor"> Playing color</param> public void Reset(ChessBoard.PlayerColorE ePlayerColor) { ResetTo(ePlayerColor, 0, 0); }
/// <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); }
/// <summary> /// Revert the board so the computer play the actual user pieces /// </summary> private void RevertBoard() { m_eComputerPlayingColor = (m_eComputerPlayingColor == ChessBoard.PlayerColorE.Black) ? ChessBoard.PlayerColorE.White : ChessBoard.PlayerColorE.Black; CheckIfComputerMustPlay(); }
/// <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; 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 (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) { iRetVal = chessBoard.Points(abInfo.m_searchMode, ePlayerColor, abInfo.m_iMaxDepth - iDepth, iWhiteMoveCount - iBlackMoveCount, abInfo.m_posInfoWhite, abInfo.m_posInfoBlack); if (ePlayerColor == ChessBoard.PlayerColorE.Black) { iRetVal = -iRetVal; } 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 posInfo); iMoveCount = moveList.Count; if (ePlayerColor == ChessBoard.PlayerColorE.White) { iWhiteMoveCount = iMoveCount; abInfo.m_posInfoWhite = posInfo; } else { iBlackMoveCount = iMoveCount; abInfo.m_posInfoBlack = posInfo; } 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> /// Default constructor /// </summary> // //********************************************************* public frmCreatePGNGame() { InitializeComponent(); m_arrMoveList = null; m_eStartingColor = ChessBoard.PlayerColorE.White; m_chessBoardStarting = null; }