Merge official-stockfish/master
authorFabian Fichter <ianfab@users.noreply.github.com>
Sat, 2 Mar 2019 10:07:32 +0000 (11:07 +0100)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sat, 2 Mar 2019 10:14:06 +0000 (11:14 +0100)
bench: 3334755

31 files changed:
1  2 
src/Makefile
src/benchmark.cpp
src/bitbase.cpp
src/bitboard.cpp
src/bitboard.h
src/endgame.cpp
src/endgame.h
src/evaluate.cpp
src/evaluate.h
src/main.cpp
src/material.cpp
src/misc.cpp
src/movegen.cpp
src/movepick.h
src/pawns.cpp
src/position.cpp
src/position.h
src/psqt.cpp
src/search.cpp
src/syzygy/tbprobe.cpp
src/thread.cpp
src/timeman.cpp
src/timeman.h
src/tt.cpp
src/tt.h
src/types.h
src/uci.cpp
src/uci.h
src/ucioption.cpp
src/variant.cpp
src/variant.h

diff --cc src/Makefile
Simple merge
Simple merge
diff --cc src/bitbase.cpp
Simple merge
Simple merge
diff --cc src/bitboard.h
Simple merge
diff --cc src/endgame.cpp
Simple merge
diff --cc src/endgame.h
Simple merge
@@@ -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) },
      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))
diff --cc src/evaluate.h
Simple merge
diff --cc src/main.cpp
Simple merge
Simple merge
diff --cc src/misc.cpp
Simple merge
diff --cc 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<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);
  
diff --cc src/movepick.h
Simple merge
diff --cc 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<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);
  }
Simple merge
diff --cc src/position.h
Simple merge
diff --cc 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
@@@ -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<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);
Simple merge
diff --cc src/thread.cpp
Simple merge
diff --cc src/timeman.cpp
Simple merge
diff --cc src/timeman.h
Simple merge
diff --cc src/tt.cpp
Simple merge
diff --cc src/tt.h
Simple merge
diff --cc src/types.h
@@@ -160,20 -145,6 +160,14 @@@ enum CastlingRight 
    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,
@@@ -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/uci.cpp
Simple merge
diff --cc src/uci.h
Simple merge
@@@ -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
--- /dev/null
@@@ -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 <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;
 +}
diff --cc src/variant.h
index 85abe9d,0000000..ed3b17c
mode 100644,000000..100644
--- /dev/null
@@@ -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 <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