< 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
 9994893230        public ulong BoardHash { get; set; }
 20750688531        public Bitboard[,] Pieces { get; }
 42267121832        public Bitboard[] Occupancies { get; }
 12927320333        public Piece[] PieceMapping { get; set; }
 23411738034        public Side SideToMove { get; private set; }
 5165625235        public Square EnPassantSquare { get; private set; }
 5903799436        public Castle Castle { get; private set; }
 6792353537        public List<Move> Moves { get; set; }
 3024118038        private int LastDrawKiller { get; set; }
 4103039939        public int MoveCount { get; set; }
 1680004640        public Move BestMove { get; set; }
 41
 42        private int _phase;
 43        public int Phase
 44        {
 3039235045            get => _phase;
 3027179846            set => _phase = value;
 47        }
 48
 430596949        public int ClippedPhase => Math.Min(_phase, GamePhase.TotalPhase);
 50
 51
 52        private void AddPiece(Square square, Side side, Piece piece)
 53        {
 1513674754            Pieces[(int)side, (int)piece] = Pieces[(int)side, (int)piece].SetBit(square);
 1513674755            Occupancies[(int)side] = Occupancies[(int)side].SetBit(square);
 1513674756            Occupancies[(int)Side.Both] = Occupancies[(int)Side.Both].SetBit(square);
 1513674757            PieceMapping[(int)square] = piece;
 1513674758            Phase = GamePhase.AddPhase(Phase, piece);
 1513674759        }
 60
 61        private Piece RemovePiece(Square square)
 62        {
 1513505163            Piece pieceOnSquare = PieceMapping[(int)square];
 1513505164            Pieces[(int)Side.White, (int)pieceOnSquare] = Pieces[(int)Side.White, (int)pieceOnSquare].ClearBit(square);
 1513505165            Pieces[(int)Side.Black, (int)pieceOnSquare] = Pieces[(int)Side.Black, (int)pieceOnSquare].ClearBit(square);
 1513505166            Occupancies[(int)Side.Black] = Occupancies[(int)Side.Black].ClearBit(square);
 1513505167            Occupancies[(int)Side.White] = Occupancies[(int)Side.White].ClearBit(square);
 1513505168            Occupancies[(int)Side.Both] = Occupancies[(int)Side.Both].ClearBit(square);
 1513505169            PieceMapping[(int)square] = Piece.None;
 1513505170            Phase = GamePhase.RemovePhase(Phase, pieceOnSquare);
 1513505171            return pieceOnSquare;
 72        }
 73
 74        public int GetPieceOn(Square square, Side side)
 75        {
 1388724076            Piece piece = PieceMapping[(int)square];
 1388724077            return Occupancies[(int)side].GetBit(square) == 1 ? (int)piece : (int)Piece.None;
 78        }
 79
 80        public int GetPieceOn(Square square)
 81        {
 6997527982            int piece = (int)PieceMapping[(int)square];
 6997830983            if (piece == (int)Piece.None) return -1;
 6997224984            return Occupancies[(int)Side.White].GetBit(square) == 1 ? piece : 6 + piece;
 85        }
 86
 87        public bool IsInCheck(Side side)
 88        {
 584793089            return IsSquareAttacked((Square)Pieces[(int)side, (int)Piece.King].GetLsb(), side.Other());
 90        }
 91        public void MakeMove(Move move)
 92        {
 551528293            Piece capturedPiece = Piece.None;
 551528294            ulong originalBoardHash = BoardHash;
 551528295            Square originalEnPassantSquare = EnPassantSquare;
 551528296            Castle originalCastlingRights = Castle;
 551528297            int originalLastDrawKiller = LastDrawKiller;
 98
 551528299            BoardHash ^= Zobrist.ZobristTable[GetPieceOn(move.Source), (int)move.Source];
 5515282100            Piece movedPiece = RemovePiece(move.Source);
 5515282101            if (movedPiece == Piece.Pawn)
 102            {
 1773095103                LastDrawKiller = MoveCount;
 104            }
 105
 106
 5515282107            if (move.IsCapture())
 108            {
 4077145109                capturedPiece = HandleCapture(move);
 110            }
 111
 5515282112            if (move.IsPromotion())
 113            {
 238372114                movedPiece = move.Type.Piece;
 115            }
 116
 5515282117            if (move.IsCastle())
 118            {
 13831119                HandleCastle(move);
 120            }
 121
 5515282122            AddPiece(move.Target, SideToMove, movedPiece);
 5515282123            BoardHash ^= Zobrist.ZobristTable[GetPieceOn(move.Target), (int)move.Target];
 124
 5515282125            UpdateCastlingRights(move);
 5515282126            UpdateEnPassant(move);
 5515282127            FlipSideToMove();
 128
 5515282129            History.SaveBoardHistory(capturedPiece, originalEnPassantSquare, originalCastlingRights, originalBoardHash, 
 5515282130            BestMove = Move.NoMove;
 5515282131            MoveCount++;
 5515282132        }
 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        {
 4077145155            Square targetSquare = move.Type == MoveTypes.EnPassant ? EnPassantSquareFor(move) : move.Target;
 156
 4077145157            BoardHash ^= Zobrist.ZobristTable[GetPieceOn(targetSquare), (int)targetSquare];
 4077145158            LastDrawKiller = MoveCount;
 159
 4077145160            return RemovePiece(targetSquare);
 161        }
 162
 163        private void FlipSideToMove()
 164        {
 5756160165            BoardHash = Zobrist.FlipSideToMoveHashes(this, BoardHash);
 5756160166            SideToMove = SideToMove.Other();
 5756160167        }
 168
 169        private void UpdateEnPassant(Move move)
 170        {
 5635721171            Square originalEnPassantSquare = EnPassantSquare;
 5635721172            BoardHash = Zobrist.HashEnPassant(this, BoardHash);
 5635721173            EnPassantSquare = move.Type == MoveTypes.DoublePush ? EnPassantSquareFor(move) : Square.NoSquare;
 5635721174            BoardHash = Zobrist.HashEnPassant(this, BoardHash);
 5635721175            if (originalEnPassantSquare != EnPassantSquare)
 237917176                LastDrawKiller = MoveCount;
 5635721177        }
 178
 179        private void UpdateCastlingRights(Move move)
 180        {
 5515282181            Castle originalCastlingRights = Castle;
 5515282182            BoardHash = Zobrist.HashCastlingRights(this, BoardHash);
 5515282183            Castle &= (Castle)CastlingConstants[(int)move.Source];
 5515282184            Castle &= (Castle)CastlingConstants[(int)move.Target];
 5515282185            BoardHash = Zobrist.HashCastlingRights(this, BoardHash);
 5515282186            if (Castle != originalCastlingRights)
 571418187                LastDrawKiller = MoveCount;
 5515282188        }
 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        {
 5514964203            History.BoardHistory history = History.RestoreBoardHistory();
 204
 5514964205            Piece movedPiece = RemovePiece(move.Target);
 5514964206            SideToMove = SideToMove.Other();
 207
 5514964208            if (history.CapturedPiece != Piece.None)
 209            {
 4077116210                if (move.Type == MoveTypes.EnPassant)
 211                {
 11581212                    AddPiece(EnPassantSquareFor(move), SideToMove.Other(), Piece.Pawn);
 213                }
 214                else
 215                {
 4065535216                    AddPiece(move.Target, SideToMove.Other(), history.CapturedPiece);
 217                }
 218            }
 219
 5514964220            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
 5514964244            AddPiece(move.Source, SideToMove, move.IsPromotion() ? Piece.Pawn : movedPiece);
 5514964245            LastDrawKiller = history.LastDrawKiller;
 5514964246            BoardHash = history.BoardHash;
 5514964247            Castle = history.CastlingRights;
 5514964248            EnPassantSquare = history.EnPassantSquare;
 5514964249            BestMove = history.BestMove;
 5514964250            MoveCount--;
 5514964251        }
 252        private Square EnPassantSquareFor(Move move)
 253        {
 164414254            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        {
 6155137294            if (MoveCount - LastDrawKiller > 100) return true;
 12310060295            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        {
 182201312            Moves = new List<Move>();
 13
 182201314            GeneratePawnMoves();
 182201315            GenerateBishopMoves();
 182201316            GenerateKnightMoves();
 182201317            GenerateRookMoves();
 182201318            GenerateQueenMoves();
 182201319            GenerateKingMoves();
 182201320        }
 21
 22        private void GenerateKingMoves()
 23        {
 182201324            int source = Pieces[(int)SideToMove, (int)Piece.King].GetLsb();
 182201325            Bitboard attacks = new Bitboard(Bitboard.KingAttacks[source]);
 26
 1157574227            while (attacks.Board > 0)
 28            {
 975372929                int target = attacks.GetLsb();
 975372930                attacks.ClearBit(target);
 975372931                if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 32                {
 33                    continue;
 34                }
 527485735                AddMoveToMovesList(source, target);
 36            }
 37
 182201338            GenerateCastleMoves();
 182201339        }
 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        {
 182201348            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Queen];
 317983449            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            }
 182201371        }
 72
 73        private void GenerateRookMoves()
 74        {
 182201375            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Rook];
 499077376            while (bitboard.Board > 0)
 77            {
 316876078                int source = bitboard.GetLsb();
 316876079                Bitboard attacks = Bitboard.GetRookAttacksFromTable((Square)source, Occupancies[(int)Side.Both]);
 80
 1919015881                while (attacks.Board > 0)
 82                {
 1602139883                    int target = attacks.GetLsb();
 84
 1602139885                    if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 86                    {
 588654887                        attacks.ClearBit(target);
 588654888                        continue;
 89                    }
 90
 1013485091                    AddMoveToMovesList(source, target);
 92
 1013485093                    attacks.ClearBit(target);
 94                }
 95
 316876096                bitboard.ClearBit(source);
 97            }
 182201398        }
 99
 100        private void GenerateKnightMoves()
 101        {
 1822013102            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Knight];
 4089586103            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            }
 1822013125        }
 126
 127        private void GenerateBishopMoves()
 128        {
 1822013129            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Bishop];
 4225530130            while (bitboard.Board > 0)
 131            {
 2403517132                int source = bitboard.GetLsb();
 2403517133                Bitboard attacks = Bitboard.GetBishopAttacksFromTable((Square)source, Occupancies[(int)Side.Both]);
 134
 15081416135                while (attacks.Board > 0)
 136                {
 12677899137                    int target = attacks.GetLsb();
 138
 12677899139                    if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 140                    {
 3051751141                        attacks.ClearBit(target);
 3051751142                        continue;
 143                    }
 144
 9626148145                    AddMoveToMovesList(source, target);
 146
 9626148147                    attacks.ClearBit(target);
 148                }
 149
 2403517150                bitboard.ClearBit(source);
 151            }
 1822013152        }
 153
 154        private void GeneratePawnMoves()
 155        {
 1822013156            Bitboard bitboard = Pieces[(int)SideToMove, (int)Piece.Pawn];
 13461263157            while (bitboard.Board > 0)
 158            {
 11639250159                int source = bitboard.GetLsb();
 11639250160                GeneratePawnPushes(source);
 11639250161                GenerateEnPassants(source);
 11639250162                GeneratePawnAttacks(source);
 163
 11639250164                bitboard.ClearBit(source);
 165            }
 1822013166        }
 167
 168        private void GenerateEnPassants(int source)
 169        {
 11639250170            if (EnPassantSquare == Square.NoSquare)
 11316846171                return;
 172
 322404173            Bitboard attacks = new Bitboard(Bitboard.PawnAttacks[(int)SideToMove, source] & (1ul << (int)EnPassantSquare
 322404174            if (attacks.Board > 0)
 175            {
 17701176                int target = attacks.GetLsb();
 17701177                AddPawnMove(source, target, true, false);
 178            }
 179
 322404180        }
 181
 182
 183        private void GeneratePawnPushes(int source)
 184        {
 11639250185            if (SideToMove == Side.Black)
 186            {
 5782213187                int oneSquarePush = source + 8;
 7168526188                if (Occupancies[(int)Side.Both].GetBit(oneSquarePush) != 0) return;
 4395900189                AddPawnMove(source, oneSquarePush, false, false);
 4395900190                if (source is <= (int)Square.h7 and >= (int)Square.a7)
 191                {
 2908649192                    int twoSquarePush = oneSquarePush + 8;
 3381288193                    if (Occupancies[(int)Side.Both].GetBit(twoSquarePush) != 0) return;
 2436010194                    AddPawnMove(source, twoSquarePush, false, true);
 195                }
 196            }
 197            else
 198            {
 5857037199                int oneSquarePush = source - 8;
 7255914200                if (Occupancies[(int)Side.Both].GetBit(oneSquarePush) != 0) return;
 4458160201                AddPawnMove(source, oneSquarePush, false, false);
 4458160202                if (source is <= (int)Square.h2 and >= (int)Square.a2)
 203                {
 2991414204                    int twoSquarePush = oneSquarePush - 8;
 3279684205                    if (Occupancies[(int)Side.Both].GetBit(twoSquarePush) != 0) return;
 2703144206                    AddPawnMove(source, twoSquarePush, false, true);
 207                }
 208            }
 5657141209        }
 210
 211        private void GeneratePawnAttacks(int source)
 212        {
 11639250213            Bitboard attacks = new Bitboard(Bitboard.PawnAttacks[(int)SideToMove, source] & Occupancies[(int)SideToMove.
 214
 13651872215            while (attacks.Board > 0)
 216            {
 2012622217                int target = attacks.GetLsb();
 218
 2012622219                if (Occupancies[(int)SideToMove].GetBit(target) == 1)
 220                {
 0221                    attacks.ClearBit(target);
 0222                    continue;
 223                }
 224
 2012622225                AddPawnMove(source, target, false, false);
 226
 2012622227                attacks.ClearBit(target);
 228            }
 11639250229        }
 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
 1822013234            Bitboard occ = Occupancies[(int)Side.Both];
 1822013235            if (SideToMove == Side.White)
 236            {
 924201237                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                }
 924201242                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            {
 897812250                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                }
 897812255                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            }
 1638402261        }
 262
 263        private bool IsSquareAttacked(Square square, Side attackingSide)
 264        {
 8566614265            if ((Bitboard.GetBishopAttacksFromTable(square, Occupancies[(int)Side.Both]).Board & Pieces[(int)attackingSi
 173943266                return true;
 8392671267            if ((Bitboard.GetRookAttacksFromTable(square, Occupancies[(int)Side.Both]).Board & Pieces[(int)attackingSide
 68303268                return true;
 8324368269            if ((Bitboard.GetQueenAttacksFromTable(square, Occupancies[(int)Side.Both]).Board & Pieces[(int)attackingSid
 503385270                return true;
 7820983271            if ((Bitboard.KnightAttacks[(int)square] & Pieces[(int)attackingSide, (int)Piece.Knight].Board) != 0)
 120338272                return true;
 7700645273            if ((Bitboard.PawnAttacks[(int)attackingSide.Other(), (int)square] & Pieces[(int)attackingSide, (int)Piece.P
 264438274                return true;
 7436207275            if ((Bitboard.KingAttacks[(int)square] & Pieces[(int)attackingSide, (int)Piece.King].Board) != 0)
 2276                return true;
 7436205277            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
 16023537283            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            }
 15809422292            else if (enpassant || doublePush)
 293            {
 5156855294                Moves.Add(new Move((Square)source, (Square)target, enpassant ? MoveTypes.EnPassant : MoveTypes.DoublePus
 295            }
 296            else
 297            {
 10652567298                AddMoveToMovesList(source, target);
 299            }
 10652567300        }
 301
 302
 303        private void AddMoveToMovesList(int source, int target)
 304        {
 55417368305            MoveType moveType = IsSquareCapture(target) ? MoveTypes.Capture : MoveTypes.Quiet;
 55417368306            Move move = new Move((Square)source, (Square)target, moveType);
 55417368307            Moves.Add(move);
 55417368308        }
 309        private bool IsSquareCapture(int target)
 310        {
 55631483311            return Occupancies[(int)SideToMove.Other()].GetBit(target) == 1;
 312        }
 313
 314        public void MakeNullMove()
 315        {
 120439316            History.SaveBoardHistory(Piece.None, EnPassantSquare, Castle, BoardHash, LastDrawKiller, BestMove);
 120439317            UpdateEnPassant(Move.NoMove);
 120439318            FlipSideToMove();
 120439319        }
 320
 321        public void UndoNullMove()
 322        {
 120439323            History.BoardHistory history = History.RestoreBoardHistory();
 120439324            FlipSideToMove();
 120439325            LastDrawKiller = history.LastDrawKiller;
 120439326            BoardHash = history.BoardHash;
 120439327            Castle = history.CastlingRights;
 120439328            EnPassantSquare = history.EnPassantSquare;
 120439329        }
 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>)