Support capablanca chess (#6)
authorFabian Fichter <ianfab@users.noreply.github.com>
Sat, 29 Sep 2018 21:27:55 +0000 (23:27 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sun, 7 Oct 2018 14:40:23 +0000 (16:40 +0200)
Generalize castling and add archbishop to support capablanca chess.

bench: 4636755

src/bitboard.cpp
src/movegen.cpp
src/position.cpp
src/position.h
src/psqt.cpp
src/types.h
src/uci.cpp
src/variant.cpp
src/variant.h

index 7ba1783..94cf477 100644 (file)
@@ -431,6 +431,8 @@ void Bitboards::init() {
         NORTH + 2 * WEST, NORTH_WEST, NORTH_EAST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // aiwok
       { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // bers/dragon
       { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
+        NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // archbishop
+      { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
         NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // chancellor
       { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
         NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // amazon
@@ -464,6 +466,8 @@ void Bitboards::init() {
         NORTH + 2 * WEST, NORTH_WEST, NORTH_EAST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // aiwok
       { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // bers/dragon
       { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
+        NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // archbishop
+      { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
         NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // chancellor
       { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
         NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // amazon
@@ -494,6 +498,7 @@ void Bitboards::init() {
     {}, // silver/khon
     { NORTH,  EAST,  SOUTH,  WEST }, // aiwok
     { NORTH,  EAST,  SOUTH,  WEST }, // bers/dragon
+    { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // archbishop
     { NORTH,  EAST,  SOUTH,  WEST }, // chancellor
     { NORTH,  EAST,  SOUTH,  WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // amazon
     { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // knibis
@@ -522,6 +527,7 @@ void Bitboards::init() {
     {}, // silver/khon
     { NORTH,  EAST,  SOUTH,  WEST }, // aiwok
     { NORTH,  EAST,  SOUTH,  WEST }, // bers/dragon
+    { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // archbishop
     { NORTH,  EAST,  SOUTH,  WEST }, // chancellor
     { NORTH,  EAST,  SOUTH,  WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // amazon
     {}, // knibis
@@ -550,6 +556,7 @@ void Bitboards::init() {
     0, // silver/khon
     FILE_MAX, // aiwok
     FILE_MAX, // bers/dragon
+    FILE_MAX, // archbishop
     FILE_MAX, // chancellor
     FILE_MAX, // amazon
     FILE_MAX, // knibis
@@ -578,6 +585,7 @@ void Bitboards::init() {
     0, // silver/khon
     FILE_MAX, // aiwok
     FILE_MAX, // bers/dragon
+    FILE_MAX, // archbishop
     FILE_MAX, // chancellor
     FILE_MAX, // amazon
     0, // knibis
index f9ccf24..6bbdb66 100644 (file)
@@ -35,9 +35,10 @@ 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, us == WHITE ? RANK_1 : RANK_8);
+    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()));
     Bitboard enemies = pos.pieces(~us);
 
     assert(!pos.checkers());
index eef10b2..00b878e 100644 (file)
@@ -358,13 +358,13 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960,
           token = char(toupper(token));
 
           if (token == 'K')
-              for (rsq = relative_square(c, SQ_H1); piece_on(rsq) != rook; --rsq) {}
+              for (rsq = make_square(FILE_MAX, relative_rank(c, RANK_1, max_rank())); piece_on(rsq) != rook; --rsq) {}
 
           else if (token == 'Q')
-              for (rsq = relative_square(c, SQ_A1); piece_on(rsq) != rook; ++rsq) {}
+              for (rsq = make_square(FILE_A, relative_rank(c, RANK_1, max_rank())); piece_on(rsq) != rook; ++rsq) {}
 
-          else if (token >= 'A' && token <= 'H')
-              rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1));
+          else if (token >= 'A' && token <= 'A' + max_file())
+              rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1, max_rank()));
 
           else
               continue;
@@ -1258,8 +1258,9 @@ void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Squ
 
   bool kingSide = to > from;
   rfrom = to; // Castling is encoded as "king captures friendly rook"
-  rto = relative_square(us, kingSide ? SQ_F1 : SQ_D1);
-  to = relative_square(us, kingSide ? SQ_G1 : SQ_C1);
+  to = make_square(kingSide ? castling_kingside_file() : castling_queenside_file(),
+                   us == WHITE ? RANK_1 : max_rank());
+  rto = to + (kingSide ? WEST : EAST);
 
   // Remove both pieces first since squares could overlap in Chess960
   Piece castling_piece = piece_on(Do ? from : to);
index 04f5bb9..ea06a38 100644 (file)
@@ -103,6 +103,8 @@ public:
   bool double_step_enabled() const;
   bool first_rank_double_steps() const;
   bool castling_enabled() const;
+  File castling_kingside_file() const;
+  File castling_queenside_file() const;
   bool checking_permitted() const;
   bool must_capture() const;
   bool piece_drops() const;
@@ -327,6 +329,16 @@ inline bool Position::castling_enabled() const {
   return var->castling;
 }
 
+inline File Position::castling_kingside_file() const {
+  assert(var != nullptr);
+  return var->castlingKingsideFile;
+}
+
+inline File Position::castling_queenside_file() const {
+  assert(var != nullptr);
+  return var->castlingQueensideFile;
+}
+
 inline bool Position::checking_permitted() const {
   assert(var != nullptr);
   return var->checking;
index 3fef593..13a0796 100644 (file)
 
 Value PieceValue[PHASE_NB][PIECE_NB] = {
   { VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg,
-    FersValueMg, AlfilValueMg, SilverValueMg, AiwokValueMg, BersValueMg, ChancellorValueMg,
-    AmazonValueMg, KnibisValueMg, BiskniValueMg,
+    FersValueMg, AlfilValueMg, SilverValueMg, AiwokValueMg, BersValueMg,
+    ArchbishopValueMg, ChancellorValueMg, AmazonValueMg, KnibisValueMg, BiskniValueMg,
     ShogiPawnValueMg, LanceValueMg, ShogiKnightValueMg, EuroShogiKnightValueMg, GoldValueMg, HorseValueMg,
     ClobberPieceValueMg, BreakthroughPieceValueMg, ImmobilePieceValueMg, CommonerValueMg },
   { VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg,
-    FersValueEg, AlfilValueEg, SilverValueEg, AiwokValueEg, BersValueEg, ChancellorValueEg,
-    AmazonValueEg, KnibisValueMg, BiskniValueMg,
+    FersValueEg, AlfilValueEg, SilverValueEg, AiwokValueEg, BersValueEg,
+    ArchbishopValueMg, ChancellorValueEg, AmazonValueEg, KnibisValueMg, BiskniValueMg,
     ShogiPawnValueEg, LanceValueEg, ShogiKnightValueEg, EuroShogiKnightValueEg, GoldValueEg, HorseValueEg,
     ClobberPieceValueEg, BreakthroughPieceValueEg, ImmobilePieceValueEg, CommonerValueEg }
 };
index d9818a5..634553b 100644 (file)
@@ -208,7 +208,8 @@ enum Value : int {
   SilverValueMg            = 600,   SilverValueEg            = 600,
   AiwokValueMg             = 2500,  AiwokValueEg             = 2500,
   BersValueMg              = 2000,  BersValueEg              = 2000,
-  ChancellorValueMg        = 2500,  ChancellorValueEg        = 2500,
+  ArchbishopValueMg        = 2000,  ArchbishopValueEg        = 2000,
+  ChancellorValueMg        = 2300,  ChancellorValueEg        = 2300,
   AmazonValueMg            = 3000,  AmazonValueEg            = 3000,
   KnibisValueMg            = 800,   KnibisValueEg            = 800,
   BiskniValueMg            = 800,   BiskniValueEg            = 800,
@@ -229,9 +230,10 @@ enum Value : int {
 const int PIECE_TYPE_BITS = 5; // PIECE_TYPE_NB = pow(2, PIECE_TYPE_BITS)
 
 enum PieceType {
-  NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK,
-  QUEEN, FERS, MET = FERS, ALFIL, SILVER, KHON = SILVER, AIWOK, BERS, DRAGON = BERS, CHANCELLOR,
-  AMAZON, KNIBIS, BISKNI, SHOGI_PAWN, LANCE, SHOGI_KNIGHT, EUROSHOGI_KNIGHT, GOLD, HORSE,
+  NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN,
+  FERS, MET = FERS, ALFIL, SILVER, KHON = SILVER, AIWOK, BERS, DRAGON = BERS,
+  ARCHBISHOP, CHANCELLOR, AMAZON, KNIBIS, BISKNI,
+  SHOGI_PAWN, LANCE, SHOGI_KNIGHT, EUROSHOGI_KNIGHT, GOLD, HORSE,
   CLOBBER_PIECE, BREAKTHROUGH_PIECE, IMMOBILE_PIECE, COMMONER, KING,
   ALL_PIECES = 0,
 
index 6ae8105..e1a9238 100644 (file)
@@ -307,7 +307,7 @@ string UCI::move(const Position& pos, Move m) {
       return "0000";
 
   if (type_of(m) == CASTLING && !pos.is_chess960())
-      to = make_square(to > from ? FILE_G : FILE_C, rank_of(from));
+      to = make_square(to > from ? pos.castling_kingside_file() : pos.castling_queenside_file(), rank_of(from));
 
   string move = (type_of(m) == DROP ? std::string{pos.piece_to_char()[type_of(pos.moved_piece(m))],
                                                   Options["Protocol"] == "usi" ? '*' : '@'}
index 90f3c49..0d2325b 100644 (file)
@@ -465,6 +465,18 @@ void VariantMap::init() {
         v->shogiPawnDropMateIllegal = true;
         return v;
     } ();
+    const Variant* capablanca = [&]{
+        Variant* v = new Variant();
+        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;
+    } ();
 #endif
 
     // Add to UCI_Variant option
@@ -504,6 +516,7 @@ void VariantMap::init() {
     add("tictactoe", tictactoe);
 #ifdef LARGEBOARDS
     add("shogi", shogi);
+    add("capablanca", capablanca);
 #endif
 }
 
index baf9d66..eda559c 100644 (file)
@@ -46,6 +46,8 @@ struct Variant {
   bool doubleStep = true;
   bool firstRankDoubleSteps = false;
   bool castling = true;
+  File castlingKingsideFile = FILE_G;
+  File castlingQueensideFile = FILE_C;
   bool checking = true;
   bool mustCapture = false;
   bool pieceDrops = false;