Ejemplo n.º 1
0
        // init_magics() computes all rook and bishop attacks at startup. Magic
        // bitboards are used to look up attacks of sliding pieces. As a reference see
        // chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we
        // use the so called "fancy" approach.
        public static void init_magics(PieceType pt, Bitboard[][] attacks, Bitboard[] magics,
                                       Bitboard[] masks, uint[] shifts, Square[] deltas, Fn index)
        {
            int[][] MagicBoosters = new int[2][] {
                new int[] { 969, 1976, 2850, 542, 2069, 2852, 1708, 164 },
                new int[] { 3101, 552, 3555, 926, 834, 26, 2131, 1117 }
            };

            RKISS rk = new RKISS();

            Bitboard[] occupancy = new UInt64[4096], reference = new UInt64[4096];
            Bitboard   edges, b;
            int        i, size, booster;

            for (Square s = SquareS.SQ_A1; s <= SquareS.SQ_H8; s++)
            {
                // Board edges are not considered in the relevant occupancies
                edges = ((BitBoard.Rank1BB | BitBoard.Rank8BB) & ~BitBoard.rank_bb_square(s)) | ((BitBoard.FileABB | BitBoard.FileHBB) & ~BitBoard.file_bb_square(s));

                // Given a square 's', the mask is the bitboard of sliding attacks from
                // 's' computed on an empty board. The index must be big enough to contain
                // all the attacks for each possible subset of the mask and so is 2 power
                // the number of 1s of the mask. Hence we deduce the size of the shift to
                // apply to the 64 or 32 bits word to get the index.
                masks[s]  = sliding_attack(deltas, s, 0) & ~edges;
                shifts[s] = 32 - (uint)Bitcount.popcount_Max15(masks[s]);

                // Use Carry-Rippler trick to enumerate all subsets of masks[s] and
                // store the corresponding sliding attack bitboard in reference[].
                b    = 0;
                size = 0;
                do
                {
                    occupancy[size] = b;
                    reference[size] = sliding_attack(deltas, s, b);
                    size++;
                    b = (b - masks[s]) & masks[s];
                } while (b != 0);

                // Set the offset for the table of the next square. We have individual
                // table sizes for each square with "Fancy Magic Bitboards".
                attacks[s] = new Bitboard[size];
                booster    = MagicBoosters[0][Types.rank_of(s)];

                // Find a magic for square 's' picking up an (almost) random number
                // until we find the one that passes the verification test.
                do
                {
                    do
                    {
                        magics[s] = rk.magic_rand(booster);
                    }while (Bitcount.popcount_Max15((magics[s] * masks[s]) >> 56) < 6);

                    Array.Clear(attacks[s], 0, size);

                    // A good magic must map every possible occupancy to an index that
                    // looks up the correct sliding attack in the attacks[s] database.
                    // Note that we build up the database for square 's' as a side
                    // effect of verifying the magic.
                    for (i = 0; i < size; i++)
                    {
                        Bitboard attack = attacks[s][index(s, occupancy[i], pt)];

                        if (attack != 0 && attack != reference[i])
                        {
                            break;
                        }

                        Debug.Assert(reference[i] != 0);

                        //attack = reference[i];
                        attacks[s][index(s, occupancy[i], pt)] = reference[i];
                    }
                } while (i != size);
            }
        }
Ejemplo n.º 2
0
        /// move_to_san() takes a position and a legal Move as input and returns its
        /// short algebraic notation representation.
        public static string move_to_san(Position pos, Move m)
        {
            if (m == MoveS.MOVE_NONE)
            {
                return("(none)");
            }

            if (m == MoveS.MOVE_NULL)
            {
                return("(null)");
            }

            Debug.Assert((new MoveList(pos, GenTypeS.LEGAL).contains(m)));

            Bitboard  others, b;
            string    san  = "";
            Color     us   = pos.side_to_move();
            Square    from = Types.from_sq(m);
            Square    to   = Types.to_sq(m);
            Piece     pc   = pos.piece_on(from);
            PieceType pt   = Types.type_of_piece(pc);

            if (Types.type_of_move(m) == MoveTypeS.CASTLING)
            {
                san = to > from ? "O-O" : "O-O-O";
            }
            else
            {
                if (pt != PieceTypeS.PAWN)
                {
                    san = "" + PieceToChar[ColorS.WHITE][pt]; // Upper case

                    // A disambiguation occurs if we have more then one piece of type 'pt'
                    // that can reach 'to' with a legal move.
                    others = b = (pos.attacks_from_piece_square(pc, to) & pos.pieces_color_piecetype(us, pt)) ^ BitBoard.SquareBB[from];

                    while (b != 0)
                    {
                        Square s = BitBoard.pop_lsb(ref b);
                        if (!pos.legal(Types.make_move(s, to), pos.pinned_pieces(us)))
                        {
                            others ^= BitBoard.SquareBB[s];
                        }
                    }

                    if (0 == others)
                    { /* Disambiguation is not needed */
                    }

                    else if (0 == (others & BitBoard.file_bb_square(from)))
                    {
                        san += Types.file_to_char(Types.file_of(from));
                    }

                    else if (0 == (others & BitBoard.rank_bb_square(from)))
                    {
                        san += Types.rank_to_char(Types.rank_of(from));
                    }

                    else
                    {
                        san += Types.square_to_string(from);
                    }
                }
                else if (pos.capture(m))
                {
                    san = "" + Types.file_to_char(Types.file_of(from));
                }

                if (pos.capture(m))
                {
                    san += 'x';
                }

                san += Types.square_to_string(to);

                if (Types.type_of_move(m) == MoveTypeS.PROMOTION)
                {
                    san += "=" + PieceToChar[ColorS.WHITE][Types.promotion_type(m)];
                }
            }

            if (pos.gives_check(m, new CheckInfo(pos)))
            {
                StateInfo st = new StateInfo();
                pos.do_move(m, st);
                san += (new MoveList(pos, GenTypeS.LEGAL)).size() > 0 ? "+" : "#";
                pos.undo_move(m);
            }

            return(san);
        }
Ejemplo n.º 3
0
        public static int generate_pawn_moves(Position pos, ExtMove[] mlist, int mPos, Bitboard target, CheckInfo ci, Color Us, GenType Type)
        {
            // Compute our parametrized parameters at compile time, named according to
            // the point of view of white side.
            Color    Them     = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE);
            Bitboard TRank8BB = (Us == ColorS.WHITE ? BitBoard.Rank8BB : BitBoard.Rank1BB);
            Bitboard TRank7BB = (Us == ColorS.WHITE ? BitBoard.Rank7BB : BitBoard.Rank2BB);
            Bitboard TRank3BB = (Us == ColorS.WHITE ? BitBoard.Rank3BB : BitBoard.Rank6BB);
            Square   Up       = (Us == ColorS.WHITE ? SquareS.DELTA_N : SquareS.DELTA_S);
            Square   Right    = (Us == ColorS.WHITE ? SquareS.DELTA_NE : SquareS.DELTA_SW);
            Square   Left     = (Us == ColorS.WHITE ? SquareS.DELTA_NW : SquareS.DELTA_SE);

            Bitboard b1, b2, dc1, dc2, emptySquares = 0;

            Bitboard pawnsOn7    = pos.pieces_color_piecetype(Us, PieceTypeS.PAWN) & TRank7BB;
            Bitboard pawnsNotOn7 = pos.pieces_color_piecetype(Us, PieceTypeS.PAWN) & ~TRank7BB;

            Bitboard enemies = (Type == GenTypeS.EVASIONS ? pos.pieces_color(Them) & target :
                                Type == GenTypeS.CAPTURES ? target : pos.pieces_color(Them));

            // Single and double pawn pushes, no promotions
            if (Type != GenTypeS.CAPTURES)
            {
                emptySquares = (Type == GenTypeS.QUIETS || Type == GenTypeS.QUIET_CHECKS ? target : ~pos.pieces());

                b1 = BitBoard.shift_bb(pawnsNotOn7, Up) & emptySquares;
                b2 = BitBoard.shift_bb(b1 & TRank3BB, Up) & emptySquares;

                if (Type == GenTypeS.EVASIONS) // Consider only blocking squares
                {
                    b1 &= target;
                    b2 &= target;
                }

                if (Type == GenTypeS.QUIET_CHECKS)
                {
                    b1 &= pos.attacks_from_pawn(ci.ksq, Them);
                    b2 &= pos.attacks_from_pawn(ci.ksq, Them);

                    // Add pawn pushes which give discovered check. This is possible only
                    // if the pawn is not on the same file as the enemy king, because we
                    // don't generate captures. Note that a possible discovery check
                    // promotion has been already generated among captures.
                    if ((pawnsNotOn7 & ci.dcCandidates) != 0)
                    {
                        dc1 = BitBoard.shift_bb(pawnsNotOn7 & ci.dcCandidates, Up) & emptySquares & ~BitBoard.file_bb_square(ci.ksq);
                        dc2 = BitBoard.shift_bb(dc1 & TRank3BB, Up) & emptySquares;

                        b1 |= dc1;
                        b2 |= dc2;
                    }
                }

                while (b1 != 0)
                {
                    Square to = BitBoard.pop_lsb(ref b1);
                    mlist[mPos++].move = Types.make_move(to - Up, to);
                }

                while (b2 != 0)
                {
                    Square to = BitBoard.pop_lsb(ref b2);
                    mlist[mPos++].move = Types.make_move(to - Up - Up, to);
                }
            }

            // Promotions and underpromotions
            if (pawnsOn7 != 0 && (Type != GenTypeS.EVASIONS || (target & TRank8BB) != 0))
            {
                if (Type == GenTypeS.CAPTURES)
                {
                    emptySquares = ~pos.pieces();
                }

                if (Type == GenTypeS.EVASIONS)
                {
                    emptySquares &= target;
                }

                mPos = generate_promotions(mlist, mPos, pawnsOn7, enemies, ci, Type, Right);
                mPos = generate_promotions(mlist, mPos, pawnsOn7, enemies, ci, Type, Left);
                mPos = generate_promotions(mlist, mPos, pawnsOn7, emptySquares, ci, Type, Up);
            }

            // Standard and en-passant captures
            if (Type == GenTypeS.CAPTURES || Type == GenTypeS.EVASIONS || Type == GenTypeS.NON_EVASIONS)
            {
                b1 = BitBoard.shift_bb(pawnsNotOn7, Right) & enemies;
                b2 = BitBoard.shift_bb(pawnsNotOn7, Left) & enemies;

                while (b1 != 0)
                {
                    Square to = BitBoard.pop_lsb(ref b1);
                    mlist[mPos++].move = Types.make_move(to - Right, to);
                }

                while (b2 != 0)
                {
                    Square to = BitBoard.pop_lsb(ref b2);
                    mlist[mPos++].move = Types.make_move(to - Left, to);
                }

                if (pos.ep_square() != SquareS.SQ_NONE)
                {
                    Debug.Assert(Types.rank_of(pos.ep_square()) == Types.relative_rank_rank(Us, RankS.RANK_6));

                    // An en passant capture can be an evasion only if the checking piece
                    // is the double pushed pawn and so is in the target. Otherwise this
                    // is a discovery check and we are forced to do otherwise.
                    if (Type == GenTypeS.EVASIONS && (target & BitBoard.SquareBB[(pos.ep_square() - Up)]) == 0)
                    {
                        return(mPos);
                    }

                    b1 = pawnsNotOn7 & pos.attacks_from_pawn(pos.ep_square(), Them);

                    Debug.Assert(b1 != 0);

                    while (b1 != 0)
                    {
                        mlist[mPos++].move = Types.make(BitBoard.pop_lsb(ref b1), pos.ep_square(), MoveTypeS.ENPASSANT);
                    }
                }
            }

            return(mPos);
        }