From 94bbcffa442cda0cd1d5f1e1a90bb54b1f84f483 Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Sun, 17 Nov 2019 15:10:37 +0100 Subject: [PATCH] Speed up move generation for xiangqi Filter out invalid soldier and general moves early. --- src/movegen.cpp | 13 +++++++++++++ src/position.cpp | 18 +++++++++--------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index 03ac9ff7c..e0b037724 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -260,6 +260,9 @@ namespace { Bitboard b1 = ( (pos.attacks_from(us, pt, from) & pos.pieces()) | (pos.moves_from(us, pt, from) & ~pos.pieces())) & target; + // Xiangqi soldier + if (pt == SOLDIER && pos.unpromoted_soldier(us, from)) + b1 &= file_bb(file_of(from)); Bitboard b2 = pos.promoted_piece_type(pt) ? b1 : Bitboard(0); Bitboard b3 = pos.piece_demotion() && pos.is_promoted(from) ? b1 : Bitboard(0); @@ -327,6 +330,8 @@ namespace { { Square ksq = pos.square(Us); Bitboard b = pos.attacks_from(ksq, Us) & target; + if (pos.xiangqi_general()) + b &= PseudoAttacks[Us][WAZIR][ksq]; while (b) moveList = make_move_and_gating(pos, moveList, Us, ksq, pop_lsb(&b)); @@ -429,7 +434,11 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { Bitboard b = pos.moves_from(us, pt, from) & ~pos.pieces(); if (pt == KING) + { b &= ~PseudoAttacks[~us][QUEEN][pos.square(~us)]; + if (pos.xiangqi_general()) + b &= PseudoAttacks[us][WAZIR][from]; + } while (b) moveList = make_move_and_gating(pos, moveList, us, from, pop_lsb(&b)); @@ -457,6 +466,8 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { { Bitboard target = pos.board_bb() & ~pos.pieces(us); Bitboard b = pos.attacks_from(ksq, us) & target; + if (pos.xiangqi_general()) + b &= PseudoAttacks[us][WAZIR][ksq]; while (b) moveList = make_move_and_gating(pos, moveList, us, ksq, pop_lsb(&b)); return us == WHITE ? generate_all(pos, moveList, target) @@ -474,6 +485,8 @@ ExtMove* generate(const Position& pos, ExtMove* moveList) { // Generate evasions for king, capture and non capture moves Bitboard b = pos.attacks_from(ksq, us) & ~pos.pieces(us) & ~sliderAttacks; + if (pos.xiangqi_general()) + b &= PseudoAttacks[us][WAZIR][ksq]; while (b) moveList = make_move_and_gating(pos, moveList, us, ksq, pop_lsb(&b)); diff --git a/src/position.cpp b/src/position.cpp index c007d0e38..92fde7a03 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -793,7 +793,7 @@ Bitboard Position::attackers_to(Square s, Bitboard occupied, Color c) const { b |= pieces(c, FERS) & gates(c) & fers_sq; } - if (var->xiangqiGeneral) + if (xiangqi_general()) b ^= b & pieces(KING) & ~PseudoAttacks[~c][WAZIR][s]; return b; @@ -928,14 +928,6 @@ bool Position::legal(Move m) const { return false; } - // Xiangqi general - if (var->xiangqiGeneral && type_of(moved_piece(m)) == KING && !(PseudoAttacks[us][WAZIR][from] & to)) - return false; - - // Xiangqi soldier - if (type_of(moved_piece(m)) == SOLDIER && unpromoted_soldier(us, from) && file_of(from) != file_of(to)) - return false; - // If the moving piece is a king, check whether the destination // square is attacked by the opponent. Castling moves are checked // for legality during move generation. @@ -974,6 +966,14 @@ bool Position::pseudo_legal(const Move m) const { if (type_of(m) != NORMAL || is_gating(m)) return MoveList(*this).contains(m); + // Xiangqi general + if (xiangqi_general() && type_of(pc) == KING && !(PseudoAttacks[us][WAZIR][from] & to)) + return false; + + // Xiangqi soldier + if (type_of(pc) == SOLDIER && unpromoted_soldier(us, from) && file_of(from) != file_of(to)) + return false; + // Handle the case where a mandatory piece promotion/demotion is not taken if ( mandatory_piece_promotion() && (is_promoted(from) ? piece_demotion() : promoted_piece_type(type_of(pc)) != NO_PIECE_TYPE)