Exemplo n.º 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));
        }
Exemplo n.º 2
0
        public static int generate_promotions(ExtMove[] mlist, int mPos, Bitboard pawnsOn7, Bitboard target, CheckInfo ci, GenType Type, Square Delta)
        {
            Bitboard b = BitBoard.shift_bb(pawnsOn7, Delta) & target;

            while (b != 0)
            {
                Square to = BitBoard.pop_lsb(ref b);

                if (Type == GenTypeS.CAPTURES || Type == GenTypeS.EVASIONS || Type == GenTypeS.NON_EVASIONS)
                {
                    mlist[mPos++].move = Types.make(to - Delta, to, MoveTypeS.PROMOTION, PieceTypeS.QUEEN);
                }

                if (Type == GenTypeS.QUIETS || Type == GenTypeS.EVASIONS || Type == GenTypeS.NON_EVASIONS)
                {
                    mlist[mPos++].move = Types.make(to - Delta, to, MoveTypeS.PROMOTION, PieceTypeS.ROOK);
                    mlist[mPos++].move = Types.make(to - Delta, to, MoveTypeS.PROMOTION, PieceTypeS.BISHOP);
                    mlist[mPos++].move = Types.make(to - Delta, to, MoveTypeS.PROMOTION, PieceTypeS.KNIGHT);
                }

                // Knight promotion is the only promotion that can give a direct check
                // that's not already included in the queen promotion.
                if (Type == GenTypeS.QUIET_CHECKS && (BitBoard.StepAttacksBB[PieceS.W_KNIGHT][to] & BitBoard.SquareBB[ci.ksq]) != 0)
                {
                    mlist[mPos++].move = Types.make(to - Delta, to, MoveTypeS.PROMOTION, PieceTypeS.KNIGHT);
                }
            }

            return(mPos);
        }
Exemplo n.º 3
0
        // polyglot_key() returns the PolyGlot hash key of the given position
        public static Key polyglot_key(Position pos)
        {
            Key      key = 0;
            Bitboard b   = pos.pieces();

            while (b != 0)
            {
                Square s  = BitBoard.pop_lsb(ref b);
                Piece  pc = pos.piece_on(s);
                // PolyGlot pieces are: BP = 0, WP = 1, BN = 2, ... BK = 10, WK = 11
                int pieceOfs = 2 * (Types.type_of_piece(pc) - 1) + ((Types.color_of(pc) == ColorS.WHITE) ? 1 : 0);
                key ^= PG[psq + (64 * pieceOfs + s)];
            }

            b = (ulong)pos.can_castle_castleright(CastlingRightS.ANY_CASTLING);

            while (b != 0)
            {
                key ^= PG[castle + BitBoard.pop_lsb(ref b)];
            }

            if (pos.ep_square() != SquareS.SQ_NONE)
            {
                key ^= PG[enpassant + Types.file_of(pos.ep_square())];
            }

            if (pos.side_to_move() == ColorS.WHITE)
            {
                key ^= PG[turn + 0];
            }

            return(key);
        }
Exemplo n.º 4
0
        public Result classify(KPKPosition[] db, Color Us)
        {
            // White to Move: If one move leads to a position classified as WIN, the result
            // of the current position is WIN. If all moves lead to positions classified
            // as DRAW, the current position is classified as DRAW, otherwise the current
            // position is classified as UNKNOWN.
            //
            // Black to Move: If one move leads to a position classified as DRAW, the result
            // of the current position is DRAW. If all moves lead to positions classified
            // as WIN, the position is classified as WIN, otherwise the current position is
            // classified as UNKNOWN.
            Color Them = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE);

            Result   r = Result.INVALID;
            Bitboard b = BitBoard.StepAttacksBB[PieceTypeS.KING][Us == ColorS.WHITE ? wksq : bksq];

            while (b != 0)
            {
                r |= (Us == ColorS.WHITE) ? db[Bitbases.index(Them, bksq, BitBoard.pop_lsb(ref b), psq)].result
                                         : db[Bitbases.index(Them, BitBoard.pop_lsb(ref b), wksq, psq)].result;
            }

            if (Us == ColorS.WHITE && Types.rank_of(psq) < RankS.RANK_7)
            {
                Square s = (psq + SquareS.DELTA_N);
                r |= db[Bitbases.index(ColorS.BLACK, bksq, wksq, s)].result; // Single push

                if (Types.rank_of(psq) == RankS.RANK_2 && s != wksq && s != bksq)
                {
                    r |= db[Bitbases.index(ColorS.BLACK, bksq, wksq, s + SquareS.DELTA_N)].result; // Double push
                }
            }

            if (Us == ColorS.WHITE)
            {
                return(result = (r & Result.WIN) != 0 ? Result.WIN : (r & Result.UNKNOWN) != 0 ? Result.UNKNOWN : Result.DRAW);
            }
            else
            {
                return(result = (r & Result.DRAW) != 0 ? Result.DRAW : (r & Result.UNKNOWN) != 0 ? Result.UNKNOWN : Result.WIN);
            }
        }
Exemplo n.º 5
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);
        }
Exemplo n.º 6
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));
        }
Exemplo n.º 7
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);
        }
Exemplo n.º 8
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);
        }
Exemplo n.º 9
0
        // evaluate_passed_pawns() evaluates the passed pawns of the given color
        public static Score evaluate_passed_pawns(Position pos, EvalInfo ei, Color Us, bool Trace)
        {
            Color Them = (Us == ColorS.WHITE ? ColorS.BLACK : ColorS.WHITE);

            Bitboard b, squaresToQueen, defendedSquares, unsafeSquares;
            Score    score = ScoreS.SCORE_ZERO;

            b = ei.pi.passed_pawns(Us);

            while (b != 0)
            {
                Square s = BitBoard.pop_lsb(ref b);

                Debug.Assert(pos.pawn_passed(Us, s));

                int r  = (int)(Types.relative_rank_square(Us, s) - RankS.RANK_2);
                int rr = r * (r - 1);

                // Base bonus based on rank
                Value mbonus = (17 * rr), ebonus = (7 * (rr + r + 1));

                if (rr != 0)
                {
                    Square blockSq = s + Types.pawn_push(Us);

                    // Adjust bonus based on kings proximity
                    ebonus += (BitBoard.square_distance(pos.king_square(Them), blockSq) * 5 * rr)
                              - (BitBoard.square_distance(pos.king_square(Us), blockSq) * 2 * rr);

                    // If blockSq is not the queening square then consider also a second push
                    if (Types.relative_rank_square(Us, blockSq) != RankS.RANK_8)
                    {
                        ebonus -= (BitBoard.square_distance(pos.king_square(Us), blockSq + Types.pawn_push(Us)) * rr);
                    }

                    // If the pawn is free to advance, increase bonus
                    if (pos.empty(blockSq))
                    {
                        squaresToQueen = BitBoard.forward_bb(Us, s);

                        // If there is an enemy rook or queen attacking the pawn from behind,
                        // add all X-ray attacks by the rook or queen. Otherwise consider only
                        // the squares in the pawn's path attacked or occupied by the enemy.
                        if ((BitBoard.forward_bb(Them, s) & pos.pieces_color_piecetype(Them, PieceTypeS.ROOK, PieceTypeS.QUEEN)) != 0 &&
                            (BitBoard.forward_bb(Them, s) & pos.pieces_color_piecetype(Them, PieceTypeS.ROOK, PieceTypeS.QUEEN) & pos.attacks_from_square_piecetype(s, PieceTypeS.ROOK)) != 0)
                        {
                            unsafeSquares = squaresToQueen;
                        }
                        else
                        {
                            unsafeSquares = squaresToQueen & (ei.attackedBy[Them][PieceTypeS.ALL_PIECES] | pos.pieces_color(Them));
                        }

                        if ((BitBoard.forward_bb(Them, s) & pos.pieces_color_piecetype(Us, PieceTypeS.ROOK, PieceTypeS.QUEEN)) != 0 &&
                            (BitBoard.forward_bb(Them, s) & pos.pieces_color_piecetype(Us, PieceTypeS.ROOK, PieceTypeS.QUEEN) & pos.attacks_from_square_piecetype(s, PieceTypeS.ROOK)) != 0)
                        {
                            defendedSquares = squaresToQueen;
                        }
                        else
                        {
                            defendedSquares = squaresToQueen & ei.attackedBy[Us][PieceTypeS.ALL_PIECES];
                        }

                        // If there aren't any enemy attacks, assign a big bonus. Otherwise
                        // assign a smaller bonus if the block square isn't attacked.
                        int k = 0 == unsafeSquares? 15 : 0 == (unsafeSquares & BitBoard.SquareBB[blockSq]) ? 9 : 0;


                        // If the path to queen is fully defended, assign a big bonus.
                        // Otherwise assign a smaller bonus if the block square is defended.
                        if (defendedSquares == squaresToQueen)
                        {
                            k += 6;
                        }

                        else if ((defendedSquares & BitBoard.SquareBB[blockSq]) != 0)
                        {
                            k += 4;
                        }

                        mbonus += (k * rr); ebonus += (k * rr);
                    }
                } // rr != 0

                if (pos.count(Us, PieceTypeS.PAWN) < pos.count(Them, PieceTypeS.PAWN))
                {
                    ebonus += ebonus / 4;
                }

                score += Types.make_score(mbonus, ebonus);
            }

            if (Trace)
            {
                Tracing.terms[Us][TermsS.PASSED] = apply_weight(score, Weights[EvalWeightS.PassedPawns]);
            }

            // Add the scores to the middle game and endgame eval
            return(Eval.apply_weight(score, Weights[EvalWeightS.PassedPawns]));
        }
Exemplo n.º 10
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);
        }