예제 #1
0
        /// generate<QUIET_CHECKS> generates all pseudo-legal non-captures and knight
        /// underpromotions that give check. Returns a pointer to the end of the move list.
        public static int generate_quiet_checks(Position pos, ExtMove[] mlist, int mPos)
        {
            Debug.Assert(0 == pos.checkers());

            Color     us = pos.side_to_move();
            CheckInfo ci = new CheckInfo(pos);
            Bitboard  dc = ci.dcCandidates;

            while (dc != 0)
            {
                Square    from = BitBoard.pop_lsb(ref dc);
                PieceType pt   = Types.type_of_piece(pos.piece_on(from));

                if (pt == PieceTypeS.PAWN)
                {
                    continue; // Will be generated togheter with direct checks
                }
                Bitboard b = pos.attacks_from_piece_square((Piece)pt, from) & ~pos.pieces();

                if (pt == PieceTypeS.KING)
                {
                    b &= ~BitBoard.PseudoAttacks[PieceTypeS.QUEEN][ci.ksq];
                }

                while (b != 0)
                {
                    mlist[mPos++].move = Types.make_move(from, BitBoard.pop_lsb(ref b));
                }
            }

            return(us == ColorS.WHITE ? generate_all(pos, mlist, mPos, ~pos.pieces(), ColorS.WHITE, GenTypeS.QUIET_CHECKS, ci) :
                   generate_all(pos, mlist, mPos, ~pos.pieces(), ColorS.BLACK, GenTypeS.QUIET_CHECKS, ci));
        }
예제 #2
0
        public static int generate_moves(Position pos, ExtMove[] mlist, int mPos, Color us, Bitboard target, CheckInfo ci, PieceType Pt, bool Checks)
        {
            Debug.Assert(Pt != PieceTypeS.KING && Pt != PieceTypeS.PAWN);

            Square[] pieceList = pos.list(us, Pt);
            int      pl        = 0;

            for (Square from = pieceList[pl]; from != SquareS.SQ_NONE; from = pieceList[++pl])
            {
                if (Checks)
                {
                    if ((Pt == PieceTypeS.BISHOP || Pt == PieceTypeS.ROOK || Pt == PieceTypeS.QUEEN) &&
                        0 == (BitBoard.PseudoAttacks[Pt][from] & target & ci.checkSq[Pt]))
                    {
                        continue;
                    }

                    if (ci.dcCandidates != 0 && (ci.dcCandidates & BitBoard.SquareBB[from]) != 0)
                    {
                        continue;
                    }
                }

                Bitboard b = pos.attacks_from_square_piecetype(from, Pt) & target;

                if (Checks)
                {
                    b &= ci.checkSq[Pt];
                }

                while (b != 0)
                {
                    mlist[mPos++].move = Types.make_move(from, BitBoard.pop_lsb(ref b));
                }
            }

            return(mPos);
        }
예제 #3
0
        /// generate<EVASIONS> generates all pseudo-legal check evasions when the side
        /// to move is in check. Returns a pointer to the end of the move list.
        public static int generate_evasions(Position pos, ExtMove[] mlist, int mPos)
        {
            Debug.Assert(pos.checkers() != 0);

            Color    us            = pos.side_to_move();
            Square   ksq           = pos.king_square(us);
            Bitboard sliderAttacks = 0;
            Bitboard sliders       = pos.checkers() & ~pos.pieces_piecetype(PieceTypeS.KNIGHT, PieceTypeS.PAWN);

            // Find all the squares attacked by slider checkers. We will remove them from
            // the king evasions in order to skip known illegal moves, which avoids any
            // useless legality checks later on.
            while (sliders != 0)
            {
                Square checksq = BitBoard.pop_lsb(ref sliders);
                sliderAttacks |= BitBoard.LineBB[checksq][ksq] ^ BitBoard.SquareBB[checksq];
            }

            // Generate evasions for king, capture and non capture moves
            Bitboard b = pos.attacks_from_square_piecetype(ksq, PieceTypeS.KING) & ~pos.pieces_color(us) & ~sliderAttacks;

            while (b != 0)
            {
                mlist[mPos++].move = Types.make_move(ksq, BitBoard.pop_lsb(ref b));
            }

            if (BitBoard.more_than_one(pos.checkers()))
            {
                return(mPos); // Double check, only a king move can save the day
            }
            // Generate blocking evasions or captures of the checking piece
            Square   checksq2 = BitBoard.lsb(pos.checkers());
            Bitboard target   = BitBoard.between_bb(checksq2, ksq) | BitBoard.SquareBB[checksq2];

            return(us == ColorS.WHITE ? generate_all(pos, mlist, mPos, target, ColorS.WHITE, GenTypeS.EVASIONS) :
                   generate_all(pos, mlist, mPos, target, ColorS.BLACK, GenTypeS.EVASIONS));
        }
예제 #4
0
        public static int generate_all(Position pos, ExtMove[] mlist, int mPos, Bitboard target, Color us, GenType Type, CheckInfo ci = null)
        {
            bool Checks = Type == GenTypeS.QUIET_CHECKS;

            mPos = generate_pawn_moves(pos, mlist, mPos, target, ci, us, Type);
            mPos = generate_moves(pos, mlist, mPos, us, target, ci, PieceTypeS.KNIGHT, Checks);
            mPos = generate_moves(pos, mlist, mPos, us, target, ci, PieceTypeS.BISHOP, Checks);
            mPos = generate_moves(pos, mlist, mPos, us, target, ci, PieceTypeS.ROOK, Checks);
            mPos = generate_moves(pos, mlist, mPos, us, target, ci, PieceTypeS.QUEEN, Checks);

            if (Type != GenTypeS.QUIET_CHECKS && Type != GenTypeS.EVASIONS)
            {
                Square   ksq = pos.king_square(us);
                Bitboard b   = pos.attacks_from_square_piecetype(ksq, PieceTypeS.KING) & target;
                while (b != 0)
                {
                    mlist[mPos++].move = Types.make_move(ksq, BitBoard.pop_lsb(ref b));
                }
            }

            if (Type != GenTypeS.CAPTURES && Type != GenTypeS.EVASIONS && pos.can_castle_color(us) != 0)
            {
                if (pos.is_chess960() != 0)
                {
                    mPos = generate_castling(pos, mlist, mPos, us, ci, (new MakeCastlingS(us, CastlingSideS.KING_SIDE)).right, Checks, true);
                    mPos = generate_castling(pos, mlist, mPos, us, ci, (new MakeCastlingS(us, CastlingSideS.QUEEN_SIDE)).right, Checks, true);
                }
                else
                {
                    mPos = generate_castling(pos, mlist, mPos, us, ci, (new MakeCastlingS(us, CastlingSideS.KING_SIDE)).right, Checks, false);
                    mPos = generate_castling(pos, mlist, mPos, us, ci, (new MakeCastlingS(us, CastlingSideS.QUEEN_SIDE)).right, Checks, false);
                }
            }

            return(mPos);
        }
예제 #5
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);
        }
예제 #6
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);
        }