return true;
}
-inline bool is_check(const Position& pos) {
- return pos.checkers()
- || (pos.extinction_pseudo_royal() && pos.attackers_to_pseudo_royals(~pos.side_to_move()));
+inline Bitboard checked(const Position& pos) {
+ return (pos.checkers() ? square_bb(pos.square<KING>(pos.side_to_move())) : Bitboard(0))
+ | (pos.extinction_pseudo_royal() ? pos.checked_pseudo_royals(pos.side_to_move()) : Bitboard(0));
}
namespace FEN {
return "0-1";
}
+ std::string checked_pieces() const {
+ Bitboard checked = Stockfish::checked(pos);
+ std::string squares;
+ while (checked) {
+ Square sr = pop_lsb(checked);
+ squares += UCI::square(pos, sr);
+ squares += DELIM;
+ }
+ save_pop_back(squares);
+ return squares;
+ }
+
bool is_check() const {
- return Stockfish::is_check(pos);
+ return Stockfish::checked(pos);
}
bool is_bikjang() const {
.function("isGameOver", select_overload<bool(bool) const>(&Board::is_game_over))
.function("result", select_overload<std::string() const>(&Board::result))
.function("result", select_overload<std::string(bool) const>(&Board::result))
+ .function("checkedPieces", &Board::checked_pieces)
.function("isCheck", &Board::is_check)
.function("isBikjang", &Board::is_bikjang)
.function("isCapture", &Board::is_capture)
return attackers_to(s, occupied, WHITE) | attackers_to(s, occupied, BLACK);
}
-/// Position::attackers_to_pseudo_royals computes a bitboard of all pieces
-/// of a particular color attacking at least one opposing pseudo-royal piece
-Bitboard Position::attackers_to_pseudo_royals(Color c) const {
+/// Position::checked_pseudo_royals computes a bitboard of
+/// all pseudo-royal pieces of a particular color that are in check
+Bitboard Position::checked_pseudo_royals(Color c) const {
assert(extinction_pseudo_royal());
- Bitboard attackers = 0;
- Bitboard pseudoRoyals = st->pseudoRoyals & pieces(~c);
- Bitboard pseudoRoyalsTheirs = st->pseudoRoyals & pieces(c);
+ Bitboard checked = 0;
+ Bitboard pseudoRoyals = st->pseudoRoyals & pieces(c);
+ Bitboard pseudoRoyalsTheirs = st->pseudoRoyals & pieces(~c);
while (pseudoRoyals)
{
Square sr = pop_lsb(pseudoRoyals);
- if ( blast_on_capture()
- && pseudoRoyalsTheirs & attacks_bb<KING>(sr))
- // skip if capturing this piece would blast all of the attacker's pseudo-royal pieces
- continue;
- attackers |= attackers_to(sr, c);
+ // skip if capturing this piece would blast any of the attacker's pseudo-royal pieces
+ if (!(blast_on_capture() && (pseudoRoyalsTheirs & attacks_bb<KING>(sr)))
+ && attackers_to(sr, ~c))
+ checked |= sr;
}
// Look for duple check
if (var->dupleCheck)
{
- Bitboard b;
- Bitboard allAttackers = 0;
- Bitboard pseudoRoyalCandidates = st->pseudoRoyalCandidates & pieces(~c);
+ Bitboard allAttacked = 0;
+ Bitboard pseudoRoyalCandidates = st->pseudoRoyalCandidates & pieces(c);
while (pseudoRoyalCandidates)
{
Square sr = pop_lsb(pseudoRoyalCandidates);
if (!(blast_on_capture() && (pseudoRoyalsTheirs & attacks_bb<KING>(sr)))
- && (b = attackers_to(sr, c)))
- allAttackers |= b;
+ && attackers_to(sr, ~c))
+ allAttacked |= sr;
else
// If at least one isn't attacked, it is not a duple check
- return attackers;
+ return checked;
}
- attackers |= allAttackers;
+ checked |= allAttacked;
}
- return attackers;
+ return checked;
}
Bitboard blockers_for_king(Color c) const;
Bitboard check_squares(PieceType pt) const;
Bitboard pinners(Color c) const;
- Bitboard attackers_to_pseudo_royals(Color c) const;
+ Bitboard checked_pseudo_royals(Color c) const;
// Attacks to/from a given square
Bitboard attackers_to(Square s) const;
StateListPtr states(new std::deque<StateInfo>(1));
buildPosition(pos, states, variant, fen, moveList, chess960);
- return Py_BuildValue("O", Stockfish::is_check(pos) ? Py_True : Py_False);
+ return Py_BuildValue("O", Stockfish::checked(pos) ? Py_True : Py_False);
}
// INPUT variant, fen, move list, move
isInsufficientMaterial(): boolean;
isGameOver(claimDraw?: boolean): boolean;
result(claimDraw?: boolean): string;
+ checkedPieces(): string;
isCheck(): boolean;
isBikjang(): boolean;
isCapture(uciMove: string): boolean;
})
})
+describe('board.checkedPieces()', function () {
+ it("it returns the squares of all checked royal pieces in a concatenated string", () => {
+ let board = new ffish.Board();
+ chai.expect(board.checkedPieces()).to.equal("");
+ board.setFen("rnbqkb1r/pppp1Bpp/5n2/4p3/4P3/8/PPPP1PPP/RNBQK1NR b KQkq - 0 3");
+ chai.expect(board.checkedPieces()).to.equal("e8");
+ board.setFen("r1bqkb1r/pppp1ppp/2n2n2/4p2Q/2B1P3/8/PPPP1PPP/RNB1K1NR w KQkq - 4 4");
+ board.pushSan("Qxf7#");
+ chai.expect(board.checkedPieces()).to.equal("e8");
+ board.delete();
+
+ board = new ffish.Board("atomic");
+ chai.expect(board.checkedPieces()).to.equal("");
+ board.setFen("rnbqkbnr/ppp1pppp/8/1B1p4/4P3/8/PPPP1PPP/RNBQK1NR b KQkq - 3 2");
+ chai.expect(board.checkedPieces()).to.equal("e8");
+ board.setFen("rnbqkbnr/ppp2ppp/8/8/8/8/PPP2PPP/RNBQKBNR w KQkq - 0 4");
+ board.pushSan("Qd7");
+ chai.expect(board.checkedPieces()).to.equal("e8");
+ board.setFen("8/8/kK6/8/8/8/Q7/8 b - - 0 1")
+ chai.expect(board.checkedPieces()).to.equal("");
+ board.delete();
+
+ board = new ffish.Board("spartan");
+ chai.expect(board.checkedPieces()).to.equal("");
+ board.setFen("lgkcckw1/hhhhhhhh/1N3lN1/8/8/8/PPPPPPPP/R1BQKB1R b KQ - 11 6");
+ chai.expect(board.checkedPieces().split(' ').sort().join()).to.equal("c8,f8");
+ chai.expect(board.isCheck()).to.equal(true);
+ board.setFen("lgkcckwl/hhhhhhhh/6N1/8/8/8/PPPPPPPP/RNBQKB1R b KQ - 5 3")
+ chai.expect(board.checkedPieces()).to.equal("");
+ board.delete();
+
+ board = new ffish.Board("shako");
+ board.setFen("10/5r4/2p3pBk1/1p6Pr/p3p5/9e/1PP2P4/P2P2PP2/ER3K2R1/8C1 w K - 7 38")
+ board.pushMoves("f2h2");
+ chai.expect(board.checkedPieces()).to.equal("i8");
+ board.delete();
+
+ board = new ffish.Board("janggi");
+ board.setFen("4ka3/4a4/9/4R4/2B6/9/9/5K3/4p4/3r5 b - - 0 113")
+ board.pushMoves("e2f2");
+ chai.expect(board.checkedPieces()).to.equal("f3");
+ board.delete();
+ })
+})
+
describe('board.isCheck()', function () {
it("it checks if a player is in check", () => {
let board = new ffish.Board();
board.setFen("8/8/kK6/8/8/8/Q7/8 b - - 0 1")
chai.expect(board.isCheck()).to.equal(false);
board.delete();
- });
-});
+
+ board = new ffish.Board("spartan");
+ board.setFen("lgkcckw1/hhhhhhhh/1N3lN1/8/8/8/PPPPPPPP/R1BQKB1R b KQ - 11 6");
+ chai.expect(board.isCheck()).to.equal(true);
+ board.setFen("lgkcckwl/hhhhhhhh/6N1/8/8/8/PPPPPPPP/RNBQKB1R b KQ - 5 3")
+ chai.expect(board.isCheck()).to.equal(false);
+ board.setFen("lgkcckwl/hhhhhhhh/8/8/8/8/PPPPPPPP/RNBQKBNR w KQ - 0 1")
+ chai.expect(board.isCheck()).to.equal(false);
+ board.delete();
+
+ board = new ffish.Board("shako");
+ board.setFen("10/5r4/2p3pBk1/1p6Pr/p3p5/9e/1PP2P4/P2P2PP2/ER3K2R1/8C1 w K - 7 38")
+ board.pushMoves("f2h2");
+ chai.expect(board.isCheck()).to.equal(true);
+ board.delete();
+
+ board = new ffish.Board("janggi");
+ board.setFen("4ka3/4a4/9/4R4/2B6/9/9/5K3/4p4/3r5 b - - 0 113")
+ board.pushMoves("e2f2");
+ chai.expect(board.isCheck()).to.equal(true);
+ board.delete();
+ })
+})
describe('board.isBikjang()', function () {
it("it checks if a player is in bikjang (only relevant for janggi)", () => {