//********************************************************* // /// <summary> /// Default constructor /// </summary> // //********************************************************* public frmPGNGamePicker() { InitializeComponent(); m_pgnUtil = new PgnUtil(); m_strSelectedGame = null; m_eStartingColor = ChessBoard.PlayerColorE.White; m_chessBoardStarting = null; }
//********************************************************* // /// <summary> /// Class constructor /// </summary> // //********************************************************* public MoveViewer() { InitializeComponent(); listViewMoveList.SelectedIndexChanged += new EventHandler(listViewMoveList_SelectedIndexChanged); m_chessBoard = null; m_eDisplayMode = DisplayModeE.MovePos; m_bIgnoreChg = false; }
//********************************************************* // /// <summary> /// Evaluates a board. The number of point is greater than 0 if white is in advantage, less than 0 if black is. /// </summary> /// <param name="pBoard"> Board.</param> /// <param name="piPiecesCount"> Number of each pieces</param> /// <param name="iAttackedPos"> Number of square attacked by all pieces. (Value computed before the last move for performance reason)</param> /// <param name="iAttackedPieces"> Number of enemy pieces attacked by all pieces. (Value computed before the last move for performance reason)</param> /// <param name="iWhiteKingPos"> Position of the white king</param> /// <param name="iBlackKingPos"> Position of the black king</param> /// <param name="bWhiteCastle"> White has castled</param> /// <param name="bBlackCastle"> Black has castled</param> /// <param name="iMoveCountDelta"> Number of possible white move - Number of possible black move</param> /// <returns> /// Points /// </returns> // //********************************************************* public virtual int Points(ChessBoard.PieceE[] pBoard, int[] piPiecesCount, int iAttackedPos, int iAttackedPieces, int iWhiteKingPos, int iBlackKingPos, bool bWhiteCastle, bool bBlackCastle, int iMoveCountDelta) { int iRetVal = 0; for (int iIndex = 0; iIndex < piPiecesCount.Length; iIndex++) { iRetVal += m_piPiecePoint[iIndex] * piPiecesCount[iIndex]; } if (pBoard[12] == ChessBoard.PieceE.Pawn) { iRetVal -= 4; } if (pBoard[52] == (ChessBoard.PieceE.Pawn | ChessBoard.PieceE.Black)) { iRetVal += 4; } if (bWhiteCastle) { iRetVal += 10; } if (bBlackCastle) { iRetVal -= 10; } iRetVal += iMoveCountDelta; iRetVal += iAttackedPos + iAttackedPieces * 2; return(iRetVal); }
//********************************************************* // /// <summary> /// Update the Zobrist key using the specified move /// </summary> /// <param name="i64ZobristKey">Zobrist key</param> /// <param name="iPos"> Piece position</param> /// <param name="eOldPiece"> Old value</param> /// <param name="eNewPiece"> New value</param> // //********************************************************* public static long UpdateZobristKey(long i64ZobristKey, int iPos, ChessBoard.PieceE eOldPiece, ChessBoard.PieceE eNewPiece) { int iBaseIndex; iBaseIndex = iPos << 4; i64ZobristKey ^= m_pi64RndTable[iBaseIndex + ((int)eOldPiece)] ^ m_pi64RndTable[iBaseIndex + ((int)eNewPiece)]; return(i64ZobristKey); }
//********************************************************* // /// <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, iWhiteMoveCount - iBlackMoveCount, 0, 0) : chessBoard.Points(searchMode, ePlayerColor, iWhiteMoveCount - iBlackMoveCount, 0, 0); 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> /// Gets the description of a move /// </summary> /// <param name="movePos"> Move to describe</param> /// <returns> /// Move description /// </returns> // //********************************************************* private string GetMoveDesc(ChessBoard.MovePosS movePos) { string strRetVal; if (m_eDisplayMode == DisplayModeE.MovePos) { strRetVal = ChessBoard.GetHumanPos(movePos); } else { strRetVal = PgnUtil.GetPGNMoveFromMove(m_chessBoard, movePos, false); if ((movePos.Type & ChessBoard.MoveTypeE.MoveFromBook) == ChessBoard.MoveTypeE.MoveFromBook) { strRetVal = "(" + strRetVal + ")"; } } return(strRetVal); }
//********************************************************* // /// <summary> /// Update the Zobrist key using the specified move /// </summary> /// <param name="i64ZobristKey">Zobrist key</param> /// <param name="iPos1"> Piece position</param> /// <param name="eOldPiece1"> Old value</param> /// <param name="eNewPiece1"> New value</param> /// <param name="iPos2"> Piece position</param> /// <param name="eOldPiece2"> Old value</param> /// <param name="eNewPiece2"> New value</param> // //********************************************************* public static long UpdateZobristKey(long i64ZobristKey, int iPos1, ChessBoard.PieceE eOldPiece1, ChessBoard.PieceE eNewPiece1, int iPos2, ChessBoard.PieceE eOldPiece2, ChessBoard.PieceE eNewPiece2) { int iBaseIndex1; int iBaseIndex2; iBaseIndex1 = iPos1 << 4; iBaseIndex2 = iPos2 << 4; i64ZobristKey ^= m_pi64RndTable[iBaseIndex1 + ((int)eOldPiece1)] ^ m_pi64RndTable[iBaseIndex1 + ((int)eNewPiece1)] ^ m_pi64RndTable[iBaseIndex2 + ((int)eOldPiece2)] ^ m_pi64RndTable[iBaseIndex2 + ((int)eNewPiece2)]; return(i64ZobristKey); }
//********************************************************* // /// <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> /// Reset the control so it represents the specified chessboard /// </summary> /// <param name="chessBoard"> Chess board. Starting one if null</param> // //********************************************************* public void Reset(ChessBoard chessBoard) { int iCurPos; int iCount; listViewMoveList.Items.Clear(); m_chessBoard = chessBoard; iCurPos = chessBoard.MovePosStack.PositionInList; iCount = chessBoard.MovePosStack.Count; chessBoard.UndoAllMoves(); for (int iIndex = 0; iIndex < iCount; iIndex++) { chessBoard.RedoMove(); AddCurrentMove(); } SelectCurrentMove(); }
//********************************************************* // /// <summary> /// Compute the current packed representation of a board /// </summary> /// <param name="peBoard"> Board array</param> /// <param name="eInfo"> Board extra info</param> // //********************************************************* private void ComputeCurrentPackedBoard(ChessBoard.PieceE[] peBoard, ChessBoard.BoardStateMaskE eInfo) { m_packedBoardCurrent = ComputePackedBoard(peBoard, eInfo); }
//********************************************************* // /// <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="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, ref ChessBoard.MovePosS moveBest, out int iPermCount, out int iCacheHit, out int iMaxDepth) { bool bRetVal = false; bool bMultipleThread; bool bUseTransTable; ChessBoard[] arrChessBoard; FindBestMoveUsingAlphaBetaAsyncDel[] arrDelFindBestMoveUsingAlphaBetaAsync; IAsyncResult[] arrAsyncResult; List<ChessBoard.MovePosS>[] arrMoveList; ChessBoard.MovePosS movePosTmp; int iPts; int iAlpha; int iBeta; int iThreadCount; int iMovePermCount; int iMaxDepthTmp; //TODO Enable transposition table when bug on 3 repetition move draw will be found. 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]; arrAsyncResult = new IAsyncResult[iThreadCount]; arrDelFindBestMoveUsingAlphaBetaAsync = new FindBestMoveUsingAlphaBetaAsyncDel[iThreadCount]; arrMoveList = new List<ChessBoard.MovePosS>[iThreadCount]; for (int iIndex = 0; iIndex < iThreadCount; iIndex++) { arrChessBoard[iIndex] = chessBoard.Clone(); arrDelFindBestMoveUsingAlphaBetaAsync[iIndex] = new FindBestMoveUsingAlphaBetaAsyncDel(FindBestMoveUsingAlphaBetaAsync); 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 iStep = 0; iStep < iThreadCount; iStep++) { arrAsyncResult[iStep] = arrDelFindBestMoveUsingAlphaBetaAsync[iStep].BeginInvoke(arrChessBoard[iStep], searchMode, ePlayerColor, iStep, arrMoveList[iStep], moveList.Count, iAlpha, iBeta, out iMovePermCount, out movePosTmp, out iMaxDepth, null, null); } iMaxDepth = 999; for (int iStep = 0; iStep < iThreadCount; iStep++) { iPts = arrDelFindBestMoveUsingAlphaBetaAsync[iStep].EndInvoke(out iMovePermCount, out movePosTmp, out iMaxDepthTmp, arrAsyncResult[iStep]); if (movePosTmp.StartPos != 255) { iPermCount += iMovePermCount; iMaxDepth = Math.Min(iMaxDepth, iMaxDepthTmp); if (bUseTransTable) { iCacheHit += TransTable.GetTransTable(iStep).CacheHit; } if (iPts > iAlpha) { iAlpha = iPts; moveBest = movePosTmp; 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]]); } iPts = FindBestMoveUsingAlphaBetaAsync(chessBoardTmp, searchMode, ePlayerColor, 0, // ThreadId moveListTmp, moveList.Count, iAlpha, iBeta, out iPermCount, out movePosTmp, out iMaxDepth); if (movePosTmp.StartPos != 255) { if (bUseTransTable) { iCacheHit += TransTable.GetTransTable(0).CacheHit; } moveBest = movePosTmp; bRetVal = true; } } return(bRetVal); }
//********************************************************* // /// <summary> /// Gets the position express in a human form /// </summary> /// <param name="move"> Move</param> /// <returns> /// Human form position /// </returns> // //********************************************************* static public string GetHumanPos(ChessBoard.MovePosS move) { string strRetVal; strRetVal = GetHumanPos(move.StartPos); strRetVal += ((move.Type & MoveTypeE.PieceEaten) == MoveTypeE.PieceEaten) ? "x" : "-"; strRetVal += GetHumanPos(move.EndPos); if ((move.Type & ChessBoard.MoveTypeE.MoveFromBook) == ChessBoard.MoveTypeE.MoveFromBook) { strRetVal = "(" + strRetVal + ")"; } switch(move.Type & ChessBoard.MoveTypeE.MoveTypeMask) { case ChessBoard.MoveTypeE.PawnPromotionToQueen: strRetVal += "=Q"; break; case ChessBoard.MoveTypeE.PawnPromotionToRook: strRetVal += "=R"; break; case ChessBoard.MoveTypeE.PawnPromotionToBishop: strRetVal += "=B"; break; case ChessBoard.MoveTypeE.PawnPromotionToKnight: strRetVal += "=N"; break; case ChessBoard.MoveTypeE.PawnPromotionToPawn: strRetVal += "=P"; break; default: break; } return(strRetVal); }
//********************************************************* // /// <summary> /// Copy the state of the board from the specified one. /// </summary> /// <param name="chessBoard"> Board to copy from</param> // //********************************************************* public void CopyFrom(ChessBoard chessBoard) { chessBoard.m_pBoard.CopyTo(m_pBoard, 0); chessBoard.m_piPiecesCount.CopyTo(m_piPiecesCount, 0); m_stackPossibleEnPassantAt = new Stack<int>(chessBoard.m_stackPossibleEnPassantAt.ToArray()); m_book = chessBoard.m_book; m_iBlackKingPos = chessBoard.m_iBlackKingPos; m_iWhiteKingPos = chessBoard.m_iWhiteKingPos; m_rnd = chessBoard.m_rnd; m_rndRep = chessBoard.m_rndRep; m_iRBlackRookMoveCount = chessBoard.m_iRBlackRookMoveCount; m_iLBlackRookMoveCount = chessBoard.m_iLBlackRookMoveCount; m_iBlackKingMoveCount = chessBoard.m_iBlackKingMoveCount; m_iRWhiteRookMoveCount = chessBoard.m_iRWhiteRookMoveCount; m_iLWhiteRookMoveCount = chessBoard.m_iLWhiteRookMoveCount; m_iWhiteKingMoveCount = chessBoard.m_iWhiteKingMoveCount; m_bWhiteCastle = chessBoard.m_bWhiteCastle; m_bBlackCastle = chessBoard.m_bBlackCastle; m_iPossibleEnPassantAt = chessBoard.m_iPossibleEnPassantAt; m_i64ZobristKey = chessBoard.m_i64ZobristKey; m_trace = chessBoard.m_trace; m_moveStack = chessBoard.m_moveStack.Clone(); m_moveHistory = chessBoard.m_moveHistory.Clone(); m_eNextMoveColor = chessBoard.m_eNextMoveColor; }
//********************************************************* // /// <summary> /// Compute a packed value of 16 pieces /// </summary> /// <param name="peBoard"> Board array</param> /// <param name="iStartPos"> Pieces starting position</param> /// <returns> /// Packed value of the 16 pieces /// </returns> // //********************************************************* private static long ComputePackedValue(ChessBoard.PieceE[] peBoard, int iStartPos) { long lRetVal = 0; for (int iIndex = 0; iIndex < 16; iIndex++) { lRetVal |= ((long)peBoard[iStartPos + iIndex] & 15) << (iIndex << 2); } return(lRetVal); }
//********************************************************* // /// <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 virtual 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) { m_board.CreateGameFromMove(chessBoardStarting, listMove, eNextMoveColor); if (m_moveListUI != null) { m_moveListUI.Reset(m_board); } WhitePlayerName = strWhitePlayerName; BlackPlayerName = strBlackPlayerName; WhitePlayerType = eWhitePlayerType; BlackPlayerType = eBlackPlayerType; OnUpdateCmdState(System.EventArgs.Empty); m_gameTimer.ResetTo(m_board.NextMoveColor, spanPlayerWhite.Ticks, spanPlayerBlack.Ticks); m_gameTimer.Enabled = true; Invalidate(); }
//********************************************************* // /// <summary> /// Update the current board packing /// </summary> /// <param name="iPos"> Position of the new piece</param> /// <param name="eNewPiece"> New piece</param> // //********************************************************* public void UpdateCurrentPackedBoard(int iPos, ChessBoard.PieceE eNewPiece) { long lNewPiece; long lMask; int iSlotInValue; iSlotInValue = (iPos & 15) << 2; lNewPiece = ((long)eNewPiece & 15) << iSlotInValue; lMask = (long)15 << iSlotInValue; if (iPos < 16) { m_packedBoardCurrent.m_lVal1 = (m_packedBoardCurrent.m_lVal1 & ~lMask) | lNewPiece; } else if (iPos < 32) { m_packedBoardCurrent.m_lVal2 = (m_packedBoardCurrent.m_lVal2 & ~lMask) | lNewPiece; } else if (iPos < 48) { m_packedBoardCurrent.m_lVal3 = (m_packedBoardCurrent.m_lVal3 & ~lMask) | lNewPiece; } else { m_packedBoardCurrent.m_lVal4 = (m_packedBoardCurrent.m_lVal4 & ~lMask) | lNewPiece; } }
//********************************************************* // /// <summary> /// Update the current board packing /// </summary> /// <param name="eInfo"> Board extra info</param> // //********************************************************* public void UpdateCurrentPackedBoard(ChessBoard.BoardStateMaskE eInfo) { m_packedBoardCurrent.m_eInfo = eInfo & ~ChessBoard.BoardStateMaskE.BlackToMove; }
//********************************************************* // /// <summary> /// Reset the move history /// </summary> /// <param name="peBoard"> Board array</param> /// <param name="eInfo"> Board extra info</param> // //********************************************************* public void Reset(ChessBoard.PieceE[] peBoard, ChessBoard.BoardStateMaskE eInfo) { m_arrCountMove[0] = 0; m_iCountMoveDepth = 0; m_iMoveCount = 0; Array.Clear(m_arrHashCount, 0, m_arrHashCount.Length); ComputeCurrentPackedBoard(peBoard, eInfo); }
//********************************************************* // /// <summary> /// Unpack a packed board to a board /// </summary> /// <param name="packedBoard"> Packed board</param> /// <param name="peBoard"> Board array</param> // //********************************************************* public static void UnpackBoard(PackedBoard packedBoard, ChessBoard.PieceE[] peBoard) { UnpackBoardValue(packedBoard.m_lVal1, peBoard, 0); UnpackBoardValue(packedBoard.m_lVal2, peBoard, 16); UnpackBoardValue(packedBoard.m_lVal3, peBoard, 32); UnpackBoardValue(packedBoard.m_lVal4, peBoard, 48); }
//********************************************************* // /// <summary> /// Unpack a packed board value to a board /// </summary> /// <param name="lVal"> Packed board value</param> /// <param name="peBoard"> Board array</param> /// <param name="iStartPos"> Offset in the board</param> // //********************************************************* private static void UnpackBoardValue(long lVal, ChessBoard.PieceE[] peBoard, int iStartPos) { for (int iIndex = 0; iIndex < 16; iIndex++) { peBoard[iStartPos + iIndex] = (ChessBoard.PieceE)((lVal >> (iIndex << 2)) & 15); } }
/// <summary> /// Constructor /// </summary> /// <param name="move"> Move position</param> public MoveSelectedEventArgs(ChessBoard.MovePosS move) { Move = move; }
//********************************************************* // /// <summary> /// Set the piece in a case. Can only be used in design mode. /// </summary> // //********************************************************* public void SetCaseValue(int iPos, ChessBoard.PieceE ePiece) { Graphics gr; int iY; int iX; if (BoardDesignMode) { iY = iPos >> 3; iX = iPos & 7; m_board[iPos] = ePiece; using(gr = CreateGraphics()) { DrawCase(gr, iY, iX, false); } } }
//********************************************************* // /// <summary> /// Trace a permutation. Can be used for debugging. /// </summary> /// <param name="iDepth"> Current depth of the search</param> /// <param name="ePlayerColor"> Color who play</param> /// <param name="move"> Move</param> /// <param name="iPts"> Points for this move</param> // //********************************************************* public virtual void TraceSearch(int iDepth, ChessBoard.PlayerColorE ePlayerColor, ChessBoard.MovePosS move, int iPts) { }
//********************************************************* // /// <summary> /// Compute the zobrist key for a board /// </summary> /// <param name="peBoard"> Board</param> // //********************************************************* public static long ComputeBoardZobristKey(ChessBoard.PieceE[] peBoard) { long lRetVal = 0; for (int iIndex = 0; iIndex < 64; iIndex++) { lRetVal ^= m_pi64RndTable[(iIndex << 4) + (int)peBoard[iIndex]]; } return(lRetVal); }
//********************************************************* // /// <summary> /// Find a move from the opening book /// </summary> /// <param name="searchMode"> Search mode</param> /// <param name="ePlayerColor"> Color doing the move</param> /// <param name="arrPrevMove"> Previous move</param> /// <param name="move"> Found move</param> /// <returns> /// true if succeed, false if no move found in book /// </returns> // //********************************************************* public bool FindBookMove(SearchEngine.SearchMode searchMode, PlayerColorE ePlayerColor, MovePosS[] arrPrevMove, out ChessBoard.MovePosS move) { bool bRetVal; int iMove; Random rnd; if (searchMode.m_eRandomMode == SearchEngine.SearchMode.RandomModeE.Off) { rnd = null; } else if (searchMode.m_eRandomMode == SearchEngine.SearchMode.RandomModeE.OnRepetitive) { rnd = m_rndRep; } else { rnd = m_rnd; } move.OriginalPiece = PieceE.None; move.StartPos = 255; move.EndPos = 255; move.Type = ChessBoard.MoveTypeE.Normal; iMove = m_book.FindMoveInBook(arrPrevMove, rnd); if (iMove == -1) { bRetVal = false; } else { move = FindIfValid(ePlayerColor, iMove & 255, iMove >> 8); move.Type |= MoveTypeE.MoveFromBook; bRetVal = (move.StartPos != 255); } return(bRetVal); }
//********************************************************* // /// <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> /// Class constructor. Use to create a new clone /// </summary> /// <param name="chessBoard"> Board to copy from</param> // //********************************************************* private ChessBoard(ChessBoard chessBoard) : this(chessBoard.m_searchEngineAlphaBeta, chessBoard.m_searchEngineMinMax) { CopyFrom(chessBoard); }
//********************************************************* // /// <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="iTotalMoveCount"> Total number of moves</param> /// <param name="iAlpha"> Alpha bound</param> /// <param name="iBeta"> Beta bound</param> /// <param name="iPermCount"> Total permutation evaluated</param> /// <param name="movePosBest"> Best move</param> /// <param name="iMaxDepth"> Maximum depth evaluated</param> /// <returns> /// Points /// </returns> // //********************************************************* private int FindBestMoveUsingAlphaBetaAsync(ChessBoard chessBoard, SearchMode searchMode, ChessBoard.PlayerColorE ePlayerColor, int iThreadId, List<ChessBoard.MovePosS> moveList, int iTotalMoveCount, int iAlpha, int iBeta, out int iPermCount, out ChessBoard.MovePosS movePosBest, out int iMaxDepth) { int iRetVal; DateTime dtTimeOut; int iDepth; int iPermCountAtLevel; int iPoint; int iBestMoveIndex; int iDepthLimit; int[] arrPoints; System.Threading.ThreadPriority eThreadPriority; TransTable transTable; bool bTimeOut; bool bIterativeDepthFirst; 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); movePosBest.StartPos = 255; movePosBest.EndPos = 255; movePosBest.OriginalPiece = ChessBoard.PieceE.None; movePosBest.Type = ChessBoard.MoveTypeE.Normal; try { 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; iRetVal = FindBestMoveUsingAlphaBetaAtDepth(chessBoard, searchMode, ePlayerColor, moveList, iTotalMoveCount, iDepth, iAlpha, iBeta, transTable, DateTime.MaxValue, out iPermCountAtLevel, out iBestMoveIndex, out bTimeOut, out arrPoints); if (iBestMoveIndex != -1) { movePosBest = moveList[iBestMoveIndex]; } iPermCount += iPermCountAtLevel; iMaxDepth = iDepth; while (DateTime.Now < dtTimeOut && !m_bCancelSearch && !bTimeOut && iDepth < iDepthLimit) { moveList = SortMoveList(moveList, arrPoints); iDepth++; iPoint = FindBestMoveUsingAlphaBetaAtDepth(chessBoard, searchMode, ePlayerColor, moveList, iTotalMoveCount, iDepth, iAlpha, iBeta, transTable, dtTimeOut, out iPermCountAtLevel, out iBestMoveIndex, out bTimeOut, out arrPoints); if (!bTimeOut) { if (iBestMoveIndex != -1) { movePosBest = moveList[iBestMoveIndex]; } iPermCount += iPermCountAtLevel; iMaxDepth = iDepth; iRetVal = iPoint; } } } else { iMaxDepth = searchMode.m_iSearchDepth; iRetVal = FindBestMoveUsingAlphaBetaAtDepth(chessBoard, searchMode, ePlayerColor, moveList, iTotalMoveCount, iMaxDepth, iAlpha, iBeta, transTable, DateTime.MaxValue, out iPermCount, out iBestMoveIndex, out bTimeOut, out arrPoints); if (iBestMoveIndex != -1) { movePosBest = moveList[iBestMoveIndex]; } } } finally { System.Threading.Thread.CurrentThread.Priority = eThreadPriority; } return(iRetVal); }
//********************************************************* // /// <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="eStartingColor"> Board starting color</param> // //********************************************************* public void CreateGameFromMove(ChessBoard chessBoardStarting, List<MovePosS> listMove, PlayerColorE eStartingColor) { BoardStateMaskE eMask; if (chessBoardStarting != null) { CopyFrom(chessBoardStarting); eMask = chessBoardStarting.ComputeBoardExtraInfo(PlayerColorE.White, false); ResetInitialBoardInfo(eStartingColor, false, eMask, chessBoardStarting.m_iPossibleEnPassantAt); } else { ResetBoard(); } foreach (MovePosS movePos in listMove) { DoMove(movePos); } }
//********************************************************* // /// <summary> /// Compute the packed representation of a board /// </summary> /// <param name="peBoard"> Board array</param> /// <param name="eInfo"> Board extra info</param> // //********************************************************* public static PackedBoard ComputePackedBoard(ChessBoard.PieceE[] peBoard, ChessBoard.BoardStateMaskE eInfo) { PackedBoard packedBoard; packedBoard.m_lVal1 = ComputePackedValue(peBoard, 0); packedBoard.m_lVal2 = ComputePackedValue(peBoard, 16); packedBoard.m_lVal3 = ComputePackedValue(peBoard, 32); packedBoard.m_lVal4 = ComputePackedValue(peBoard, 48); packedBoard.m_eInfo = eInfo & ~ChessBoard.BoardStateMaskE.BlackToMove; return(packedBoard); }