public void SwapPlayers() { PlayerColorE p1Color = Player1.Color; PlayerColorE p2Color = Player2.Color; Player p = Player1; Player1 = Player2; Player1.Color = p1Color; Player2 = p; Player2.Color = p2Color; UpdateGameDataPlayers(); Flags.IsEngineBlack = !Flags.IsEngineBlack; if (AfterSwapPlayers != null) { AfterSwapPlayers(this, EventArgs.Empty); } }
//********************************************************* // /// <summary> /// Try to close the design mode. /// </summary> /// <param name="eNextMoveColor"> Color of the next move</param> /// <param name="eBoardMask"> Board extra information</param> /// <param name="iEnPassant"> Position of en passant or 0 if none</param> /// <returns> /// true if succeed, false if board is invalid /// </returns> // //********************************************************* public bool CloseDesignMode(PlayerColorE eNextMoveColor, BoardStateMaskE eBoardMask, int iEnPassant) { bool bRetVal; if (!m_bDesignMode) { bRetVal = true; } else { ResetInitialBoardInfo(eNextMoveColor, false, eBoardMask, iEnPassant); if (m_piPiecesCount[(int)(PieceE.King | PieceE.White)] == 1 && m_piPiecesCount[(int)(PieceE.King | PieceE.Black)] == 1) { bRetVal = true; } else { bRetVal = false; } } return(bRetVal); }
//********************************************************* // /// <summary> /// Load the content of the board into the specified stream /// </summary> /// <param name="reader"> Binary reader</param> // //********************************************************* public bool LoadBoard(BinaryReader reader) { bool bRetVal; MoveHistory.PackedBoard packetBoard; string strVersion; int iEnPassant; strVersion = reader.ReadString(); if (strVersion != "SRCBD095") { bRetVal = false; } else { bRetVal = true; ResetBoard(); m_bStdInitialBoard = reader.ReadBoolean(); if (!m_bStdInitialBoard) { packetBoard.m_lVal1 = reader.ReadInt64(); packetBoard.m_lVal2 = reader.ReadInt64(); packetBoard.m_lVal3 = reader.ReadInt64(); packetBoard.m_lVal4 = reader.ReadInt64(); packetBoard.m_eInfo = (BoardStateMaskE)reader.ReadInt32(); iEnPassant = reader.ReadInt32(); MoveHistory.UnpackBoard(packetBoard, m_pBoard); m_eNextMoveColor = ((packetBoard.m_eInfo & BoardStateMaskE.BlackToMove) == BoardStateMaskE.BlackToMove) ? PlayerColorE.Black : PlayerColorE.White; ResetInitialBoardInfo(m_eNextMoveColor, m_bStdInitialBoard, packetBoard.m_eInfo, iEnPassant); } m_moveStack.LoadFromReader(reader); for (int iIndex = 0; iIndex <= m_moveStack.PositionInList; iIndex++) { DoMoveNoLog(m_moveStack.List[iIndex]); } } return(bRetVal); }
//********************************************************* // /// <summary> /// Compute extra information about the board /// </summary> /// <param name="ePlayerToMove"> Player color to move</param> /// <param name="bAddRepetitionInfo"> true to add board repetition information</param> /// <returns> /// Extra information about the board to discriminate between two boards with sames pieces but /// different setting. /// </returns> // //********************************************************* public BoardStateMaskE ComputeBoardExtraInfo(PlayerColorE ePlayerToMove, bool bAddRepetitionInfo) { BoardStateMaskE eRetVal; eRetVal = (BoardStateMaskE)m_iPossibleEnPassantAt; if (m_iWhiteKingMoveCount == 0) { if (m_iRWhiteRookMoveCount == 0) { eRetVal |= BoardStateMaskE.WRCastling; } if (m_iLWhiteRookMoveCount == 0) { eRetVal |= BoardStateMaskE.WLCastling; } } if (m_iBlackKingMoveCount == 0) { if (m_iRBlackRookMoveCount == 0) { eRetVal |= BoardStateMaskE.BRCastling; } if (m_iLBlackRookMoveCount == 0) { eRetVal |= BoardStateMaskE.BLCastling; } } if (ePlayerToMove == PlayerColorE.Black) { eRetVal |= BoardStateMaskE.BlackToMove; } if (bAddRepetitionInfo) { eRetVal = (BoardStateMaskE)((m_moveHistory.GetCurrentBoardCount(m_i64ZobristKey) & 7) << 11); } return(eRetVal); }
//********************************************************* // /// <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 type of pawn promotion are valid for the specified starting/ending position /// </summary> /// <param name="ePlayerColor"> Color doing the move</param> /// <param name="iStartPos"> Position to start</param> /// <param name="iEndPos"> Ending position</param> /// <returns> /// None or a combination of Queen, Rook, Bishop, Knight and Pawn /// /// </returns> // //********************************************************* public ValidPawnPromotionE FindValidPawnPromotion(PlayerColorE ePlayerColor, int iStartPos, int iEndPos) { ValidPawnPromotionE eRetVal = ValidPawnPromotionE.None; List<MovePosS> moveList; moveList = EnumMoveList(ePlayerColor); foreach (MovePosS move in moveList) { if (move.StartPos == iStartPos && move.EndPos == iEndPos) { switch(move.Type & MoveTypeE.MoveTypeMask) { case MoveTypeE.PawnPromotionToQueen: eRetVal |= ValidPawnPromotionE.Queen; break; case MoveTypeE.PawnPromotionToRook: eRetVal |= ValidPawnPromotionE.Rook; break; case MoveTypeE.PawnPromotionToBishop: eRetVal |= ValidPawnPromotionE.Bishop; break; case MoveTypeE.PawnPromotionToKnight: eRetVal |= ValidPawnPromotionE.Knight; break; case MoveTypeE.PawnPromotionToPawn: eRetVal |= ValidPawnPromotionE.Pawn; break; default: break; } } } return(eRetVal); }
//********************************************************* // /// <summary> /// Enumerates all the possible moves for a player /// </summary> /// <param name="ePlayerColor"> Color doing the the move</param> /// <param name="iAttackedPos"> Number of positions attacked by pieces</param> /// <param name="iAttackedPieces"> Number of pieces attacked by pieces</param> // //********************************************************* public void ComputePiecesCoverage(PlayerColorE ePlayerColor, out int iAttackedPos, out int iAttackedPieces) { EnumMoveList(ePlayerColor, false, out iAttackedPos, out iAttackedPieces); }
//********************************************************* // /// <summary> /// Enumerates all the possible moves for a player /// </summary> /// <param name="ePlayerColor"> Color doing the the move</param> /// <param name="bMoveList"> true to returns a MoveList</param> /// <param name="iAttackedPos"> Number of positions attacked by pieces</param> /// <param name="iAttackedPieces"> Number if pieces attacked by pieces</param> /// <returns> /// List of possible moves or null /// </returns> // //********************************************************* public List<MovePosS> EnumMoveList(PlayerColorE ePlayerColor, bool bMoveList, out int iAttackedPos, out int iAttackedPieces) { PieceE ePiece; List<MovePosS> arrMovePos; m_iAttackedPos = 0; m_iAttackedPieces = 0; arrMovePos = (bMoveList) ? new List<MovePosS>(256) : null; for (int iIndex = 0; iIndex < 64; iIndex++) { ePiece = m_pBoard[iIndex]; if (ePiece != PieceE.None && ((ePiece & PieceE.Black) != 0) == (ePlayerColor == PlayerColorE.Black)) { switch(ePiece & PieceE.PieceMask) { case PieceE.Pawn: EnumPawnMove(ePlayerColor, iIndex, arrMovePos); break; case PieceE.Knight: EnumFromArray(ePlayerColor, iIndex, m_ppiCaseMoveKnight[iIndex], arrMovePos); break; case PieceE.Bishop: EnumFromArray(ePlayerColor, iIndex, m_pppiCaseMoveDiagonal[iIndex], arrMovePos); break; case PieceE.Rook: EnumFromArray(ePlayerColor, iIndex, m_pppiCaseMoveLine[iIndex], arrMovePos); break; case PieceE.Queen: EnumFromArray(ePlayerColor, iIndex, m_pppiCaseMoveDiagLine[iIndex], arrMovePos); break; case PieceE.King: EnumFromArray(ePlayerColor, iIndex, m_ppiCaseMoveKing[iIndex], arrMovePos); break; } } } EnumCastleMove(ePlayerColor, arrMovePos); EnumEnPassant(ePlayerColor, arrMovePos); iAttackedPos = m_iAttackedPos; iAttackedPieces = m_iAttackedPieces; return(arrMovePos); }
//********************************************************* // /// <summary> /// Determine if the specified king is attacked /// </summary> /// <param name="eColor"> King's color to check</param> /// <param name="iKingPos"> Position of the king</param> /// <returns> /// true if in check /// </returns> // //********************************************************* private bool IsCheck(PlayerColorE eColor, int iKingPos) { return(EnumAttackPos(eColor, iKingPos, null) != 0); }
//********************************************************* // /// <summary> /// Enumerates all position which can attack a given position /// </summary> /// <param name="ePlayerColor"> Position to check for black or white</param> /// <param name="iPos"> Position to check.</param> /// <param name="arrAttackPos"> Array to fill with the attacking position. Can be null if only the count is wanted</param> /// <returns> /// Count of attacker /// </returns> // //********************************************************* private int EnumAttackPos(PlayerColorE ePlayerColor, int iPos, List<byte> arrAttackPos) { int iRetVal; PieceE eColor; PieceE eEnemyQueen; PieceE eEnemyRook; PieceE eEnemyKing; PieceE eEnemyBishop; PieceE eEnemyKnight; PieceE eEnemyPawn; eColor = (ePlayerColor == PlayerColorE.Black) ? PieceE.White : PieceE.Black; eEnemyQueen = PieceE.Queen | eColor; eEnemyRook = PieceE.Rook | eColor; eEnemyKing = PieceE.King | eColor; eEnemyBishop = PieceE.Bishop | eColor; eEnemyKnight = PieceE.Knight | eColor; eEnemyPawn = PieceE.Pawn | eColor; iRetVal = EnumTheseAttackPos(arrAttackPos, m_pppiCaseMoveDiagonal[iPos], eEnemyQueen, eEnemyBishop); iRetVal += EnumTheseAttackPos(arrAttackPos, m_pppiCaseMoveLine[iPos], eEnemyQueen, eEnemyRook); iRetVal += EnumTheseAttackPos(arrAttackPos, m_ppiCaseMoveKing[iPos], eEnemyKing); iRetVal += EnumTheseAttackPos(arrAttackPos, m_ppiCaseMoveKnight[iPos], eEnemyKnight); iRetVal += EnumTheseAttackPos(arrAttackPos, (ePlayerColor == PlayerColorE.Black) ? m_ppiCaseWhitePawnCanAttackFrom[iPos] : m_ppiCaseBlackPawnCanAttackFrom[iPos], eEnemyPawn); return(iRetVal); }
//********************************************************* // /// <summary> /// Undo a move (without no log) /// </summary> /// <param name="movePos"> Move to undo</param> // //********************************************************* public void UndoMoveNoLog(MovePosS movePos) { PieceE ePiece; PieceE eOriginalPiece; int iOldPiecePos; m_moveHistory.RemoveLastMove(m_i64ZobristKey); ePiece = m_pBoard[movePos.EndPos]; switch(movePos.Type & MoveTypeE.MoveTypeMask) { case MoveTypeE.Castle: UpdatePackedBoardAndZobristKey(movePos.StartPos, ePiece, movePos.EndPos, PieceE.None); m_pBoard[movePos.StartPos] = ePiece; m_pBoard[movePos.EndPos] = PieceE.None; if ((ePiece & PieceE.Black) != 0) { if (movePos.EndPos == 57) { UpdatePackedBoardAndZobristKey(56, m_pBoard[58], 58, PieceE.None); m_pBoard[56] = m_pBoard[58]; m_pBoard[58] = PieceE.None; } else { UpdatePackedBoardAndZobristKey(63, m_pBoard[60], 60, PieceE.None); m_pBoard[63] = m_pBoard[60]; m_pBoard[60] = PieceE.None; } m_bBlackCastle = false; m_iBlackKingPos = movePos.StartPos; } else { if (movePos.EndPos == 1) { UpdatePackedBoardAndZobristKey(0, m_pBoard[2], 2, PieceE.None); m_pBoard[0] = m_pBoard[2]; m_pBoard[2] = PieceE.None; } else { UpdatePackedBoardAndZobristKey(7, m_pBoard[4], 4, PieceE.None); m_pBoard[7] = m_pBoard[4]; m_pBoard[4] = PieceE.None; } m_bWhiteCastle = false; m_iWhiteKingPos = movePos.StartPos; } break; case MoveTypeE.EnPassant: UpdatePackedBoardAndZobristKey(movePos.StartPos, ePiece, movePos.EndPos, PieceE.None); m_pBoard[movePos.StartPos] = ePiece; m_pBoard[movePos.EndPos] = PieceE.None; eOriginalPiece = PieceE.Pawn | (((ePiece & PieceE.Black) == 0) ? PieceE.Black : PieceE.White); iOldPiecePos = (movePos.StartPos & 56) + (movePos.EndPos & 7); UpdatePackedBoardAndZobristKey(iOldPiecePos, eOriginalPiece); m_pBoard[iOldPiecePos] = eOriginalPiece; m_piPiecesCount[(int)eOriginalPiece]++; break; default: // Normal // PawnPromotionTo??? eOriginalPiece = movePos.OriginalPiece; switch(movePos.Type & MoveTypeE.MoveTypeMask) { case MoveTypeE.PawnPromotionToQueen: case MoveTypeE.PawnPromotionToRook: case MoveTypeE.PawnPromotionToBishop: case MoveTypeE.PawnPromotionToKnight: m_piPiecesCount[(int)ePiece]--; ePiece = PieceE.Pawn | (ePiece & PieceE.Black); m_piPiecesCount[(int)ePiece]++; break; case MoveTypeE.PawnPromotionToPawn: default: break; } UpdatePackedBoardAndZobristKey(movePos.StartPos, ePiece, movePos.EndPos, eOriginalPiece); m_pBoard[movePos.StartPos] = ePiece; m_pBoard[movePos.EndPos] = eOriginalPiece; m_piPiecesCount[(int)eOriginalPiece]++; switch(ePiece) { case PieceE.King | PieceE.Black: m_iBlackKingPos = movePos.StartPos; if (movePos.StartPos == 59) { m_iBlackKingMoveCount--; } break; case PieceE.King: m_iWhiteKingPos = movePos.StartPos; if (movePos.StartPos == 3) { m_iWhiteKingMoveCount--; } break; case PieceE.Rook | PieceE.Black: if (movePos.StartPos == 56) { m_iLBlackRookMoveCount--; } else if (movePos.StartPos == 63) { m_iRBlackRookMoveCount--; } break; case PieceE.Rook: if (movePos.StartPos == 0) { m_iLWhiteRookMoveCount--; } else if (movePos.StartPos == 7) { m_iRWhiteRookMoveCount--; } break; } break; } m_iPossibleEnPassantAt = m_stackPossibleEnPassantAt.Pop(); m_eNextMoveColor = (m_eNextMoveColor == PlayerColorE.White) ? PlayerColorE.Black : PlayerColorE.White; }
public Player(Game game, PlayerColorE color) { Game = game; Color = color; }
/// <summary> /// Enumerates all the possible moves for a player /// </summary> /// <param name="ePlayerColor"> Color doing the the move</param> /// <param name="posInfo"> Structure to fill with pieces information</param> public void ComputePiecesCoverage(PlayerColorE ePlayerColor, out PosInfoS posInfo) { EnumMoveList(ePlayerColor, false, out posInfo); }
/// <summary> /// Reset initial board info /// </summary> /// <param name="eNextMoveColor"> Next color moving</param> /// <param name="bInitialBoardStd"> true if its a standard board, false if coming from FEN or design mode</param> /// <param name="eMask"> Extra bord information</param> /// <param name="iEnPassant"> Position for en passant</param> private void ResetInitialBoardInfo(PlayerColorE eNextMoveColor, bool bInitialBoardStd, BoardStateMaskE eMask, int iEnPassant) { PieceE ePiece; int iEnPassantCol; Array.Clear(m_piPiecesCount, 0, m_piPiecesCount.Length); for (int iIndex = 0; iIndex < 64; iIndex++) { ePiece = m_pBoard[iIndex]; switch(ePiece) { case PieceE.King | PieceE.White: m_iWhiteKingPos = iIndex; break; case PieceE.King | PieceE.Black: m_iBlackKingPos = iIndex; break; } m_piPiecesCount[(int)ePiece]++; } if (iEnPassant != 0) { iEnPassantCol = (iEnPassant >> 3); if (iEnPassantCol != 2 && iEnPassantCol != 5) { if (iEnPassantCol == 3) { // Fixing old saved board which was keeping the en passant position at the position of the pawn instead of behind it iEnPassant -= 8; } else if (iEnPassantCol == 4) { iEnPassant += 8; } else { iEnPassant = 0; } } } m_iPossibleEnPassantAt = iEnPassant; m_iRBlackRookMoveCount = ((eMask & BoardStateMaskE.BRCastling) == BoardStateMaskE.BRCastling) ? 0 : 1; m_iLBlackRookMoveCount = ((eMask & BoardStateMaskE.BLCastling) == BoardStateMaskE.BLCastling) ? 0 : 1; m_iBlackKingMoveCount = 0; m_iRWhiteRookMoveCount = ((eMask & BoardStateMaskE.WRCastling) == BoardStateMaskE.WRCastling) ? 0 : 1; m_iLWhiteRookMoveCount = ((eMask & BoardStateMaskE.WLCastling) == BoardStateMaskE.WLCastling) ? 0 : 1; m_iWhiteKingMoveCount = 0; m_bWhiteCastle = false; m_bBlackCastle = false; m_i64ZobristKey = ZobristKey.ComputeBoardZobristKey(m_pBoard); m_eNextMoveColor = eNextMoveColor; m_bDesignMode = false; m_bStdInitialBoard = bInitialBoardStd; m_moveHistory.Reset(m_pBoard, ComputeBoardExtraInfo(PlayerColorE.White, false)); m_moveStack.Clear(); m_stackPossibleEnPassantAt.Clear(); }
/// <summary> /// Enumerates the en passant move /// </summary> /// <param name="ePlayerColor"> Color doing the the move</param> /// <param name="arrMovePos"> List of move</param> private void EnumEnPassant(PlayerColorE ePlayerColor, List<MovePosS> arrMovePos) { int iColPos; PieceE eAttackingPawn; PieceE ePawnInDanger; int iPosBehindPawn; int iPosPawnInDanger; if (m_iPossibleEnPassantAt != 0) { iPosBehindPawn = m_iPossibleEnPassantAt; if (ePlayerColor == PlayerColorE.White) { iPosPawnInDanger = iPosBehindPawn - 8; eAttackingPawn = PieceE.Pawn | PieceE.White; } else { iPosPawnInDanger = iPosBehindPawn + 8; eAttackingPawn = PieceE.Pawn | PieceE.Black; } ePawnInDanger = m_pBoard[iPosPawnInDanger]; // Check if there is an attacking pawn at the left iColPos = iPosPawnInDanger & 7; if (iColPos > 0 && m_pBoard[iPosPawnInDanger - 1] == eAttackingPawn) { m_pBoard[iPosPawnInDanger] = PieceE.None; AddIfNotCheck(ePlayerColor, iPosPawnInDanger - 1, iPosBehindPawn, MoveTypeE.EnPassant, arrMovePos); m_pBoard[iPosPawnInDanger] = ePawnInDanger; } if (iColPos < 7 && m_pBoard[iPosPawnInDanger+1] == eAttackingPawn) { m_pBoard[iPosPawnInDanger] = PieceE.None; AddIfNotCheck(ePlayerColor, iPosPawnInDanger + 1, iPosBehindPawn, MoveTypeE.EnPassant, arrMovePos); m_pBoard[iPosPawnInDanger] = ePawnInDanger; } } }
/// <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="searchMode"> Search mode</param> /// <param name="ePlayerToPlay"> Color of the player to play</param> /// <param name="iDepth"> Depth of the search</param> /// <param name="iMoveCountDelta"> White move count - Black move count</param> /// <param name="posInfoWhite"> Information about pieces attack</param> /// <param name="posInfoBlack"> Information about pieces attack</param> /// <returns> /// Number of points for the current board /// </returns> public int Points(SearchEngine.SearchMode searchMode, PlayerColorE ePlayerToPlay, int iDepth, int iMoveCountDelta, PosInfoS posInfoWhite, PosInfoS posInfoBlack) { int iRetVal; IBoardEvaluation boardEval; PosInfoS posInfoTmp; if (ePlayerToPlay == PlayerColorE.White) { boardEval = searchMode.m_boardEvaluationWhite; posInfoTmp = posInfoWhite; } else { boardEval = searchMode.m_boardEvaluationBlack; posInfoTmp.m_iAttackedPieces = -posInfoBlack.m_iAttackedPieces; posInfoTmp.m_iPiecesDefending = -posInfoBlack.m_iPiecesDefending; } iRetVal = boardEval.Points(m_pBoard, m_piPiecesCount, posInfoTmp, m_iWhiteKingPos, m_iBlackKingPos, m_bWhiteCastle, m_bBlackCastle, iMoveCountDelta); return(iRetVal); }
//********************************************************* // /// <summary> /// Enumerates the move a specified piece can do using the pre-compute move array /// </summary> /// <param name="ePlayerColor"> Color doing the the move</param> /// <param name="iStartPos"> Starting position</param> /// <param name="piMoveListForThisCase"> Array of possible moves</param> /// <param name="arrMovePos"> List of move</param> // //********************************************************* private void EnumFromArray(PlayerColorE ePlayerColor, int iStartPos, int[] piMoveListForThisCase, List<MovePosS> arrMovePos) { foreach (int iNewPos in piMoveListForThisCase) { AddMoveIfEnemyOrEmpty(ePlayerColor, iStartPos, iNewPos, arrMovePos); } }
//********************************************************* // /// <summary> /// Determine if the specified king is attacked /// </summary> /// <param name="eColor"> King's color to check</param> /// <returns> /// true if in check /// </returns> // //********************************************************* public bool IsCheck(PlayerColorE eColor) { return(IsCheck(eColor, (eColor == PlayerColorE.Black) ? m_iBlackKingPos : m_iWhiteKingPos)); }
//********************************************************* // /// <summary> /// Enumerates all the possible moves for a player /// </summary> /// <param name="ePlayerColor"> Color doing the the move</param> /// <returns> /// List of possible moves /// </returns> // //********************************************************* public List<MovePosS> EnumMoveList(PlayerColorE ePlayerColor) { int iAttackedPos; int iAttackedPieces; return(EnumMoveList(ePlayerColor, true, out iAttackedPos, out iAttackedPieces)); }
//********************************************************* // /// <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="searchMode"> Search mode</param> /// <param name="ePlayerToPlay"> Color of the player to play</param> /// <param name="iMoveCountDelta"> White move count - Black move count</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 peices attacked by all pieces. (Value computed before the last move for performance reason)</param> /// <returns> /// Number of points for the current board /// </returns> // //********************************************************* public int Points(SearchEngine.SearchMode searchMode, PlayerColorE ePlayerToPlay, int iMoveCountDelta, int iAttackedPos, int iAttackedPieces) { int iRetVal; IBoardEvaluation boardEval; if (ePlayerToPlay == PlayerColorE.White) { boardEval = searchMode.m_boardEvaluationWhite; } else { boardEval = searchMode.m_boardEvaluationBlack; iAttackedPos = -iAttackedPos; iAttackedPieces = -iAttackedPieces; } iRetVal = boardEval.Points(m_pBoard, m_piPiecesCount, iAttackedPos, iAttackedPieces, m_iWhiteKingPos, m_iBlackKingPos, m_bWhiteCastle, m_bBlackCastle, iMoveCountDelta); return(iRetVal); }
//********************************************************* // /// <summary> /// Find the best move for a player using alpha-beta pruning or minmax search /// </summary> /// <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(SearchEngine.SearchMode searchMode, PlayerColorE ePlayerColor, out MovePosS moveBest, out int iPermCount, out int iCacheHit, out int iMaxDepth) { bool bRetVal; bool bUseAlphaBeta; SearchEngine searchEngine; bUseAlphaBeta = ((searchMode.m_eOption & SearchEngine.SearchMode.OptionE.UseAlphaBeta) != 0); searchEngine = bUseAlphaBeta ? (SearchEngine)m_searchEngineAlphaBeta : (SearchEngine)m_searchEngineMinMax; bRetVal = searchEngine.FindBestMove(this, searchMode, ePlayerColor, out moveBest, out iPermCount, out iCacheHit, out iMaxDepth); return(bRetVal); }
//********************************************************* // /// <summary> /// Add a move to the move list if the move doesn't provokes the king to be attacked. /// </summary> /// <param name="ePlayerColor"> Color doing the the move</param> /// <param name="iStartPos"> Starting position</param> /// <param name="iEndPos"> Ending position</param> /// <param name="eType"> type of the move</param> /// <param name="arrMovePos"> List of move</param> // //********************************************************* private void AddIfNotCheck(PlayerColorE ePlayerColor, int iStartPos, int iEndPos, MoveTypeE eType, List<MovePosS> arrMovePos) { PieceE eNewPiece; PieceE eOldPiece; MovePosS tMovePos; bool bIsCheck; eOldPiece = m_pBoard[iEndPos]; eNewPiece = m_pBoard[iStartPos]; m_pBoard[iEndPos] = eNewPiece; m_pBoard[iStartPos] = PieceE.None; bIsCheck = ((eNewPiece & PieceE.PieceMask) == PieceE.King) ? IsCheck(ePlayerColor, iEndPos) : IsCheck(ePlayerColor); m_pBoard[iStartPos] = m_pBoard[iEndPos]; m_pBoard[iEndPos] = eOldPiece; if (!bIsCheck) { tMovePos.OriginalPiece = m_pBoard[iEndPos]; tMovePos.StartPos = (byte)iStartPos; tMovePos.EndPos = (byte)iEndPos; tMovePos.Type = eType; if (m_pBoard[iEndPos] != PieceE.None || eType == MoveTypeE.EnPassant) { tMovePos.Type |= MoveTypeE.PieceEaten; m_iAttackedPieces++; } if (arrMovePos != null) { arrMovePos.Add(tMovePos); } } }
//********************************************************* // /// <summary> /// Find a move from the valid move list /// </summary> /// <param name="ePlayerColor"> Color doing the move</param> /// <param name="iStartPos"> Position to start</param> /// <param name="iEndPos"> Ending position</param> /// <returns> /// Move or -1 /// </returns> // //********************************************************* public MovePosS FindIfValid(PlayerColorE ePlayerColor, int iStartPos, int iEndPos) { MovePosS tMoveRetVal; List<MovePosS> moveList; tMoveRetVal.StartPos = 255; tMoveRetVal.EndPos = 255; tMoveRetVal.OriginalPiece = PieceE.None; tMoveRetVal.Type = MoveTypeE.Normal; moveList = EnumMoveList(ePlayerColor); foreach (MovePosS move in moveList) { if (move.StartPos == iStartPos && move.EndPos == iEndPos) { tMoveRetVal = move; break; } } return(tMoveRetVal); }
//********************************************************* // /// <summary> /// Add a pawn promotion series of moves to the move list if the move doesn't provokes the king to be attacked. /// </summary> /// <param name="ePlayerColor"> Color doing the the move</param> /// <param name="iStartPos"> Starting position</param> /// <param name="iEndPos"> Ending position</param> /// <param name="arrMovePos"> List of move</param> // //********************************************************* private void AddPawnPromotionIfNotCheck(PlayerColorE ePlayerColor, int iStartPos, int iEndPos, List<MovePosS> arrMovePos) { AddIfNotCheck(ePlayerColor, iStartPos, iEndPos, MoveTypeE.PawnPromotionToQueen, arrMovePos); AddIfNotCheck(ePlayerColor, iStartPos, iEndPos, MoveTypeE.PawnPromotionToRook, arrMovePos); AddIfNotCheck(ePlayerColor, iStartPos, iEndPos, MoveTypeE.PawnPromotionToBishop, arrMovePos); AddIfNotCheck(ePlayerColor, iStartPos, iEndPos, MoveTypeE.PawnPromotionToKnight, arrMovePos); AddIfNotCheck(ePlayerColor, iStartPos, iEndPos, MoveTypeE.PawnPromotionToPawn, arrMovePos); }
//********************************************************* // /// <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> /// Add a move to the move list if the new position is empty or is an enemy /// </summary> /// <param name="ePlayerColor"> Color doing the the move</param> /// <param name="iStartPos"> Starting position</param> /// <param name="iEndPos"> Ending position</param> /// <param name="arrMovePos"> List of move</param> // //********************************************************* private bool AddMoveIfEnemyOrEmpty(PlayerColorE ePlayerColor, int iStartPos, int iEndPos, List<MovePosS> arrMovePos) { bool bRetVal; PieceE eOldPiece; bRetVal = (m_pBoard[iEndPos] == PieceE.None); eOldPiece = m_pBoard[iEndPos]; if (bRetVal || ((eOldPiece & PieceE.Black) != 0) != (ePlayerColor == PlayerColorE.Black)) { AddIfNotCheck(ePlayerColor, iStartPos, iEndPos, MoveTypeE.Normal, arrMovePos); } return(bRetVal); }
//********************************************************* // /// <summary> /// Reset initial board info /// </summary> /// <param name="eNextMoveColor"> Next color moving</param> /// <param name="bInitialBoardStd"> true if its a standard board, false if coming from FEN or design mode</param> /// <param name="eMask"> Extra bord information</param> /// <param name="iEnPassant"> Position for en passant</param> // //********************************************************* private void ResetInitialBoardInfo(PlayerColorE eNextMoveColor, bool bInitialBoardStd, BoardStateMaskE eMask, int iEnPassant) { PieceE ePiece; for (int iIndex = 0; iIndex < m_piPiecesCount.Length; iIndex++) { m_piPiecesCount[iIndex] = 0; } for (int iIndex = 0; iIndex < 64; iIndex++) { ePiece = m_pBoard[iIndex]; switch(ePiece) { case PieceE.King | PieceE.White: m_iWhiteKingPos = iIndex; break; case PieceE.King | PieceE.Black: m_iBlackKingPos = iIndex; break; } m_piPiecesCount[(int)ePiece]++; } m_iPossibleEnPassantAt = iEnPassant; m_iRBlackRookMoveCount = ((eMask & BoardStateMaskE.BRCastling) == BoardStateMaskE.BRCastling) ? 0 : 1; m_iLBlackRookMoveCount = ((eMask & BoardStateMaskE.BLCastling) == BoardStateMaskE.BLCastling) ? 0 : 1; m_iBlackKingMoveCount = 0; m_iRWhiteRookMoveCount = ((eMask & BoardStateMaskE.WRCastling) == BoardStateMaskE.WRCastling) ? 0 : 1; m_iLWhiteRookMoveCount = ((eMask & BoardStateMaskE.WLCastling) == BoardStateMaskE.WLCastling) ? 0 : 1; m_iWhiteKingMoveCount = 0; m_bWhiteCastle = false; m_bBlackCastle = false; m_i64ZobristKey = ZobristKey.ComputeBoardZobristKey(m_pBoard); m_eNextMoveColor = eNextMoveColor; m_bDesignMode = false; m_bStdInitialBoard = bInitialBoardStd; m_moveHistory.Reset(m_pBoard, ComputeBoardExtraInfo(PlayerColorE.White, false)); m_moveStack.Clear(); m_stackPossibleEnPassantAt.Clear(); }
//********************************************************* // /// <summary> /// Enumerates the castling move /// </summary> /// <param name="ePlayerColor"> Color doing the the move</param> /// <param name="arrMovePos"> List of move</param> // //********************************************************* private void EnumCastleMove(PlayerColorE ePlayerColor, List<MovePosS> arrMovePos) { if (ePlayerColor == PlayerColorE.Black) { if (!m_bBlackCastle) { if (m_iBlackKingMoveCount == 0) { if (m_iLBlackRookMoveCount == 0 && m_pBoard[57] == PieceE.None && m_pBoard[58] == PieceE.None) { if (EnumAttackPos(ePlayerColor, 58, null) == 0 && EnumAttackPos(ePlayerColor, 59, null) == 0) { AddIfNotCheck(ePlayerColor, 59, 57, MoveTypeE.Castle, arrMovePos); } } if (m_iRBlackRookMoveCount == 0 && m_pBoard[60] == PieceE.None && m_pBoard[61] == PieceE.None && m_pBoard[62] == PieceE.None) { if (EnumAttackPos(ePlayerColor, 59, null) == 0 && EnumAttackPos(ePlayerColor, 60, null) == 0) { AddIfNotCheck(ePlayerColor, 59, 61, MoveTypeE.Castle, arrMovePos); } } } } } else { if (!m_bWhiteCastle) { if (m_iWhiteKingMoveCount == 0) { if (m_iLWhiteRookMoveCount == 0 && m_pBoard[1] == PieceE.None && m_pBoard[2] == PieceE.None) { if (EnumAttackPos(ePlayerColor, 2, null) == 0 && EnumAttackPos(ePlayerColor, 3, null) == 0) { AddIfNotCheck(ePlayerColor, 3, 1, MoveTypeE.Castle, arrMovePos); } } if (m_iRWhiteRookMoveCount == 0 && m_pBoard[4] == PieceE.None && m_pBoard[5] == PieceE.None && m_pBoard[6] == PieceE.None) { if (EnumAttackPos(ePlayerColor, 3, null) == 0 && EnumAttackPos(ePlayerColor, 4, null) == 0) { AddIfNotCheck(ePlayerColor, 3, 5, MoveTypeE.Castle, arrMovePos); } } } } } }
//********************************************************* // /// <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> /// Enumerates the move a specified pawn can do /// </summary> /// <param name="ePlayerColor"> Color doing the the move</param> /// <param name="iStartPos"> Pawn position</param> /// <param name="arrMovePos"> List of move</param> // //********************************************************* private void EnumPawnMove(PlayerColorE ePlayerColor, int iStartPos, List<MovePosS> arrMovePos) { int iDir; int iNewPos; int iNewColPos; int iRowPos; bool bCanMove2Case; iRowPos = (iStartPos >> 3); bCanMove2Case = (ePlayerColor == PlayerColorE.Black) ? (iRowPos == 6) : (iRowPos == 1); iDir = (ePlayerColor == PlayerColorE.Black) ? -8 : 8; iNewPos = iStartPos + iDir; if (iNewPos >= 0 && iNewPos < 64) { if (m_pBoard[iNewPos] == PieceE.None) { iRowPos = (iNewPos >> 3); if (iRowPos == 0 || iRowPos == 7) { AddPawnPromotionIfNotCheck(ePlayerColor, iStartPos, iNewPos, arrMovePos); } else { AddIfNotCheck(ePlayerColor, iStartPos, iNewPos, MoveTypeE.Normal, arrMovePos); } if (bCanMove2Case && m_pBoard[iNewPos+iDir] == PieceE.None) { AddIfNotCheck(ePlayerColor, iStartPos, iNewPos+iDir, MoveTypeE.Normal, arrMovePos); } } } iNewPos = iStartPos + iDir; if (iNewPos >= 0 && iNewPos < 64) { iNewColPos = iNewPos & 7; iRowPos = (iNewPos >> 3); if (iNewColPos != 0 && m_pBoard[iNewPos - 1] != PieceE.None && ((m_pBoard[iNewPos - 1] & PieceE.Black) == 0) == (ePlayerColor == PlayerColorE.Black)) { if (iRowPos == 0 || iRowPos == 7) { AddPawnPromotionIfNotCheck(ePlayerColor, iStartPos, iNewPos - 1, arrMovePos); } else { AddIfNotCheck(ePlayerColor, iStartPos, iNewPos - 1, MoveTypeE.Normal, arrMovePos); } } if (iNewColPos != 7 && m_pBoard[iNewPos + 1] != PieceE.None && ((m_pBoard[iNewPos + 1] & PieceE.Black) == 0) == (ePlayerColor == PlayerColorE.Black)) { if (iRowPos == 0 || iRowPos == 7) { AddPawnPromotionIfNotCheck(ePlayerColor, iStartPos, iNewPos + 1, arrMovePos); } else { AddIfNotCheck(ePlayerColor, iStartPos, iNewPos + 1, MoveTypeE.Normal, arrMovePos); } } } }
//********************************************************* // /// <summary> /// Do the move (without log) /// </summary> /// <param name="movePos"> Move to do</param> /// <returns> /// NoRepeat No repetition /// ThreeFoldRepeat Three times the same board /// FiftyRuleRepeat Fifty moves without pawn move or piece eaten /// </returns> // //********************************************************* public RepeatResultE DoMoveNoLog(MovePosS movePos) { RepeatResultE eRetVal; PieceE ePiece; PieceE eOldPiece; int iOldPiecePos; int iDelta; bool bPawnMoveOrPieceEaten; m_stackPossibleEnPassantAt.Push(m_iPossibleEnPassantAt); m_iPossibleEnPassantAt = 0; ePiece = m_pBoard[movePos.StartPos]; bPawnMoveOrPieceEaten = ((ePiece & PieceE.PieceMask) == PieceE.Pawn) | ((movePos.Type & MoveTypeE.PieceEaten) == MoveTypeE.PieceEaten); switch(movePos.Type & MoveTypeE.MoveTypeMask) { case MoveTypeE.Castle: UpdatePackedBoardAndZobristKey(movePos.EndPos, ePiece, movePos.StartPos, PieceE.None); m_pBoard[movePos.EndPos] = ePiece; m_pBoard[movePos.StartPos] = PieceE.None; eOldPiece = PieceE.None; if ((ePiece & PieceE.Black) != 0) { if (movePos.EndPos == 57) { UpdatePackedBoardAndZobristKey(58, m_pBoard[56], 56, PieceE.None); m_pBoard[58] = m_pBoard[56]; m_pBoard[56] = PieceE.None; } else { UpdatePackedBoardAndZobristKey(60, m_pBoard[63], 63, PieceE.None); m_pBoard[60] = m_pBoard[63]; m_pBoard[63] = PieceE.None; } m_bBlackCastle = true; m_iBlackKingPos = movePos.EndPos; } else { if (movePos.EndPos == 1) { UpdatePackedBoardAndZobristKey(2, m_pBoard[0], 0, PieceE.None); m_pBoard[2] = m_pBoard[0]; m_pBoard[0] = PieceE.None; } else { UpdatePackedBoardAndZobristKey(4, m_pBoard[7], 7, PieceE.None); m_pBoard[4] = m_pBoard[7]; m_pBoard[7] = PieceE.None; } m_bWhiteCastle = true; m_iWhiteKingPos = movePos.EndPos; } break; case MoveTypeE.EnPassant: UpdatePackedBoardAndZobristKey(movePos.EndPos, ePiece, movePos.StartPos, PieceE.None); m_pBoard[movePos.EndPos] = ePiece; m_pBoard[movePos.StartPos] = PieceE.None; iOldPiecePos = (movePos.StartPos & 56) + (movePos.EndPos & 7); eOldPiece = m_pBoard[iOldPiecePos]; UpdatePackedBoardAndZobristKey(iOldPiecePos, PieceE.None); m_pBoard[iOldPiecePos] = PieceE.None; m_piPiecesCount[(int)eOldPiece]--; break; default: // Normal // PawnPromotionTo??? eOldPiece = m_pBoard[movePos.EndPos]; switch(movePos.Type & MoveTypeE.MoveTypeMask) { case MoveTypeE.PawnPromotionToQueen: m_piPiecesCount[(int)ePiece]--; ePiece = PieceE.Queen | (ePiece & PieceE.Black); m_piPiecesCount[(int)ePiece]++; break; case MoveTypeE.PawnPromotionToRook: m_piPiecesCount[(int)ePiece]--; ePiece = PieceE.Rook | (ePiece & PieceE.Black); m_piPiecesCount[(int)ePiece]++; break; case MoveTypeE.PawnPromotionToBishop: m_piPiecesCount[(int)ePiece]--; ePiece = PieceE.Bishop | (ePiece & PieceE.Black); m_piPiecesCount[(int)ePiece]++; break; case MoveTypeE.PawnPromotionToKnight: m_piPiecesCount[(int)ePiece]--; ePiece = PieceE.Knight | (ePiece & PieceE.Black); m_piPiecesCount[(int)ePiece]++; break; case MoveTypeE.PawnPromotionToPawn: default: break; } UpdatePackedBoardAndZobristKey(movePos.EndPos, ePiece, movePos.StartPos, PieceE.None); m_pBoard[movePos.EndPos] = ePiece; m_pBoard[movePos.StartPos] = PieceE.None; m_piPiecesCount[(int)eOldPiece]--; switch(ePiece) { case PieceE.King | PieceE.Black: m_iBlackKingPos = movePos.EndPos; if (movePos.StartPos == 59) { m_iBlackKingMoveCount++; } break; case PieceE.King: m_iWhiteKingPos = movePos.EndPos; if (movePos.StartPos == 3) { m_iWhiteKingMoveCount++; } break; case PieceE.Rook | PieceE.Black: if (movePos.StartPos == 56) { m_iLBlackRookMoveCount++; } else if (movePos.StartPos == 63) { m_iRBlackRookMoveCount++; } break; case PieceE.Rook: if (movePos.StartPos == 0) { m_iLWhiteRookMoveCount++; } else if (movePos.StartPos == 7) { m_iRWhiteRookMoveCount++; } break; case PieceE.Pawn: case PieceE.Pawn | PieceE.Black: iDelta = movePos.StartPos - movePos.EndPos; if (iDelta == -16 || iDelta == 16) { m_iPossibleEnPassantAt = movePos.EndPos; } break; } break; } m_moveHistory.UpdateCurrentPackedBoard(ComputeBoardExtraInfo(PlayerColorE.White, false)); eRetVal = m_moveHistory.AddCurrentPackedBoard(m_i64ZobristKey, bPawnMoveOrPieceEaten); m_eNextMoveColor = (m_eNextMoveColor == PlayerColorE.White) ? PlayerColorE.Black : PlayerColorE.White; return(eRetVal); }
//********************************************************* // /// <summary> /// Enumerates the en passant move /// </summary> /// <param name="ePlayerColor"> Color doing the the move</param> /// <param name="arrMovePos"> List of move</param> // //********************************************************* private void EnumEnPassant(PlayerColorE ePlayerColor, List<MovePosS> arrMovePos) { int iColPos; PieceE eFriendlyPawn; PieceE eEnemyPawn; int iDelta; if (m_iPossibleEnPassantAt != 0) { eEnemyPawn = m_pBoard[m_iPossibleEnPassantAt]; eFriendlyPawn = eEnemyPawn ^ PieceE.Black; iColPos = m_iPossibleEnPassantAt & 7; iDelta = (ePlayerColor == PlayerColorE.Black) ? -8 : 8; if (iColPos > 0 && m_pBoard[m_iPossibleEnPassantAt - 1] == eFriendlyPawn) { m_pBoard[m_iPossibleEnPassantAt] = PieceE.None; AddIfNotCheck(ePlayerColor, m_iPossibleEnPassantAt - 1, m_iPossibleEnPassantAt + iDelta, MoveTypeE.EnPassant, arrMovePos); m_pBoard[m_iPossibleEnPassantAt] = eEnemyPawn; } if (iColPos < 7 && m_pBoard[m_iPossibleEnPassantAt+1] == eFriendlyPawn) { m_pBoard[m_iPossibleEnPassantAt] = PieceE.None; AddIfNotCheck(ePlayerColor, m_iPossibleEnPassantAt + 1, m_iPossibleEnPassantAt + iDelta, MoveTypeE.EnPassant, arrMovePos); m_pBoard[m_iPossibleEnPassantAt] = eEnemyPawn; } } }