No functional change.
void Bitboards::init() {
+ // Piece moves
+ std::vector<Direction> RookDirectionsV = { NORTH, SOUTH};
+ std::vector<Direction> RookDirectionsH = { EAST, WEST };
+ std::vector<Direction> BishopDirections = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
+ std::vector<Direction> HorseDirections = {2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
+ NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST };
+ std::vector<Direction> ElephantDirections = { 2 * NORTH_EAST, 2 * SOUTH_EAST, 2 * SOUTH_WEST, 2 * NORTH_WEST };
+ std::vector<Direction> JanggiElephantDirections = { NORTH + 2 * NORTH_EAST, EAST + 2 * NORTH_EAST,
+ EAST + 2 * SOUTH_EAST, SOUTH + 2 * SOUTH_EAST,
+ SOUTH + 2 * SOUTH_WEST, WEST + 2 * SOUTH_WEST,
+ WEST + 2 * NORTH_WEST, NORTH + 2 * NORTH_WEST };
+
+ // Initialize rider types
+ for (PieceType pt = PAWN; pt <= KING; ++pt)
+ {
+ const PieceInfo* pi = pieceMap.find(pt)->second;
+
+ if (pi->lameLeaper)
+ {
+ for (Direction d : pi->stepsCapture)
+ {
+ if (std::find(HorseDirections.begin(), HorseDirections.end(), d) != HorseDirections.end())
+ AttackRiderTypes[pt] |= RIDER_HORSE;
+ if (std::find(ElephantDirections.begin(), ElephantDirections.end(), d) != ElephantDirections.end())
+ AttackRiderTypes[pt] |= RIDER_ELEPHANT;
+ if (std::find(JanggiElephantDirections.begin(), JanggiElephantDirections.end(), d) != JanggiElephantDirections.end())
+ AttackRiderTypes[pt] |= RIDER_JANGGI_ELEPHANT;
+ }
+ for (Direction d : pi->stepsQuiet)
+ {
+ if (std::find(HorseDirections.begin(), HorseDirections.end(), d) != HorseDirections.end())
+ MoveRiderTypes[pt] |= RIDER_HORSE;
+ if (std::find(ElephantDirections.begin(), ElephantDirections.end(), d) != ElephantDirections.end())
+ MoveRiderTypes[pt] |= RIDER_ELEPHANT;
+ if (std::find(JanggiElephantDirections.begin(), JanggiElephantDirections.end(), d) != JanggiElephantDirections.end())
+ MoveRiderTypes[pt] |= RIDER_JANGGI_ELEPHANT;
+ }
+ }
+ for (Direction d : pi->sliderCapture)
+ {
+ if (std::find(BishopDirections.begin(), BishopDirections.end(), d) != BishopDirections.end())
+ AttackRiderTypes[pt] |= RIDER_BISHOP;
+ if (std::find(RookDirectionsH.begin(), RookDirectionsH.end(), d) != RookDirectionsH.end())
+ AttackRiderTypes[pt] |= RIDER_ROOK_H;
+ if (std::find(RookDirectionsV.begin(), RookDirectionsV.end(), d) != RookDirectionsV.end())
+ AttackRiderTypes[pt] |= RIDER_ROOK_V;
+ }
+ for (Direction d : pi->sliderQuiet)
+ {
+ if (std::find(BishopDirections.begin(), BishopDirections.end(), d) != BishopDirections.end())
+ MoveRiderTypes[pt] |= RIDER_BISHOP;
+ if (std::find(RookDirectionsH.begin(), RookDirectionsH.end(), d) != RookDirectionsH.end())
+ MoveRiderTypes[pt] |= RIDER_ROOK_H;
+ if (std::find(RookDirectionsV.begin(), RookDirectionsV.end(), d) != RookDirectionsV.end())
+ MoveRiderTypes[pt] |= RIDER_ROOK_V;
+ }
+ for (Direction d : pi->hopperCapture)
+ {
+ if (std::find(RookDirectionsH.begin(), RookDirectionsH.end(), d) != RookDirectionsH.end())
+ AttackRiderTypes[pt] |= RIDER_CANNON_H;
+ if (std::find(RookDirectionsV.begin(), RookDirectionsV.end(), d) != RookDirectionsV.end())
+ AttackRiderTypes[pt] |= RIDER_CANNON_V;
+ }
+ for (Direction d : pi->hopperQuiet)
+ {
+ if (std::find(RookDirectionsH.begin(), RookDirectionsH.end(), d) != RookDirectionsH.end())
+ MoveRiderTypes[pt] |= RIDER_CANNON_H;
+ if (std::find(RookDirectionsV.begin(), RookDirectionsV.end(), d) != RookDirectionsV.end())
+ MoveRiderTypes[pt] |= RIDER_CANNON_V;
+ }
+ }
+
for (unsigned i = 0; i < (1 << 16); ++i)
- PopCnt16[i] = std::bitset<16>(i).count();
+ PopCnt16[i] = uint8_t(std::bitset<16>(i).count());
- for (Square s = SQ_A1; s <= SQ_H8; ++s)
- SquareBB[s] = (1ULL << s);
-
- for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
- for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
- SquareDistance[s1][s2] = std::max(distance<File>(s1, s2), distance<Rank>(s1, s2));
-
- Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST };
- Direction BishopDirections[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
-
- init_magics(RookTable, RookMagics, RookDirections);
- init_magics(BishopTable, BishopMagics, BishopDirections);
-
- for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
+ for (Square s = SQ_A1; s <= SQ_MAX; ++s)
+ SquareBB[s] = make_bitboard(s);
+
+ for (File f = FILE_A; f <= FILE_MAX; ++f)
+ for (Rank r = RANK_1; r <= RANK_MAX; ++r)
+ BoardSizeBB[f][r] = forward_file_bb(BLACK, make_square(f, r)) | SquareBB[make_square(f, r)] | (f > FILE_A ? BoardSizeBB[f - 1][r] : Bitboard(0));
+
+ for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1)
+ for (Square s2 = SQ_A1; s2 <= SQ_MAX; ++s2)
+ SquareDistance[s1][s2] = std::max(distance<File>(s1, s2), distance<Rank>(s1, s2));
+
+#ifdef PRECOMPUTED_MAGICS
+ init_magics<RIDER>(RookTableH, RookMagicsH, RookDirectionsH, RookMagicHInit);
+ init_magics<RIDER>(RookTableV, RookMagicsV, RookDirectionsV, RookMagicVInit);
+ init_magics<RIDER>(BishopTable, BishopMagics, BishopDirections, BishopMagicInit);
+ init_magics<HOPPER>(CannonTableH, CannonMagicsH, RookDirectionsH, CannonMagicHInit);
+ init_magics<HOPPER>(CannonTableV, CannonMagicsV, RookDirectionsV, CannonMagicVInit);
+ init_magics<LAME_LEAPER>(HorseTable, HorseMagics, HorseDirections, HorseMagicInit);
+ init_magics<LAME_LEAPER>(ElephantTable, ElephantMagics, ElephantDirections, ElephantMagicInit);
+ init_magics<LAME_LEAPER>(JanggiElephantTable, JanggiElephantMagics, JanggiElephantDirections, JanggiElephantMagicInit);
+#else
+ init_magics<RIDER>(RookTableH, RookMagicsH, RookDirectionsH);
+ init_magics<RIDER>(RookTableV, RookMagicsV, RookDirectionsV);
+ init_magics<RIDER>(BishopTable, BishopMagics, BishopDirections);
+ init_magics<HOPPER>(CannonTableH, CannonMagicsH, RookDirectionsH);
+ init_magics<HOPPER>(CannonTableV, CannonMagicsV, RookDirectionsV);
+ init_magics<LAME_LEAPER>(HorseTable, HorseMagics, HorseDirections);
+ init_magics<LAME_LEAPER>(ElephantTable, ElephantMagics, ElephantDirections);
+ init_magics<LAME_LEAPER>(JanggiElephantTable, JanggiElephantMagics, JanggiElephantDirections);
+#endif
+
+ for (Color c : { WHITE, BLACK })
+ for (PieceType pt = PAWN; pt <= KING; ++pt)
+ {
+ const PieceInfo* pi = pieceMap.find(pt)->second;
+
+ for (Square s = SQ_A1; s <= SQ_MAX; ++s)
+ {
+ for (Direction d : pi->stepsCapture)
+ {
+ PseudoAttacks[c][pt][s] |= safe_destination(s, c == WHITE ? d : -d);
+ if (!pi->lameLeaper)
+ LeaperAttacks[c][pt][s] |= safe_destination(s, c == WHITE ? d : -d);
+ }
+ for (Direction d : pi->stepsQuiet)
+ {
+ PseudoMoves[c][pt][s] |= safe_destination(s, c == WHITE ? d : -d);
+ if (!pi->lameLeaper)
+ LeaperMoves[c][pt][s] |= safe_destination(s, c == WHITE ? d : -d);
+ }
+ PseudoAttacks[c][pt][s] |= sliding_attack<RIDER>(pi->sliderCapture, s, 0, c);
+ PseudoAttacks[c][pt][s] |= sliding_attack<RIDER>(pi->hopperCapture, s, 0, c);
+ PseudoMoves[c][pt][s] |= sliding_attack<RIDER>(pi->sliderQuiet, s, 0, c);
+ PseudoMoves[c][pt][s] |= sliding_attack<RIDER>(pi->hopperQuiet, s, 0, c);
+ }
+ }
+
+ for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1)
{
- PawnAttacks[WHITE][s1] = pawn_attacks_bb<WHITE>(square_bb(s1));
- PawnAttacks[BLACK][s1] = pawn_attacks_bb<BLACK>(square_bb(s1));
-
- for (int step : {-9, -8, -7, -1, 1, 7, 8, 9} )
- PseudoAttacks[KING][s1] |= safe_destination(s1, step);
-
- for (int step : {-17, -15, -10, -6, 6, 10, 15, 17} )
- PseudoAttacks[KNIGHT][s1] |= safe_destination(s1, step);
-
- PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb<BISHOP>(s1, 0);
- PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ ROOK][s1] = attacks_bb< ROOK>(s1, 0);
-
for (PieceType pt : { BISHOP, ROOK })
- for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
- if (PseudoAttacks[pt][s1] & s2)
- LineBB[s1][s2] = (attacks_bb(pt, s1, 0) & attacks_bb(pt, s2, 0)) | s1 | s2;
+ for (Square s2 = SQ_A1; s2 <= SQ_MAX; ++s2)
+ if (PseudoAttacks[WHITE][pt][s1] & s2)
+ LineBB[s1][s2] = (attacks_bb(WHITE, pt, s1, 0) & attacks_bb(WHITE, pt, s2, 0)) | s1 | s2;
}
}
template<Color Us, GenType Type>
- ExtMove* generate_all(const Position& pos, ExtMove* moveList, Bitboard target) {
+ ExtMove* generate_all(const Position& pos, ExtMove* moveList) {
constexpr bool Checks = Type == QUIET_CHECKS; // Reduce template instantations
+ Bitboard target;
+
+ switch (Type)
+ {
+ case CAPTURES:
+ target = pos.pieces(~Us);
+ break;
+ case QUIETS:
+ case QUIET_CHECKS:
+ target = ~pos.pieces();
+ break;
+ case EVASIONS:
+ {
++ if (pos.checkers() & (pos.pieces(CANNON, BANNER) | pos.pieces(HORSE, ELEPHANT) | pos.pieces(JANGGI_CANNON, JANGGI_ELEPHANT)))
++ {
++ target = ~pos.pieces(Us);
++ break;
++ }
+ Square checksq = lsb(pos.checkers());
+ target = between_bb(pos.square<KING>(Us), checksq) | checksq;
++ // Leaper attacks can not be blocked
++ if (LeaperAttacks[~Us][type_of(pos.piece_on(checksq))][checksq] & pos.square<KING>(Us))
++ target = square_bb(checksq);
+ break;
+ }
+ case NON_EVASIONS:
+ target = ~pos.pieces(Us);
+ break;
+ default:
+ static_assert(true, "Unsupported type in generate_all()");
+ }
++ target &= pos.board_bb();
moveList = generate_pawn_moves<Us, Type>(pos, moveList, target);
- moveList = generate_moves<KNIGHT, Checks>(pos, moveList, Us, target);
- moveList = generate_moves<BISHOP, Checks>(pos, moveList, Us, target);
- moveList = generate_moves< ROOK, Checks>(pos, moveList, Us, target);
- moveList = generate_moves< QUEEN, Checks>(pos, moveList, Us, target);
-
- if (Type != QUIET_CHECKS && Type != EVASIONS)
+ for (PieceType pt : pos.piece_types())
+ if (pt != PAWN && pt != KING)
+ moveList = generate_moves<Checks>(pos, moveList, Us, pt, target);
+ // generate drops
+ if (pos.piece_drops() && Type != CAPTURES && pos.count_in_hand(Us, ALL_PIECES))
+ for (PieceType pt : pos.piece_types())
+ moveList = generate_drops<Us, Checks>(pos, moveList, pt, target & ~pos.pieces(~Us));
+
+ if (Type != QUIET_CHECKS && Type != EVASIONS && pos.count<KING>(Us))
{
Square ksq = pos.square<KING>(Us);
- Bitboard b = pos.attacks_from<KING>(ksq) & target;
+ Bitboard b = ( (pos.attacks_from(Us, KING, ksq) & pos.pieces())
+ | (pos.moves_from(Us, KING, ksq) & ~pos.pieces())) & target;
while (b)
- *moveList++ = make_move(ksq, pop_lsb(&b));
+ moveList = make_move_and_gating<NORMAL>(pos, moveList, Us, ksq, pop_lsb(&b));
+
+ // Passing move by king
+ if (pos.pass())
+ *moveList++ = make<SPECIAL>(ksq, ksq);
if ((Type != CAPTURES) && pos.can_castle(Us & ANY_CASTLING))
for(CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } )
Square from = pop_lsb(&dc);
PieceType pt = type_of(pos.piece_on(from));
- Bitboard b = pos.attacks_from(pt, from) & ~pos.pieces();
+ Bitboard b = pos.moves_from(us, pt, from) & ~pos.pieces();
- if (pt == KING)
- b &= ~PseudoAttacks[QUEEN][pos.square<KING>(~us)];
+ if (pt == KING && pos.king_type() == KING)
+ b &= ~PseudoAttacks[~us][QUEEN][pos.square<KING>(~us)];
while (b)
- *moveList++ = make_move(from, pop_lsb(&b));
+ moveList = make_move_and_gating<NORMAL>(pos, moveList, us, from, pop_lsb(&b));
}
- return us == WHITE ? generate_all<WHITE, QUIET_CHECKS>(pos, moveList, ~pos.pieces() & pos.board_bb())
- : generate_all<BLACK, QUIET_CHECKS>(pos, moveList, ~pos.pieces() & pos.board_bb());
+ return us == WHITE ? generate_all<WHITE, QUIET_CHECKS>(pos, moveList)
+ : generate_all<BLACK, QUIET_CHECKS>(pos, moveList);
}
Color us = pos.side_to_move();
Square ksq = pos.square<KING>(us);
Bitboard sliderAttacks = 0;
- Bitboard sliders = pos.checkers() & ~pos.pieces(KNIGHT, PAWN);
+ Bitboard sliders = pos.checkers();
+
+ // Passing move by king in bikjang
+ if (pos.bikjang() && pos.pass())
+ *moveList++ = make<SPECIAL>(ksq, ksq);
+
+ // Consider all evasion moves for special pieces
+ if (sliders & (pos.pieces(CANNON, BANNER) | pos.pieces(HORSE, ELEPHANT) | pos.pieces(JANGGI_CANNON, JANGGI_ELEPHANT)))
+ {
+ Bitboard target = pos.board_bb() & ~pos.pieces(us);
+ Bitboard b = ( (pos.attacks_from(us, KING, ksq) & pos.pieces())
+ | (pos.moves_from(us, KING, ksq) & ~pos.pieces())) & target;
+ while (b)
+ moveList = make_move_and_gating<NORMAL>(pos, moveList, us, ksq, pop_lsb(&b));
- return us == WHITE ? generate_all<WHITE, EVASIONS>(pos, moveList, target)
- : generate_all<BLACK, EVASIONS>(pos, moveList, target);
++ return us == WHITE ? generate_all<WHITE, EVASIONS>(pos, moveList)
++ : generate_all<BLACK, EVASIONS>(pos, moveList);
+ }
// 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
// Flag the pawn
opposed = theirPawns & forward_file_bb(Us, s);
- blocked = theirPawns & (s + Up);
+ blocked = is_ok(s + Up) ? theirPawns & (s + Up) : Bitboard(0);
stoppers = theirPawns & passed_pawn_span(Us, s);
- lever = theirPawns & PawnAttacks[Us][s];
- leverPush = theirPawns & PawnAttacks[Us][s + Up];
- doubled = ourPawns & (s - Up);
+ lever = theirPawns & PseudoAttacks[Us][PAWN][s];
+ leverPush = relative_rank(Them, s, pos.max_rank()) > RANK_1 ? theirPawns & PseudoAttacks[Us][PAWN][s + Up] : Bitboard(0);
+ doubled = r > RANK_1 ? ourPawns & (s - Up) : Bitboard(0);
neighbours = ourPawns & adjacent_files_bb(s);
phalanx = neighbours & rank_bb(s);
- support = neighbours & rank_bb(s - Up);
+ support = r > RANK_1 ? neighbours & rank_bb(s - Up) : Bitboard(0);
- e->blockedCount += blocked || more_than_one(leverPush);
-
// A pawn is backward when it is behind all pawns of the same color on
// the adjacent files and cannot safely advance.
- backward = !(neighbours & forward_ranks_bb(Them, s + Up))
- && (leverPush | blocked);
+ backward = is_ok(s + Up)
+ && !(neighbours & forward_ranks_bb(Them, s + Up))
+ && (stoppers & blocked);
// Compute additional span if pawn is not backward nor blocked
if (!backward && !blocked)
for (File f = File(center - 1); f <= File(center + 1); ++f)
{
b = ourPawns & file_bb(f);
- int ourRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0;
+ int ourRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : 0;
b = theirPawns & file_bb(f);
- int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : 0;
+ int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : 0;
- File d = std::min(File(edge_distance(f, pos.max_file())), FILE_D);
- int d = edge_distance(f);
- bonus += make_score(ShelterStrength[d][ourRank], 0);
++ int d = std::min(File(edge_distance(f, pos.max_file())), FILE_D);
+ bonus += make_score(ShelterStrength[d][ourRank], 0) * (1 + (pos.captures_to_hand() && ourRank <= RANK_2)
+ + (pos.check_counting() && d == 0 && ourRank == RANK_2));
if (ourRank && (ourRank == theirRank - 1))
bonus -= BlockedStorm * int(theirRank == RANK_3);
return thisThread;
}
-inline void Position::put_piece(Piece pc, Square s) {
+inline void Position::put_piece(Piece pc, Square s, bool isPromoted, Piece unpromotedPc) {
board[s] = pc;
- byTypeBB[ALL_PIECES] |= s;
- byTypeBB[type_of(pc)] |= s;
+ byTypeBB[ALL_PIECES] |= byTypeBB[type_of(pc)] |= s;
byColorBB[color_of(pc)] |= s;
index[s] = pieceCount[pc]++;
pieceList[pc][index[s]] = s;
if (Limits.npmsec)
Time.availableNodes += Limits.inc[us] - Threads.nodes_searched();
- Thread* bestThread = this;
+ bestThread = this;
// Check if there are threads with a better score than main thread
- if ( Options["MultiPV"] == 1
+ if ( int(Options["MultiPV"]) == 1
&& !Limits.depth
- && !(Skill(Options["Skill Level"]).enabled() || Options["UCI_LimitStrength"])
+ && !(Skill(Options["Skill Level"]).enabled() || int(Options["UCI_LimitStrength"]))
&& rootMoves[0].pv[0] != MOVE_NONE)
{
std::map<Move, int64_t> votes;
// 1) x basetime (+z increment)
// 2) x moves in y seconds (+z increment)
-void TimeManagement::init(Search::LimitsType& limits, Color us, int ply) {
+void TimeManagement::init(const Position& pos, Search::LimitsType& limits, Color us, int ply) {
- TimePoint minThinkingTime = Options["Minimum Thinking Time"];
- TimePoint moveOverhead = Options["Move Overhead"];
- TimePoint slowMover = Options["Slow Mover"];
- TimePoint npmsec = Options["nodestime"];
+ TimePoint minThinkingTime = TimePoint(Options["Minimum Thinking Time"]);
+ TimePoint moveOverhead = TimePoint(Options["Move Overhead"]);
+ TimePoint slowMover = TimePoint(Options["Slow Mover"]);
+ TimePoint npmsec = TimePoint(Options["nodestime"]);
// opt_scale is a percentage of available time to use for the current move.
// max_scale is a multiplier applied to optimumTime.
UCI::OptionsMap Options; // Global object
+namespace PSQT {
+ void init(const Variant* v);
+}
+
namespace UCI {
+// standard variants of XBoard/WinBoard
+std::set<string> standard_variants = {
+ "normal", "nocastle", "fischerandom", "knightmate", "3check", "makruk", "shatranj",
+ "asean", "seirawan", "crazyhouse", "bughouse", "suicide", "giveaway", "losers",
+ "capablanca", "gothic", "janus", "caparandom", "grand", "shogi", "xiangqi"
+};
+
/// 'On change' actions, triggered by an option's value change
void on_clear_hash(const Option&) { Search::clear(); }
- void on_hash_size(const Option& o) { TT.resize(o); }
+ void on_hash_size(const Option& o) { TT.resize(size_t(o)); }
void on_logger(const Option& o) { start_logger(o); }
- void on_threads(const Option& o) { Threads.set(o); }
+ void on_threads(const Option& o) { Threads.set(size_t(o)); }
void on_tb_path(const Option& o) { Tablebases::init(o); }
+void on_variant_path(const Option& o) { variants.parse<false>(o); Options["UCI_Variant"].set_combo(variants.get_keys()); }
+void on_variant_change(const Option &o) {
+ const Variant* v = variants.find(o)->second;
+ PSQT::init(v);
+ // Do not send setup command for known variants
+ if (standard_variants.find(o) != standard_variants.end())
+ return;
+ int pocketsize = v->pieceDrops ? (v->pocketSize ? v->pocketSize : v->pieceTypes.size()) : 0;
+ if (Options["Protocol"] == "xboard")
+ {
+ // Send setup command
+ sync_cout << "setup (" << v->pieceToCharTable << ") "
+ << v->maxFile + 1 << "x" << v->maxRank + 1
+ << "+" << pocketsize << "_" << v->variantTemplate
+ << " " << v->startFen
+ << sync_endl;
+ // Send piece command with Betza notation
+ // https://www.gnu.org/software/xboard/Betza.html
+ for (PieceType pt : v->pieceTypes)
+ {
+ string suffix = pt == PAWN && v->doubleStep ? "ifmnD"
+ : pt == KING && v->cambodianMoves ? "ismN"
+ : pt == FERS && v->cambodianMoves ? "ifD"
+ : "";
+ // Janggi palace moves
+ if (v->diagonalLines)
+ {
+ PieceType pt2 = pt == KING ? v->kingType : pt;
+ if (pt2 == WAZIR)
+ suffix += "F";
+ else if (pt2 == SOLDIER)
+ suffix += "fF";
+ else if (pt2 == ROOK)
+ suffix += "B";
+ else if (pt2 == JANGGI_CANNON)
+ suffix += "pB";
+ }
+ // Castling
+ if (pt == KING && v->castling)
+ suffix += "O" + std::to_string((v->castlingKingsideFile - v->castlingQueensideFile) / 2);
+ // Drop region
+ if (v->pieceDrops)
+ {
+ if (pt == PAWN && !v->firstRankPawnDrops)
+ suffix += "j";
+ else if (pt == SHOGI_PAWN && !v->shogiDoubledPawn)
+ suffix += "f";
+ else if (pt == BISHOP && v->dropOppositeColoredBishop)
+ suffix += "s";
+ suffix += "@" + std::to_string(pt == PAWN && !v->promotionZonePawnDrops ? v->promotionRank : v->maxRank + 1);
+ }
+ sync_cout << "piece " << v->pieceToChar[pt] << "& " << pieceMap.find(pt == KING ? v->kingType : pt)->second->betza << suffix << sync_endl;
+ PieceType promType = v->promotedPieceType[pt];
+ if (promType)
+ sync_cout << "piece +" << v->pieceToChar[pt] << "& " << pieceMap.find(promType)->second->betza << sync_endl;
+ }
+ }
+ else
+ sync_cout << "info string variant " << (std::string)o
+ << " files " << v->maxFile + 1
+ << " ranks " << v->maxRank + 1
+ << " pocket " << pocketsize
+ << " template " << v->variantTemplate
+ << " startpos " << v->startFen
+ << sync_endl;
+}
/// Our case insensitive less() function as required by UCI protocol