Merge official-stockfish/master
authorFabian Fichter <ianfab@users.noreply.github.com>
Fri, 8 Mar 2019 21:43:44 +0000 (22:43 +0100)
committerFabian Fichter <ianfab@users.noreply.github.com>
Fri, 8 Mar 2019 21:43:44 +0000 (22:43 +0100)
bench: 3428840

17 files changed:
1  2 
.travis.yml
Readme.md
appveyor.yml
src/bitboard.h
src/endgame.cpp
src/evaluate.cpp
src/evaluate.h
src/misc.cpp
src/movegen.cpp
src/pawns.cpp
src/position.cpp
src/position.h
src/psqt.cpp
src/search.cpp
src/syzygy/tbprobe.cpp
src/thread.cpp
src/tt.cpp

diff --cc .travis.yml
@@@ -34,9 -34,13 +34,9 @@@ matrix
      - os: osx
        compiler: clang
        env:
-         - COMPILER=clang++ V='Apple LLVM 6.0' # Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
+         - COMPILER=clang++ V='Apple LLVM 9.4.1' # Apple LLVM version 9.1.0 (clang-902.0.39.2)
          - COMP=clang
  
 -branches:
 -  only:
 -   - master
 -
  before_script:
    - cd src
  
diff --cc Readme.md
+++ b/Readme.md
@@@ -1,62 -1,17 +1,55 @@@
 -## Overview
 -
 -[![Build Status](https://travis-ci.org/official-stockfish/Stockfish.svg?branch=master)](https://travis-ci.org/official-stockfish/Stockfish)
 -[![Build Status](https://ci.appveyor.com/api/projects/status/github/official-stockfish/Stockfish?svg=true)](https://ci.appveyor.com/project/mcostalba/stockfish)
 +## Fairy-Stockfish
 +
 +[![Build Status](https://travis-ci.org/ianfab/Fairy-Stockfish.svg?branch=master)](https://travis-ci.org/ianfab/Fairy-Stockfish)
 +[![Build Status](https://ci.appveyor.com/api/projects/status/github/ianfab/Fairy-Stockfish?svg=true)](https://ci.appveyor.com/project/ianfab/Fairy-Stockfish)
 +
 +Fairy-Stockfish is a Stockfish fork designed for the support of (fairy) chess variants and to make the addition/configuration of new variants as simple and flexible as possible. The goal of the project is to create an engine supporting a large variety of chess-like games, equipped with the powerful search of Stockfish. It is complementary to Stockfish forks more specialized for certain chess variants, such as [multi-variant Stockfish](https://github.com/ddugovic/Stockfish), [Seirawan-Stockfish](https://github.com/ianfab/Seirawan-Stockfish), [Makruk-Stockfish](https://github.com/ianfab/Makruk-Stockfish), etc., supporting more variants with the tradeoff of slightly lower performance.
 +
 +Besides chess, the currently supported games are:
 +
 +**Regional and historical games**
 +- [Shatranj](https://en.wikipedia.org/wiki/Shatranj), [Courier](https://en.wikipedia.org/wiki/Courier_chess)
 +- [Makruk](https://en.wikipedia.org/wiki/Makruk), [ASEAN](http://hgm.nubati.net/rules/ASEAN.html), Ai-Wok
 +- [Sittuyin](https://en.wikipedia.org/wiki/Sittuyin)
 +- [Shatar](https://en.wikipedia.org/wiki/Shatar), [Jeson Mor](https://en.wikipedia.org/wiki/Jeson_Mor)
 +- [Shogi](https://en.wikipedia.org/wiki/Shogi)
 +
 +**Chess variants**
 +- [Capablanca](https://en.wikipedia.org/wiki/Capablanca_Chess), [Janus](https://en.wikipedia.org/wiki/Janus_Chess), [Embassy](https://en.wikipedia.org/wiki/Embassy_Chess)
 +- [Chess960](https://en.wikipedia.org/wiki/Chess960), [Placement/Pre-Chess](https://www.chessvariants.com/link/placement-chess)
 +- [Crazyhouse](https://en.wikipedia.org/wiki/Crazyhouse), [Loop](https://en.wikipedia.org/wiki/Crazyhouse#Variations), [Chessgi](https://en.wikipedia.org/wiki/Crazyhouse#Variations), [Pocket Knight](http://www.chessvariants.com/other.dir/pocket.html)
 +- [Amazon](https://en.wikipedia.org/wiki/Amazon_(chess)), [Chigorin](https://en.wikipedia.org/wiki/Chigorin_Chess), [Almost chess](https://en.wikipedia.org/wiki/Almost_Chess), [Hoppel-Poppel](http://www.chessvariants.com/diffmove.dir/hoppel-poppel.html)
 +- [Antichess](https://lichess.org/variant/antichess), [Giveaway](http://www.chessvariants.com/diffobjective.dir/giveaway.old.html), [Losers](https://www.chessclub.com/help/Wild17), [Codrus](http://www.binnewirtz.com/Schlagschach1.htm)
 +- [Extinction](https://en.wikipedia.org/wiki/Extinction_chess), [Kinglet](https://en.wikipedia.org/wiki/V._R._Parton#Kinglet_Chess)
 +- [King of the Hill](https://en.wikipedia.org/wiki/King_of_the_Hill_(chess)), [Racing Kings](https://en.wikipedia.org/wiki/V._R._Parton#Racing_Kings)
 +- [Three-check](https://en.wikipedia.org/wiki/Three-check_chess), Five-check
 +- [Los Alamos](https://en.wikipedia.org/wiki/Los_Alamos_chess)
 +- [Horde](https://en.wikipedia.org/wiki/Dunsany%27s_Chess#Horde_Chess)
 +
 +**Shogi variants**
 +- [Minishogi](https://en.wikipedia.org/wiki/Minishogi), [EuroShogi](https://en.wikipedia.org/wiki/EuroShogi), [Judkins shogi](https://en.wikipedia.org/wiki/Judkins_shogi)
 +- [Kyoto shogi](https://en.wikipedia.org/wiki/Kyoto_shogi), [Microshogi](https://en.wikipedia.org/wiki/Micro_shogi)
 +- [Dobutsu shogi](https://en.wikipedia.org/wiki/Dōbutsu_shōgi), [Goro goro shogi](https://en.wikipedia.org/wiki/D%C5%8Dbutsu_sh%C5%8Dgi#Variation)
 +
 +**Related games**
 +- [Breakthrough](https://en.wikipedia.org/wiki/Breakthrough_(board_game))
 +- [Clobber](https://en.wikipedia.org/wiki/Clobber)
 +- [Connect4](https://en.wikipedia.org/wiki/Connect_Four), [Tic-Tac-Toe](https://en.wikipedia.org/wiki/Tic-tac-toe)
 +
 +See the [Fairy-Stockfish Wiki](https://github.com/ianfab/Fairy-Stockfish/wiki) for more info.
 +
 +## Stockfish
 +### Overview
  
- Stockfish is a free UCI chess engine derived from Glaurung 2.1. It is
- not a complete chess program and requires some UCI-compatible GUI
- (e.g. XBoard with PolyGlot, eboard, Arena, Sigma Chess, Shredder, Chess
- Partner or Fritz) in order to be used comfortably. Read the
- documentation for your GUI of choice for information about how to use
+ [Stockfish](https://stockfishchess.org) is a free, powerful UCI chess engine
+ derived from Glaurung 2.1. It is not a complete chess program and requires a
+ UCI-compatible GUI (e.g. XBoard with PolyGlot, Scid, Cute Chess, eboard, Arena,
+ Sigma Chess, Shredder, Chess Partner or Fritz) in order to be used comfortably.
+ Read the documentation for your GUI of choice for information about how to use
  Stockfish with it.
  
- This version of Stockfish supports up to 512 cores. The engine defaults
- to one search thread, so it is therefore recommended to inspect the value of
- the *Threads* UCI parameter, and to make sure it equals the number of CPU
- cores on your computer.
  
- This version of Stockfish has support for Syzygybases.
- ### Files
+ ## Files
  
  This distribution of Stockfish consists of the following files:
  
diff --cc appveyor.yml
Simple merge
diff --cc src/bitboard.h
@@@ -178,15 -135,7 +178,14 @@@ constexpr bool more_than_one(Bitboard b
    return b & (b - 1);
  }
  
 +/// board_size_bb() returns a bitboard representing all the squares
 +/// on a board with given size.
 +
 +inline Bitboard board_size_bb(File f, Rank r) {
 +  return BoardSizeBB[f][r];
 +}
 +
  inline bool opposite_colors(Square s1, Square s2) {
    return bool(DarkSquares & s1) != bool(DarkSquares & s2);
  }
  
diff --cc src/endgame.cpp
@@@ -45,32 -45,19 +45,32 @@@ namespace 
    // Table used to drive the king towards a corner square of the
    // right color in KBN vs K endgames.
    constexpr int PushToCorners[SQUARE_NB] = {
-     200, 190, 180, 170, 160, 150, 140, 130,
-     190, 180, 170, 160, 150, 140, 130, 140,
-     180, 170, 155, 140, 140, 125, 140, 150,
-     170, 160, 140, 120, 110, 140, 150, 160,
-     160, 150, 140, 110, 120, 140, 160, 170,
-     150, 140, 125, 140, 140, 155, 170, 180,
-     140, 130, 140, 150, 160, 170, 180, 190,
-     130, 140, 150, 160, 170, 180, 190, 200
+      6400, 6080, 5760, 5440, 5120, 4800, 4480, 4160,
+      6080, 5760, 5440, 5120, 4800, 4480, 4160, 4480,
+      5760, 5440, 4960, 4480, 4480, 4000, 4480, 4800,
+      5440, 5120, 4480, 3840, 3520, 4480, 4800, 5120,
+      5120, 4800, 4480, 3520, 3840, 4480, 5120, 5440,
+      4800, 4480, 4000, 4480, 4480, 4960, 5440, 5760,
+      4480, 4160, 4480, 4800, 5120, 5440, 5760, 6080,
+      4160, 4480, 4800, 5120, 5440, 5760, 6080, 6400
    };
  
 +  // Table used to drive the king towards the edge of the board
 +  // in KSF vs K.
 +  constexpr int PushToOpposingSideEdges[SQUARE_NB] = {
 +     30, 10,  5,  0,  0,  5, 10,  30,
 +     40, 20,  5,  0,  0,  5, 20,  40,
 +     50, 30, 10,  0,  0, 10, 30,  50,
 +     60, 40, 20, 10, 10, 20, 40,  60,
 +     70, 50, 30, 20, 20, 30, 50,  70,
 +     80, 60, 40, 30, 30, 40, 60,  80,
 +     90, 70, 60, 50, 50, 60, 70,  90,
 +    100, 90, 80, 70, 70, 80, 90, 100
 +  };
 +
    // Tables used to drive a piece towards or away from another piece
 -  constexpr int PushClose[8] = { 0, 0, 100, 80, 60, 40, 20, 10 };
 -  constexpr int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 };
 +  constexpr int PushClose[FILE_NB] = { 0, 0, 100, 80, 60, 40, 20, 10 };
 +  constexpr int PushAway [FILE_NB] = { 0, 5, 20, 40, 60, 80, 90, 100 };
  
    // Pawn Rank based scaling factors used in KRPPKRP endgame
    constexpr int KRPPKRPScaleFactors[RANK_NB] = { 0, 9, 10, 14, 21, 44, 0, 0 };
@@@ -157,29 -151,26 +157,29 @@@ namespace 
      S(-30,-14), S(-9, -8), S( 0,  9), S( -1,  7)
    };
  
 +  // KingProximity contains a penalty according to distance from king
 +  constexpr Score KingProximity = S(2, 2);
 +
    // Assorted bonuses and penalties
-   constexpr Score BishopPawns        = S(  3,  8);
-   constexpr Score CloseEnemies       = S(  7,  0);
+   constexpr Score BishopPawns        = S(  3,  7);
+   constexpr Score CloseEnemies       = S(  8,  0);
    constexpr Score CorneredBishop     = S( 50, 50);
-   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 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);
+   constexpr Score Hanging            = S( 69, 36);
+   constexpr Score KingProtector      = S(  7,  8);
+   constexpr Score KnightOnQueen      = S( 16, 12);
+   constexpr Score LongDiagonalBishop = S( 45,  0);
+   constexpr Score MinorBehindPawn    = S( 18,  3);
+   constexpr Score PawnlessFlank      = S( 17, 95);
+   constexpr Score RestrictedPiece    = S(  7,  7);
+   constexpr Score RookOnPawn         = S( 10, 32);
+   constexpr Score SliderOnQueen      = S( 59, 18);
+   constexpr Score ThreatByKing       = S( 24, 89);
+   constexpr Score ThreatByPawnPush   = S( 48, 39);
+   constexpr Score ThreatByRank       = S( 13,  0);
+   constexpr Score ThreatBySafePawn   = S(173, 94);
+   constexpr Score TrappedRook        = S( 96,  4);
+   constexpr Score WeakQueen          = S( 49, 15);
+   constexpr Score WeakUnopposedPawn  = S( 12, 23);
  
  #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
+     kingRing[Us] = attackedBy[Us][KING];
 -    if (relative_rank(Us, pos.square<KING>(Us)) == RANK_1)
++    if (pos.count<KING>(Us) && relative_rank(Us, pos.square<KING>(Us), pos.max_rank()) == RANK_1)
+         kingRing[Us] |= shift<Up>(kingRing[Us]);
  
-     // Init our king safety tables only if we are going to use them
-     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), pos.max_rank()) == RANK_1)
-             kingRing[Us] |= shift<Up>(kingRing[Us]);
-         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]);
 -    if (file_of(pos.square<KING>(Us)) == FILE_H)
++    if (pos.count<KING>(Us) && file_of(pos.square<KING>(Us)) == pos.max_file())
+         kingRing[Us] |= shift<WEST>(kingRing[Us]);
  
-         kingRing[Us] &= pos.board_bb();
 -    else if (file_of(pos.square<KING>(Us)) == FILE_A)
++    else if (pos.count<KING>(Us) && file_of(pos.square<KING>(Us)) == FILE_A)
+         kingRing[Us] |= shift<EAST>(kingRing[Us]);
  
-         kingAttackersCount[Them] = popcount(kingRing[Us] & (pe->pawn_attacks(Them) | shift<Down>(pos.pieces(Them, SHOGI_PAWN))));
-         kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
-     }
+     kingAttackersCount[Them] = popcount(kingRing[Us] & pe->pawn_attacks(Them));
+     kingRing[Us] &= ~double_pawn_attacks_bb<Us>(pos.pieces(Us, PAWN));
+     kingAttacksCount[Them] = kingAttackersWeight[Them] = 0;
++    kingRing[Us] &= pos.board_bb();
    }
  
  
          attackedBy[Us][Pt] |= b;
          attackedBy[Us][ALL_PIECES] |= b;
  
-         if (b & kingRing[Them] & ~double_pawn_attacks_bb<Them>(pos.pieces(Them, PAWN)))
+         if (b & kingRing[Them])
          {
              kingAttackersCount[Us]++;
 -            kingAttackersWeight[Us] += KingAttackWeights[Pt];
 +            kingAttackersWeight[Us] += KingAttackWeights[std::min(int(Pt), QUEEN + 1)];
              kingAttacksCount[Us] += popcount(b & attackedBy[Them][KING]);
          }
  
      int tropism = popcount(b1) + popcount(b2);
  
      // Main king safety evaluation
-     if ((kingAttackersCount[Them] > 1 - pos.count<QUEEN>(Them)) || pos.captures_to_hand())
+     int kingDanger = 0;
+     unsafeChecks = 0;
+     // Attacked squares defended at most once by our queen or king
+     weak =  attackedBy[Them][ALL_PIECES]
+           & ~attackedBy2[Us]
+           & (~attackedBy[Us][ALL_PIECES] | attackedBy[Us][KING] | attackedBy[Us][QUEEN]);
+     // Analyse the safe enemy's checks which are possible on next move
+     safe  = ~pos.pieces(Them);
+     safe &= ~attackedBy[Us][ALL_PIECES] | (weak & attackedBy2[Them]);
 -    b1 = attacks_bb<ROOK  >(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
 -    b2 = attacks_bb<BISHOP>(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN));
 -
 -    // Enemy queen safe checks
 -    if ((b1 | b2) & attackedBy[Them][QUEEN] & safe & ~attackedBy[Us][QUEEN])
 -        kingDanger += QueenSafeCheck;
 -
 -    b1 &= attackedBy[Them][ROOK];
 -    b2 &= attackedBy[Them][BISHOP];
 -
 -    // Enemy rooks checks
 -    if (b1 & safe)
 -        kingDanger += RookSafeCheck;
 -    else
 -        unsafeChecks |= b1;
 -
 -    // Enemy bishops checks
 -    if (b2 & safe)
 -        kingDanger += BishopSafeCheck;
 -    else
 -        unsafeChecks |= b2;
++    std::function <Bitboard (Color, PieceType)> get_attacks = [this](Color c, PieceType pt) {
++        return attackedBy[c][pt] | (pos.captures_to_hand() && pos.count_in_hand(c, pt) ? ~pos.pieces() : 0);
++    };
++    for (PieceType pt : pos.piece_types())
 +    {
-         int kingDanger = 0;
-         unsafeChecks = 0;
-         // Attacked squares defended at most once by our queen or king
-         weak =  attackedBy[Them][ALL_PIECES]
-               & ~attackedBy2[Us]
-               & (~attackedBy[Us][ALL_PIECES] | attackedBy[Us][KING] | attackedBy[Us][QUEEN]);
-         // Analyse the safe enemy's checks which are possible on next move
-         safe  = ~pos.pieces(Them);
-         safe &= ~attackedBy[Us][ALL_PIECES] | (weak & attackedBy2[Them]);
-         std::function <Bitboard (Color, PieceType)> get_attacks = [this](Color c, PieceType pt) {
-             return attackedBy[c][pt] | (pos.captures_to_hand() && pos.count_in_hand(c, pt) ? ~pos.pieces() : 0);
-         };
-         for (PieceType pt : pos.piece_types())
++        switch (pt)
 +        {
-             switch (pt)
++        case QUEEN:
++            b = attacks_bb(Us, pt, ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)) & get_attacks(Them, pt) & safe & ~attackedBy[Us][QUEEN] & pos.board_bb();
++            if (b)
++                kingDanger += QueenSafeCheck;
++            break;
++        case ROOK:
++        case BISHOP:
++        case KNIGHT:
++            b = attacks_bb(Us, pt, ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)) & get_attacks(Them, pt) & pos.board_bb();
++            if (b & safe)
++                kingDanger +=  pt == ROOK   ? RookSafeCheck
++                                : pt == BISHOP ? BishopSafeCheck
++                                            : KnightSafeCheck;
++            else
++                unsafeChecks |= b;
++            break;
++        case PAWN:
++            if (pos.captures_to_hand() && pos.count_in_hand(Them, pt))
 +            {
-             case QUEEN:
-                 b = attacks_bb(Us, pt, ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)) & get_attacks(Them, pt) & safe & ~attackedBy[Us][QUEEN] & pos.board_bb();
-                 if (b)
-                     kingDanger += QueenSafeCheck;
-                 break;
-             case ROOK:
-             case BISHOP:
-             case KNIGHT:
-                 b = attacks_bb(Us, pt, ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)) & get_attacks(Them, pt) & pos.board_bb();
-                 if (b & safe)
-                     kingDanger +=  pt == ROOK   ? RookSafeCheck
-                                  : pt == BISHOP ? BishopSafeCheck
-                                                 : KnightSafeCheck;
-                 else
-                     unsafeChecks |= b;
-                 break;
-             case PAWN:
-                 if (pos.captures_to_hand() && pos.count_in_hand(Them, pt))
-                 {
-                     b = attacks_bb(Us, pt, ksq, pos.pieces()) & ~pos.pieces() & pos.board_bb();
-                     if (b & safe)
-                         kingDanger += OtherSafeCheck;
-                     else
-                         unsafeChecks |= b;
-                 }
-                 break;
-             case SHOGI_PAWN:
-             case KING:
-                 break;
-             default:
-                 b = attacks_bb(Us, pt, ksq, pos.pieces()) & get_attacks(Them, pt) & pos.board_bb();
++                b = attacks_bb(Us, pt, ksq, pos.pieces()) & ~pos.pieces() & pos.board_bb();
 +                if (b & safe)
 +                    kingDanger += OtherSafeCheck;
 +                else
 +                    unsafeChecks |= b;
 +            }
++            break;
++        case SHOGI_PAWN:
++        case KING:
++            break;
++        default:
++            b = attacks_bb(Us, pt, ksq, pos.pieces()) & get_attacks(Them, pt) & pos.board_bb();
++            if (b & safe)
++                kingDanger += OtherSafeCheck;
++            else
++                unsafeChecks |= b;
 +        }
-         if (pos.max_check_count())
-             kingDanger *= 2;
-         // Unsafe or occupied checking squares will also be considered, as long as
-         // the square is in the attacker's mobility area.
-         unsafeChecks &= mobilityArea[Them];
-         kingDanger +=        kingAttackersCount[Them] * kingAttackersWeight[Them]
-                      + 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)
-                      +       tropism * tropism / 4
-                      - 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)
-             score -= make_score(std::min(kingDanger * kingDanger / 4096, 3000), kingDanger / 16);
 +    }
  
 -    // Enemy knights checks
 -    b = pos.attacks_from<KNIGHT>(ksq) & attackedBy[Them][KNIGHT];
 -    if (b & safe)
 -        kingDanger += KnightSafeCheck;
 -    else
 -        unsafeChecks |= b;
++    if (pos.max_check_count())
++        kingDanger *= 2;
+     // Unsafe or occupied checking squares will also be considered, as long as
+     // the square is in the attacker's mobility area.
+     unsafeChecks &= mobilityArea[Them];
+     kingDanger +=        kingAttackersCount[Them] * kingAttackersWeight[Them]
 -                 +  69 * kingAttacksCount[Them]
 -                 + 185 * popcount(kingRing[Us] & weak)
 -                 + 150 * popcount(pos.blockers_for_king(Us) | unsafeChecks)
 -                 +       tropism * tropism / 4
 -                 - 873 * !pos.count<QUEEN>(Them)
 -                 -   6 * mg_value(score) / 8
 -                 +       mg_value(mobility[Them] - mobility[Us])
 -                 -   30;
++                    + 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)
++                    +       tropism * tropism / 4
++                    - 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)
 -        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
      if (!(pos.pieces(PAWN) & kingFlank))
          score -= PawnlessFlank;
      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, SHOGI_PAWN);
 -    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.
--    stronglyProtected =  attackedBy[Them][PAWN]
++    stronglyProtected =  (attackedBy[Them][PAWN] | attackedBy[Them][SHOGI_PAWN])
                         | (attackedBy2[Them] & ~attackedBy2[Us]);
  
      // Non-pawn enemies, strongly protected
diff --cc src/evaluate.h
Simple merge
diff --cc src/misc.cpp
Simple merge
diff --cc src/movegen.cpp
@@@ -355,7 -277,7 +355,7 @@@ namespace 
              *moveList++ = make_move(ksq, pop_lsb(&b));
      }
  
-     if (pos.castling_enabled() && Type != CAPTURES && Type != EVASIONS && pos.can_castle(Us))
 -    if (Type != CAPTURES && Type != EVASIONS && pos.castling_rights(Us))
++    if (pos.castling_enabled() && Type != CAPTURES && Type != EVASIONS && pos.castling_rights(Us))
      {
          if (pos.is_chess960())
          {
diff --cc src/pawns.cpp
@@@ -97,12 -97,12 +97,12 @@@ namespace 
          // Flag the pawn
          opposed    = theirPawns & forward_file_bb(Us, s);
          stoppers   = theirPawns & passed_pawn_mask(Us, s);
 -        lever      = theirPawns & PawnAttacks[Us][s];
 -        leverPush  = theirPawns & PawnAttacks[Us][s + Up];
 -        doubled    = ourPawns   & (s - Up);
 +        lever      = theirPawns & PseudoAttacks[Us][PAWN][s];
 +        leverPush  = relative_rank(Them, s, pos.max_rank()) > RANK_1 ? theirPawns & PseudoAttacks[Us][PAWN][s + Up] : 0;
 +        doubled    = relative_rank(Us, s, pos.max_rank()) > RANK_1 ? ourPawns & (s - Up) : 0;
          neighbours = ourPawns   & adjacent_files_bb(f);
          phalanx    = neighbours & rank_bb(s);
-         supported  = relative_rank(Us, s, pos.max_rank()) > RANK_1 ? neighbours & rank_bb(s - Up) : 0;
 -        support    = neighbours & rank_bb(s - Up);
++        support    = relative_rank(Us, s, pos.max_rank()) > RANK_1 ? neighbours & rank_bb(s - Up) : 0;
  
          // A pawn is backward when it is behind all pawns of the same color
          // on the adjacent files and cannot be safely advanced.
              && popcount(phalanx)   >= popcount(leverPush))
              e->passedPawns[Us] |= s;
  
 -        else if (   stoppers == SquareBB[s + Up]
 -                 && relative_rank(Us, s) >= RANK_5)
 +        else if (   relative_rank(Them, s, pos.max_rank()) > RANK_1
 +                 && stoppers == SquareBB[s + Up]
 +                 && relative_rank(Us, s, pos.max_rank()) >= RANK_5)
          {
-             b = shift<Up>(supported) & ~theirPawns;
+             b = shift<Up>(support) & ~theirPawns;
              while (b)
 -                if (!more_than_one(theirPawns & PawnAttacks[Us][pop_lsb(&b)]))
 +                if (!more_than_one(theirPawns & PseudoAttacks[Us][PAWN][pop_lsb(&b)]))
                      e->passedPawns[Us] |= s;
          }
  
          // Score this pawn
-         if (supported | phalanx)
-             score += Connected[opposed][bool(phalanx)][popcount(supported)][relative_rank(Us, s, pos.max_rank())];
+         if (support | phalanx)
 -            score += Connected[opposed][bool(phalanx)][popcount(support)][relative_rank(Us, s)];
++            score += Connected[opposed][bool(phalanx)][popcount(support)][relative_rank(Us, s, pos.max_rank())];
  
          else if (!neighbours)
 -            score -= Isolated, e->weakUnopposed[Us] += !opposed;
 +            score -= Isolated * (1 + 2 * pos.must_capture()), e->weakUnopposed[Us] += !opposed;
  
          else if (backward)
              score -= Backward, e->weakUnopposed[Us] += !opposed;
@@@ -241,14 -214,13 +241,14 @@@ 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), pos.max_rank()) : 0;
 -      Rank ourRank = b ? relative_rank(Us, backmost_sq(Us, b)) : RANK_1;
++      Rank ourRank = b ? relative_rank(Us, backmost_sq(Us, b), pos.max_rank()) : RANK_1;
  
        b = theirPawns & file_bb(f);
-       int theirRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : 0;
 -      Rank theirRank = b ? relative_rank(Us, frontmost_sq(Them, b)) : RANK_1;
++      Rank theirRank = b ? relative_rank(Us, frontmost_sq(Them, b), pos.max_rank()) : RANK_1;
  
 -      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)) ? 66 * (theirRank == RANK_3)
                                                          : UnblockedStorm[d][theirRank];
    }
@@@ -627,21 -476,11 +627,21 @@@ const string Position::fen() const 
    if (can_castle(BLACK_OOO))
        ss << (chess960 ? char('a' + file_of(castling_rook_square(BLACK | QUEEN_SIDE))) : 'q');
  
-   if (!can_castle(WHITE) && !can_castle(BLACK))
+   if (!can_castle(ANY_CASTLING))
        ss << '-';
  
 -  ss << (ep_square() == SQ_NONE ? " - " : " " + UCI::square(ep_square()) + " ")
 -     << st->rule50 << " " << 1 + (gamePly - (sideToMove == BLACK)) / 2;
 +  // check count
 +  if (max_check_count())
 +      ss << " " << (max_check_count() - st->checksGiven[WHITE]) << "+" << (max_check_count() - st->checksGiven[BLACK]);
 +
 +  // Counting limit and counting ply, or ep-square and 50-move rule counter
 +  if (st->countingLimit)
 +      ss << " " << st->countingLimit << " " << st->countingPly;
 +  else
 +      ss << (ep_square() == SQ_NONE ? " - " : " " + UCI::square(*this, ep_square()) + " ")
 +         << st->rule50;
 +
 +  ss << " " << 1 + (gamePly - (sideToMove == BLACK)) / 2;
  
    return ss.str();
  }
diff --cc src/position.h
Simple merge
diff --cc src/psqt.cpp
@@@ -44,17 -35,9 +44,9 @@@ namespace PSQT 
  // type on a given square a (middlegame, endgame) score pair is assigned. Table
  // is defined for files A..D and white side: it is symmetric for black side and
  // second half of the files.
 -constexpr Score Bonus[][RANK_NB][int(FILE_NB) / 2] = {
 +constexpr Score Bonus[PIECE_TYPE_NB][RANK_NB][int(FILE_NB) / 2] = {
    { },
-   { // Pawn
-    { S(  0, 0), S(  0,  0), S(  0, 0), S( 0, 0) },
-    { S(-11,-3), S(  7, -1), S(  7, 7), S(17, 2) },
-    { S(-16,-2), S( -3,  2), S( 23, 6), S(23,-1) },
-    { S(-14, 7), S( -7, -4), S( 20,-8), S(24, 2) },
-    { S( -5,13), S( -2, 10), S( -1,-1), S(12,-8) },
-    { S(-11,16), S(-12,  6), S( -2, 1), S( 4,16) },
-    { S( -2, 1), S( 20,-12), S(-10, 6), S(-2,25) }
-   },
+   { },
    { // Knight
     { S(-169,-105), S(-96,-74), S(-80,-46), S(-79,-18) },
     { S( -79, -70), S(-39,-56), S(-24,-15), S( -9,  6) },
@@@ -106,11 -87,23 +98,22 @@@ constexpr Score KingBonus[RANK_NB][int(
     { S(122, 87), S(159,164), S(85, 174), S(36, 189) },
     { S(87,  40), S(120, 99), S(64, 128), S(25, 141) },
     { S(64,   5), S(87,  60), S(49,  75), S(0,   75) }
 -  }
  };
  
 -constexpr Score PBonus[RANK_NB][FILE_NB] =\r
 -  { // Pawn\r
 -   { S(  0,  0), S(  0,  0), S(  0,  0), S(  0,  0), S(  0,  0), S(  0,  0), S(  0,  0), S(  0,  0) },\r
 -   { S(  0,-11), S( -3, -4), S( 13, -1), S( 19, -4), S( 16, 17), S( 13,  7), S(  4,  4), S( -4,-13) },\r
 -   { S(-16, -8), S(-12, -6), S( 20, -3), S( 21,  0), S( 25,-11), S( 29,  3), S(  0,  0), S(-27, -1) },\r
 -   { S(-11,  3), S(-17,  6), S( 11,-10), S( 21,  1), S( 32, -6), S( 19,-11), S( -5,  0), S(-14, -2) },\r
 -   { S(  4, 13), S(  6,  7), S( -8,  3), S(  3, -5), S(  8,-15), S( -2, -1), S(-19,  9), S( -5, 13) },\r
 -   { S( -5, 25), S(-19, 20), S(  7, 16), S(  8, 12), S( -7, 21), S( -2,  3), S(-10, -4), S(-16, 15) },\r
 -   { S(-10,  6), S(  9, -5), S( -7, 16), S(-12, 27), S( -7, 15), S( -8, 11), S( 16, -7), S( -8,  4) }\r
++constexpr Score PBonus[RANK_NB][FILE_NB] =
++  { // Pawn
++   { S(  0,  0), S(  0,  0), S(  0,  0), S(  0,  0), S(  0,  0), S(  0,  0), S(  0,  0), S(  0,  0) },
++   { S(  0,-11), S( -3, -4), S( 13, -1), S( 19, -4), S( 16, 17), S( 13,  7), S(  4,  4), S( -4,-13) },
++   { S(-16, -8), S(-12, -6), S( 20, -3), S( 21,  0), S( 25,-11), S( 29,  3), S(  0,  0), S(-27, -1) },
++   { S(-11,  3), S(-17,  6), S( 11,-10), S( 21,  1), S( 32, -6), S( 19,-11), S( -5,  0), S(-14, -2) },
++   { S(  4, 13), S(  6,  7), S( -8,  3), S(  3, -5), S(  8,-15), S( -2, -1), S(-19,  9), S( -5, 13) },
++   { S( -5, 25), S(-19, 20), S(  7, 16), S(  8, 12), S( -7, 21), S( -2,  3), S(-10, -4), S(-16, 15) },
++   { S(-10,  6), S(  9, -5), S( -7, 16), S(-12, 27), S( -7, 15), S( -8, 11), S( 16, -7), S( -8,  4) }
+   };
  #undef S
  
 -Score psq[PIECE_NB][SQUARE_NB];
 +Score psq[PIECE_NB][SQUARE_NB + 1];
  
  // init() initializes piece-square tables: the white halves of the tables are
  // copied from Bonus[] adding the piece value, then the black halves of the
@@@ -126,30 -117,13 +129,31 @@@ void init(const Variant* v) 
  
        Score score = make_score(PieceValue[MG][pc], PieceValue[EG][pc]);
  
 -      for (Square s = SQ_A1; s <= SQ_H8; ++s)
 +      // For drop variants, halve the piece values
 +      if (v->capturesToHand || !v->checking)
 +          score = make_score(mg_value(score) * int(MidgameLimit / 2) / (MidgameLimit + mg_value(score)),
 +                             eg_value(score) * int(MidgameLimit / 2) / (MidgameLimit + eg_value(score)));
 +
 +      // For antichess variants, use negative piece values
 +      if (   v->extinctionValue == VALUE_MATE
 +          && v->extinctionPieceTypes.find(ALL_PIECES) != v->extinctionPieceTypes.end())
 +          score = -score / 8;
 +      else if (v->bareKingValue == VALUE_MATE)
 +          score = -score / 8;
 +
 +      for (Square s = SQ_A1; s <= SQ_MAX; ++s)
        {
 -          File f = std::min(file_of(s), ~file_of(s));
 -          psq[ pc][ s] = score + (type_of(pc) == PAWN ? PBonus[rank_of(s)][file_of(s)]
 -                                                      : Bonus[pc][rank_of(s)][f]);
 -          psq[~pc][~s] = -psq[pc][s];
 +          File f = std::max(std::min(file_of(s), File(v->maxFile - file_of(s))), FILE_A);
 +          Rank r = rank_of(s);
-           psq[ pc][ s] = score + (  pt == KING  ? KingBonus[std::min(r, RANK_8)][std::min(f, FILE_D)]
++          psq[ pc][ s] = score + (  pt == PAWN  ? PBonus[std::min(r, RANK_8)][std::min(file_of(s), FILE_H)]
++                                  : pt == KING  ? KingBonus[std::min(r, RANK_8)][std::min(f, FILE_D)]
 +                                  : pt <= QUEEN ? Bonus[pc][std::min(r, RANK_8)][std::min(f, FILE_D)]
 +                                                : make_score(5, 5) * (2 * f + std::max(std::min(r, Rank(v->maxRank - r)), RANK_1) - 8));
 +          psq[~pc][rank_of(s) <= v->maxRank ? relative_square(BLACK, s, v->maxRank) : s] = -psq[pc][s];
        }
 +      // pieces in pocket
 +      psq[ pc][SQ_NONE] = score + make_score(20, 20);
 +      psq[~pc][SQ_NONE] = -psq[pc][SQ_NONE];
    }
  }
  
diff --cc src/search.cpp
@@@ -761,27 -764,18 +769,28 @@@ namespace 
      }
  
      // Step 7. Razoring (~2 Elo)
-     if (   depth < 2 * ONE_PLY
+     if (   !rootNode // The required rootNode PV handling is not available in qsearch
+         &&  depth < 2 * ONE_PLY
 +        && !pos.must_capture()
 +        && !pos.capture_the_flag_piece()
 +        && !pos.max_check_count()
-         && eval <= alpha - RazorMargin)
+         &&  eval <= alpha - RazorMargin)
          return qsearch<NT>(pos, ss, alpha, beta);
  
      improving =   ss->staticEval >= (ss-2)->staticEval
                 || (ss-2)->staticEval == VALUE_NONE;
  
 +    // Skip early pruning in case of mandatory capture
 +    if (pos.must_capture() && MoveList<CAPTURES>(pos).size())
 +        goto moves_loop;
 +
      // Step 8. Futility pruning: child node (~30 Elo)
-     if (   !rootNode
+     if (   !PvNode
          &&  depth < 7 * ONE_PLY
 -        &&  eval - futility_margin(depth, improving) >= beta
 +        && !(   pos.extinction_value() == -VALUE_MATE
 +             && pos.extinction_piece_types().find(ALL_PIECES) == pos.extinction_piece_types().end())
 +        && (pos.checking_permitted() || !pos.capture_the_flag_piece())
 +        &&  eval - futility_margin(depth, improving) * (1 + !!pos.max_check_count()) >= beta
          &&  eval < VALUE_KNOWN_WIN) // Do not return unproven wins
          return eval;
  
      // much above beta, we can (almost) safely prune the previous move.
      if (   !PvNode
          &&  depth >= 5 * ONE_PLY
 +        &&  (pos.pieces() ^ pos.pieces(CLOBBER_PIECE))
          &&  abs(beta) < VALUE_MATE_IN_MAX_PLY)
      {
-         Value rbeta = std::min(beta + 216 * (1 + !!pos.max_check_count() + (pos.extinction_value() != VALUE_NONE)) - 48 * improving, VALUE_INFINITE);
-         MovePicker mp(pos, ttMove, rbeta - ss->staticEval, &thisThread->captureHistory);
 -        Value raisedBeta = std::min(beta + 216 - 48 * improving, VALUE_INFINITE);
++        Value raisedBeta = std::min(beta + 216 * (1 + !!pos.max_check_count() + (pos.extinction_value() != VALUE_NONE)) - 48 * improving, VALUE_INFINITE);
+         MovePicker mp(pos, ttMove, raisedBeta - ss->staticEval, &thisThread->captureHistory);
          int probCutCount = 0;
  
          while (  (move = mp.next_move()) != MOVE_NONE
@@@ -982,8 -969,7 +991,8 @@@ moves_loop: // When in check, search st
        {
            if (   !captureOrPromotion
                && !givesCheck
 +              && (!pos.must_capture() || !pos.attackers_to(to_sq(move), ~pos.side_to_move()))
-               && (!pos.advanced_pawn_push(move) || pos.non_pawn_material() >= Value(5000)))
+               && !pos.advanced_pawn_push(move))
            {
                // Move count based pruning (~30 Elo)
                if (moveCountPruning)
Simple merge
diff --cc src/thread.cpp
Simple merge
diff --cc src/tt.cpp
Simple merge