From: Fabian Fichter Date: Fri, 14 Aug 2020 13:15:08 +0000 (+0200) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=83d6ecea37e54038fdec9c095b86de7879f7e7fb;p=fairystockfish.git Merge official-stockfish/master No functional change. --- 83d6ecea37e54038fdec9c095b86de7879f7e7fb diff --cc src/bitboard.cpp index a1f8993,f650eef..5e8844a --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@@ -175,144 -68,40 +175,144 @@@ const std::string Bitboards::pretty(Bit void Bitboards::init() { + // Piece moves + std::vector RookDirectionsV = { NORTH, SOUTH}; + std::vector RookDirectionsH = { EAST, WEST }; + std::vector BishopDirections = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }; + std::vector 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 ElephantDirections = { 2 * NORTH_EAST, 2 * SOUTH_EAST, 2 * SOUTH_WEST, 2 * NORTH_WEST }; + std::vector 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(s1, s2), distance(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(s1, s2), distance(s1, s2)); + +#ifdef PRECOMPUTED_MAGICS + init_magics(RookTableH, RookMagicsH, RookDirectionsH, RookMagicHInit); + init_magics(RookTableV, RookMagicsV, RookDirectionsV, RookMagicVInit); + init_magics(BishopTable, BishopMagics, BishopDirections, BishopMagicInit); + init_magics(CannonTableH, CannonMagicsH, RookDirectionsH, CannonMagicHInit); + init_magics(CannonTableV, CannonMagicsV, RookDirectionsV, CannonMagicVInit); + init_magics(HorseTable, HorseMagics, HorseDirections, HorseMagicInit); + init_magics(ElephantTable, ElephantMagics, ElephantDirections, ElephantMagicInit); + init_magics(JanggiElephantTable, JanggiElephantMagics, JanggiElephantDirections, JanggiElephantMagicInit); +#else + init_magics(RookTableH, RookMagicsH, RookDirectionsH); + init_magics(RookTableV, RookMagicsV, RookDirectionsV); + init_magics(BishopTable, BishopMagics, BishopDirections); + init_magics(CannonTableH, CannonMagicsH, RookDirectionsH); + init_magics(CannonTableV, CannonMagicsV, RookDirectionsV); + init_magics(HorseTable, HorseMagics, HorseDirections); + init_magics(ElephantTable, ElephantMagics, ElephantDirections); + init_magics(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(pi->sliderCapture, s, 0, c); + PseudoAttacks[c][pt][s] |= sliding_attack(pi->hopperCapture, s, 0, c); + PseudoMoves[c][pt][s] |= sliding_attack(pi->sliderQuiet, s, 0, c); + PseudoMoves[c][pt][s] |= sliding_attack(pi->hopperQuiet, s, 0, c); + } + } + + for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1) { - PawnAttacks[WHITE][s1] = pawn_attacks_bb(square_bb(s1)); - PawnAttacks[BLACK][s1] = pawn_attacks_bb(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(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; } } diff --cc src/movegen.cpp index 6714a7c,5787d17..31d7118 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@@ -318,29 -213,44 +318,61 @@@ namespace template - 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(Us), checksq) | checksq; ++ // Leaper attacks can not be blocked ++ if (LeaperAttacks[~Us][type_of(pos.piece_on(checksq))][checksq] & pos.square(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(pos, moveList, target); - moveList = generate_moves(pos, moveList, Us, target); - moveList = generate_moves(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(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(pos, moveList, pt, target & ~pos.pieces(~Us)); + + if (Type != QUIET_CHECKS && Type != EVASIONS && pos.count(Us)) { Square ksq = pos.square(Us); - Bitboard b = pos.attacks_from(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(pos, moveList, Us, ksq, pop_lsb(&b)); + + // Passing move by king + if (pos.pass()) + *moveList++ = make(ksq, ksq); if ((Type != CAPTURES) && pos.can_castle(Us & ANY_CASTLING)) for(CastlingRights cr : { Us & KING_SIDE, Us & QUEEN_SIDE } ) @@@ -432,17 -303,17 +459,17 @@@ ExtMove* generate(const P 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(~us)]; + if (pt == KING && pos.king_type() == KING) + b &= ~PseudoAttacks[~us][QUEEN][pos.square(~us)]; while (b) - *moveList++ = make_move(from, pop_lsb(&b)); + moveList = make_move_and_gating(pos, moveList, us, from, pop_lsb(&b)); } - return us == WHITE ? generate_all(pos, moveList, ~pos.pieces() & pos.board_bb()) - : generate_all(pos, moveList, ~pos.pieces() & pos.board_bb()); + return us == WHITE ? generate_all(pos, moveList) + : generate_all(pos, moveList); } @@@ -456,23 -327,7 +483,23 @@@ ExtMove* generate(const Posit Color us = pos.side_to_move(); Square ksq = pos.square(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(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(pos, moveList, us, ksq, pop_lsb(&b)); - return us == WHITE ? generate_all(pos, moveList, target) - : generate_all(pos, moveList, target); ++ return us == WHITE ? generate_all(pos, moveList) ++ : generate_all(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 diff --cc src/pawns.cpp index 3690916,b883dda..eacf62b --- a/src/pawns.cpp +++ b/src/pawns.cpp @@@ -97,22 -98,19 +98,20 @@@ namespace // 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) @@@ -234,14 -210,13 +233,14 @@@ Score Entry::evaluate_shelter(const Pos 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); diff --cc src/position.h index 083acb5,ae62492..285773b --- a/src/position.h +++ b/src/position.h @@@ -1062,11 -396,10 +1062,10 @@@ inline Thread* Position::this_thread() 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; diff --cc src/search.cpp index c904275,3b3c0f2..d8cb9e9 --- a/src/search.cpp +++ b/src/search.cpp @@@ -291,12 -269,12 +291,12 @@@ void MainThread::search() 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 votes; diff --cc src/timeman.cpp index c83859b,1f59874..a691047 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@@ -34,12 -33,12 +34,12 @@@ TimeManagement Time; // Our global tim // 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. diff --cc src/ucioption.cpp index 7cdbb44,16add76..fa69dc3 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@@ -37,91 -34,14 +37,91 @@@ using std::string UCI::OptionsMap Options; // Global object +namespace PSQT { + void init(const Variant* v); +} + namespace UCI { +// standard variants of XBoard/WinBoard +std::set 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(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