/// 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)); }
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); }
/// 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)); }
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); }
/// 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); }
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); }