public Bitboard[] GetPinLimitations(int valuablePieceSquareIndex, GameSide attackingSide) { var result = DefaultPinLimitations.Copy(); var enemyPieces = PiecePosition[attackingSide]; var ownPieces = PiecePosition[attackingSide.Invert()]; var queens = PiecePosition[attackingSide.ToPiece(PieceType.Queen)]; var bishops = PiecePosition[attackingSide.ToPiece(PieceType.Bishop)]; var rooks = PiecePosition[attackingSide.ToPiece(PieceType.Rook)]; PopulatePinLimitations( result, enemyPieces, valuablePieceSquareIndex, ownPieces, DiagonallySlidingAttacks, queens | bishops); PopulatePinLimitations( result, enemyPieces, valuablePieceSquareIndex, ownPieces, StraightSlidingAttacks, queens | rooks); return(result); }
public static bool HasNonPawnMaterial([NotNull] this GameBoard board, GameSide side) { if (board is null) { throw new ArgumentNullException(nameof(board)); } var nonPawnBitboard = board.GetBitboard(side) & ~board.GetBitboard(side.ToPiece(PieceType.King)) & ~board.GetBitboard(side.ToPiece(PieceType.Pawn)); return(nonPawnBitboard.IsAny); }
public bool IsInCheck(GameSide side) { var king = side.ToPiece(PieceType.King); var oppositeSide = side.Invert(); var kingSquares = PiecePosition[king].GetSquares(); return(kingSquares.Length != 0 && IsAnyUnderAttack(kingSquares, oppositeSide)); }
private bool IsKingLeftOnly(GameSide side) { var sideBitboard = PiecePosition[side]; var kingBitboard = PiecePosition[side.ToPiece(PieceType.King)]; var otherPieces = sideBitboard & ~kingBitboard; return(otherPieces.IsNone); }
protected void GeneratePotentialKingMoves( [NotNull] ICollection <GameMoveData2> resultMoves, GameSide side, GeneratedMoveTypes moveTypes, Bitboard target, CastlingOptions allowedCastlingOptions) { if (resultMoves is null) { throw new ArgumentNullException(nameof(resultMoves)); } var kingPiece = side.ToPiece(PieceType.King); var kings = PiecePosition[kingPiece]; while (kings.IsAny) { var kingSquareIndex = Bitboard.PopFirstSquareIndex(ref kings); var sourceSquare = new Square(kingSquareIndex); var moves = KingAttacksOrMoves[kingSquareIndex]; var movesOnTarget = moves & target; if (moveTypes.IsAnySet(GeneratedMoveTypes.Capture)) { var enemies = PiecePosition[side.Invert()]; var captures = movesOnTarget & enemies; PopulateSimpleMoves(resultMoves, sourceSquare, captures, GameMoveFlags.IsRegularCapture); } //// ReSharper disable once InvertIf if (moveTypes.IsAnySet(GeneratedMoveTypes.Quiet)) { var emptySquares = PiecePosition[Piece.None]; var nonCaptures = movesOnTarget & emptySquares; PopulateSimpleMoves(resultMoves, sourceSquare, nonCaptures, GameMoveFlags.None); var nonEmptySquares = ~emptySquares; PopulateKingCastlingMoves( resultMoves, sourceSquare, target, allowedCastlingOptions, nonEmptySquares, CastlingSide.KingSide.ToCastlingType(side)); PopulateKingCastlingMoves( resultMoves, sourceSquare, target, allowedCastlingOptions, nonEmptySquares, CastlingSide.QueenSide.ToCastlingType(side)); } } }
public void GenerateKingMoves( [NotNull] ICollection <GameMoveData> resultMoves, GameSide side, CastlingOptions allowedCastlingOptions, Bitboard target) { if (resultMoves is null) { throw new ArgumentNullException(nameof(resultMoves)); } var kingPiece = side.ToPiece(PieceType.King); var king = PiecePosition[kingPiece]; if (king.IsNone) { return; } if (!king.IsExactlyOneSquare()) { throw new ChessPlatformException( $@"There are multiple {kingPiece.GetDescription()} pieces ({king.GetSquareCount()}) on the board."); } var kingSquareIndex = king.FindFirstSquareIndex(); var sourceSquare = new Square(kingSquareIndex); var directTargets = KingAttacksOrMoves[kingSquareIndex] & target; var emptySquares = PiecePosition[Piece.None]; var nonCaptures = directTargets & emptySquares; PopulateSimpleMoves(resultMoves, sourceSquare, nonCaptures, GameMoveFlags.None); var enemies = PiecePosition[side.Invert()]; var captures = directTargets & enemies; PopulateSimpleMoves(resultMoves, sourceSquare, captures, GameMoveFlags.IsRegularCapture); var nonEmptySquares = ~emptySquares; PopulateKingCastlingMoves( resultMoves, sourceSquare, allowedCastlingOptions, nonEmptySquares, CastlingSide.KingSide.ToCastlingType(side)); PopulateKingCastlingMoves( resultMoves, sourceSquare, allowedCastlingOptions, nonEmptySquares, CastlingSide.QueenSide.ToCastlingType(side)); }
public static bool IsInCheck([NotNull] this GamePosition gamePosition, GameSide side) { if (gamePosition is null) { throw new ArgumentNullException(nameof(gamePosition)); } var king = side.ToPiece(PieceType.King); var attackingSide = side.Invert(); var kingSquares = gamePosition.PiecePosition[king].GetSquares(); return(gamePosition.IsAnyUnderAttack(kingSquares, attackingSide)); }
private static int EvaluatePawnStructureBySide(GameBoard board, GameSide side, GamePhase gamePhase) { var pawnPiece = side.ToPiece(PieceType.Pawn); var pawns = board.GetBitboard(pawnPiece); if (pawns.IsNone) { return(0); } int[] extraPawnPenalties; int[] isolatedPawnPenalties; if (gamePhase == GamePhase.Endgame) { extraPawnPenalties = EndgameExtraPawnPenalties; isolatedPawnPenalties = EndgameIsolatedPawnPenalties; } else { extraPawnPenalties = MiddlegameExtraPawnPenalties; isolatedPawnPenalties = MiddlegameIsolatedPawnPenalties; } var result = 0; for (var fileIndex = 0; fileIndex < ChessConstants.FileCount; fileIndex++) { var file = Bitboards.Files[fileIndex]; var pawnsOnFile = pawns & file; if (pawnsOnFile.IsNone) { continue; } var count = pawnsOnFile.GetSquareCount(); //// Extra pawns on files (double/triple/etc) var extraCount = Math.Max(0, count - 1); result -= extraCount * extraPawnPenalties[fileIndex]; var adjacentFiles = AdjacentFiles[fileIndex]; var adjacentFilesPawns = pawns & adjacentFiles; if (adjacentFilesPawns.IsNone) { //// Isolated pawns on file result -= count * isolatedPawnPenalties[fileIndex]; } } return(result); }
private static int EvaluateKingTropism([NotNull] GameBoard board, GameSide kingSide) { var king = kingSide.ToPiece(PieceType.King); var kingSquare = board.GetBitboard(king).GetFirstSquare(); var allAttackersBitboard = board.GetBitboard(kingSide.Invert()); var result = 0; var remainingAttackers = allAttackersBitboard; int attackerSquareIndex; while ((attackerSquareIndex = Bitboard.PopFirstSquareIndex(ref remainingAttackers)) >= 0) { var attackerSquare = new Square(attackerSquareIndex); var score = GetKingTropismScore(board, attackerSquare, kingSquare); result -= score; } return(result / KingTropismRelativeFactor); }
public void TestToPiece(GameSide side, PieceType pieceType, Piece expectedPiece) { var piece = side.ToPiece(pieceType); Assert.That(piece, Is.EqualTo(expectedPiece)); }
protected void GeneratePotentialPawnMoves( [NotNull] ICollection <GameMoveData2> resultMoves, GameSide side, GeneratedMoveTypes moveTypes, Bitboard target, Bitboard enPassantCaptureTarget) { if (resultMoves is null) { throw new ArgumentNullException(nameof(resultMoves)); } var pawnPiece = side.ToPiece(PieceType.Pawn); var pawns = PiecePosition[pawnPiece]; if (pawns.IsNone) { return; } var rank8 = side == GameSide.White ? Bitboards.Rank8 : Bitboards.Rank1; if (moveTypes.IsAnySet(GeneratedMoveTypes.Quiet)) { var forwardDirection = side == GameSide.White ? ShiftDirection.North : ShiftDirection.South; var emptySquares = PiecePosition[Piece.None]; var pushes = pawns.Shift(forwardDirection) & emptySquares; var targetPushes = pushes & target; if (targetPushes.IsAny) { var nonPromotionPushes = targetPushes & ~rank8; PopulatePawnMoves(resultMoves, nonPromotionPushes, (int)forwardDirection, GameMoveFlags.None); var promotionPushes = targetPushes & rank8; PopulatePawnMoves( resultMoves, promotionPushes, (int)forwardDirection, GameMoveFlags.IsPawnPromotion); } if (pushes.IsAny) { var rank3 = side == GameSide.White ? Bitboards.Rank3 : Bitboards.Rank6; var doublePushes = (pushes & rank3).Shift(forwardDirection) & emptySquares & target; PopulatePawnMoves( resultMoves, doublePushes, (int)forwardDirection << 1, GameMoveFlags.None); } } //// ReSharper disable once InvertIf if (moveTypes.IsAnySet(GeneratedMoveTypes.Capture)) { var enemies = PiecePosition[side.Invert()]; var enemyTargets = enemies & target; var leftCaptureOffset = side == GameSide.White ? ShiftDirection.NorthWest : ShiftDirection.SouthEast; PopulatePawnCaptures(resultMoves, pawns, enemyTargets, leftCaptureOffset, rank8, enPassantCaptureTarget); var rightCaptureOffset = side == GameSide.White ? ShiftDirection.NorthEast : ShiftDirection.SouthWest; PopulatePawnCaptures(resultMoves, pawns, enemyTargets, rightCaptureOffset, rank8, enPassantCaptureTarget); } }
protected void GeneratePotentialKnightMoves( [NotNull] ICollection <GameMoveData2> resultMoves, GameSide side, GeneratedMoveTypes moveTypes, Bitboard target) { if (resultMoves is null) { throw new ArgumentNullException(nameof(resultMoves)); } var emptySquares = PiecePosition[Piece.None]; var enemies = PiecePosition[side.Invert()]; var internalTarget = Bitboard.None; if (moveTypes.IsAnySet(GeneratedMoveTypes.Quiet)) { internalTarget |= emptySquares; } if (moveTypes.IsAnySet(GeneratedMoveTypes.Capture)) { internalTarget |= enemies; } var actualTarget = target & internalTarget; if (actualTarget.IsNone) { return; } var knightPiece = side.ToPiece(PieceType.Knight); var knights = PiecePosition[knightPiece]; while (knights.IsAny) { var sourceSquareIndex = Bitboard.PopFirstSquareIndex(ref knights); var moves = KnightAttacksOrMoves[sourceSquareIndex]; var movesOnTarget = moves & actualTarget; if (movesOnTarget.IsNone) { continue; } var sourceSquare = new Square(sourceSquareIndex); if (moveTypes.IsAnySet(GeneratedMoveTypes.Capture)) { var captures = movesOnTarget & enemies; PopulateSimpleMoves(resultMoves, sourceSquare, captures, GameMoveFlags.IsRegularCapture); } //// ReSharper disable once InvertIf if (moveTypes.IsAnySet(GeneratedMoveTypes.Quiet)) { var nonCaptures = movesOnTarget & emptySquares; PopulateSimpleMoves(resultMoves, sourceSquare, nonCaptures, GameMoveFlags.None); } } }
private Bitboard GetAttackersInternal( Square targetSquare, GameSide attackingSide, bool findFirstAttackOnly) { var result = new Bitboard(); var targetBitboard = targetSquare.Bitboard; var targetSquareIndex = targetSquare.SquareIndex; var opponentPawns = PiecePosition[attackingSide.ToPiece(PieceType.Pawn)]; if (opponentPawns.IsAny) { ShiftDirection left; ShiftDirection right; if (attackingSide == GameSide.White) { left = ShiftDirection.SouthEast; right = ShiftDirection.SouthWest; } else { left = ShiftDirection.NorthWest; right = ShiftDirection.NorthEast; } var attackingPawns = (targetBitboard.Shift(left) | targetBitboard.Shift(right)) & opponentPawns; result |= attackingPawns; if (findFirstAttackOnly && result.IsAny) { return(result); } } var opponentKnights = PiecePosition[attackingSide.ToPiece(PieceType.Knight)]; if (opponentKnights.IsAny) { var knightAttacks = KnightAttacksOrMoves[targetSquareIndex]; var attackingKnights = knightAttacks & opponentKnights; result |= attackingKnights; if (findFirstAttackOnly && result.IsAny) { return(result); } } var opponentKings = PiecePosition[attackingSide.ToPiece(PieceType.King)]; if (opponentKings.IsAny) { var kingAttacks = KingAttacksOrMoves[targetSquareIndex]; var attackingKings = kingAttacks & opponentKings; result |= attackingKings; if (findFirstAttackOnly && result.IsAny) { return(result); } } var emptySquareBitboard = PiecePosition[Piece.None]; var opponentQueens = PiecePosition[attackingSide.ToPiece(PieceType.Queen)]; var opponentRooks = PiecePosition[attackingSide.ToPiece(PieceType.Rook)]; var opponentSlidingStraightPieces = opponentQueens | opponentRooks; var slidingStraightAttackers = GetSlidingAttackers( targetSquareIndex, opponentSlidingStraightPieces, StraightSlidingAttacks, emptySquareBitboard, findFirstAttackOnly); result |= slidingStraightAttackers; if (findFirstAttackOnly && result.IsAny) { return(result); } var opponentBishops = PiecePosition[attackingSide.ToPiece(PieceType.Bishop)]; var opponentSlidingDiagonallyPieces = opponentQueens | opponentBishops; var slidingDiagonallyAttackers = GetSlidingAttackers( targetSquareIndex, opponentSlidingDiagonallyPieces, DiagonallySlidingAttacks, emptySquareBitboard, findFirstAttackOnly); result |= slidingDiagonallyAttackers; return(result); }