Send piece command in XBoard protocol
authorFabian Fichter <ianfab@users.noreply.github.com>
Tue, 24 Dec 2019 13:01:42 +0000 (14:01 +0100)
committerFabian Fichter <ianfab@users.noreply.github.com>
Tue, 24 Dec 2019 13:01:42 +0000 (14:01 +0100)
Use Betza notation to communicate piece movement options to GUI.
Improves compatibility with XBoard/WinBoard and allows to play
most variants with legality testing enabled.

Closes #56.

src/piece.cpp
src/piece.h
src/ucioption.cpp
src/variant.cpp

index f193266..3b9a789 100644 (file)
@@ -34,6 +34,7 @@ namespace {
   PieceInfo* pawn_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "pawn";
+      p->betza = "fmWfceF";
       p->stepsQuiet = {NORTH};
       p->stepsCapture = {NORTH_WEST, NORTH_EAST};
       return p;
@@ -41,6 +42,7 @@ namespace {
   PieceInfo* knight_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "knight";
+      p->betza = "N";
       p->stepsQuiet = {2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
                        NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST };
       p->stepsCapture = {2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST,
@@ -50,6 +52,7 @@ namespace {
   PieceInfo* bishop_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "bishop";
+      p->betza = "B";
       p->sliderQuiet = {NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST};
       p->sliderCapture = {NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST};
       return p;
@@ -57,6 +60,7 @@ namespace {
   PieceInfo* rook_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "rook";
+      p->betza = "R";
       p->sliderQuiet = {NORTH, EAST, SOUTH, WEST};
       p->sliderCapture = {NORTH, EAST, SOUTH, WEST};
       return p;
@@ -64,6 +68,7 @@ namespace {
   PieceInfo* queen_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "queen";
+      p->betza = "RB";
       p->sliderQuiet = {NORTH, EAST, SOUTH, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST};
       p->sliderCapture = {NORTH, EAST, SOUTH, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST};
       return p;
@@ -71,6 +76,7 @@ namespace {
   PieceInfo* king_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "king";
+      p->betza = "K";
       p->stepsQuiet = {SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST};
       p->stepsCapture = {SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST};
       return p;
@@ -83,6 +89,7 @@ namespace {
   PieceInfo* fers_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "fers";
+      p->betza = "F";
       p->stepsQuiet = {SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST};
       p->stepsCapture = {SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST};
       return p;
@@ -90,6 +97,7 @@ namespace {
   PieceInfo* wazir_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "wazir";
+      p->betza = "W";
       p->stepsQuiet = {SOUTH, WEST, EAST, NORTH};
       p->stepsCapture = {SOUTH, WEST, EAST, NORTH};
       return p;
@@ -97,6 +105,7 @@ namespace {
   PieceInfo* alfil_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "alfil";
+      p->betza = "A";
       p->stepsQuiet = {2 * SOUTH_WEST, 2 * SOUTH_EAST, 2 * NORTH_WEST, 2 * NORTH_EAST};
       p->stepsCapture = {2 * SOUTH_WEST, 2 * SOUTH_EAST, 2 * NORTH_WEST, 2 * NORTH_EAST};
       return p;
@@ -104,6 +113,7 @@ namespace {
   PieceInfo* fers_alfil_piece() {
       PieceInfo* p = fers_piece();
       p->name = "fers_alfil";
+      p->betza = "FA";
       PieceInfo* p2 = alfil_piece();
       p->merge(p2);
       delete p2;
@@ -112,6 +122,7 @@ namespace {
   PieceInfo* silver_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "silver";
+      p->betza = "FfW";
       p->stepsQuiet = {SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH, NORTH_EAST};
       p->stepsCapture = {SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH, NORTH_EAST};
       return p;
@@ -119,6 +130,7 @@ namespace {
   PieceInfo* aiwok_piece() {
       PieceInfo* p = rook_piece();
       p->name = "aiwok";
+      p->betza = "RNF";
       PieceInfo* p2 = knight_piece();
       PieceInfo* p3 = fers_piece();
       p->merge(p2);
@@ -130,6 +142,7 @@ namespace {
   PieceInfo* bers_piece() {
       PieceInfo* p = rook_piece();
       p->name = "bers";
+      p->betza = "RF";
       PieceInfo* p2 = fers_piece();
       p->merge(p2);
       delete p2;
@@ -138,6 +151,7 @@ namespace {
   PieceInfo* archbishop_piece() {
       PieceInfo* p = bishop_piece();
       p->name = "archbishop";
+      p->betza = "BN";
       PieceInfo* p2 = knight_piece();
       p->merge(p2);
       delete p2;
@@ -146,6 +160,7 @@ namespace {
   PieceInfo* chancellor_piece() {
       PieceInfo* p = rook_piece();
       p->name = "chancellor";
+      p->betza = "RN";
       PieceInfo* p2 = knight_piece();
       p->merge(p2);
       delete p2;
@@ -154,6 +169,7 @@ namespace {
   PieceInfo* amazon_piece() {
       PieceInfo* p = queen_piece();
       p->name = "amazon";
+      p->betza = "RBN";
       PieceInfo* p2 = knight_piece();
       p->merge(p2);
       delete p2;
@@ -162,6 +178,7 @@ namespace {
   PieceInfo* knibis_piece() {
       PieceInfo* p = bishop_piece();
       p->name = "knibis";
+      p->betza = "mNcB";
       PieceInfo* p2 = knight_piece();
       p->merge(p2);
       delete p2;
@@ -172,6 +189,7 @@ namespace {
   PieceInfo* biskni_piece() {
       PieceInfo* p = bishop_piece();
       p->name = "biskni";
+      p->betza = "mBcN";
       PieceInfo* p2 = knight_piece();
       p->merge(p2);
       delete p2;
@@ -182,6 +200,7 @@ namespace {
   PieceInfo* kniroo_piece() {
       PieceInfo* p = rook_piece();
       p->name = "kniroo";
+      p->betza = "mNcR";
       PieceInfo* p2 = knight_piece();
       p->merge(p2);
       delete p2;
@@ -192,6 +211,7 @@ namespace {
   PieceInfo* rookni_piece() {
       PieceInfo* p = rook_piece();
       p->name = "rookni";
+      p->betza = "mRcN";
       PieceInfo* p2 = knight_piece();
       p->merge(p2);
       delete p2;
@@ -202,6 +222,7 @@ namespace {
   PieceInfo* shogi_pawn_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "shogi_pawn";
+      p->betza = "fW";
       p->stepsQuiet = {NORTH};
       p->stepsCapture = {NORTH};
       return p;
@@ -209,6 +230,7 @@ namespace {
   PieceInfo* lance_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "lance";
+      p->betza = "fR";
       p->sliderQuiet = {NORTH};
       p->sliderCapture = {NORTH};
       return p;
@@ -216,6 +238,7 @@ namespace {
   PieceInfo* shogi_knight_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "shogi_knight";
+      p->betza = "fN";
       p->stepsQuiet = {2 * NORTH + WEST, 2 * NORTH + EAST};
       p->stepsCapture = {2 * NORTH + WEST, 2 * NORTH + EAST};
       return p;
@@ -223,6 +246,7 @@ namespace {
   PieceInfo* euroshogi_knight_piece() {
       PieceInfo* p = shogi_knight_piece();
       p->name = "euroshogi_knight";
+      p->betza = "fNsW";
       p->stepsQuiet.push_back(WEST);
       p->stepsQuiet.push_back(EAST);
       p->stepsCapture.push_back(WEST);
@@ -232,6 +256,7 @@ namespace {
   PieceInfo* gold_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "gold";
+      p->betza = "WfF";
       p->stepsQuiet = {SOUTH, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST};
       p->stepsCapture = {SOUTH, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST};
       return p;
@@ -239,6 +264,7 @@ namespace {
   PieceInfo* dragon_horse_piece() {
       PieceInfo* p = bishop_piece();
       p->name = "dragon_horse";
+      p->betza = "BW";
       PieceInfo* p2 = wazir_piece();
       p->merge(p2);
       delete p2;
@@ -247,12 +273,14 @@ namespace {
   PieceInfo* clobber_piece() {
       PieceInfo* p = wazir_piece();
       p->name = "clobber";
+      p->betza = "cW";
       p->stepsQuiet = {};
       return p;
   }
   PieceInfo* breakthrough_piece() {
       PieceInfo* p = pawn_piece();
       p->name = "breakthrough";
+      p->betza = "fWfFcF";
       p->stepsQuiet.push_back(NORTH_WEST);
       p->stepsQuiet.push_back(NORTH_EAST);
       return p;
@@ -265,6 +293,7 @@ namespace {
   PieceInfo* cannon_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "cannon";
+      p->betza = "mRcpR";
       p->sliderQuiet = {NORTH, EAST, SOUTH, WEST};
       p->hopperCapture = {NORTH, EAST, SOUTH, WEST};
       return p;
@@ -272,6 +301,7 @@ namespace {
   PieceInfo* soldier_piece() {
       PieceInfo* p = new PieceInfo();
       p->name = "soldier";
+      p->betza = "fsW";
       p->stepsQuiet = {NORTH, WEST, EAST};
       p->stepsCapture = {NORTH, WEST, EAST};
       return p;
@@ -279,18 +309,21 @@ namespace {
   PieceInfo* horse_piece() {
       PieceInfo* p = knight_piece();
       p->name = "horse";
+      p->betza = "nN";
       p->lameLeaper = true;
       return p;
   }
   PieceInfo* elephant_piece() {
       PieceInfo* p = alfil_piece();
       p->name = "elephant";
+      p->betza = "nA";
       p->lameLeaper = true;
       return p;
   }
   PieceInfo* banner_piece() {
       PieceInfo* p = rook_piece();
       p->name = "banner";
+      p->betza = "RcpRnN";
       PieceInfo* p2 = horse_piece();
       p->merge(p2);
       delete p2;
@@ -301,6 +334,7 @@ namespace {
   PieceInfo* centaur_piece() {
       PieceInfo* p = commoner_piece();
       p->name = "centaur";
+      p->betza = "KN";
       PieceInfo* p2 = knight_piece();
       p->merge(p2);
       delete p2;
index 55c6505..70df241 100644 (file)
@@ -30,6 +30,7 @@
 
 struct PieceInfo {
   std::string name = "";
+  std::string betza = "";
   std::vector<Direction> stepsQuiet = {};
   std::vector<Direction> stepsCapture = {};
   std::vector<Direction> sliderQuiet = {};
index c101a6e..a23618c 100644 (file)
@@ -25,6 +25,7 @@
 #include <iostream>
 
 #include "misc.h"
+#include "piece.h"
 #include "search.h"
 #include "thread.h"
 #include "tt.h"
@@ -64,11 +65,36 @@ void on_variant_change(const Option &o) {
         return;
     int pocketsize = v->pieceDrops ? (v->pocketSize ? v->pocketSize : v->pieceTypes.size()) : 0;
     if (Options["Protocol"] == "xboard")
+    {
+        // Send setup command
         sync_cout << "setup (" << v->pieceToCharTable << ") "
                   << v->maxFile + 1 << "x" << v->maxRank + 1
                   << "+" << pocketsize << "_" << v->variantTemplate
                   << " " << v->startFen
                   << sync_endl;
+        // Send piece command with Betza notation
+        for (PieceType pt : v->pieceTypes)
+        {
+            string suffix =   pt == PAWN && v->doubleStep     ? "ifmnD"
+                            : pt == KING && v->cambodianMoves ? "ismN"
+                            : pt == FERS && v->cambodianMoves ? "ifnD"
+                                                              : "";
+            if (v->pieceDrops)
+            {
+                if (pt == PAWN && !v->firstRankDrops)
+                    suffix += "j";
+                else if (pt == SHOGI_PAWN && !v->shogiDoubledPawn)
+                    suffix += "f";
+                else if (pt == BISHOP && v->dropOppositeColoredBishop)
+                    suffix += "s";
+                suffix += "@" + std::to_string(pt == PAWN ? v->promotionRank : v->maxRank + 1);
+            }
+            sync_cout << "piece " << v->pieceToChar[pt] << "& " << pieceMap.find(pt)->second->betza << suffix << sync_endl;
+            PieceType promType = v->promotedPieceType[pt];
+            if (promType)
+                sync_cout << "piece +" << v->pieceToChar[pt] << "& " << pieceMap.find(promType)->second->betza << sync_endl;
+        }
+    }
     else
         sync_cout << "info string variant " << (std::string)o
                 << " files " << v->maxFile + 1
index ebc7468..f81399a 100644 (file)
@@ -263,6 +263,7 @@ namespace {
     }
     Variant* placement_variant() {
         Variant* v = chess_variant();
+        v->variantTemplate = "bughouse";
         v->startFen = "8/pppppppp/8/8/8/8/PPPPPPPP/8[KQRRBBNNkqrrbbnn] w - - 0 1";
         v->mustDrop = true;
         v->pieceDrops = true;
@@ -275,6 +276,7 @@ namespace {
     }
     Variant* sittuyin_variant() {
         Variant* v = makruk_variant();
+        v->variantTemplate = "bughouse";
         v->pieceToCharTable = "PN.R.F....SKpn.r.f....sk";
         v->startFen = "8/8/4pppp/pppp4/4PPPP/PPPP4/8/8[KFRRSSNNkfrrssnn] w - - 0 1";
         v->remove_piece(MET);
@@ -499,6 +501,7 @@ namespace {
     }
     Variant* clobber_variant() {
         Variant* v = fairy_variant_base();
+        v->pieceToCharTable = "P.................p.................";
         v->maxRank = RANK_6;
         v->maxFile = FILE_E;
         v->reset_pieces();
@@ -513,6 +516,7 @@ namespace {
     }
     Variant* breakthrough_variant() {
         Variant* v = fairy_variant_base();
+        v->pieceToCharTable = "P.................p.................";
         v->reset_pieces();
         v->add_piece(BREAKTHROUGH_PIECE, 'p');
         v->startFen = "pppppppp/pppppppp/8/8/8/8/PPPPPPPP/PPPPPPPP w 0 1";