< 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
 9984974930        public ulong BoardHash { get; set; }
 20733956731        public Bitboard[,] Pieces { get; }
 42227630732        public Bitboard[] Occupancies { get; }
 12915342033        public Piece[] PieceMapping { get; set; }
 23388138234        public Side SideToMove { get; private set; }
 5160136435        public Square EnPassantSquare { get; private set; }
 5897672436        public Castle Castle { get; private set; }
 6785013337        public List<Move> Moves { get; set; }
 3021261038        private int LastDrawKiller { get; set; }
 4099066939        public int MoveCount { get; set; }
 1678243440        public Move BestMove { get; set; }
 41
 42        private int _phase;
 43        public int Phase
 44        {
 3036514145            get => _phase;
 3024459046            set => _phase = value;
 47        }
 48
 430325849        public int ClippedPhase => Math.Min(_phase, GamePhase.TotalPhase);
 50
 51
 52        private void AddPiece(Square square, Side side, Piece piece)
 53        {
 1512314354            Pieces[(int)side, (int)piece] = Pieces[(int)side, (int)piece].SetBit(square);
 1512314355            Occupancies[(int)side] = Occupancies[(int)side].SetBit(square);
 1512314356            Occupancies[(int)Side.Both] = Occupancies[(int)Side.Both].SetBit(square);
 1512314357            PieceMapping[(int)square] = piece;
 1512314358            Phase = GamePhase.AddPhase(Phase, piece);
 1512314359        }
 60
 61        private Piece RemovePiece(Square square)
 62        {
 1512144763            Piece pieceOnSquare = PieceMapping[(int)square];
 1512144764            Pieces[(int)Side.White, (int)pieceOnSquare] = Pieces[(int)Side.White, (int)pieceOnSquare].ClearBit(square);
 1512144765            Pieces[(int)Side.Black, (int)pieceOnSquare] = Pieces[(int)Side.Black, (int)pieceOnSquare].ClearBit(square);
 1512144766            Occupancies[(int)Side.Black] = Occupancies[(int)Side.Black].ClearBit(square);
 1512144767            Occupancies[(int)Side.White] = Occupancies[(int)Side.White].ClearBit(square);
 1512144768            Occupancies[(int)Side.Both] = Occupancies[(int)Side.Both].ClearBit(square);
 1512144769            PieceMapping[(int)square] = Piece.None;
 1512144770            Phase = GamePhase.RemovePhase(Phase, pieceOnSquare);
 1512144771            return pieceOnSquare;
 72        }
 73
 74        public int GetPieceOn(Square square, Side side)
 75        {
 1388215976            Piece piece = PieceMapping[(int)square];
 1388215977            return Occupancies[(int)side].GetBit(square) == 1 ? (int)piece : (int)Piece.None;
 78        }
 79
 80        public int GetPieceOn(Square square)
 81        {
 6990138982            int piece = (int)PieceMapping[(int)square];
 6990441983            if (piece == (int)Piece.None) return -1;
 6989835984            return Occupancies[(int)Side.White].GetBit(square) == 1 ? piece : 6 + piece;
 85        }
 86
 87        public bool IsInCheck(Side side)
 88        {
 584234889            return IsSquareAttacked((Square)Pieces[(int)side, (int)Piece.King].GetLsb(), side.Other());
 90        }
 91        public void MakeMove(Move move)
 92        {
 550970193            Piece capturedPiece = Piece.None;
 550970194            ulong originalBoardHash = BoardHash;
 550970195            Square originalEnPassantSquare = EnPassantSquare;
 550970196            Castle originalCastlingRights = Castle;
 550970197            int originalLastDrawKiller = LastDrawKiller;
 98
 550970199            BoardHash ^= Zobrist.ZobristTable[GetPieceOn(move.Source), (int)move.Source];
 5509701100            Piece movedPiece = RemovePiece(move.Source);
 5509701101            if (movedPiece == Piece.Pawn)
 102            {
 1771426103                LastDrawKiller = MoveCount;
 104            }
 105
 106
 5509701107            if (move.IsCapture())
 108            {
 4074703109                capturedPiece = HandleCapture(move);
 110            }
 111
 5509701112            if (move.IsPromotion())
 113            {
 238372114                movedPiece = move.Type.Piece;
 115            }
 116
 5509701117            if (move.IsCastle())
 118            {
 13831119                HandleCastle(move);
 120            }
 121
 5509701122            AddPiece(move.Target, SideToMove, movedPiece);
 5509701123            BoardHash ^= Zobrist.ZobristTable[GetPieceOn(move.Target), (int)move.Target];
 124
 5509701125            UpdateCastlingRights(move);
 5509701126            UpdateEnPassant(move);
 5509701127            FlipSideToMove();
 128
 5509701129            History.SaveBoardHistory(capturedPiece, originalEnPassantSquare, originalCastlingRights, originalBoardHash, 
 5509701130            BestMove = Move.NoMove;
 5509701131            MoveCount++;
 5509701132        }
 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        {
 4074703155            Square targetSquare = move.Type == MoveTypes.EnPassant ? EnPassantSquareFor(move) : move.Target;
 156
 4074703157            BoardHash ^= Zobrist.ZobristTable[GetPieceOn(targetSquare), (int)targetSquare];
 4074703158            LastDrawKiller = MoveCount;
 159
 4074703160            return RemovePiece(targetSquare);
 161        }
 162
 163        private void FlipSideToMove()
 164        {
 5750577165            BoardHash = Zobrist.FlipSideToMoveHashes(this, BoardHash);
 5750577166            SideToMove = SideToMove.Other();
 5750577167        }
 168
 169        private void UpdateEnPassant(Move move)
 170        {
 5630139171            Square originalEnPassantSquare = EnPassantSquare;
 5630139172            BoardHash = Zobrist.HashEnPassant(this, BoardHash);
 5630139173            EnPassantSquare = move.Type == MoveTypes.DoublePush ? EnPassantSquareFor(move) : Square.NoSquare;
 5630139174            BoardHash = Zobrist.HashEnPassant(this, BoardHash);
 5630139175            if (originalEnPassantSquare != EnPassantSquare)
 236952176                LastDrawKiller = MoveCount;
 5630139177        }
 178
 179        private void UpdateCastlingRights(Move move)
 180        {
 5509701181            Castle originalCastlingRights = Castle;
 5509701182            BoardHash = Zobrist.HashCastlingRights(this, BoardHash);
 5509701183            Castle &= (Castle)CastlingConstants[(int)move.Source];
 5509701184            Castle &= (Castle)CastlingConstants[(int)move.Target];
 5509701185            BoardHash = Zobrist.HashCastlingRights(this, BoardHash);
 5509701186            if (Castle != originalCastlingRights)
 571418187                LastDrawKiller = MoveCount;
 5509701188        }
 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        {
 5509383203            History.BoardHistory history = History.RestoreBoardHistory();
 204
 5509383205            Piece movedPiece = RemovePiece(move.Target);
 5509383206            SideToMove = SideToMove.Other();
 207
 5509383208            if (history.CapturedPiece != Piece.None)
 209            {
 4074674210                if (move.Type == MoveTypes.EnPassant)
 211                {
 11273212                    AddPiece(EnPassantSquareFor(move), SideToMove.Other(), Piece.Pawn);
 213                }
 214                else
 215                {
 4063401216                    AddPiece(move.Target, SideToMove.Other(), history.CapturedPiece);
 217                }
 218            }
 219
 5509383220            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
 5509383244            AddPiece(move.Source, SideToMove, move.IsPromotion() ? Piece.Pawn : movedPiece);
 5509383245            LastDrawKiller = history.LastDrawKiller;
 5509383246            BoardHash = history.BoardHash;
 5509383247            Castle = history.CastlingRights;
 5509383248            EnPassantSquare = history.EnPassantSquare;
 5509383249            BestMove = history.BestMove;
 5509383250            MoveCount--;
 5509383251        }
 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        {
 6148972294            if (MoveCount - LastDrawKiller > 100) return true;
 12297730295            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        {
 181928412            Moves = new List<Move>();
 13
 181928414            GeneratePawnMoves();
 181928415            GenerateBishopMoves();
 181928416            GenerateKnightMoves();
 181928417            GenerateRookMoves();
 181928418            GenerateQueenMoves();
 181928419            GenerateKingMoves();
 181928420        }
 21
 22        private void GenerateKingMoves()
 23        {
 181928424            int source = Pieces[(int)SideToMove, (int)Piece.King].GetLsb();
 181928425            Bitboard attacks = new Bitboard(Bitboard.KingAttacks[source]);
 26
 1155656327            while (attacks.Board > 0)
 28            {
 973727929                int target = attacks.GetLsb();
 973727930                attacks.ClearBit(target);
 973727931                if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 32                {
 33                    continue;
 34                }
 526218435                AddMoveToMovesList(source, target);
 36            }
 37
 181928438            GenerateCastleMoves();
 181928439        }
 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        {
 181928448            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Queen];
 317710549            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            }
 181928471        }
 72
 73        private void GenerateRookMoves()
 74        {
 181928475            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Rook];
 498453176            while (bitboard.Board > 0)
 77            {
 316524778                int source = bitboard.GetLsb();
 316524779                Bitboard attacks = Bitboard.GetRookAttacksFromTable((Square)source, Occupancies[(int)Side.Both]);
 80
 1915518681                while (attacks.Board > 0)
 82                {
 1598993983                    int target = attacks.GetLsb();
 84
 1598993985                    if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 86                    {
 588116587                        attacks.ClearBit(target);
 588116588                        continue;
 89                    }
 90
 1010877491                    AddMoveToMovesList(source, target);
 92
 1010877493                    attacks.ClearBit(target);
 94                }
 95
 316524796                bitboard.ClearBit(source);
 97            }
 181928498        }
 99
 100        private void GenerateKnightMoves()
 101        {
 1819284102            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Knight];
 4086857103            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            }
 1819284125        }
 126
 127        private void GenerateBishopMoves()
 128        {
 1819284129            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Bishop];
 4220537130            while (bitboard.Board > 0)
 131            {
 2401253132                int source = bitboard.GetLsb();
 2401253133                Bitboard attacks = Bitboard.GetBishopAttacksFromTable((Square)source, Occupancies[(int)Side.Both]);
 134
 15064041135                while (attacks.Board > 0)
 136                {
 12662788137                    int target = attacks.GetLsb();
 138
 12662788139                    if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 140                    {
 3048330141                        attacks.ClearBit(target);
 3048330142                        continue;
 143                    }
 144
 9614458145                    AddMoveToMovesList(source, target);
 146
 9614458147                    attacks.ClearBit(target);
 148                }
 149
 2401253150                bitboard.ClearBit(source);
 151            }
 1819284152        }
 153
 154        private void GeneratePawnMoves()
 155        {
 1819284156            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Pawn];
 13445228157            while (bitboard.Board > 0)
 158            {
 11625944159                int source = bitboard.GetLsb();
 11625944160                GeneratePawnPushes(source);
 11625944161                GenerateEnPassants(source);
 11625944162                GeneratePawnAttacks(source);
 163
 11625944164                bitboard.ClearBit(source);
 165            }
 1819284166        }
 167
 168        private void GenerateEnPassants(int source)
 169        {
 11625944170            if (EnPassantSquare == Square.NoSquare)
 11305078171                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        {
 11625944185            if (SideToMove == Side.Black)
 186            {
 5773921187                int oneSquarePush = source + 8;
 7158581188                if (Occupancies[(int)Side.Both].GetBit(oneSquarePush) != 0) return;
 4389261189                AddPawnMove(source, oneSquarePush, false, false);
 4389261190                if (source is <= (int)Square.h7 and >= (int)Square.a7)
 191                {
 2905897192                    int twoSquarePush = oneSquarePush + 8;
 3378510193                    if (Occupancies[(int)Side.Both].GetBit(twoSquarePush) != 0) return;
 2433284194                    AddPawnMove(source, twoSquarePush, false, true);
 195                }
 196            }
 197            else
 198            {
 5852023199                int oneSquarePush = source - 8;
 7249603200                if (Occupancies[(int)Side.Both].GetBit(oneSquarePush) != 0) return;
 4454443201                AddPawnMove(source, oneSquarePush, false, false);
 4454443202                if (source is <= (int)Square.h2 and >= (int)Square.a2)
 203                {
 2990696204                    int twoSquarePush = oneSquarePush - 8;
 3278946205                    if (Occupancies[(int)Side.Both].GetBit(twoSquarePush) != 0) return;
 2702446206                    AddPawnMove(source, twoSquarePush, false, true);
 207                }
 208            }
 5649557209        }
 210
 211        private void GeneratePawnAttacks(int source)
 212        {
 11625944213            Bitboard attacks = new Bitboard(Bitboard.PawnAttacks[(int)SideToMove, source] & Occupancies[(int)SideToMove.
 214
 13637901215            while (attacks.Board > 0)
 216            {
 2011957217                int target = attacks.GetLsb();
 218
 2011957219                if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 220                {
 0221                    attacks.ClearBit(target);
 0222                    continue;
 223                }
 224
 2011957225                AddPawnMove(source, target, false, false);
 226
 2011957227                attacks.ClearBit(target);
 228            }
 11625944229        }
 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
 1819284234            Bitboard occ = Occupancies[(int)Side.Both];
 1819284235            if (SideToMove == Side.White)
 236            {
 922871237                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                }
 922871242                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            {
 896413250                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                }
 896413255                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            }
 1635673261        }
 262
 263        private bool IsSquareAttacked(Square square, Side attackingSide)
 264        {
 8561032265            if ((Bitboard.GetBishopAttacksFromTable(square, Occupancies[(int)Side.Both]).Board & Pieces[(int)attackingSi
 173915266                return true;
 8387117267            if ((Bitboard.GetRookAttacksFromTable(square, Occupancies[(int)Side.Both]).Board & Pieces[(int)attackingSide
 67780268                return true;
 8319337269            if ((Bitboard.GetQueenAttacksFromTable(square, Occupancies[(int)Side.Both]).Board & Pieces[(int)attackingSid
 503385270                return true;
 7815952271            if ((Bitboard.KnightAttacks[(int)square] & Pieces[(int)attackingSide, (int)Piece.Knight].Board) != 0)
 120338272                return true;
 7695614273            if ((Bitboard.PawnAttacks[(int)attackingSide.Other(), (int)square] & Pieces[(int)attackingSide, (int)Piece.P
 264384274                return true;
 7431230275            if ((Bitboard.KingAttacks[(int)square] & Pieces[(int)attackingSide, (int)Piece.King].Board) != 0)
 2276                return true;
 7431228277            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
 16008761283            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            }
 15794646292            else if (enpassant || doublePush)
 293            {
 5153100294                Moves.Add(new Move((Square)source, (Square)target, enpassant ? MoveTypes.EnPassant : MoveTypes.DoublePus
 295            }
 296            else
 297            {
 10641546298                AddMoveToMovesList(source, target);
 299            }
 10641546300        }
 301
 302
 303        private void AddMoveToMovesList(int source, int target)
 304        {
 55355908305            MoveType moveType = IsSquareCapture(target) ? MoveTypes.Capture : MoveTypes.Quiet;
 55355908306            Move move = new Move((Square)source, (Square)target, moveType);
 55355908307            Moves.Add(move);
 55355908308        }
 309        private bool IsSquareCapture(int target)
 310        {
 55570023311            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>)