< Summary

Line coverage
96%
Covered lines: 375
Uncovered lines: 15
Coverable lines: 390
Total lines: 777
Line coverage: 96.1%
Branch coverage
89%
Covered branches: 237
Total branches: 265
Branch coverage: 89.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: .ctor()100%22100%
File 1: Default()100%11100%
File 1: get_BoardHash()100%11100%
File 1: get_Pieces()100%11100%
File 1: get_Occupancies()100%11100%
File 1: get_PieceMapping()100%11100%
File 1: get_SideToMove()100%11100%
File 1: get_EnPassantSquare()100%11100%
File 1: get_Castle()100%11100%
File 1: get_Moves()100%11100%
File 1: get_LastDrawKiller()100%11100%
File 1: get_MoveCount()100%11100%
File 1: get_BestMove()100%11100%
File 1: get_Phase()100%11100%
File 1: set_Phase(...)100%11100%
File 1: get_ClippedPhase()100%11100%
File 1: AddPiece(...)100%11100%
File 1: RemovePiece(...)100%11100%
File 1: GetPieceOn(...)50%22100%
File 1: GetPieceOn(...)100%44100%
File 1: IsInCheck(...)100%11100%
File 1: MakeMove(...)100%88100%
File 1: HandleCastle(...)80%1010100%
File 1: HandleCapture(...)100%22100%
File 1: FlipSideToMove()100%11100%
File 1: UpdateEnPassant(...)100%44100%
File 1: UpdateCastlingRights(...)100%22100%
File 1: MoveRookFrom(...)100%11100%
File 1: UnmakeMove(...)88.88%181896.66%
File 1: EnPassantSquareFor(...)100%22100%
File 1: Equals(...)66.66%1818100%
File 1: Equals(...)0%4260%
File 1: GetHashCode()100%210%
File 1: ToString()0%620%
File 1: IsDraw()100%44100%
File 2: ParseFEN(...)100%11100%
File 2: ParseEnPassant(...)100%22100%
File 2: ParseCastling(...)100%1212100%
File 2: ParseSideToMove(...)100%22100%
File 2: ParsePieces(...)100%88100%
File 2: SymbolToPiece(...)63.63%111187.5%
File 2: SymbolToSide(...)100%22100%
File 3: GenerateMoves()100%11100%
File 3: GenerateKingMoves()100%44100%
File 3: FindBestMove(...)100%11100%
File 3: GenerateQueenMoves()100%66100%
File 3: GenerateRookMoves()100%66100%
File 3: GenerateKnightMoves()100%66100%
File 3: GenerateBishopMoves()100%66100%
File 3: GeneratePawnMoves()100%22100%
File 3: GenerateEnPassants(...)100%44100%
File 3: GeneratePawnPushes(...)100%1818100%
File 3: GeneratePawnAttacks(...)75%4477.77%
File 3: GenerateCastleMoves()100%4646100%
File 3: IsSquareAttacked(...)100%1212100%
File 3: AddPawnMove(...)100%2020100%
File 3: AddMoveToMovesList(...)100%22100%
File 3: IsSquareCapture(...)100%11100%
File 3: MakeNullMove()100%11100%
File 3: UndoNullMove()100%11100%
File 4: .cctor()100%11100%
File 4: op_Equality(...)100%210%
File 4: op_Inequality(...)100%210%
File 4: NullRespectingSequenceEqual(...)50%12860%

File(s)

/home/runner/work/rudim/rudim/Rudim/Board/BoardState.cs

#LineLine coverage
 1using Rudim.Common;
 2using System;
 3using System.Collections.Generic;
 4using System.Linq;
 5
 6namespace Rudim.Board
 7{
 8    public partial class BoardState : IEquatable<BoardState>
 9    {
 7410        private BoardState()
 11        {
 7412            Pieces = new Bitboard[Constants.Sides, Constants.Pieces];
 7413            Occupancies = new Bitboard[Constants.SidesWithBoth];
 7414            PieceMapping = new Piece[Constants.Squares];
 7415            SideToMove = Side.White;
 7416            EnPassantSquare = Square.NoSquare;
 7417            Castle = Castle.None;
 7418            Moves = new List<Move>(32);
 7419            MoveCount = 0;
 962020            for (int square = 0; square < Constants.Squares; ++square)
 473621                PieceMapping[square] = Piece.None;
 7422            BestMove = Move.NoMove;
 7423        }
 24
 25        public static BoardState Default()
 26        {
 2927            return ParseFEN(Helpers.StartingFEN);
 28        }
 29
 8877131230        public ulong BoardHash { get; set; }
 19107161431        public Bitboard[,] Pieces { get; }
 37385853732        public Bitboard[] Occupancies { get; }
 11411685233        public Piece[] PieceMapping { get; set; }
 20779252134        public Side SideToMove { get; private set; }
 4612333535        public Square EnPassantSquare { get; private set; }
 5246083836        public Castle Castle { get; private set; }
 6008257137        public List<Move> Moves { get; set; }
 2701487638        private int LastDrawKiller { get; set; }
 3659702339        public int MoveCount { get; set; }
 1492385340        public Move BestMove { get; set; }
 41
 42        private int _phase;
 43        public int Phase
 44        {
 2688919445            get => _phase;
 2678290246            set => _phase = value;
 47        }
 48
 383968149        public int ClippedPhase => Math.Min(_phase, GamePhase.TotalPhase);
 50
 51
 52        private void AddPiece(Square square, Side side, Piece piece)
 53        {
 1339242454            Pieces[(int)side, (int)piece] = Pieces[(int)side, (int)piece].SetBit(square);
 1339242455            Occupancies[(int)side] = Occupancies[(int)side].SetBit(square);
 1339242456            Occupancies[(int)Side.Both] = Occupancies[(int)Side.Both].SetBit(square);
 1339242457            PieceMapping[(int)square] = piece;
 1339242458            Phase = GamePhase.AddPhase(Phase, piece);
 1339242459        }
 60
 61        private Piece RemovePiece(Square square)
 62        {
 1339047863            Piece pieceOnSquare = PieceMapping[(int)square];
 1339047864            Pieces[(int)Side.White, (int)pieceOnSquare] = Pieces[(int)Side.White, (int)pieceOnSquare].ClearBit(square);
 1339047865            Pieces[(int)Side.Black, (int)pieceOnSquare] = Pieces[(int)Side.Black, (int)pieceOnSquare].ClearBit(square);
 1339047866            Occupancies[(int)Side.Black] = Occupancies[(int)Side.Black].ClearBit(square);
 1339047867            Occupancies[(int)Side.White] = Occupancies[(int)Side.White].ClearBit(square);
 1339047868            Occupancies[(int)Side.Both] = Occupancies[(int)Side.Both].ClearBit(square);
 1339047869            PieceMapping[(int)square] = Piece.None;
 1339047870            Phase = GamePhase.RemovePhase(Phase, pieceOnSquare);
 1339047871            return pieceOnSquare;
 72        }
 73
 74        public int GetPieceOn(Square square, Side side)
 75        {
 1205717876            Piece piece = PieceMapping[(int)square];
 1205717877            return Occupancies[(int)side].GetBit(square) == 1 ? (int)piece : (int)Piece.None;
 78        }
 79
 80        public int GetPieceOn(Square square)
 81        {
 6188148482            int piece = (int)PieceMapping[(int)square];
 6188522483            if (piece == (int)Piece.None) return -1;
 6187774484            return Occupancies[(int)Side.White].GetBit(square) == 1 ? piece : 6 + piece;
 85        }
 86
 87        public bool IsInCheck(Side side)
 88        {
 521055089            return IsSquareAttacked((Square)Pieces[(int)side, (int)Piece.King].GetLsb(), side.Other());
 90        }
 91        public void MakeMove(Move move)
 92        {
 489757693            Piece capturedPiece = Piece.None;
 489757694            ulong originalBoardHash = BoardHash;
 489757695            Square originalEnPassantSquare = EnPassantSquare;
 489757696            Castle originalCastlingRights = Castle;
 489757697            int originalLastDrawKiller = LastDrawKiller;
 98
 489757699            BoardHash ^= Zobrist.ZobristTable[GetPieceOn(move.Source), (int)move.Source];
 4897576100            Piece movedPiece = RemovePiece(move.Source);
 4897576101            if (movedPiece == Piece.Pawn)
 102            {
 1592572103                LastDrawKiller = MoveCount;
 104            }
 105
 106
 4897576107            if (move.IsCapture())
 108            {
 3571966109                capturedPiece = HandleCapture(move);
 110            }
 111
 4897576112            if (move.IsPromotion())
 113            {
 198505114                movedPiece = move.Type.Piece;
 115            }
 116
 4897576117            if (move.IsCastle())
 118            {
 11840119                HandleCastle(move);
 120            }
 121
 4897576122            AddPiece(move.Target, SideToMove, movedPiece);
 4897576123            BoardHash ^= Zobrist.ZobristTable[GetPieceOn(move.Target), (int)move.Target];
 124
 4897576125            UpdateCastlingRights(move);
 4897576126            UpdateEnPassant(move);
 4897576127            FlipSideToMove();
 128
 4897576129            History.SaveBoardHistory(capturedPiece, originalEnPassantSquare, originalCastlingRights, originalBoardHash, 
 4897576130            BestMove = Move.NoMove;
 4897576131            MoveCount++;
 4897576132        }
 133
 134        private void HandleCastle(Move move)
 135        {
 11840136            switch (move.Target)
 137            {
 138                case Square.c1:
 2934139                    MoveRookFrom(Square.a1, Square.d1, SideToMove);
 2934140                    break;
 141                case Square.g1:
 2937142                    MoveRookFrom(Square.h1, Square.f1, SideToMove);
 2937143                    break;
 144                case Square.c8:
 3279145                    MoveRookFrom(Square.a8, Square.d8, SideToMove);
 3279146                    break;
 147                case Square.g8:
 2690148                    MoveRookFrom(Square.h8, Square.f8, SideToMove);
 149                    break;
 150            }
 2690151        }
 152
 153        private Piece HandleCapture(Move move)
 154        {
 3571966155            Square targetSquare = move.Type == MoveTypes.EnPassant ? EnPassantSquareFor(move) : move.Target;
 156
 3571966157            BoardHash ^= Zobrist.ZobristTable[GetPieceOn(targetSquare), (int)targetSquare];
 3571966158            LastDrawKiller = MoveCount;
 159
 3571966160            return RemovePiece(targetSquare);
 161        }
 162
 163        private void FlipSideToMove()
 164        {
 5109920165            BoardHash = Zobrist.FlipSideToMoveHashes(this, BoardHash);
 5109920166            SideToMove = SideToMove.Other();
 5109920167        }
 168
 169        private void UpdateEnPassant(Move move)
 170        {
 5003748171            Square originalEnPassantSquare = EnPassantSquare;
 5003748172            BoardHash = Zobrist.HashEnPassant(this, BoardHash);
 5003748173            EnPassantSquare = move.Type == MoveTypes.DoublePush ? EnPassantSquareFor(move) : Square.NoSquare;
 5003748174            BoardHash = Zobrist.HashEnPassant(this, BoardHash);
 5003748175            if (originalEnPassantSquare != EnPassantSquare)
 209334176                LastDrawKiller = MoveCount;
 5003748177        }
 178
 179        private void UpdateCastlingRights(Move move)
 180        {
 4897576181            Castle originalCastlingRights = Castle;
 4897576182            BoardHash = Zobrist.HashCastlingRights(this, BoardHash);
 4897576183            Castle &= (Castle)CastlingConstants[(int)move.Source];
 4897576184            Castle &= (Castle)CastlingConstants[(int)move.Target];
 4897576185            BoardHash = Zobrist.HashCastlingRights(this, BoardHash);
 4897576186            if (Castle != originalCastlingRights)
 492316187                LastDrawKiller = MoveCount;
 4897576188        }
 189
 190        private void MoveRookFrom(Square source, Square target, Side sideToMove)
 191        {
 11840192            RemovePiece(source);
 11840193            AddPiece(target, sideToMove, Piece.Rook);
 194
 11840195            int rookIndex = GetPieceOn(target);
 11840196            BoardHash ^= Zobrist.ZobristTable[rookIndex, (int)source];
 11840197            BoardHash ^= Zobrist.ZobristTable[rookIndex, (int)target];
 11840198        }
 199
 200
 201        public void UnmakeMove(Move move)
 202        {
 4897258203            History.BoardHistory history = History.RestoreBoardHistory();
 204
 4897258205            Piece movedPiece = RemovePiece(move.Target);
 4897258206            SideToMove = SideToMove.Other();
 207
 4897258208            if (history.CapturedPiece != Piece.None)
 209            {
 3571937210                if (move.Type == MoveTypes.EnPassant)
 211                {
 6787212                    AddPiece(EnPassantSquareFor(move), SideToMove.Other(), Piece.Pawn);
 213                }
 214                else
 215                {
 3565150216                    AddPiece(move.Target, SideToMove.Other(), history.CapturedPiece);
 217                }
 218            }
 219
 4897258220            if (move.IsCastle())
 221            {
 11838222                switch (move.Target)
 223                {
 224                    case Square.c1:
 2934225                        RemovePiece(Square.d1);
 2934226                        AddPiece(Square.a1, SideToMove, Piece.Rook);
 2934227                        break;
 228                    case Square.g1:
 2936229                        RemovePiece(Square.f1);
 2936230                        AddPiece(Square.h1, SideToMove, Piece.Rook);
 2936231                        break;
 232                    case Square.c8:
 3279233                        RemovePiece(Square.d8);
 3279234                        AddPiece(Square.a8, SideToMove, Piece.Rook);
 3279235                        break;
 236                    case Square.g8:
 2689237                        RemovePiece(Square.f8);
 2689238                        AddPiece(Square.h8, SideToMove, Piece.Rook);
 2689239                        break;
 0240                    default: throw new ArgumentOutOfRangeException(nameof(move.Target));
 241                }
 242            }
 243
 4897258244            AddPiece(move.Source, SideToMove, move.IsPromotion() ? Piece.Pawn : movedPiece);
 4897258245            LastDrawKiller = history.LastDrawKiller;
 4897258246            BoardHash = history.BoardHash;
 4897258247            Castle = history.CastlingRights;
 4897258248            EnPassantSquare = history.EnPassantSquare;
 4897258249            BestMove = history.BestMove;
 4897258250            MoveCount--;
 4897258251        }
 252        private Square EnPassantSquareFor(Move move)
 253        {
 142229254            return move.Target + 8 * (SideToMove == Side.Black ? -1 : 1);
 255        }
 256
 257        public bool Equals(BoardState other)
 258        {
 7259            if (ReferenceEquals(null, other)) return false;
 7260            if (ReferenceEquals(this, other)) return true;
 261
 7262            if (Pieces.Rank != other.Pieces.Rank ||
 7263                Enumerable.Range(0, Pieces.Rank).Any(dimension =>
 14264                    Pieces.GetLength(dimension) != other.Pieces.GetLength(dimension)) ||
 7265                !Pieces.Cast<Bitboard>().SequenceEqual(other.Pieces.Cast<Bitboard>()))
 2266                return false;
 267
 5268            return NullRespectingSequenceEqual(Occupancies, other.Occupancies) &&
 5269                   SideToMove == other.SideToMove && EnPassantSquare == other.EnPassantSquare &&
 5270                   Castle == other.Castle && NullRespectingSequenceEqual(Moves, other.Moves);
 271        }
 272
 273        public override bool Equals(object obj)
 274        {
 0275            if (ReferenceEquals(null, obj)) return false;
 0276            if (ReferenceEquals(this, obj)) return true;
 0277            if (obj.GetType() != this.GetType()) return false;
 0278            return Equals((BoardState)obj);
 279        }
 280
 281        public override int GetHashCode()
 282        {
 0283            return HashCode.Combine(Pieces, Occupancies);
 284        }
 285
 286        public override string ToString()
 287        {
 0288            ulong boardHash = BoardHash;
 0289            return CommonStateNames.TryGetValue(boardHash, out string commonName) ? commonName : boardHash.ToString();
 290        }
 291
 292        public bool IsDraw()
 293        {
 5570547294            if (MoveCount - LastDrawKiller > 100) return true;
 11140671295            if (MoveCount - LastDrawKiller <= 7) return false;
 419296            return History.HasHashAppearedTwice(BoardHash, LastDrawKiller);
 297        }
 298    }
 299}

/home/runner/work/rudim/rudim/Rudim/Board/BoardState.FEN.cs

#LineLine coverage
 1using Rudim.Common;
 2using System;
 3
 4namespace Rudim.Board
 5{
 6    public partial class BoardState
 7    {
 8        public static BoardState ParseFEN(string FEN)
 9        {
 7410            BoardState board = new BoardState();
 7411            string[] sections = FEN.Split(' ');
 7412            ParsePieces(board, sections[0]);
 7413            ParseSideToMove(board, sections[1]);
 7414            ParseCastling(board, sections[2]);
 7415            ParseEnPassant(board, sections[3]);
 16            // ParsePly(board, sections[4]);
 7417            board.BoardHash = Zobrist.GetBoardHash(board);
 7418            return board;
 19        }
 20
 21        private static void ParseEnPassant(BoardState board, string fen)
 22        {
 7423            if (fen != "-")
 824                board.EnPassantSquare = (Square)Enum.Parse(typeof(Square), fen);
 7425        }
 26
 27        private static void ParseCastling(BoardState board, string fen)
 28        {
 66029            foreach (char character in fen)
 30            {
 31                switch (character)
 32                {
 12233                    case 'K': board.Castle |= Castle.WhiteShort; break;
 12234                    case 'Q': board.Castle |= Castle.WhiteLong; break;
 12035                    case 'k': board.Castle |= Castle.BlackShort; break;
 6136                    case 'q': board.Castle |= Castle.BlackLong; break;
 37                }
 38            }
 7439        }
 40
 41        private static void ParseSideToMove(BoardState board, string fen)
 42        {
 7443            board.SideToMove = fen == "w" ? Side.White : Side.Black;
 7444        }
 45
 46        private static void ParsePieces(BoardState board, string fen)
 47        {
 7448            string[] ranks = fen.Split('/');
 49
 133250            for (int rank = 0; rank < 8; rank++)
 51            {
 59252                int index = rank * 8;
 620253                for (int file = 0; file < ranks[rank].Length; file++)
 54                {
 250955                    char symbol = ranks[rank][file];
 250956                    if (char.IsLetter(symbol))
 57                    {
 197558                        board.AddPiece((Square)index, SymbolToSide(symbol), SymbolToPiece(symbol));
 197559                        index++;
 60                    }
 53461                    else if (char.IsDigit(symbol))
 62                    {
 53463                        index += symbol - '0';
 64                    }
 65                }
 66            }
 7467        }
 68        private static Piece SymbolToPiece(char symbol)
 69        {
 197570            switch (char.ToLower(symbol))
 71            {
 101072                case 'p': return Piece.Pawn;
 25473                case 'r': return Piece.Rook;
 22074                case 'n': return Piece.Knight;
 23075                case 'b': return Piece.Bishop;
 11576                case 'q': return Piece.Queen;
 14677                case 'k': return Piece.King;
 78            }
 079            return Piece.None;
 80        }
 81
 82        private static Side SymbolToSide(char symbol)
 83        {
 197584            return char.IsUpper(symbol) ? Side.White : Side.Black;
 85        }
 86
 87    }
 88}

/home/runner/work/rudim/rudim/Rudim/Board/BoardState.Moves.cs

#LineLine coverage
 1using Rudim.Common;
 2using Rudim.Search;
 3using System.Collections.Generic;
 4using System.Threading;
 5
 6namespace Rudim.Board
 7{
 8    public partial class BoardState
 9    {
 10        public void GenerateMoves()
 11        {
 163618912            Moves = new List<Move>();
 13
 163618914            GeneratePawnMoves();
 163618915            GenerateBishopMoves();
 163618916            GenerateKnightMoves();
 163618917            GenerateRookMoves();
 163618918            GenerateQueenMoves();
 163618919            GenerateKingMoves();
 163618920        }
 21
 22        private void GenerateKingMoves()
 23        {
 163618924            int source = Pieces[(int)SideToMove, (int)Piece.King].GetLsb();
 163618925            Bitboard attacks = new Bitboard(Bitboard.KingAttacks[source]);
 26
 1045627227            while (attacks.Board > 0)
 28            {
 882008329                int target = attacks.GetLsb();
 882008330                attacks.ClearBit(target);
 882008331                if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 32                {
 33                    continue;
 34                }
 474555635                AddMoveToMovesList(source, target);
 36            }
 37
 163618938            GenerateCastleMoves();
 163618939        }
 40        public Move FindBestMove(int depth, CancellationToken cancellationToken, ref bool debugMode)
 41        {
 542            IterativeDeepening.Search(this, depth, cancellationToken, ref debugMode);
 543            return IterativeDeepening.BestMove;
 44        }
 45
 46        private void GenerateQueenMoves()
 47        {
 163618948            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Queen];
 286589449            while (bitboard.Board > 0)
 50            {
 122970551                int source = bitboard.GetLsb();
 122970552                Bitboard attacks = Bitboard.GetQueenAttacksFromTable((Square)source, Occupancies[(int)Side.Both]);
 53
 1471560954                while (attacks.Board > 0)
 55                {
 1348590456                    int target = attacks.GetLsb();
 57
 1348590458                    if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 59                    {
 481694860                        attacks.ClearBit(target);
 481694861                        continue;
 62                    }
 63
 866895664                    AddMoveToMovesList(source, target);
 65
 866895666                    attacks.ClearBit(target);
 67                }
 68
 122970569                bitboard.ClearBit(source);
 70            }
 163618971        }
 72
 73        private void GenerateRookMoves()
 74        {
 163618975            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Rook];
 445786976            while (bitboard.Board > 0)
 77            {
 282168078                int source = bitboard.GetLsb();
 282168079                Bitboard attacks = Bitboard.GetRookAttacksFromTable((Square)source, Occupancies[(int)Side.Both]);
 80
 1660734181                while (attacks.Board > 0)
 82                {
 1378566183                    int target = attacks.GetLsb();
 84
 1378566185                    if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 86                    {
 527613787                        attacks.ClearBit(target);
 527613788                        continue;
 89                    }
 90
 850952491                    AddMoveToMovesList(source, target);
 92
 850952493                    attacks.ClearBit(target);
 94                }
 95
 282168096                bitboard.ClearBit(source);
 97            }
 163618998        }
 99
 100        private void GenerateKnightMoves()
 101        {
 1636189102            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Knight];
 3710687103            while (bitboard.Board > 0)
 104            {
 2074498105                int source = bitboard.GetLsb();
 2074498106                Bitboard attacks = new Bitboard(Bitboard.KnightAttacks[source]);
 107
 13480157108                while (attacks.Board > 0)
 109                {
 11405659110                    int target = attacks.GetLsb();
 111
 11405659112                    if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 113                    {
 2737059114                        attacks.ClearBit(target);
 2737059115                        continue;
 116                    }
 117
 8668600118                    AddMoveToMovesList(source, target);
 119
 8668600120                    attacks.ClearBit(target);
 121                }
 122
 2074498123                bitboard.ClearBit(source);
 124            }
 1636189125        }
 126
 127        private void GenerateBishopMoves()
 128        {
 1636189129            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Bishop];
 3829075130            while (bitboard.Board > 0)
 131            {
 2192886132                int source = bitboard.GetLsb();
 2192886133                Bitboard attacks = Bitboard.GetBishopAttacksFromTable((Square)source, Occupancies[(int)Side.Both]);
 134
 13533812135                while (attacks.Board > 0)
 136                {
 11340926137                    int target = attacks.GetLsb();
 138
 11340926139                    if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 140                    {
 2783949141                        attacks.ClearBit(target);
 2783949142                        continue;
 143                    }
 144
 8556977145                    AddMoveToMovesList(source, target);
 146
 8556977147                    attacks.ClearBit(target);
 148                }
 149
 2192886150                bitboard.ClearBit(source);
 151            }
 1636189152        }
 153
 154        private void GeneratePawnMoves()
 155        {
 1636189156            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Pawn];
 12214648157            while (bitboard.Board > 0)
 158            {
 10578459159                int source = bitboard.GetLsb();
 10578459160                GeneratePawnPushes(source);
 10578459161                GenerateEnPassants(source);
 10578459162                GeneratePawnAttacks(source);
 163
 10578459164                bitboard.ClearBit(source);
 165            }
 1636189166        }
 167
 168        private void GenerateEnPassants(int source)
 169        {
 10578459170            if (EnPassantSquare == Square.NoSquare)
 10274898171                return;
 172
 303561173            Bitboard attacks = new Bitboard(Bitboard.PawnAttacks[(int)SideToMove, source] & (1ul << (int)EnPassantSquare
 303561174            if (attacks.Board > 0)
 175            {
 12613176                int target = attacks.GetLsb();
 12613177                AddPawnMove(source, target, true, false);
 178            }
 179
 303561180        }
 181
 182
 183        private void GeneratePawnPushes(int source)
 184        {
 10578459185            if (SideToMove == Side.Black)
 186            {
 5243999187                int oneSquarePush = source + 8;
 6473327188                if (Occupancies[(int)Side.Both].GetBit(oneSquarePush) != 0) return;
 4014671189                AddPawnMove(source, oneSquarePush, false, false);
 4014671190                if (source is <= (int)Square.h7 and >= (int)Square.a7)
 191                {
 2711195192                    int twoSquarePush = oneSquarePush + 8;
 3112744193                    if (Occupancies[(int)Side.Both].GetBit(twoSquarePush) != 0) return;
 2309646194                    AddPawnMove(source, twoSquarePush, false, true);
 195                }
 196            }
 197            else
 198            {
 5334460199                int oneSquarePush = source - 8;
 6587310200                if (Occupancies[(int)Side.Both].GetBit(oneSquarePush) != 0) return;
 4081610201                AddPawnMove(source, oneSquarePush, false, false);
 4081610202                if (source is <= (int)Square.h2 and >= (int)Square.a2)
 203                {
 2742940204                    int twoSquarePush = oneSquarePush - 8;
 2996783205                    if (Occupancies[(int)Side.Both].GetBit(twoSquarePush) != 0) return;
 2489097206                    AddPawnMove(source, twoSquarePush, false, true);
 207                }
 208            }
 5131243209        }
 210
 211        private void GeneratePawnAttacks(int source)
 212        {
 10578459213            Bitboard attacks = new Bitboard(Bitboard.PawnAttacks[(int)SideToMove, source] & Occupancies[(int)SideToMove.
 214
 12359173215            while (attacks.Board > 0)
 216            {
 1780714217                int target = attacks.GetLsb();
 218
 1780714219                if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 220                {
 0221                    attacks.ClearBit(target);
 0222                    continue;
 223                }
 224
 1780714225                AddPawnMove(source, target, false, false);
 226
 1780714227                attacks.ClearBit(target);
 228            }
 10578459229        }
 230        private void GenerateCastleMoves()
 231        {
 232            // Squares should be empty and shouldn't castle through check, can avoid checking if landing position is che
 233
 1636189234            Bitboard occ = Occupancies[(int)Side.Both];
 1636189235            if (SideToMove == Side.White)
 236            {
 826938237                if (Castle.HasFlag(Castle.WhiteShort))
 238                {
 488600239                    if (occ.GetBit(Square.f1) == 0 && occ.GetBit(Square.g1) == 0 && !IsSquareAttacked(Square.e1, Side.Bl
 142383240                        Moves.Add(new Move(Square.e1, Square.g1, MoveTypes.Castle));
 241                }
 826938242                if (Castle.HasFlag(Castle.WhiteLong))
 243                {
 520802244                    if (occ.GetBit(Square.d1) == 0 && occ.GetBit(Square.c1) == 0 && occ.GetBit(Square.b1) == 0 && !IsSqu
 143048245                        Moves.Add(new Move(Square.e1, Square.c1, MoveTypes.Castle));
 246                }
 247            }
 248            else
 249            {
 809251250                if (Castle.HasFlag(Castle.BlackShort))
 251                {
 477542252                    if (occ.GetBit(Square.f8) == 0 && occ.GetBit(Square.g8) == 0 && !IsSquareAttacked(Square.e8, Side.Wh
 263941253                        Moves.Add(new Move(Square.e8, Square.g8, MoveTypes.Castle));
 254                }
 809251255                if (Castle.HasFlag(Castle.BlackLong))
 256                {
 662833257                    if (occ.GetBit(Square.d8) == 0 && occ.GetBit(Square.c8) == 0 && occ.GetBit(Square.b8) == 0 && !IsSqu
 273280258                        Moves.Add(new Move(Square.e8, Square.c8, MoveTypes.Castle));
 259                }
 260            }
 1493141261        }
 262
 263        private bool IsSquareAttacked(Square square, Side attackingSide)
 264        {
 7423630265            if ((Bitboard.GetBishopAttacksFromTable(square, Occupancies[(int)Side.Both]).Board & Pieces[(int)attackingSi
 166860266                return true;
 7256770267            if ((Bitboard.GetRookAttacksFromTable(square, Occupancies[(int)Side.Both]).Board & Pieces[(int)attackingSide
 63200268                return true;
 7193570269            if ((Bitboard.GetQueenAttacksFromTable(square, Occupancies[(int)Side.Both]).Board & Pieces[(int)attackingSid
 358914270                return true;
 6834656271            if ((Bitboard.KnightAttacks[(int)square] & Pieces[(int)attackingSide, (int)Piece.Knight].Board) != 0)
 91106272                return true;
 6743550273            if ((Bitboard.PawnAttacks[(int)attackingSide.Other(), (int)square] & Pieces[(int)attackingSide, (int)Piece.P
 254167274                return true;
 6489383275            if ((Bitboard.KingAttacks[(int)square] & Pieces[(int)attackingSide, (int)Piece.King].Board) != 0)
 2276                return true;
 6489381277            return false;
 278        }
 279
 280        private void AddPawnMove(int source, int target, bool enpassant, bool doublePush)
 281        {
 282            // This assumes all incoming pawn moves are valid
 14688351283            if (target is >= (int)Square.a1 and <= (int)Square.h1 || target is <= (int)Square.h8 and >= (int)Square.a8)
 284            {
 171385285                bool capture = IsSquareCapture(target);
 286
 171385287                Moves.Add(new Move((Square)source, (Square)target, capture ? MoveTypes.KnightPromotionCapture : MoveType
 171385288                Moves.Add(new Move((Square)source, (Square)target, capture ? MoveTypes.BishopPromotionCapture : MoveType
 171385289                Moves.Add(new Move((Square)source, (Square)target, capture ? MoveTypes.RookPromotionCapture : MoveTypes.
 171385290                Moves.Add(new Move((Square)source, (Square)target, capture ? MoveTypes.QueenPromotionCapture : MoveTypes
 291            }
 14516966292            else if (enpassant || doublePush)
 293            {
 4811356294                Moves.Add(new Move((Square)source, (Square)target, enpassant ? MoveTypes.EnPassant : MoveTypes.DoublePus
 295            }
 296            else
 297            {
 9705610298                AddMoveToMovesList(source, target);
 299            }
 9705610300        }
 301
 302
 303        private void AddMoveToMovesList(int source, int target)
 304        {
 48855223305            MoveType moveType = IsSquareCapture(target) ? MoveTypes.Capture : MoveTypes.Quiet;
 48855223306            Move move = new Move((Square)source, (Square)target, moveType);
 48855223307            Moves.Add(move);
 48855223308        }
 309        private bool IsSquareCapture(int target)
 310        {
 49026608311            return Occupancies[(int)SideToMove.Other()].GetBit(target) == 1;
 312        }
 313
 314        public void MakeNullMove()
 315        {
 106172316            History.SaveBoardHistory(Piece.None, EnPassantSquare, Castle, BoardHash, LastDrawKiller, BestMove);
 106172317            UpdateEnPassant(Move.NoMove);
 106172318            FlipSideToMove();
 106172319        }
 320
 321        public void UndoNullMove()
 322        {
 106172323            History.BoardHistory history = History.RestoreBoardHistory();
 106172324            FlipSideToMove();
 106172325            LastDrawKiller = history.LastDrawKiller;
 106172326            BoardHash = history.BoardHash;
 106172327            Castle = history.CastlingRights;
 106172328            EnPassantSquare = history.EnPassantSquare;
 106172329        }
 330    }
 331}

/home/runner/work/rudim/rudim/Rudim/Board/BoardState.Static.cs

#LineLine coverage
 1using Rudim.Common;
 2using System.Collections.Generic;
 3using System.Linq;
 4
 5namespace Rudim.Board
 6{
 7    public partial class BoardState
 8    {
 19        private static readonly Dictionary<ulong, string> CommonStateNames = new();
 10
 111        private static readonly int[] CastlingConstants =
 112        {
 113            7, 15, 15, 15, 3, 15, 15, 11,
 114            15, 15, 15, 15, 15, 15, 15, 15,
 115            15, 15, 15, 15, 15, 15, 15, 15,
 116            15, 15, 15, 15, 15, 15, 15, 15,
 117            15, 15, 15, 15, 15, 15, 15, 15,
 118            15, 15, 15, 15, 15, 15, 15, 15,
 119            15, 15, 15, 15, 15, 15, 15, 15,
 120            13, 15, 15, 15, 12, 15, 15, 14
 121        };
 22
 23        static BoardState()
 24        {
 25
 126            CommonStateNames[Zobrist.GetBoardHash(ParseFEN(Helpers.StartingFEN))] = "Starting State";
 127            CommonStateNames[Zobrist.GetBoardHash(ParseFEN(Helpers.EndgameFEN))] = "Endgame State";
 128            CommonStateNames[Zobrist.GetBoardHash(ParseFEN(Helpers.KiwiPeteFEN))] = "KiwiPete State";
 129            CommonStateNames[Zobrist.GetBoardHash(ParseFEN(Helpers.KiwiPeteFEN))] = "Random State";
 130            CommonStateNames[Zobrist.GetBoardHash(ParseFEN(Helpers.AdvancedMoveFEN))] = "Advanced Move State";
 131        }
 32
 33        public static bool operator ==(BoardState left, BoardState right)
 34        {
 035            return Equals(left, right);
 36        }
 37
 38        public static bool operator !=(BoardState left, BoardState right)
 39        {
 040            return !Equals(left, right);
 41        }
 42
 43        // This can move to an extension method
 44        private static bool NullRespectingSequenceEqual<T>(IEnumerable<T> first, IEnumerable<T> second)
 45        {
 1046            if (first == null && second == null)
 47            {
 048                return true;
 49            }
 50
 1051            if (first == null || second == null)
 52            {
 053                return false;
 54            }
 55
 1056            return first.SequenceEqual(second);
 57        }
 58    }
 59}

Methods/Properties

.ctor()
Default()
get_BoardHash()
get_Pieces()
get_Occupancies()
get_PieceMapping()
get_SideToMove()
get_EnPassantSquare()
get_Castle()
get_Moves()
get_LastDrawKiller()
get_MoveCount()
get_BestMove()
get_Phase()
set_Phase(System.Int32)
get_ClippedPhase()
AddPiece(Rudim.Common.Square,Rudim.Common.Side,Rudim.Common.Piece)
RemovePiece(Rudim.Common.Square)
GetPieceOn(Rudim.Common.Square,Rudim.Common.Side)
GetPieceOn(Rudim.Common.Square)
IsInCheck(Rudim.Common.Side)
MakeMove(Rudim.Common.Move)
HandleCastle(Rudim.Common.Move)
HandleCapture(Rudim.Common.Move)
FlipSideToMove()
UpdateEnPassant(Rudim.Common.Move)
UpdateCastlingRights(Rudim.Common.Move)
MoveRookFrom(Rudim.Common.Square,Rudim.Common.Square,Rudim.Common.Side)
UnmakeMove(Rudim.Common.Move)
EnPassantSquareFor(Rudim.Common.Move)
Equals(Rudim.Board.BoardState)
Equals(System.Object)
GetHashCode()
ToString()
IsDraw()
ParseFEN(System.String)
ParseEnPassant(Rudim.Board.BoardState,System.String)
ParseCastling(Rudim.Board.BoardState,System.String)
ParseSideToMove(Rudim.Board.BoardState,System.String)
ParsePieces(Rudim.Board.BoardState,System.String)
SymbolToPiece(System.Char)
SymbolToSide(System.Char)
GenerateMoves()
GenerateKingMoves()
FindBestMove(System.Int32,System.Threading.CancellationToken,System.Boolean&)
GenerateQueenMoves()
GenerateRookMoves()
GenerateKnightMoves()
GenerateBishopMoves()
GeneratePawnMoves()
GenerateEnPassants(System.Int32)
GeneratePawnPushes(System.Int32)
GeneratePawnAttacks(System.Int32)
GenerateCastleMoves()
IsSquareAttacked(Rudim.Common.Square,Rudim.Common.Side)
AddPawnMove(System.Int32,System.Int32,System.Boolean,System.Boolean)
AddMoveToMovesList(System.Int32,System.Int32)
IsSquareCapture(System.Int32)
MakeNullMove()
UndoNullMove()
.cctor()
op_Equality(Rudim.Board.BoardState,Rudim.Board.BoardState)
op_Inequality(Rudim.Board.BoardState,Rudim.Board.BoardState)
NullRespectingSequenceEqual(System.Collections.Generic.IEnumerable`1<T>,System.Collections.Generic.IEnumerable`1<T>)