// 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) },
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
// 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<Down>(pos.pieces(Them, SHOGI_PAWN)));
// Initialise attackedBy bitboards for kings and pawns
- attackedBy[Us][KING] = pos.attacks_from<KING>(pos.square<KING>(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<KING>(Us) ? pos.attacks_from<KING>(Us, pos.square<KING>(Us)) : 0;
+ attackedBy[Us][PAWN] = pe->pawn_attacks(Us);
+ attackedBy[Us][SHOGI_PAWN] = shift<Up>(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<KING>(Us) && pos.non_pawn_material(Them) >= RookValueMg + KnightValueMg) || pos.captures_to_hand())
{
kingRing[Us] = attackedBy[Us][KING];
- if (relative_rank(Us, pos.square<KING>(Us)) == RANK_1)
+ if (relative_rank(Us, pos.square<KING>(Us), pos.max_rank()) == RANK_1)
kingRing[Us] |= shift<Up>(kingRing[Us]);
- if (file_of(pos.square<KING>(Us)) == FILE_H)
+ if (file_of(pos.square<KING>(Us)) == pos.max_file())
kingRing[Us] |= shift<WEST>(kingRing[Us]);
else if (file_of(pos.square<KING>(Us)) == FILE_A)
kingRing[Us] |= shift<EAST>(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<Down>(pos.pieces(Them, SHOGI_PAWN))));
kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
}
- else
- kingRing[Us] = kingAttackersCount[Them] = 0;
}
Bitboard kingFlank, weak, b, b1, b2, safe, unsafeChecks;
// King shelter and enemy pawns storm
- Score score = pe->king_safety<Us>(pos, ksq);
+ Score score = pe->king_safety<Us>(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);
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<QUEEN>(Them)
+ - 873 * !(pos.count<QUEEN>(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
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.
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);
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))
// After castling, the rook and king final positions are the same in Chess960
// as they would be in standard chess.
- Square kfrom = pos.count<KING>(us) ? pos.square<KING>(us) : make_square(FILE_E, relative_rank(us, RANK_1, pos.max_rank()));
- Square kfrom = pos.square<KING>(Us);
++ Square kfrom = pos.count<KING>(Us) ? pos.square<KING>(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<ROOK>(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<CASTLING>(kfrom, rfrom);
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];
}
Value bonus = evaluate_shelter<Us>(pos, ksq);
// If we can castle use the bonus after the castling if it is bigger
- if (pos.can_castle(MakeCastling<Us, KING_SIDE>::right))
+ if (pos.can_castle(Us | KING_SIDE))
- bonus = std::max(bonus, evaluate_shelter<Us>(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<Us>(pos, s));
+ }
- if (pos.can_castle(MakeCastling<Us, QUEEN_SIDE>::right))
+ if (pos.can_castle(Us | QUEEN_SIDE))
- bonus = std::max(bonus, evaluate_shelter<Us>(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<Us>(pos, s));
+ }
return make_score(bonus, -16 * minKingPawnDistance);
}
{ 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) },
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
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<CAPTURES>(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;
// 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);
CASTLING_RIGHT_NB = 16
};
- template<Color C, CastlingSide S> 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,
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
};
// 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);
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <string>
+
+#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<std::string, const Variant*>(s, v));
+}
+
+void VariantMap::clear_all() {
+ for (auto const& element : *this)
+ delete element.second;
+ clear();
+}
+
+std::vector<std::string> VariantMap::get_keys() {
+ std::vector<std::string> keys;
+ for (auto const& element : *this)
+ keys.push_back(element.first);
+ return keys;
+}
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef VARIANT_H_INCLUDED
+#define VARIANT_H_INCLUDED
+
+#include <set>
+#include <map>
+#include <vector>
+#include <string>
+#include <functional>
+
+#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<PieceType> 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<PieceType, std::greater<PieceType> > 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<PieceType> 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<std::string, const Variant*> {
+ void init();
+ void add(std::string s, const Variant* v);
+ void clear_all();
+ std::vector<std::string> get_keys();
+};
+
+extern VariantMap variants;
+
+#endif // #ifndef VARIANT_H_INCLUDED