From 4e996b1dbaa2ba31daf3b438b73344216e7b532c Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Tue, 24 Dec 2019 14:01:42 +0100 Subject: [PATCH] Send piece command in XBoard protocol 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 | 34 ++++++++++++++++++++++++++++++++++ src/piece.h | 1 + src/ucioption.cpp | 26 ++++++++++++++++++++++++++ src/variant.cpp | 4 ++++ 4 files changed, 65 insertions(+), 0 deletions(-) diff --git a/src/piece.cpp b/src/piece.cpp index f193266..3b9a789 100644 --- a/src/piece.cpp +++ b/src/piece.cpp @@ -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; diff --git a/src/piece.h b/src/piece.h index 55c6505..70df241 100644 --- a/src/piece.h +++ b/src/piece.h @@ -30,6 +30,7 @@ struct PieceInfo { std::string name = ""; + std::string betza = ""; std::vector stepsQuiet = {}; std::vector stepsCapture = {}; std::vector sliderQuiet = {}; diff --git a/src/ucioption.cpp b/src/ucioption.cpp index c101a6e..a23618c 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -25,6 +25,7 @@ #include #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 diff --git a/src/variant.cpp b/src/variant.cpp index ebc7468..f81399a 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -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"; -- 1.7.0.4