From: Fabian Fichter Date: Sat, 2 Mar 2019 10:07:32 +0000 (+0100) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=b0e16fbeca8c05372642743e7c49d8ddad0600dc;p=fairystockfish.git Merge official-stockfish/master bench: 3334755 --- b0e16fbeca8c05372642743e7c49d8ddad0600dc diff --cc src/evaluate.cpp index 2b0d228,aeaa433..634dda3 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@@ -101,13 -101,9 +101,13 @@@ namespace // MobilityBonus[PieceType-2][attacked] contains bonuses for middle and end game, // indexed by piece type and number of attacked squares in the mobility area. +#ifdef LARGEBOARDS + constexpr Score MobilityBonus[][38] = { +#else constexpr Score MobilityBonus[][32] = { +#endif - { S(-75,-76), S(-57,-54), S( -9,-28), S( -2,-10), S( 6, 5), S( 14, 12), // Knights - S( 22, 26), S( 29, 29), S( 36, 29) }, + { S(-62,-81), S(-53,-56), S(-12,-30), S( -4,-14), S( 3, 8), S( 13, 15), // Knights + S( 22, 23), S( 28, 27), S( 33, 33) }, { S(-48,-59), S(-20,-23), S( 16, -3), S( 26, 13), S( 38, 24), S( 51, 42), // Bishops S( 55, 54), S( 63, 57), S( 63, 65), S( 68, 73), S( 81, 78), S( 81, 86), S( 91, 88), S( 98, 97) }, @@@ -157,32 -151,27 +157,30 @@@ S(-30,-14), S(-9, -8), S( 0, 9), S( -1, 7) }; - // PassedDanger[Rank] contains a term to weight the passed score - constexpr int PassedDanger[RANK_NB] = { 0, 0, 0, 3, 7, 11, 20 }; - + // KingProximity contains a penalty according to distance from king + constexpr Score KingProximity = S(2, 2); + // Assorted bonuses and penalties - constexpr Score BishopPawns = S( 3, 7); - constexpr Score CloseEnemies = S( 6, 0); + constexpr Score BishopPawns = S( 3, 8); + constexpr Score CloseEnemies = S( 7, 0); constexpr Score CorneredBishop = S( 50, 50); - constexpr Score Hanging = S( 57, 32); - constexpr Score KingProtector = S( 6, 6); - constexpr Score KnightOnQueen = S( 21, 11); - constexpr Score LongDiagonalBishop = S( 46, 0); + constexpr Score Hanging = S( 62, 34); + constexpr Score KingProtector = S( 6, 7); + constexpr Score KnightOnQueen = S( 20, 12); + constexpr Score LongDiagonalBishop = S( 44, 0); constexpr Score MinorBehindPawn = S( 16, 0); - constexpr Score Overload = S( 13, 6); - constexpr Score PawnlessFlank = S( 19, 84); - constexpr Score RookOnPawn = S( 10, 30); - constexpr Score SliderOnQueen = S( 42, 21); - constexpr Score ThreatByKing = S( 23, 76); - constexpr Score ThreatByPawnPush = S( 45, 40); - constexpr Score ThreatByRank = S( 16, 3); - constexpr Score ThreatBySafePawn = S(173,102); - constexpr Score TrappedRook = S( 92, 0); - constexpr Score WeakQueen = S( 50, 10); - constexpr Score WeakUnopposedPawn = S( 5, 29); + constexpr Score Overload = S( 12, 6); + constexpr Score PawnlessFlank = S( 18, 94); + constexpr Score RestrictedPiece = S( 7, 6); + constexpr Score RookOnPawn = S( 10, 28); + constexpr Score SliderOnQueen = S( 49, 21); + constexpr Score ThreatByKing = S( 21, 84); + constexpr Score ThreatByPawnPush = S( 48, 42); + constexpr Score ThreatByRank = S( 14, 3); + constexpr Score ThreatBySafePawn = S(169, 99); + constexpr Score TrappedRook = S( 98, 5); + constexpr Score WeakQueen = S( 51, 10); + constexpr Score WeakUnopposedPawn = S( 14, 20); #undef S @@@ -264,40 -251,32 +262,40 @@@ // Squares occupied by those pawns, by our king or queen, or controlled by enemy pawns // are excluded from the mobility area. - mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pe->pawn_attacks(Them)); + if (pos.must_capture()) + mobilityArea[Us] = AllSquares; + else + mobilityArea[Us] = ~(b | pos.pieces(Us, KING, QUEEN) | pe->pawn_attacks(Them) | shift(pos.pieces(Them, SHOGI_PAWN))); // Initialise attackedBy bitboards for kings and pawns - attackedBy[Us][KING] = pos.attacks_from(pos.square(Us)); - attackedBy[Us][PAWN] = pe->pawn_attacks(Us); - attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN]; - attackedBy2[Us] = attackedBy[Us][KING] & attackedBy[Us][PAWN]; + attackedBy[Us][KING] = pos.count(Us) ? pos.attacks_from(Us, pos.square(Us)) : 0; + attackedBy[Us][PAWN] = pe->pawn_attacks(Us); + attackedBy[Us][SHOGI_PAWN] = shift(pos.pieces(Us, SHOGI_PAWN)); + attackedBy[Us][ALL_PIECES] = attackedBy[Us][KING] | attackedBy[Us][PAWN] | attackedBy[Us][SHOGI_PAWN]; + attackedBy2[Us] = (attackedBy[Us][KING] & attackedBy[Us][PAWN]) + | (attackedBy[Us][KING] & attackedBy[Us][SHOGI_PAWN]) + | (attackedBy[Us][PAWN] & attackedBy[Us][SHOGI_PAWN]); + kingRing[Us] = kingAttackersCount[Them] = 0; + // Init our king safety tables only if we are going to use them - if (pos.non_pawn_material(Them) >= RookValueMg + KnightValueMg) + if ((pos.count(Us) && pos.non_pawn_material(Them) >= RookValueMg + KnightValueMg) || pos.captures_to_hand()) { kingRing[Us] = attackedBy[Us][KING]; - if (relative_rank(Us, pos.square(Us)) == RANK_1) + if (relative_rank(Us, pos.square(Us), pos.max_rank()) == RANK_1) kingRing[Us] |= shift(kingRing[Us]); - if (file_of(pos.square(Us)) == FILE_H) + if (file_of(pos.square(Us)) == pos.max_file()) kingRing[Us] |= shift(kingRing[Us]); else if (file_of(pos.square(Us)) == FILE_A) kingRing[Us] |= shift(kingRing[Us]); - kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them)); + kingRing[Us] &= pos.board_bb(); + + kingAttackersCount[Them] = popcount(kingRing[Us] & (pe->pawn_attacks(Them) | shift(pos.pieces(Them, SHOGI_PAWN)))); kingAttacksCount[Them] = kingAttackersWeight[Them] = 0; } - else - kingRing[Us] = kingAttackersCount[Them] = 0; } @@@ -483,14 -413,13 +481,14 @@@ Bitboard kingFlank, weak, b, b1, b2, safe, unsafeChecks; // King shelter and enemy pawns storm - Score score = pe->king_safety(pos, ksq); + Score score = pe->king_safety(pos); // Find the squares that opponent attacks in our king flank, and the squares - // which are attacked twice in that flank. - kingFlank = KingFlank[file_of(ksq)]; + // which are attacked twice in that flank but not defended by our pawns. + File f = std::max(std::min(file_of(ksq), File(pos.max_file() - 1)), FILE_B); + kingFlank = pos.max_file() == FILE_H ? KingFlank[file_of(ksq)] : file_bb(f) | adjacent_files_bb(f); b1 = attackedBy[Them][ALL_PIECES] & kingFlank & Camp; - b2 = b1 & attackedBy2[Them] & ~attackedBy[Us][PAWN] & ~attackedBy[Us][SHOGI_PAWN]; + b2 = b1 & attackedBy2[Them]; int tropism = popcount(b1) + popcount(b2); @@@ -562,21 -472,18 +560,18 @@@ unsafeChecks &= mobilityArea[Them]; kingDanger += kingAttackersCount[Them] * kingAttackersWeight[Them] - + 69 * kingAttacksCount[Them] - + 185 * popcount(kingRing[Us] & weak) + + 69 * kingAttacksCount[Them] * (1 + 2 * !!pos.max_check_count()) + + 185 * popcount(kingRing[Us] & weak) * (1 + pos.captures_to_hand() + !!pos.max_check_count()) + 150 * popcount(pos.blockers_for_king(Us) | unsafeChecks) - + 4 * tropism + + tropism * tropism / 4 - - 873 * !pos.count(Them) + - 873 * !(pos.count(Them) || pos.captures_to_hand()) / (1 + !!pos.max_check_count()) - 6 * mg_value(score) / 8 + + mg_value(mobility[Them] - mobility[Us]) - 30; // Transform the kingDanger units into a Score, and subtract it from the evaluation if (kingDanger > 0) - { - int mobilityDanger = mg_value(mobility[Them] - mobility[Us]); - kingDanger = std::max(0, kingDanger + mobilityDanger); - score -= make_score(kingDanger * kingDanger / 4096, kingDanger / 16); + score -= make_score(std::min(kingDanger * kingDanger / 4096, 3000), kingDanger / 16); - } } // Penalty when our king is on a pawnless flank @@@ -606,29 -509,11 +601,29 @@@ constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); - Bitboard b, weak, defended, nonPawnEnemies, stronglyProtected, safe; + Bitboard b, weak, defended, nonPawnEnemies, stronglyProtected, safe, restricted; Score score = SCORE_ZERO; + // Bonuses for variants with mandatory captures + if (pos.must_capture()) + { + // Penalties for possible captures + score -= make_score(100, 100) * popcount(attackedBy[Us][ALL_PIECES] & pos.pieces(Them)); + + // Bonus if we threaten to force captures + Bitboard moves = 0, piecebb = pos.pieces(Us); + while (piecebb) + { + Square s = pop_lsb(&piecebb); + if (type_of(pos.piece_on(s)) != KING) + moves |= pos.moves_from(Us, type_of(pos.piece_on(s)), s); + } + score += make_score(200, 200) * popcount(attackedBy[Them][ALL_PIECES] & moves & ~pos.pieces()); + score += make_score(200, 200) * popcount(attackedBy[Them][ALL_PIECES] & moves & ~pos.pieces() & ~attackedBy2[Us]); + } + // Non-pawn enemies - nonPawnEnemies = pos.pieces(Them) ^ pos.pieces(Them, PAWN); + nonPawnEnemies = pos.pieces(Them) ^ pos.pieces(Them, PAWN, SHOGI_PAWN); // Squares strongly protected by the enemy, either because they defend the // square with a pawn, or because they defend the square twice and we don't. @@@ -674,6 -559,13 +669,13 @@@ score += Overload * popcount(b); } + // Bonus for restricting their piece moves + restricted = attackedBy[Them][ALL_PIECES] - & ~attackedBy[Them][PAWN] ++ & ~(attackedBy[Them][PAWN] | attackedBy[Them][SHOGI_PAWN]) + & ~attackedBy2[Them] + & attackedBy[Us][ALL_PIECES]; + score += RestrictedPiece * popcount(restricted); + // Bonus for enemy unopposed weak pawns if (pos.pieces(Us, ROOK, QUEEN)) score += WeakUnopposedPawn * pe->weak_unopposed(Them); @@@ -741,26 -633,22 +743,26 @@@ assert(!(pos.pieces(Them, PAWN) & forward_file_bb(Us, s + Up))); - int r = relative_rank(Us, s); + int r = std::max(RANK_8 - std::max(pos.promotion_rank() - relative_rank(Us, s, pos.max_rank()), 0), 0); Score bonus = PassedRank[r]; - if (w) + if (r > RANK_3) { + int w = (r-2) * (r-2) + 2; Square blockSq = s + Up; - // Adjust bonus based on the king's proximity - bonus += make_score(0, ( king_proximity(Them, blockSq) * 5 - - king_proximity(Us, blockSq) * 2) * w); + // Skip bonus for antichess variants + if (pos.extinction_value() != VALUE_MATE) + { + // Adjust bonus based on the king's proximity + bonus += make_score(0, ( king_proximity(Them, blockSq) * 5 + - king_proximity(Us, blockSq) * 2) * w); - // If blockSq is not the queening square then consider also a second push - if (r != RANK_7) - bonus -= make_score(0, king_proximity(Us, blockSq + Up) * w); + // If blockSq is not the queening square then consider also a second push + if (r != pos.promotion_rank() - 1) + bonus -= make_score(0, king_proximity(Us, blockSq + Up) * w); + } // If the pawn is free to advance, then increase the bonus if (pos.empty(blockSq)) diff --cc src/movegen.cpp index 751685e,833cd2f..5eb3c3a --- a/src/movegen.cpp +++ b/src/movegen.cpp @@@ -35,28 -36,25 +36,29 @@@ namespace // After castling, the rook and king final positions are the same in Chess960 // as they would be in standard chess. - Square kfrom = pos.count(us) ? pos.square(us) : make_square(FILE_E, relative_rank(us, RANK_1, pos.max_rank())); - Square kfrom = pos.square(Us); ++ Square kfrom = pos.count(Us) ? pos.square(Us) : make_square(FILE_E, relative_rank(Us, RANK_1, pos.max_rank())); Square rfrom = pos.castling_rook_square(Cr); - Square kto = relative_square(Us, KingSide ? SQ_G1 : SQ_C1); + Square kto = make_square(KingSide ? pos.castling_kingside_file() : pos.castling_queenside_file(), - relative_rank(us, RANK_1, pos.max_rank())); ++ relative_rank(Us, RANK_1, pos.max_rank())); + Bitboard enemies = pos.pieces(~Us); assert(!pos.checkers()); const Direction step = Chess960 ? kto > kfrom ? WEST : EAST : KingSide ? WEST : EAST; - for (Square s = kto; s != kfrom; s += step) - if (pos.attackers_to(s) & enemies) - return moveList; + if (type_of(pos.piece_on(kfrom)) == KING) + { + for (Square s = kto; s != kfrom; s += step) - if (pos.attackers_to(s, ~us)) ++ if (pos.attackers_to(s, ~Us) & enemies) + return moveList; - // Because we generate only legal castling moves we need to verify that - // when moving the castling rook we do not discover some hidden checker. - // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1. - if (Chess960 && (attacks_bb(kto, pos.pieces() ^ rfrom) & pos.pieces(~Us, ROOK, QUEEN))) - return moveList; + // Because we generate only legal castling moves we need to verify that + // when moving the castling rook we do not discover some hidden checker. + // For instance an enemy queen in SQ_A1 when castling rook is in SQ_B1. - if (Chess960 && pos.attackers_to(kto, pos.pieces() ^ rfrom, ~us)) ++ if (Chess960 && pos.attackers_to(kto, pos.pieces() ^ rfrom, ~Us)) + return moveList; + } Move m = make(kfrom, rfrom); diff --cc src/pawns.cpp index 65f1160,7d39a4a..ed79aab --- a/src/pawns.cpp +++ b/src/pawns.cpp @@@ -245,15 -214,14 +241,15 @@@ Value 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, backmost_sq(Us, b)) : 0; + int ourRank = b ? relative_rank(Us, backmost_sq(Us, 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; - int d = std::min(f, ~f); - safety += ShelterStrength[d][ourRank]; + int d = std::min(std::min(f, File(pos.max_file() - f)), FILE_D); + // higher weight for pawns on second rank and missing shelter in drop variants + safety += ShelterStrength[d][ourRank] * (1 + (pos.captures_to_hand() && ourRank <= RANK_2)); - safety -= (ourRank && (ourRank == theirRank - 1)) ? BlockedStorm[theirRank] + safety -= (ourRank && (ourRank == theirRank - 1)) ? 66 * (theirRank == RANK_3) : UnblockedStorm[d][theirRank]; } @@@ -278,17 -247,11 +275,17 @@@ Score Entry::do_king_safety(const Posit Value bonus = evaluate_shelter(pos, ksq); // If we can castle use the bonus after the castling if it is bigger - if (pos.can_castle(MakeCastling::right)) + if (pos.can_castle(Us | KING_SIDE)) - bonus = std::max(bonus, evaluate_shelter(pos, relative_square(Us, SQ_G1))); + { + Square s = make_square(pos.castling_kingside_file(), Us == WHITE ? RANK_1 : pos.max_rank()); + bonus = std::max(bonus, evaluate_shelter(pos, s)); + } - if (pos.can_castle(MakeCastling::right)) + if (pos.can_castle(Us | QUEEN_SIDE)) - bonus = std::max(bonus, evaluate_shelter(pos, relative_square(Us, SQ_C1))); + { + Square s = make_square(pos.castling_queenside_file(), Us == WHITE ? RANK_1 : pos.max_rank()); + bonus = std::max(bonus, evaluate_shelter(pos, s)); + } return make_score(bonus, -16 * minKingPawnDistance); } diff --cc src/psqt.cpp index 9d998d0,4703da3..ea44619 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@@ -76,28 -67,26 +76,28 @@@ constexpr Score Bonus[PIECE_TYPE_NB][RA { S(-47,-55), S( -7,-32), S(-17,-36), S(-29,-17) } }, { // Rook - { S(-25, 0), S(-16, 0), S(-16, 0), S(-9, 0) }, - { S(-21, 0), S( -8, 0), S( -3, 0), S( 0, 0) }, - { S(-21, 0), S( -9, 0), S( -4, 0), S( 2, 0) }, - { S(-22, 0), S( -6, 0), S( -1, 0), S( 2, 0) }, - { S(-22, 0), S( -7, 0), S( 0, 0), S( 1, 0) }, - { S(-21, 0), S( -7, 0), S( 0, 0), S( 2, 0) }, - { S(-12, 0), S( 4, 0), S( 8, 0), S(12, 0) }, - { S(-23, 0), S(-15, 0), S(-11, 0), S(-5, 0) } + { S(-24, 0), S(-15, 3), S( -8, 0), S( 0, 3) }, + { S(-18,-7), S( -5,-5), S( -1,-5), S( 1,-1) }, + { S(-19, 6), S(-10,-7), S( 1, 3), S( 0, 3) }, + { S(-21, 0), S( -7, 4), S( -4,-2), S(-4, 1) }, + { S(-21,-7), S(-12, 5), S( -1,-5), S( 4,-7) }, + { S(-23, 3), S(-10, 2), S( 1,-1), S( 6, 3) }, + { S(-11,-1), S( 8, 7), S( 9,11), S(12,-1) }, + { S(-25, 6), S(-18, 4), S(-11, 6), S( 2, 2) } }, { // Queen - { S( 0,-71), S(-4,-56), S(-3,-42), S(-1,-29) }, - { S(-4,-56), S( 6,-30), S( 9,-21), S( 8, -5) }, - { S(-2,-39), S( 6,-17), S( 9, -8), S( 9, 5) }, - { S(-1,-29), S( 8, -5), S(10, 9), S( 7, 19) }, - { S(-3,-27), S( 9, -5), S( 8, 10), S( 7, 21) }, - { S(-2,-40), S( 6,-16), S( 8,-10), S(10, 3) }, - { S(-2,-55), S( 7,-30), S( 7,-21), S( 6, -6) }, - { S(-1,-74), S(-4,-55), S(-1,-43), S( 0,-30) } + { S( 3,-69), S(-5,-57), S(-5,-47), S( 4,-26) }, + { S( -3,-55), S( 5,-31), S( 8,-22), S(12, -4) }, + { S( -3,-39), S( 6,-18), S(13, -9), S( 7, 3) }, + { S( 4,-23), S( 5, -3), S( 9, 13), S( 8, 24) }, + { S( 0,-29), S(14, -6), S(12, 9), S( 5, 21) }, + { S( -4,-38), S(10,-18), S( 6,-12), S( 8, 1) }, + { S( -5,-50), S( 6,-27), S(10,-24), S( 8, -8) }, + { S( -2,-75), S(-2,-52), S( 1,-43), S(-2,-36) } - }, - { // King + } +}; + +constexpr Score KingBonus[RANK_NB][int(FILE_NB) / 2] = { { S(272, 0), S(325, 41), S(273, 80), S(190, 93) }, { S(277, 57), S(305, 98), S(241,138), S(183,131) }, { S(198, 86), S(253,138), S(168,165), S(120,173) }, diff --cc src/search.cpp index 31fbdc9,62788fa..dcabf47 --- a/src/search.cpp +++ b/src/search.cpp @@@ -589,14 -595,11 +597,14 @@@ namespace if (!rootNode) { + Value variantResult; + if (pos.is_game_end(variantResult, ss->ply)) + return variantResult; + // Step 2. Check for aborted search and immediate draw if ( Threads.stop.load(std::memory_order_relaxed) - || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY) - return (ss->ply >= MAX_PLY && !inCheck) ? evaluate(pos) + return (ss->ply >= MAX_PLY && !inCheck) ? evaluate(pos) : value_draw(depth, pos.this_thread()); // Step 3. Mate distance pruning. Even if we mate at the next move our score @@@ -953,11 -947,11 +965,15 @@@ moves_loop: // When in check, search st else if ( givesCheck // Check extension (~2 Elo) && pos.see_ge(move)) extension = ONE_PLY; + else if ( pos.must_capture() // Capture extension (all moves are captures) + && pos.capture(move) + && MoveList(pos).size() == 1) + extension = ONE_PLY; + // Extension if castling + else if (type_of(move) == CASTLING) + extension = ONE_PLY; + // Calculate new depth for this move newDepth = depth - ONE_PLY + extension; @@@ -1438,10 -1411,11 +1446,11 @@@ // All legal moves have been searched. A special case: If we're in check // and no legal moves were found, it is checkmate. if (inCheck && bestValue == -VALUE_INFINITE) - return mated_in(ss->ply); // Plies to mate from the root + return pos.checkmate_value(ss->ply); // Plies to mate from the root tte->save(posKey, value_to_tt(bestValue, ss->ply), - PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER, + bestValue >= beta ? BOUND_LOWER : + PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER, ttDepth, bestMove, ss->staticEval); assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); diff --cc src/types.h index 75b0831,3b5afec..4ebfa6b --- a/src/types.h +++ b/src/types.h @@@ -160,20 -145,6 +160,14 @@@ enum CastlingRight CASTLING_RIGHT_NB = 16 }; - template struct MakeCastling { - static constexpr CastlingRight - right = C == WHITE ? S == QUEEN_SIDE ? WHITE_OOO : WHITE_OO - : S == QUEEN_SIDE ? BLACK_OOO : BLACK_OO; - }; - +enum CheckCount : int { + CHECKS_0 = 0, CHECKS_NB = 11 +}; + +enum CountingRule { + NO_COUNTING, MAKRUK_COUNTING, ASEAN_COUNTING +}; + enum Phase { PHASE_ENDGAME, PHASE_MIDGAME = 128, @@@ -205,32 -176,11 +199,32 @@@ enum Value : int VALUE_MATE_IN_MAX_PLY = VALUE_MATE - 2 * MAX_PLY, VALUE_MATED_IN_MAX_PLY = -VALUE_MATE + 2 * MAX_PLY, - PawnValueMg = 142, PawnValueEg = 207, - KnightValueMg = 784, KnightValueEg = 868, - BishopValueMg = 828, BishopValueEg = 916, - RookValueMg = 1286, RookValueEg = 1378, - QueenValueMg = 2528, QueenValueEg = 2698, - PawnValueMg = 136, PawnValueEg = 208, - KnightValueMg = 782, KnightValueEg = 865, - BishopValueMg = 830, BishopValueEg = 918, - RookValueMg = 1289, RookValueEg = 1378, - QueenValueMg = 2529, QueenValueEg = 2687, ++ PawnValueMg = 136, PawnValueEg = 208, ++ KnightValueMg = 782, KnightValueEg = 865, ++ BishopValueMg = 830, BishopValueEg = 918, ++ RookValueMg = 1289, RookValueEg = 1378, ++ QueenValueMg = 2529, QueenValueEg = 2687, + FersValueMg = 400, FersValueEg = 400, + AlfilValueMg = 300, AlfilValueEg = 300, + SilverValueMg = 600, SilverValueEg = 600, + AiwokValueMg = 2500, AiwokValueEg = 2500, + BersValueMg = 2000, BersValueEg = 2000, + ArchbishopValueMg = 2000, ArchbishopValueEg = 2000, + ChancellorValueMg = 2300, ChancellorValueEg = 2300, + AmazonValueMg = 3000, AmazonValueEg = 3000, + KnibisValueMg = 800, KnibisValueEg = 800, + BiskniValueMg = 800, BiskniValueEg = 800, + ShogiPawnValueMg = 100, ShogiPawnValueEg = 100, + LanceValueMg = 300, LanceValueEg = 300, + ShogiKnightValueMg = 300, ShogiKnightValueEg = 300, + EuroShogiKnightValueMg = 400, EuroShogiKnightValueEg = 400, + GoldValueMg = 600, GoldValueEg = 600, + HorseValueMg = 1500, HorseValueEg = 1500, + ClobberPieceValueMg = 300, ClobberPieceValueEg = 300, + BreakthroughPieceValueMg = 300, BreakthroughPieceValueEg = 300, + ImmobilePieceValueMg = 100, ImmobilePieceValueEg = 100, + WazirValueMg = 400, WazirValueEg = 400, + CommonerValueMg = 600, CommonerValueEg = 600, MidgameLimit = 15258, EndgameLimit = 3915 }; diff --cc src/ucioption.cpp index ad334d3,1c6ef77..f4b190b --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@@ -74,10 -58,9 +74,10 @@@ void init(OptionsMap& o) // at most 2^32 clusters. constexpr int MaxHashMB = Is64Bit ? 131072 : 2048; + o["Protocol"] << Option("uci", {"uci", "usi"}); o["Debug Log File"] << Option("", on_logger); - o["Contempt"] << Option(21, -100, 100); + o["Contempt"] << Option(24, -100, 100); - o["Analysis Contempt"] << Option("Both var Off var White var Black var Both", "Both"); + o["Analysis Contempt"] << Option("Both", {"Both", "Off", "White", "Black"}); o["Threads"] << Option(1, 1, 512, on_threads); o["Hash"] << Option(16, 1, MaxHashMB, on_hash_size); o["Clear Hash"] << Option(on_clear_hash); diff --cc src/variant.cpp index 56b55e3,0000000..a773a49 mode 100644,000000..100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@@ -1,637 -1,0 +1,637 @@@ +/* + Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish - Copyright (C) 2018 Fabian Fichter ++ Copyright (C) 2018-2019 Fabian Fichter + + Fairy-Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Fairy-Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include + +#include "variant.h" + +using std::string; + +VariantMap variants; // Global object + + // Define variant rules + Variant* fairy_variant_base() { + Variant* v = new Variant(); + v->endgameEval = false; + return v; + } + Variant* chess_variant() { + Variant* v = fairy_variant_base(); + v->endgameEval = true; + return v; + } + Variant* fairy_variant() { + Variant* v = chess_variant(); + v->add_piece(SILVER, 's'); + v->add_piece(FERS, 'f'); + return v; + } + Variant* makruk_variant() { + Variant* v = chess_variant(); + v->remove_piece(BISHOP); + v->remove_piece(QUEEN); + v->add_piece(KHON, 's'); + v->add_piece(MET, 'm'); + v->startFen = "rnsmksnr/8/pppppppp/8/8/PPPPPPPP/8/RNSKMSNR w - - 0 1"; + v->promotionRank = RANK_6; + v->promotionPieceTypes = {MET}; + v->doubleStep = false; + v->castling = false; + v->nMoveRule = 0; + v->countingRule = MAKRUK_COUNTING; + return v; + } + Variant* asean_variant() { + Variant* v = chess_variant(); + v->remove_piece(BISHOP); + v->remove_piece(QUEEN); + v->add_piece(KHON, 'b'); + v->add_piece(MET, 'q'); + v->startFen = "rnbqkbnr/8/pppppppp/8/8/PPPPPPPP/8/RNBQKBNR w - - 0 1"; + v->promotionPieceTypes = {ROOK, KNIGHT, KHON, MET}; + v->doubleStep = false; + v->castling = false; + v->countingRule = ASEAN_COUNTING; + return v; + } + Variant* aiwok_variant() { + Variant* v = makruk_variant(); + v->remove_piece(MET); + v->add_piece(AIWOK, 'a'); + v->startFen = "rnsaksnr/8/pppppppp/8/8/PPPPPPPP/8/RNSKASNR w - - 0 1"; + v->promotionPieceTypes = {AIWOK}; + return v; + } + Variant* shatranj_variant() { + Variant* v = fairy_variant_base(); + v->remove_piece(BISHOP); + v->remove_piece(QUEEN); + v->add_piece(ALFIL, 'b'); + v->add_piece(FERS, 'q'); + v->startFen = "rnbkqbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBKQBNR w - - 0 1"; + v->promotionPieceTypes = {FERS}; + v->doubleStep = false; + v->castling = false; + v->bareKingValue = -VALUE_MATE; + v->bareKingMove = true; + v->stalemateValue = -VALUE_MATE; + v->nMoveRule = 70; + return v; + } + Variant* amazon_variant() { + Variant* v = chess_variant(); + v->remove_piece(QUEEN); + v->add_piece(AMAZON, 'a'); + v->startFen = "rnbakbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBAKBNR w KQkq - 0 1"; + v->promotionPieceTypes = {AMAZON, ROOK, BISHOP, KNIGHT}; + return v; + } + Variant* hoppelpoppel_variant() { + Variant* v = chess_variant(); + v->remove_piece(KNIGHT); + v->remove_piece(BISHOP); + v->add_piece(KNIBIS, 'n'); + v->add_piece(BISKNI, 'b'); + v->promotionPieceTypes = {QUEEN, ROOK, BISKNI, KNIBIS}; + return v; + } + Variant* kingofthehill_variant() { + Variant* v = fairy_variant_base(); + v->flagPiece = KING; + v->whiteFlag = make_bitboard(SQ_D4, SQ_E4, SQ_D5, SQ_E5); + v->blackFlag = make_bitboard(SQ_D4, SQ_E4, SQ_D5, SQ_E5); + v->flagMove = false; + return v; + } + Variant* racingkings_variant() { + Variant* v = fairy_variant_base(); + v->startFen = "8/8/8/8/8/8/krbnNBRK/qrbnNBRQ w - - 0 1"; + v->flagPiece = KING; + v->whiteFlag = Rank8BB; + v->blackFlag = Rank8BB; + v->flagMove = true; + v->castling = false; + v->checking = false; + return v; + } + Variant* losers_variant() { + Variant* v = fairy_variant_base(); + v->checkmateValue = VALUE_MATE; + v->stalemateValue = VALUE_MATE; + v->bareKingValue = VALUE_MATE; + v->bareKingMove = false; + v->mustCapture = true; + return v; + } + Variant* giveaway_variant() { + Variant* v = fairy_variant_base(); + v->remove_piece(KING); + v->add_piece(COMMONER, 'k'); + v->promotionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT}; + v->stalemateValue = VALUE_MATE; + v->extinctionValue = VALUE_MATE; + v->extinctionPieceTypes = {ALL_PIECES}; + v->mustCapture = true; + return v; + } + Variant* antichess_variant() { + Variant* v = giveaway_variant(); + v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w - - 0 1"; + v->castling = false; + return v; + } + Variant* codrus_variant() { + Variant* v = giveaway_variant(); + v->promotionPieceTypes = {QUEEN, ROOK, BISHOP, KNIGHT}; + v->extinctionPieceTypes = {COMMONER}; + return v; + } + Variant* extinction_variant() { + Variant* v = fairy_variant_base(); + v->remove_piece(KING); + v->add_piece(COMMONER, 'k'); + v->promotionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT}; + v->extinctionValue = -VALUE_MATE; + v->extinctionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT, PAWN}; + return v; + } + Variant* kinglet_variant() { + Variant* v = extinction_variant(); + v->promotionPieceTypes = {COMMONER}; + v->extinctionPieceTypes = {PAWN}; + return v; + } + Variant* horde_variant() { + Variant* v = fairy_variant_base(); + v->startFen = "rnbqkbnr/pppppppp/8/1PP2PP1/PPPPPPPP/PPPPPPPP/PPPPPPPP/PPPPPPPP w kq - 0 1"; + v->firstRankDoubleSteps = true; + v->extinctionValue = -VALUE_MATE; + v->extinctionPieceTypes = {ALL_PIECES}; + return v; + } + Variant* threecheck_variant() { + Variant* v = fairy_variant_base(); + v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 3+3 0 1"; + v->maxCheckCount = CheckCount(3); + return v; + } + Variant* fivecheck_variant() { + Variant* v = fairy_variant_base(); + v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 5+5 0 1"; + v->maxCheckCount = CheckCount(5); + return v; + } + Variant* crazyhouse_variant() { + Variant* v = fairy_variant_base(); + v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR[] w KQkq - 0 1"; + v->pieceDrops = true; + v->capturesToHand = true; + return v; + } + Variant* loop_variant() { + Variant* v = crazyhouse_variant(); + v->dropLoop = true; + return v; + } + Variant* chessgi_variant() { + Variant* v = loop_variant(); + v->firstRankDrops = true; + return v; + } + Variant* pocketknight_variant() { + Variant* v = fairy_variant_base(); + v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR[Nn] w KQkq - 0 1"; + v->pieceDrops = true; + v->capturesToHand = false; + return v; + } + Variant* placement_variant() { + Variant* v = chess_variant(); + v->startFen = "8/pppppppp/8/8/8/8/PPPPPPPP/8[KQRRBBNNkqrrbbnn] w - - 0 1"; + v->mustDrop = true; + v->pieceDrops = true; + v->capturesToHand = false; + v->whiteDropRegion = Rank1BB; + v->blackDropRegion = Rank8BB; + v->dropOppositeColoredBishop = true; + v->castlingDroppedPiece = true; + return v; + } + Variant* sittuyin_variant() { + Variant* v = makruk_variant(); + v->startFen = "8/8/4pppp/pppp4/4PPPP/PPPP4/8/8[KFRRSSNNkfrrssnn] w - - 0 1"; + v->remove_piece(MET); + v->add_piece(MET, 'f'); + v->mustDrop = true; + v->pieceDrops = true; + v->capturesToHand = false; + v->whiteDropRegion = Rank1BB | Rank2BB | Rank3BB; + v->blackDropRegion = Rank8BB | Rank7BB | Rank6BB; + v->sittuyinRookDrop = true; + v->promotionRank = RANK_1; // no regular promotions + v->sittuyinPromotion = true; + v->immobilityIllegal = false; + v->countingRule = ASEAN_COUNTING; + return v; + } + Variant* minishogi_variant_base() { + Variant* v = fairy_variant_base(); + v->variantTemplate = "shogi"; + v->maxRank = RANK_5; + v->maxFile = FILE_E; + v->reset_pieces(); + v->add_piece(SHOGI_PAWN, 'p'); + v->add_piece(SILVER, 's'); + v->add_piece(GOLD, 'g'); + v->add_piece(BISHOP, 'b'); + v->add_piece(HORSE, 'h'); + v->add_piece(ROOK, 'r'); + v->add_piece(DRAGON, 'd'); + v->add_piece(KING, 'k'); + v->startFen = "rbsgk/4p/5/P4/KGSBR[-] w 0 1"; + v->pieceDrops = true; + v->capturesToHand = true; + v->promotionRank = RANK_5; + v->promotionPieceTypes = {}; + v->doubleStep = false; + v->castling = false; + v->promotedPieceType[SHOGI_PAWN] = GOLD; + v->promotedPieceType[SILVER] = GOLD; + v->promotedPieceType[BISHOP] = HORSE; + v->promotedPieceType[ROOK] = DRAGON; + v->shogiDoubledPawn = false; + v->immobilityIllegal = true; + v->shogiPawnDropMateIllegal = true; + v->stalemateValue = -VALUE_MATE; + v->nFoldRule = 4; + v->nMoveRule = 0; + v->perpetualCheckIllegal = true; + return v; + } + Variant* minishogi_variant() { + Variant* v = minishogi_variant_base(); + v->pocketSize = 5; + v->nFoldValue = -VALUE_MATE; + v->nFoldValueAbsolute = true; + return v; + } + Variant* kyotoshogi_variant() { + Variant* v = minishogi_variant_base(); + v->add_piece(LANCE, 'l'); + v->add_piece(SHOGI_KNIGHT, 'n'); + v->startFen = "p+nks+l/5/5/5/+LSK+NP[-] w 0 1"; + v->promotionRank = RANK_1; + v->mandatoryPiecePromotion = true; + v->pieceDemotion = true; + v->dropPromoted = true; + v->promotedPieceType[LANCE] = GOLD; + v->promotedPieceType[SILVER] = BISHOP; + v->promotedPieceType[SHOGI_KNIGHT] = GOLD; + v->promotedPieceType[SHOGI_PAWN] = ROOK; + v->promotedPieceType[GOLD] = NO_PIECE_TYPE; + v->promotedPieceType[BISHOP] = NO_PIECE_TYPE; + v->promotedPieceType[ROOK] = NO_PIECE_TYPE; + v->immobilityIllegal = false; + v->shogiPawnDropMateIllegal = false; + v->shogiDoubledPawn = true; + return v; + } + Variant* microshogi_variant() { + Variant* v = kyotoshogi_variant(); + v->maxFile = FILE_D; + v->startFen = "kb+r+l/p3/4/3P/+L+RBK[-] w 0 1"; + v->promotionRank = RANK_1; + v->piecePromotionOnCapture = true; + v->promotedPieceType[LANCE] = SILVER; + v->promotedPieceType[BISHOP] = GOLD; + v->promotedPieceType[ROOK] = GOLD; + v->promotedPieceType[SHOGI_PAWN] = SHOGI_KNIGHT; + v->promotedPieceType[SILVER] = NO_PIECE_TYPE; + v->promotedPieceType[GOLD] = NO_PIECE_TYPE; + v->promotedPieceType[SHOGI_KNIGHT] = NO_PIECE_TYPE; + return v; + } + Variant* dobutsu_variant() { + Variant* v = minishogi_variant_base(); + v->maxRank = RANK_4; + v->maxFile = FILE_C; + v->reset_pieces(); + v->add_piece(SHOGI_PAWN, 'c'); + v->add_piece(GOLD, 'h'); + v->add_piece(FERS, 'e'); + v->add_piece(WAZIR, 'g'); + v->add_piece(KING, 'l'); + v->startFen = "gle/1c1/1C1/ELG[-] w 0 1"; + v->promotionRank = RANK_4; + v->immobilityIllegal = false; + v->shogiPawnDropMateIllegal = false; + v->flagPiece = KING; + v->whiteFlag = Rank4BB; + v->blackFlag = Rank1BB; + v->shogiDoubledPawn = true; + return v; + } + Variant* gorogoroshogi_variant() { + Variant* v = minishogi_variant_base(); + v->maxRank = RANK_6; + v->maxFile = FILE_E; + v->startFen = "sgkgs/5/1ppp1/1PPP1/5/SGKGS[-] w 0 1"; + v->promotionRank = RANK_5; + return v; + } + Variant* judkinsshogi_variant() { + Variant* v = minishogi_variant_base(); + v->maxRank = RANK_6; + v->maxFile = FILE_F; + v->add_piece(SHOGI_KNIGHT, 'n'); + v->startFen = "rbnsgk/5p/6/6/P5/KGSNBR[-] w 0 1"; + v->promotionRank = RANK_5; + v->promotedPieceType[SHOGI_KNIGHT] = GOLD; + return v; + } + Variant* euroshogi_variant() { + Variant* v = minishogi_variant_base(); + v->maxRank = RANK_8; + v->maxFile = FILE_H; + v->add_piece(EUROSHOGI_KNIGHT, 'n'); + v->startFen = "1nbgkgn1/1r4b1/pppppppp/8/8/PPPPPPPP/1B4R1/1NGKGBN1[-] w 0 1"; + v->promotionRank = RANK_6; + v->promotedPieceType[EUROSHOGI_KNIGHT] = GOLD; + v->mandatoryPiecePromotion = true; + return v; + } + Variant* losalamos_variant() { + Variant* v = fairy_variant_base(); + v->maxRank = RANK_6; + v->maxFile = FILE_F; + v->remove_piece(BISHOP); + v->startFen = "rnqknr/pppppp/6/6/PPPPPP/RNQKNR w - - 0 1"; + v->promotionRank = RANK_6; + v->promotionPieceTypes = {QUEEN, ROOK, KNIGHT}; + v->doubleStep = false; + v->castling = false; + return v; + } + Variant* almost_variant() { + Variant* v = chess_variant(); + v->remove_piece(QUEEN); + v->add_piece(CHANCELLOR, 'c'); + v->startFen = "rnbckbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBCKBNR w KQkq - 0 1"; + v->promotionPieceTypes = {CHANCELLOR, ROOK, BISHOP, KNIGHT}; + return v; + } + Variant* chigorin_variant() { + Variant* v = chess_variant(); + v->add_piece(CHANCELLOR, 'c'); + v->startFen = "rbbqkbbr/pppppppp/8/8/8/8/PPPPPPPP/RNNCKNNR w KQkq - 0 1"; + v->promotionPieceTypes = {QUEEN, CHANCELLOR, ROOK, BISHOP, KNIGHT}; + return v; + } + Variant* shatar_variant() { + Variant* v = chess_variant(); + v->remove_piece(QUEEN); + v->add_piece(BERS, 'j'); + v->startFen = "rnbjkbnr/ppp1pppp/8/3p4/3P4/8/PPP1PPPP/RNBJKBNR w - - 0 1"; + v->promotionPieceTypes = {BERS}; + v->doubleStep = false; + v->castling = false; + v->bareKingValue = VALUE_DRAW; // Robado + v->shatarMateRule = true; + return v; + } + Variant* clobber_variant() { + Variant* v = fairy_variant_base(); + v->maxRank = RANK_6; + v->maxFile = FILE_E; + v->reset_pieces(); + v->add_piece(CLOBBER_PIECE, 'p'); + v->startFen = "PpPpP/pPpPp/PpPpP/pPpPp/PpPpP/pPpPp w 0 1"; + v->promotionPieceTypes = {}; + v->doubleStep = false; + v->castling = false; + v->stalemateValue = -VALUE_MATE; + v->immobilityIllegal = false; + return v; + } + Variant* breakthrough_variant() { + Variant* v = fairy_variant_base(); + v->reset_pieces(); + v->add_piece(BREAKTHROUGH_PIECE, 'p'); + v->startFen = "pppppppp/pppppppp/8/8/8/8/PPPPPPPP/PPPPPPPP w 0 1"; + v->promotionPieceTypes = {}; + v->firstRankDoubleSteps = false; + v->castling = false; + v->stalemateValue = -VALUE_MATE; + v->flagPiece = BREAKTHROUGH_PIECE; + v->whiteFlag = Rank8BB; + v->blackFlag = Rank1BB; + return v; + } + Variant* connect4_variant() { + Variant* v = fairy_variant_base(); + v->maxRank = RANK_6; + v->maxFile = FILE_G; + v->reset_pieces(); + v->add_piece(IMMOBILE_PIECE, 'p'); + v->startFen = "7/7/7/7/7/7[PPPPPPPPPPPPPPPPPPPPPppppppppppppppppppppp] w 0 1"; + v->pieceDrops = true; + v->dropOnTop = true; + v->promotionPieceTypes = {}; + v->doubleStep = false; + v->castling = false; + v->stalemateValue = VALUE_DRAW; + v->immobilityIllegal = false; + v->connectN = 4; + return v; + } + Variant* tictactoe_variant() { + Variant* v = fairy_variant_base(); + v->maxRank = RANK_3; + v->maxFile = FILE_C; + v->reset_pieces(); + v->add_piece(IMMOBILE_PIECE, 'p'); + v->startFen = "3/3/3[PPPPPpppp] w 0 1"; + v->pieceDrops = true; + v->promotionPieceTypes = {}; + v->doubleStep = false; + v->castling = false; + v->stalemateValue = VALUE_DRAW; + v->immobilityIllegal = false; + v->connectN = 3; + return v; + } +#ifdef LARGEBOARDS + Variant* shogi_variant() { + Variant* v = minishogi_variant_base(); + v->maxRank = RANK_9; + v->maxFile = FILE_I; + v->add_piece(LANCE, 'l'); + v->add_piece(SHOGI_KNIGHT, 'n'); + v->startFen = "lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL[-] w 0 1"; + v->promotionRank = RANK_7; + v->promotedPieceType[LANCE] = GOLD; + v->promotedPieceType[SHOGI_KNIGHT] = GOLD; + return v; + } + Variant* capablanca_variant() { + Variant* v = fairy_variant_base(); + v->maxRank = RANK_8; + v->maxFile = FILE_J; + v->castlingKingsideFile = FILE_I; + v->castlingQueensideFile = FILE_C; + v->add_piece(ARCHBISHOP, 'a'); + v->add_piece(CHANCELLOR, 'c'); + v->startFen = "rnabqkbcnr/pppppppppp/10/10/10/10/PPPPPPPPPP/RNABQKBCNR w KQkq - 0 1"; + v->promotionPieceTypes = {ARCHBISHOP, CHANCELLOR, QUEEN, ROOK, BISHOP, KNIGHT}; + return v; + } + Variant* janus_variant() { + Variant* v = fairy_variant_base(); + v->maxRank = RANK_8; + v->maxFile = FILE_J; + v->castlingKingsideFile = FILE_I; + v->castlingQueensideFile = FILE_B; + v->add_piece(ARCHBISHOP, 'j'); + v->startFen = "rjnbkqbnjr/pppppppppp/10/10/10/10/PPPPPPPPPP/RJNBKQBNJR w KQkq - 0 1"; + v->promotionPieceTypes = {ARCHBISHOP, QUEEN, ROOK, BISHOP, KNIGHT}; + return v; + } + Variant* embassy_variant() { + Variant* v = capablanca_variant(); + v->castlingKingsideFile = FILE_H; + v->castlingQueensideFile = FILE_B; + v->startFen = "rnbqkcabnr/pppppppppp/10/10/10/10/PPPPPPPPPP/RNBQKCABNR w KQkq - 0 1"; + return v; + } + Variant* jesonmor_variant() { + Variant* v = fairy_variant_base(); + v->maxRank = RANK_9; + v->maxFile = FILE_I; + v->reset_pieces(); + v->add_piece(KNIGHT, 'n'); + v->startFen = "nnnnnnnnn/9/9/9/9/9/9/9/NNNNNNNNN w - - 0 1"; + v->promotionPieceTypes = {}; + v->doubleStep = false; + v->castling = false; + v->stalemateValue = -VALUE_MATE; + v->flagPiece = KNIGHT; + v->whiteFlag = make_bitboard(SQ_E5); + v->blackFlag = make_bitboard(SQ_E5); + v->flagMove = true; + return v; + } + Variant* courier_variant() { + Variant* v = fairy_variant_base(); + v->maxRank = RANK_8; + v->maxFile = FILE_L; + v->remove_piece(QUEEN); + v->add_piece(ALFIL, 'e'); + v->add_piece(FERS, 'f'); + v->add_piece(COMMONER, 'm'); + v->add_piece(WAZIR, 'w'); + v->startFen = "rnebmk1wbenr/1ppppp1pppp1/6f5/p5p4p/P5P4P/6F5/1PPPPP1PPPP1/RNEBMK1WBENR w - - 0 1"; + v->promotionPieceTypes = {FERS}; + v->doubleStep = false; + v->castling = false; + v->bareKingValue = -VALUE_MATE; + v->bareKingMove = true; + v->stalemateValue = -VALUE_MATE; + return v; + } + Variant* clobber10_variant() { + Variant* v = clobber_variant(); + v->maxRank = RANK_10; + v->maxFile = FILE_J; + v->startFen = "PpPpPpPpPp/pPpPpPpPpP/PpPpPpPpPp/pPpPpPpPpP/PpPpPpPpPp/" + "pPpPpPpPpP/PpPpPpPpPp/pPpPpPpPpP/PpPpPpPpPp/pPpPpPpPpP w 0 1"; + return v; + } +#endif + + +void VariantMap::init() { + // Add to UCI_Variant option + add("chess", chess_variant()); + add("standard", chess_variant()); + add("fairy", fairy_variant()); // fairy variant used for endgame code initialization + add("makruk", makruk_variant()); + add("asean", asean_variant()); + add("ai-wok", aiwok_variant()); + add("shatranj", shatranj_variant()); + add("amazon", amazon_variant()); + add("hoppelpoppel", hoppelpoppel_variant()); + add("kingofthehill", kingofthehill_variant()); + add("racingkings", racingkings_variant()); + add("losers", losers_variant()); + add("giveaway", giveaway_variant()); + add("antichess", antichess_variant()); + add("codrus", codrus_variant()); + add("extinction", extinction_variant()); + add("kinglet", kinglet_variant()); + add("horde", horde_variant()); + add("3check", threecheck_variant()); + add("5check", fivecheck_variant()); + add("crazyhouse", crazyhouse_variant()); + add("loop", loop_variant()); + add("chessgi", chessgi_variant()); + add("pocketknight", pocketknight_variant()); + add("placement", placement_variant()); + add("sittuyin", sittuyin_variant()); + add("minishogi", minishogi_variant()); + add("mini", minishogi_variant()); + add("kyotoshogi", kyotoshogi_variant()); + add("micro", microshogi_variant()); + add("dobutsu", dobutsu_variant()); + add("gorogoro", gorogoroshogi_variant()); + add("judkins", judkinsshogi_variant()); + add("euroshogi", euroshogi_variant()); + add("losalamos", losalamos_variant()); + add("almost", almost_variant()); + add("chigorin", chigorin_variant()); + add("shatar", shatar_variant()); + add("clobber", clobber_variant()); + add("breakthrough", breakthrough_variant()); + add("connect4", connect4_variant()); + add("tictactoe", tictactoe_variant()); +#ifdef LARGEBOARDS + add("shogi", shogi_variant()); + add("capablanca", capablanca_variant()); + add("janus", janus_variant()); + add("embassy", embassy_variant()); + add("jesonmor", jesonmor_variant()); + add("courier", courier_variant()); + add("clobber10", clobber10_variant()); +#endif +} + +void VariantMap::add(std::string s, const Variant* v) { + insert(std::pair(s, v)); +} + +void VariantMap::clear_all() { + for (auto const& element : *this) + delete element.second; + clear(); +} + +std::vector VariantMap::get_keys() { + std::vector keys; + for (auto const& element : *this) + keys.push_back(element.first); + return keys; +} diff --cc src/variant.h index 85abe9d,0000000..ed3b17c mode 100644,000000..100644 --- a/src/variant.h +++ b/src/variant.h @@@ -1,121 -1,0 +1,121 @@@ +/* + Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish - Copyright (C) 2018 Fabian Fichter ++ Copyright (C) 2018-2019 Fabian Fichter + + Fairy-Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Fairy-Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef VARIANT_H_INCLUDED +#define VARIANT_H_INCLUDED + +#include +#include +#include +#include +#include + +#include "types.h" +#include "bitboard.h" + + +/// Variant struct stores information needed to determine the rules of a variant. + +struct Variant { + std::string variantTemplate = "fairy"; + int pocketSize = 0; + Rank maxRank = RANK_8; + File maxFile = FILE_H; + std::set pieceTypes = { PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING }; + std::string pieceToChar = " PNBRQ" + std::string(KING - QUEEN - 1, ' ') + "K" + std::string(PIECE_TYPE_NB - KING - 1, ' ') + + " pnbrq" + std::string(KING - QUEEN - 1, ' ') + "k" + std::string(PIECE_TYPE_NB - KING - 1, ' '); + std::string startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; + Rank promotionRank = RANK_8; + std::set > promotionPieceTypes = { QUEEN, ROOK, BISHOP, KNIGHT }; + bool sittuyinPromotion = false; + PieceType promotedPieceType[PIECE_TYPE_NB] = {}; + bool piecePromotionOnCapture = false; + bool mandatoryPiecePromotion = false; + bool pieceDemotion = false; + bool endgameEval = false; + bool doubleStep = true; + bool firstRankDoubleSteps = false; + bool castling = true; + bool castlingDroppedPiece = false; + File castlingKingsideFile = FILE_G; + File castlingQueensideFile = FILE_C; + bool checking = true; + bool mustCapture = false; + bool mustDrop = false; + bool pieceDrops = false; + bool dropLoop = false; + bool capturesToHand = false; + bool firstRankDrops = false; + bool dropOnTop = false; + Bitboard whiteDropRegion = AllSquares; + Bitboard blackDropRegion = AllSquares; + bool sittuyinRookDrop = false; + bool dropOppositeColoredBishop = false; + bool dropPromoted = false; + bool shogiDoubledPawn = true; + bool immobilityIllegal = false; + // game end + int nMoveRule = 50; + int nFoldRule = 3; + Value nFoldValue = VALUE_DRAW; + bool nFoldValueAbsolute = false; + bool perpetualCheckIllegal = false; + Value stalemateValue = VALUE_DRAW; + Value checkmateValue = -VALUE_MATE; + bool shogiPawnDropMateIllegal = false; + bool shatarMateRule = false; + Value bareKingValue = VALUE_NONE; + Value extinctionValue = VALUE_NONE; + bool bareKingMove = false; + std::set extinctionPieceTypes = {}; + PieceType flagPiece = NO_PIECE_TYPE; + Bitboard whiteFlag = 0; + Bitboard blackFlag = 0; + bool flagMove = false; + CheckCount maxCheckCount = CheckCount(0); + int connectN = 0; + CountingRule countingRule = NO_COUNTING; + + void add_piece(PieceType pt, char c) { + pieceToChar[make_piece(WHITE, pt)] = toupper(c); + pieceToChar[make_piece(BLACK, pt)] = tolower(c); + pieceTypes.insert(pt); + } + + void remove_piece(PieceType pt) { + pieceToChar[make_piece(WHITE, pt)] = ' '; + pieceToChar[make_piece(BLACK, pt)] = ' '; + pieceTypes.erase(pt); + } + + void reset_pieces() { + pieceToChar = std::string(PIECE_NB, ' '); + pieceTypes.clear(); + } +}; + +struct VariantMap : public std::map { + void init(); + void add(std::string s, const Variant* v); + void clear_all(); + std::vector get_keys(); +}; + +extern VariantMap variants; + +#endif // #ifndef VARIANT_H_INCLUDED