< 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    {
 5910        private BoardState()
 11        {
 5912            Pieces = new Bitboard[Constants.Sides, Constants.Pieces];
 5913            Occupancies = new Bitboard[Constants.SidesWithBoth];
 5914            PieceMapping = new Piece[Constants.Squares];
 5915            SideToMove = Side.White;
 5916            EnPassantSquare = Square.NoSquare;
 5917            Castle = Castle.None;
 5918            Moves = new List<Move>(32);
 5919            MoveCount = 0;
 767020            for (int square = 0; square < Constants.Squares; ++square)
 377621                PieceMapping[square] = Piece.None;
 5922            BestMove = Move.NoMove;
 5923        }
 24
 25        public static BoardState Default()
 26        {
 2227            return ParseFEN(Helpers.StartingFEN);
 28        }
 29
 9984939130        public ulong BoardHash { get; set; }
 20733894031        public Bitboard[,] Pieces { get; }
 42227484032        public Bitboard[] Occupancies { get; }
 12915297933        public Piece[] PieceMapping { get; set; }
 23388051834        public Side SideToMove { get; private set; }
 5160117535        public Square EnPassantSquare { get; private set; }
 5897650436        public Castle Castle { get; private set; }
 6784986437        public List<Move> Moves { get; set; }
 3021250938        private int LastDrawKiller { get; set; }
 4099052839        public int MoveCount { get; set; }
 1678237140        public Move BestMove { get; set; }
 41
 42        private int _phase;
 43        public int Phase
 44        {
 3036504145            get => _phase;
 3024449046            set => _phase = value;
 47        }
 48
 430324749        public int ClippedPhase => Math.Min(_phase, GamePhase.TotalPhase);
 50
 51
 52        private void AddPiece(Square square, Side side, Piece piece)
 53        {
 1512309354            Pieces[(int)side, (int)piece] = Pieces[(int)side, (int)piece].SetBit(square);
 1512309355            Occupancies[(int)side] = Occupancies[(int)side].SetBit(square);
 1512309356            Occupancies[(int)Side.Both] = Occupancies[(int)Side.Both].SetBit(square);
 1512309357            PieceMapping[(int)square] = piece;
 1512309358            Phase = GamePhase.AddPhase(Phase, piece);
 1512309359        }
 60
 61        private Piece RemovePiece(Square square)
 62        {
 1512139763            Piece pieceOnSquare = PieceMapping[(int)square];
 1512139764            Pieces[(int)Side.White, (int)pieceOnSquare] = Pieces[(int)Side.White, (int)pieceOnSquare].ClearBit(square);
 1512139765            Pieces[(int)Side.Black, (int)pieceOnSquare] = Pieces[(int)Side.Black, (int)pieceOnSquare].ClearBit(square);
 1512139766            Occupancies[(int)Side.Black] = Occupancies[(int)Side.Black].ClearBit(square);
 1512139767            Occupancies[(int)Side.White] = Occupancies[(int)Side.White].ClearBit(square);
 1512139768            Occupancies[(int)Side.Both] = Occupancies[(int)Side.Both].ClearBit(square);
 1512139769            PieceMapping[(int)square] = Piece.None;
 1512139770            Phase = GamePhase.RemovePhase(Phase, pieceOnSquare);
 1512139771            return pieceOnSquare;
 72        }
 73
 74        public int GetPieceOn(Square square, Side side)
 75        {
 1388214376            Piece piece = PieceMapping[(int)square];
 1388214377            return Occupancies[(int)side].GetBit(square) == 1 ? (int)piece : (int)Piece.None;
 78        }
 79
 80        public int GetPieceOn(Square square)
 81        {
 6990111482            int piece = (int)PieceMapping[(int)square];
 6990414483            if (piece == (int)Piece.None) return -1;
 6989808484            return Occupancies[(int)Side.White].GetBit(square) == 1 ? piece : 6 + piece;
 85        }
 86
 87        public bool IsInCheck(Side side)
 88        {
 584232889            return IsSquareAttacked((Square)Pieces[(int)side, (int)Piece.King].GetLsb(), side.Other());
 90        }
 91        public void MakeMove(Move move)
 92        {
 550968193            Piece capturedPiece = Piece.None;
 550968194            ulong originalBoardHash = BoardHash;
 550968195            Square originalEnPassantSquare = EnPassantSquare;
 550968196            Castle originalCastlingRights = Castle;
 550968197            int originalLastDrawKiller = LastDrawKiller;
 98
 550968199            BoardHash ^= Zobrist.ZobristTable[GetPieceOn(move.Source), (int)move.Source];
 5509681100            Piece movedPiece = RemovePiece(move.Source);
 5509681101            if (movedPiece == Piece.Pawn)
 102            {
 1771421103                LastDrawKiller = MoveCount;
 104            }
 105
 106
 5509681107            if (move.IsCapture())
 108            {
 4074693109                capturedPiece = HandleCapture(move);
 110            }
 111
 5509681112            if (move.IsPromotion())
 113            {
 238372114                movedPiece = move.Type.Piece;
 115            }
 116
 5509681117            if (move.IsCastle())
 118            {
 13831119                HandleCastle(move);
 120            }
 121
 5509681122            AddPiece(move.Target, SideToMove, movedPiece);
 5509681123            BoardHash ^= Zobrist.ZobristTable[GetPieceOn(move.Target), (int)move.Target];
 124
 5509681125            UpdateCastlingRights(move);
 5509681126            UpdateEnPassant(move);
 5509681127            FlipSideToMove();
 128
 5509681129            History.SaveBoardHistory(capturedPiece, originalEnPassantSquare, originalCastlingRights, originalBoardHash, 
 5509681130            BestMove = Move.NoMove;
 5509681131            MoveCount++;
 5509681132        }
 133
 134        private void HandleCastle(Move move)
 135        {
 13831136            switch (move.Target)
 137            {
 138                case Square.c1:
 3678139                    MoveRookFrom(Square.a1, Square.d1, SideToMove);
 3678140                    break;
 141                case Square.g1:
 3834142                    MoveRookFrom(Square.h1, Square.f1, SideToMove);
 3834143                    break;
 144                case Square.c8:
 3463145                    MoveRookFrom(Square.a8, Square.d8, SideToMove);
 3463146                    break;
 147                case Square.g8:
 2856148                    MoveRookFrom(Square.h8, Square.f8, SideToMove);
 149                    break;
 150            }
 2856151        }
 152
 153        private Piece HandleCapture(Move move)
 154        {
 4074693155            Square targetSquare = move.Type == MoveTypes.EnPassant ? EnPassantSquareFor(move) : move.Target;
 156
 4074693157            BoardHash ^= Zobrist.ZobristTable[GetPieceOn(targetSquare), (int)targetSquare];
 4074693158            LastDrawKiller = MoveCount;
 159
 4074693160            return RemovePiece(targetSquare);
 161        }
 162
 163        private void FlipSideToMove()
 164        {
 5750557165            BoardHash = Zobrist.FlipSideToMoveHashes(this, BoardHash);
 5750557166            SideToMove = SideToMove.Other();
 5750557167        }
 168
 169        private void UpdateEnPassant(Move move)
 170        {
 5630119171            Square originalEnPassantSquare = EnPassantSquare;
 5630119172            BoardHash = Zobrist.HashEnPassant(this, BoardHash);
 5630119173            EnPassantSquare = move.Type == MoveTypes.DoublePush ? EnPassantSquareFor(move) : Square.NoSquare;
 5630119174            BoardHash = Zobrist.HashEnPassant(this, BoardHash);
 5630119175            if (originalEnPassantSquare != EnPassantSquare)
 236952176                LastDrawKiller = MoveCount;
 5630119177        }
 178
 179        private void UpdateCastlingRights(Move move)
 180        {
 5509681181            Castle originalCastlingRights = Castle;
 5509681182            BoardHash = Zobrist.HashCastlingRights(this, BoardHash);
 5509681183            Castle &= (Castle)CastlingConstants[(int)move.Source];
 5509681184            Castle &= (Castle)CastlingConstants[(int)move.Target];
 5509681185            BoardHash = Zobrist.HashCastlingRights(this, BoardHash);
 5509681186            if (Castle != originalCastlingRights)
 571418187                LastDrawKiller = MoveCount;
 5509681188        }
 189
 190        private void MoveRookFrom(Square source, Square target, Side sideToMove)
 191        {
 13831192            RemovePiece(source);
 13831193            AddPiece(target, sideToMove, Piece.Rook);
 194
 13831195            int rookIndex = GetPieceOn(target);
 13831196            BoardHash ^= Zobrist.ZobristTable[rookIndex, (int)source];
 13831197            BoardHash ^= Zobrist.ZobristTable[rookIndex, (int)target];
 13831198        }
 199
 200
 201        public void UnmakeMove(Move move)
 202        {
 5509363203            History.BoardHistory history = History.RestoreBoardHistory();
 204
 5509363205            Piece movedPiece = RemovePiece(move.Target);
 5509363206            SideToMove = SideToMove.Other();
 207
 5509363208            if (history.CapturedPiece != Piece.None)
 209            {
 4074664210                if (move.Type == MoveTypes.EnPassant)
 211                {
 11273212                    AddPiece(EnPassantSquareFor(move), SideToMove.Other(), Piece.Pawn);
 213                }
 214                else
 215                {
 4063391216                    AddPiece(move.Target, SideToMove.Other(), history.CapturedPiece);
 217                }
 218            }
 219
 5509363220            if (move.IsCastle())
 221            {
 13829222                switch (move.Target)
 223                {
 224                    case Square.c1:
 3678225                        RemovePiece(Square.d1);
 3678226                        AddPiece(Square.a1, SideToMove, Piece.Rook);
 3678227                        break;
 228                    case Square.g1:
 3833229                        RemovePiece(Square.f1);
 3833230                        AddPiece(Square.h1, SideToMove, Piece.Rook);
 3833231                        break;
 232                    case Square.c8:
 3463233                        RemovePiece(Square.d8);
 3463234                        AddPiece(Square.a8, SideToMove, Piece.Rook);
 3463235                        break;
 236                    case Square.g8:
 2855237                        RemovePiece(Square.f8);
 2855238                        AddPiece(Square.h8, SideToMove, Piece.Rook);
 2855239                        break;
 0240                    default: throw new ArgumentOutOfRangeException(nameof(move.Target));
 241                }
 242            }
 243
 5509363244            AddPiece(move.Source, SideToMove, move.IsPromotion() ? Piece.Pawn : movedPiece);
 5509363245            LastDrawKiller = history.LastDrawKiller;
 5509363246            BoardHash = history.BoardHash;
 5509363247            Castle = history.CastlingRights;
 5509363248            EnPassantSquare = history.EnPassantSquare;
 5509363249            BestMove = history.BestMove;
 5509363250            MoveCount--;
 5509363251        }
 252        private Square EnPassantSquareFor(Move move)
 253        {
 163426254            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        {
 6148949294            if (MoveCount - LastDrawKiller > 100) return true;
 12297684295            if (MoveCount - LastDrawKiller <= 7) return false;
 210296            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        {
 5910            BoardState board = new BoardState();
 5911            string[] sections = FEN.Split(' ');
 5912            ParsePieces(board, sections[0]);
 5913            ParseSideToMove(board, sections[1]);
 5914            ParseCastling(board, sections[2]);
 5915            ParseEnPassant(board, sections[3]);
 16            // ParsePly(board, sections[4]);
 5917            board.BoardHash = Zobrist.GetBoardHash(board);
 5918            return board;
 19        }
 20
 21        private static void ParseEnPassant(BoardState board, string fen)
 22        {
 5923            if (fen != "-")
 824                board.EnPassantSquare = (Square)Enum.Parse(typeof(Square), fen);
 5925        }
 26
 27        private static void ParseCastling(BoardState board, string fen)
 28        {
 55829            foreach (char character in fen)
 30            {
 31                switch (character)
 32                {
 10833                    case 'K': board.Castle |= Castle.WhiteShort; break;
 10834                    case 'Q': board.Castle |= Castle.WhiteLong; break;
 10635                    case 'k': board.Castle |= Castle.BlackShort; break;
 5436                    case 'q': board.Castle |= Castle.BlackLong; break;
 37                }
 38            }
 5939        }
 40
 41        private static void ParseSideToMove(BoardState board, string fen)
 42        {
 5943            board.SideToMove = fen == "w" ? Side.White : Side.Black;
 5944        }
 45
 46        private static void ParsePieces(BoardState board, string fen)
 47        {
 5948            string[] ranks = fen.Split('/');
 49
 106250            for (int rank = 0; rank < 8; rank++)
 51            {
 47252                int index = rank * 8;
 525453                for (int file = 0; file < ranks[rank].Length; file++)
 54                {
 215555                    char symbol = ranks[rank][file];
 215556                    if (char.IsLetter(symbol))
 57                    {
 172558                        board.AddPiece((Square)index, SymbolToSide(symbol), SymbolToPiece(symbol));
 172559                        index++;
 60                    }
 43061                    else if (char.IsDigit(symbol))
 62                    {
 43063                        index += symbol - '0';
 64                    }
 65                }
 66            }
 5967        }
 68        private static Piece SymbolToPiece(char symbol)
 69        {
 172570            switch (char.ToLower(symbol))
 71            {
 88672                case 'p': return Piece.Pawn;
 22673                case 'r': return Piece.Rook;
 19274                case 'n': return Piece.Knight;
 20275                case 'b': return Piece.Bishop;
 10176                case 'q': return Piece.Queen;
 11877                case 'k': return Piece.King;
 78            }
 079            return Piece.None;
 80        }
 81
 82        private static Side SymbolToSide(char symbol)
 83        {
 172584            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        {
 181927412            Moves = new List<Move>();
 13
 181927414            GeneratePawnMoves();
 181927415            GenerateBishopMoves();
 181927416            GenerateKnightMoves();
 181927417            GenerateRookMoves();
 181927418            GenerateQueenMoves();
 181927419            GenerateKingMoves();
 181927420        }
 21
 22        private void GenerateKingMoves()
 23        {
 181927424            int source = Pieces[(int)SideToMove, (int)Piece.King].GetLsb();
 181927425            Bitboard attacks = new Bitboard(Bitboard.KingAttacks[source]);
 26
 1155649727            while (attacks.Board > 0)
 28            {
 973722329                int target = attacks.GetLsb();
 973722330                attacks.ClearBit(target);
 973722331                if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 32                {
 33                    continue;
 34                }
 526214635                AddMoveToMovesList(source, target);
 36            }
 37
 181927438            GenerateCastleMoves();
 181927439        }
 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        {
 181927448            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Queen];
 317709549            while (bitboard.Board > 0)
 50            {
 135782151                int source = bitboard.GetLsb();
 135782152                Bitboard attacks = Bitboard.GetQueenAttacksFromTable((Square)source, Occupancies[(int)Side.Both]);
 53
 1672490854                while (attacks.Board > 0)
 55                {
 1536708756                    int target = attacks.GetLsb();
 57
 1536708758                    if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 59                    {
 530977460                        attacks.ClearBit(target);
 530977461                        continue;
 62                    }
 63
 1005731364                    AddMoveToMovesList(source, target);
 65
 1005731366                    attacks.ClearBit(target);
 67                }
 68
 135782169                bitboard.ClearBit(source);
 70            }
 181927471        }
 72
 73        private void GenerateRookMoves()
 74        {
 181927475            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Rook];
 498450676            while (bitboard.Board > 0)
 77            {
 316523278                int source = bitboard.GetLsb();
 316523279                Bitboard attacks = Bitboard.GetRookAttacksFromTable((Square)source, Occupancies[(int)Side.Both]);
 80
 1915504781                while (attacks.Board > 0)
 82                {
 1598981583                    int target = attacks.GetLsb();
 84
 1598981585                    if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 86                    {
 588113387                        attacks.ClearBit(target);
 588113388                        continue;
 89                    }
 90
 1010868291                    AddMoveToMovesList(source, target);
 92
 1010868293                    attacks.ClearBit(target);
 94                }
 95
 316523296                bitboard.ClearBit(source);
 97            }
 181927498        }
 99
 100        private void GenerateKnightMoves()
 101        {
 1819274102            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Knight];
 4086847103            while (bitboard.Board > 0)
 104            {
 2267573105                int source = bitboard.GetLsb();
 2267573106                Bitboard attacks = new Bitboard(Bitboard.KnightAttacks[source]);
 107
 15043450108                while (attacks.Board > 0)
 109                {
 12775877110                    int target = attacks.GetLsb();
 111
 12775877112                    if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 113                    {
 3104244114                        attacks.ClearBit(target);
 3104244115                        continue;
 116                    }
 117
 9671633118                    AddMoveToMovesList(source, target);
 119
 9671633120                    attacks.ClearBit(target);
 121                }
 122
 2267573123                bitboard.ClearBit(source);
 124            }
 1819274125        }
 126
 127        private void GenerateBishopMoves()
 128        {
 1819274129            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Bishop];
 4220517130            while (bitboard.Board > 0)
 131            {
 2401243132                int source = bitboard.GetLsb();
 2401243133                Bitboard attacks = Bitboard.GetBishopAttacksFromTable((Square)source, Occupancies[(int)Side.Both]);
 134
 15063966135                while (attacks.Board > 0)
 136                {
 12662723137                    int target = attacks.GetLsb();
 138
 12662723139                    if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 140                    {
 3048318141                        attacks.ClearBit(target);
 3048318142                        continue;
 143                    }
 144
 9614405145                    AddMoveToMovesList(source, target);
 146
 9614405147                    attacks.ClearBit(target);
 148                }
 149
 2401243150                bitboard.ClearBit(source);
 151            }
 1819274152        }
 153
 154        private void GeneratePawnMoves()
 155        {
 1819274156            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Pawn];
 13445169157            while (bitboard.Board > 0)
 158            {
 11625895159                int source = bitboard.GetLsb();
 11625895160                GeneratePawnPushes(source);
 11625895161                GenerateEnPassants(source);
 11625895162                GeneratePawnAttacks(source);
 163
 11625895164                bitboard.ClearBit(source);
 165            }
 1819274166        }
 167
 168        private void GenerateEnPassants(int source)
 169        {
 11625895170            if (EnPassantSquare == Square.NoSquare)
 11305029171                return;
 172
 320866173            Bitboard attacks = new Bitboard(Bitboard.PawnAttacks[(int)SideToMove, source] & (1ul << (int)EnPassantSquare
 320866174            if (attacks.Board > 0)
 175            {
 17370176                int target = attacks.GetLsb();
 17370177                AddPawnMove(source, target, true, false);
 178            }
 179
 320866180        }
 181
 182
 183        private void GeneratePawnPushes(int source)
 184        {
 11625895185            if (SideToMove == Side.Black)
 186            {
 5773891187                int oneSquarePush = source + 8;
 7158546188                if (Occupancies[(int)Side.Both].GetBit(oneSquarePush) != 0) return;
 4389236189                AddPawnMove(source, oneSquarePush, false, false);
 4389236190                if (source is <= (int)Square.h7 and >= (int)Square.a7)
 191                {
 2905887192                    int twoSquarePush = oneSquarePush + 8;
 3378500193                    if (Occupancies[(int)Side.Both].GetBit(twoSquarePush) != 0) return;
 2433274194                    AddPawnMove(source, twoSquarePush, false, true);
 195                }
 196            }
 197            else
 198            {
 5852004199                int oneSquarePush = source - 8;
 7249580200                if (Occupancies[(int)Side.Both].GetBit(oneSquarePush) != 0) return;
 4454428201                AddPawnMove(source, oneSquarePush, false, false);
 4454428202                if (source is <= (int)Square.h2 and >= (int)Square.a2)
 203                {
 2990691204                    int twoSquarePush = oneSquarePush - 8;
 3278941205                    if (Occupancies[(int)Side.Both].GetBit(twoSquarePush) != 0) return;
 2702441206                    AddPawnMove(source, twoSquarePush, false, true);
 207                }
 208            }
 5649527209        }
 210
 211        private void GeneratePawnAttacks(int source)
 212        {
 11625895213            Bitboard attacks = new Bitboard(Bitboard.PawnAttacks[(int)SideToMove, source] & Occupancies[(int)SideToMove.
 214
 13637851215            while (attacks.Board > 0)
 216            {
 2011956217                int target = attacks.GetLsb();
 218
 2011956219                if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 220                {
 0221                    attacks.ClearBit(target);
 0222                    continue;
 223                }
 224
 2011956225                AddPawnMove(source, target, false, false);
 226
 2011956227                attacks.ClearBit(target);
 228            }
 11625895229        }
 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
 1819274234            Bitboard occ = Occupancies[(int)Side.Both];
 1819274235            if (SideToMove == Side.White)
 236            {
 922866237                if (Castle.HasFlag(Castle.WhiteShort))
 238                {
 537662239                    if (occ.GetBit(Square.f1) == 0 && occ.GetBit(Square.g1) == 0 && !IsSquareAttacked(Square.e1, Side.Bl
 179021240                        Moves.Add(new Move(Square.e1, Square.g1, MoveTypes.Castle));
 241                }
 922866242                if (Castle.HasFlag(Castle.WhiteLong))
 243                {
 579572244                    if (occ.GetBit(Square.d1) == 0 && occ.GetBit(Square.c1) == 0 && occ.GetBit(Square.b1) == 0 && !IsSqu
 183611245                        Moves.Add(new Move(Square.e1, Square.c1, MoveTypes.Castle));
 246                }
 247            }
 248            else
 249            {
 896408250                if (Castle.HasFlag(Castle.BlackShort))
 251                {
 560227252                    if (occ.GetBit(Square.f8) == 0 && occ.GetBit(Square.g8) == 0 && !IsSquareAttacked(Square.e8, Side.Wh
 329146253                        Moves.Add(new Move(Square.e8, Square.g8, MoveTypes.Castle));
 254                }
 896408255                if (Castle.HasFlag(Castle.BlackLong))
 256                {
 732269257                    if (occ.GetBit(Square.d8) == 0 && occ.GetBit(Square.c8) == 0 && occ.GetBit(Square.b8) == 0 && !IsSqu
 335817258                        Moves.Add(new Move(Square.e8, Square.c8, MoveTypes.Castle));
 259                }
 260            }
 1635663261        }
 262
 263        private bool IsSquareAttacked(Square square, Side attackingSide)
 264        {
 8561012265            if ((Bitboard.GetBishopAttacksFromTable(square, Occupancies[(int)Side.Both]).Board & Pieces[(int)attackingSi
 173914266                return true;
 8387098267            if ((Bitboard.GetRookAttacksFromTable(square, Occupancies[(int)Side.Both]).Board & Pieces[(int)attackingSide
 67780268                return true;
 8319318269            if ((Bitboard.GetQueenAttacksFromTable(square, Occupancies[(int)Side.Both]).Board & Pieces[(int)attackingSid
 503385270                return true;
 7815933271            if ((Bitboard.KnightAttacks[(int)square] & Pieces[(int)attackingSide, (int)Piece.Knight].Board) != 0)
 120338272                return true;
 7695595273            if ((Bitboard.PawnAttacks[(int)attackingSide.Other(), (int)square] & Pieces[(int)attackingSide, (int)Piece.P
 264384274                return true;
 7431211275            if ((Bitboard.KingAttacks[(int)square] & Pieces[(int)attackingSide, (int)Piece.King].Board) != 0)
 2276                return true;
 7431209277            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
 16008705283            if (target is >= (int)Square.a1 and <= (int)Square.h1 || target is <= (int)Square.h8 and >= (int)Square.a8)
 284            {
 214115285                bool capture = IsSquareCapture(target);
 286
 214115287                Moves.Add(new Move((Square)source, (Square)target, capture ? MoveTypes.KnightPromotionCapture : MoveType
 214115288                Moves.Add(new Move((Square)source, (Square)target, capture ? MoveTypes.BishopPromotionCapture : MoveType
 214115289                Moves.Add(new Move((Square)source, (Square)target, capture ? MoveTypes.RookPromotionCapture : MoveTypes.
 214115290                Moves.Add(new Move((Square)source, (Square)target, capture ? MoveTypes.QueenPromotionCapture : MoveTypes
 291            }
 15794590292            else if (enpassant || doublePush)
 293            {
 5153085294                Moves.Add(new Move((Square)source, (Square)target, enpassant ? MoveTypes.EnPassant : MoveTypes.DoublePus
 295            }
 296            else
 297            {
 10641505298                AddMoveToMovesList(source, target);
 299            }
 10641505300        }
 301
 302
 303        private void AddMoveToMovesList(int source, int target)
 304        {
 55355684305            MoveType moveType = IsSquareCapture(target) ? MoveTypes.Capture : MoveTypes.Quiet;
 55355684306            Move move = new Move((Square)source, (Square)target, moveType);
 55355684307            Moves.Add(move);
 55355684308        }
 309        private bool IsSquareCapture(int target)
 310        {
 55569799311            return Occupancies[(int)SideToMove.Other()].GetBit(target) == 1;
 312        }
 313
 314        public void MakeNullMove()
 315        {
 120438316            History.SaveBoardHistory(Piece.None, EnPassantSquare, Castle, BoardHash, LastDrawKiller, BestMove);
 120438317            UpdateEnPassant(Move.NoMove);
 120438318            FlipSideToMove();
 120438319        }
 320
 321        public void UndoNullMove()
 322        {
 120438323            History.BoardHistory history = History.RestoreBoardHistory();
 120438324            FlipSideToMove();
 120438325            LastDrawKiller = history.LastDrawKiller;
 120438326            BoardHash = history.BoardHash;
 120438327            Castle = history.CastlingRights;
 120438328            EnPassantSquare = history.EnPassantSquare;
 120438329        }
 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>)