Sliding piece move generation - Chess
===

I'm trying to develop my own chess engine in C#.
Recently I switched to bitboards and I'm rewriting my move generator:
I implemented pawn, knight and king move generation, but now I'm stuck with sliding piece move generation (queen, rook and bishop)...
I would like to use an occupancy look-up approach like shown here:
https://chessprogramming.wikispaces.com/First+Rank+Attacks

but, maybe for my english, I really can't understand how should I proceed.
I really need a clear explanation about all this stuff, maybe with some pseudo-code implementation (or better in C#, Java, C++, ecc.).
More specifically I can't understand how sould I initialize the attack array for files and ranks (but please, don't focus only on this topic :) )...
I would be very grateful to anyone who will explain clearly and in depth Sliding piece move generation.

if needed, I post my implementation of NON-Sliding piece move generation:


Here is my MoveGenerator static class:

     internal static class MoveGenerator
        {
            private static List<Move> moveList = new List<Move>();
            private static BitBoard targets;
            private static Square fromSquare;
            private static Square toSquare;
            private static int fromIndex;
            private static int toIndex;
    
            private delegate BitBoard GetTargetsDelegate(PieceColor color, BitBoard pieces, Board board);
    
            private static List<Move> ExtractMoves(PieceColor color, PieceType type, BitBoard pieces, Board board, GetTargetsDelegate getTargets)
            {
                moveList.Clear();
    
                while (pieces != 0)
                {
                    fromIndex = BitBoard.BitScanForwardReset(ref pieces); // search for LS1B and then reset it
                    fromSquare = new Square(fromIndex);
                    targets = getTargets.Invoke(color, BitBoard.ToBitBoard(fromIndex), board);
    
                    while (targets != 0)
                    {
                        toIndex = BitBoard.BitScanForwardReset(ref targets); // search for LS1B and then reset it
                        toSquare = new Square(toIndex);
                        moveList.Add(new Move(fromSquare, toSquare, type));                    
                    }
                }
                return moveList;
            }
    
            internal static List<Move> GetAllMoves(PieceColor color, Board board)
            {
                List<Move> allMoves = new List<Move>(30);
                allMoves.AddRange(GetPawnMoves(color, board.GetPieceSet(color, PieceType.Pawn), board));
                allMoves.AddRange(GetKnightMoves(color, board.GetPieceSet(color, PieceType.Knight), board));
                allMoves.AddRange(GetKingMoves(color, board.GetPieceSet(color, PieceType.King), board));
                return allMoves;
            }
            internal static List<Move> GetPawnMoves(PieceColor color, BitBoard pawns, Board board)
            {
                return ExtractMoves(color, PieceType.Pawn, pawns, board, Pawn.GetAllTargets);
            }
            internal static List<Move> GetKingMoves(PieceColor color, BitBoard king, Board board)
            {
                return ExtractMoves(color, PieceType.King, king, board, King.GetAllTargets);
            }
            internal static List<Move> GetKnightMoves(PieceColor color, BitBoard knights, Board board)
            {
                return ExtractMoves(color, PieceType.Knight, knights, board, Knight.GetAllTargets);
            }
        }

I use a delegate to abstract move serialization, cause every piece type has his own "GetTargets" method.


this is my color-generalized Pawn class:

     internal static class Pawn
        {
            internal static BitBoard GetAllTargets(PieceColor color, BitBoard pawns, Board board)
            {
                BitBoard empty = board.GetEmptySquares();
                BitBoard enemyPieces = board.GetEnemyPieces(color);
    
                return GetQuietTargets(color, pawns, empty) | GetAnyAttack(color, pawns, board);
            }
    
            private static BitBoard GetQuietTargets(PieceColor color, BitBoard pawns, BitBoard empty)
            {
                return GetSinglePushTargets(color, pawns, empty) | GetDoublePushTargets(color, pawns, empty);
            }
    
            private static BitBoard GetSinglePushTargets(PieceColor color, BitBoard pawns, BitBoard empty)
            {
                switch (color)
                {
                    case PieceColor.White:
                        {
                            return CompassRose.OneStepNorth(pawns) & empty;
                        }
                    case PieceColor.Black:
                        {
                            return CompassRose.OneStepSouth(pawns) & empty;
                        }
                    default:
                        throw new NotImplementedException();
                }
            }
            private static BitBoard GetDoublePushTargets(PieceColor color, BitBoard pawns, BitBoard empty)
            {
                switch (color)
                {
                    case PieceColor.White:
                        {
                            BitBoard singlePush = GetSinglePushTargets(color, pawns, empty);
                            return CompassRose.OneStepNorth(singlePush) & empty & Constants.Ranks.Four;
                        }
                    case PieceColor.Black:
                        {
                            BitBoard singlePush = GetSinglePushTargets(color, pawns, empty);
                            return CompassRose.OneStepSouth(singlePush) & empty & Constants.Ranks.Five;
                        }
                    default:
                        throw new NotImplementedException();
                }
            }
    
            private static BitBoard GetPawnsAbleToSinglePush(PieceColor color, BitBoard pawns, BitBoard empty)
            {
                switch (color)
                {
                    case PieceColor.White:
                        return CompassRose.OneStepSouth(empty) & pawns;
                    case PieceColor.Black:
                        return CompassRose.OneStepNorth(empty) & pawns;
                    default:
                        throw new NotImplementedException();
                }
            }
            private static BitBoard GetPawnsAbleToDoublePush(PieceColor color, BitBoard pawns, BitBoard empty)
            {
                switch (color)
                {
                    case PieceColor.White:
                        {
                            BitBoard emptyRank3 = CompassRose.OneStepSouth(empty & Constants.Ranks.Four) & empty;
                            return GetPawnsAbleToSinglePush(color, pawns, emptyRank3);
                        }
                    case PieceColor.Black:
                        {
                            BitBoard emptyRank6 = CompassRose.OneStepNorth(empty & Constants.Ranks.Six) & empty;
                            return GetPawnsAbleToSinglePush(color, pawns, emptyRank6);
                        }
                    default:
                        throw new NotImplementedException();
                }
            }
    
            private static BitBoard GetEastAttacks(PieceColor color, BitBoard pawns)
            {
                switch (color)
                {
                    case PieceColor.White:
                        return CompassRose.OneStepNorthEast(pawns);
                    case PieceColor.Black:
                        return CompassRose.OneStepSouthEast(pawns);
                    default:
                        throw new NotImplementedException();
                }
            }
            private static BitBoard GetWestAttacks(PieceColor color, BitBoard pawns)
            {
                switch (color)
                {
                    case PieceColor.White:
                        return CompassRose.OneStepNorthWest(pawns);
                    case PieceColor.Black:
                        return CompassRose.OneStepSouthWest(pawns);
                    default:
                        throw new NotImplementedException();
                }
            }
    
            private static BitBoard GetAnyAttack(PieceColor color, BitBoard pawns, Board board)
            {
                return (GetEastAttacks(color, pawns) | GetWestAttacks(color, pawns)) & board.GetEnemyPieces(color);
            }
        }

and here are my King and Knight classes:

    internal static class King
        {
            internal static BitBoard GetAllTargets(PieceColor pieceColor, BitBoard king, Board board)
            {
                BitBoard kingMoves = MovePackHelper.KingAttacks[(BitBoard.BitScanForward(king))];
                return kingMoves & ~board.GetPlayerPieces(pieceColor);
            }
            internal static void InitKingAttacks()
            {
                for (int sq = 0; sq < 64; sq++)
                {
                    MovePackHelper.KingAttacks[sq] = GetKingAttacks(BitBoard.ToBitBoard(sq));
                }
            }
            private static BitBoard GetKingAttacks(BitBoard king)
            {
                BitBoard attacks = CompassRose.OneStepEast(king) | CompassRose.OneStepWest(king);
                king |= attacks;
                attacks |= CompassRose.OneStepNorth(king) | CompassRose.OneStepSouth(king);
                return attacks;
            }      
        }


    internal static class Knight
        {
            internal static BitBoard GetAllTargets(PieceColor pieceColor, BitBoard knights, Board board)
            {
                BitBoard targets = Constants.Empty;
    
                while (knights != 0)
                {
                    // accede all'array di mosse precalcolate cercando il primo bit attivo all'interno della bitboard
                    targets |= MovePackHelper.KnightAttacks[(BitBoard.BitScanForwardReset(ref knights))];
                }
    
                return targets & ~board.GetPlayerPieces(pieceColor);
            }
            internal static void InitKnightAttacks()
            {
                // inizializza l'array di mosse precalcolate
                for (int sq = 0; sq < 64; sq++)
                {
                    MovePackHelper.KnightAttacks[sq] = GetKnightAttacks(BitBoard.ToBitBoard(sq));
                }
            }
            private static BitBoard GetKnightAttacks(BitBoard knights)
            {
                BitBoard west, east, attacks;
                east = CompassRose.OneStepEast(knights);
                west = CompassRose.OneStepWest(knights);
                attacks = (east | west) << 16;
                attacks |= (east | west) >> 16;
                east = CompassRose.OneStepEast(east);
                west = CompassRose.OneStepWest(west);
                attacks |= (east | west) << 8;
                attacks |= (east | west) >> 8;
    
                return attacks;
            }
        }


I would like to emphasize that a clear and detailed answer would be a LOT BETTER than an "useful link", for me and for everyone who will visit this thread :)

thanks to all :)
