From: Fabian Fichter Date: Sun, 11 Apr 2021 14:44:51 +0000 (+0200) Subject: Define piece types using Betza notation X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=5673d380631d9cf550bd011c77e6f3ad95325219;p=fairystockfish.git Define piece types using Betza notation As preparation for configurable piece types, simplify definition of piece types by using Betza notation. No functional change. --- diff --git a/src/piece.cpp b/src/piece.cpp index 48bd240..c750be3 100644 --- a/src/piece.cpp +++ b/src/piece.cpp @@ -16,334 +16,153 @@ along with this program. If not, see . */ +#include #include +#include #include "types.h" #include "piece.h" PieceMap pieceMap; // Global object -void PieceInfo::merge(const PieceInfo* pi) { - stepsQuiet.insert(stepsQuiet.end(), pi->stepsQuiet.begin(), pi->stepsQuiet.end()); - stepsCapture.insert(stepsCapture.end(), pi->stepsCapture.begin(), pi->stepsCapture.end()); - sliderQuiet.insert(sliderQuiet.end(), pi->sliderQuiet.begin(), pi->sliderQuiet.end()); - sliderCapture.insert(sliderCapture.end(), pi->sliderCapture.begin(), pi->sliderCapture.end()); -} 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; - } - 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, - NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }; - return p; - } - 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; - } - 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; - } - 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; - } - 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; - } - PieceInfo* commoner_piece() { - PieceInfo* p = king_piece(); - p->name = "commoner"; - return p; - } - 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; - } - 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; - } - 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; - } - PieceInfo* fers_alfil_piece() { - PieceInfo* p = fers_piece(); - p->name = "fersAlfil"; - p->betza = "FA"; - PieceInfo* p2 = alfil_piece(); - p->merge(p2); - delete p2; - return p; - } - 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; - } - PieceInfo* aiwok_piece() { - PieceInfo* p = rook_piece(); - p->name = "aiwok"; - p->betza = "RNF"; - PieceInfo* p2 = knight_piece(); - PieceInfo* p3 = fers_piece(); - p->merge(p2); - p->merge(p3); - delete p2; - delete p3; - return p; - } - PieceInfo* bers_piece() { - PieceInfo* p = rook_piece(); - p->name = "bers"; - p->betza = "RF"; - PieceInfo* p2 = fers_piece(); - p->merge(p2); - delete p2; - return p; - } - PieceInfo* archbishop_piece() { - PieceInfo* p = bishop_piece(); - p->name = "archbishop"; - p->betza = "BN"; - PieceInfo* p2 = knight_piece(); - p->merge(p2); - delete p2; - return p; - } - PieceInfo* chancellor_piece() { - PieceInfo* p = rook_piece(); - p->name = "chancellor"; - p->betza = "RN"; - PieceInfo* p2 = knight_piece(); - p->merge(p2); - delete p2; - return p; - } - PieceInfo* amazon_piece() { - PieceInfo* p = queen_piece(); - p->name = "amazon"; - p->betza = "RBN"; - PieceInfo* p2 = knight_piece(); - p->merge(p2); - delete p2; - return p; - } - PieceInfo* knibis_piece() { - PieceInfo* p = bishop_piece(); - p->name = "knibis"; - p->betza = "mNcB"; - p->sliderQuiet.clear(); - PieceInfo* p2 = knight_piece(); - p2->stepsCapture.clear(); - p->merge(p2); - delete p2; - return p; - } - PieceInfo* biskni_piece() { - PieceInfo* p = bishop_piece(); - p->name = "biskni"; - p->betza = "mBcN"; - p->sliderCapture.clear(); - PieceInfo* p2 = knight_piece(); - p2->stepsQuiet.clear(); - p->merge(p2); - delete p2; - return p; - } - PieceInfo* kniroo_piece() { - PieceInfo* p = rook_piece(); - p->name = "kniroo"; - p->betza = "mNcR"; - p->sliderQuiet.clear(); - PieceInfo* p2 = knight_piece(); - p2->stepsCapture.clear(); - p->merge(p2); - delete p2; - return p; - } - PieceInfo* rookni_piece() { - PieceInfo* p = rook_piece(); - p->name = "rookni"; - p->betza = "mRcN"; - p->sliderCapture.clear(); - PieceInfo* p2 = knight_piece(); - p2->stepsQuiet.clear(); - p->merge(p2); - delete p2; - return p; - } - PieceInfo* shogi_pawn_piece() { - PieceInfo* p = new PieceInfo(); - p->name = "shogiPawn"; - p->betza = "fW"; - p->stepsQuiet = {NORTH}; - p->stepsCapture = {NORTH}; - return p; - } - PieceInfo* lance_piece() { - PieceInfo* p = new PieceInfo(); - p->name = "lance"; - p->betza = "fR"; - p->sliderQuiet = {NORTH}; - p->sliderCapture = {NORTH}; - return p; - } - PieceInfo* shogi_knight_piece() { - PieceInfo* p = new PieceInfo(); - p->name = "shogiKnight"; - p->betza = "fN"; - p->stepsQuiet = {2 * NORTH + WEST, 2 * NORTH + EAST}; - p->stepsCapture = {2 * NORTH + WEST, 2 * NORTH + EAST}; - return p; - } - PieceInfo* euroshogi_knight_piece() { - PieceInfo* p = shogi_knight_piece(); - p->name = "euroshogiKnight"; - p->betza = "fNsW"; - p->stepsQuiet.push_back(WEST); - p->stepsQuiet.push_back(EAST); - p->stepsCapture.push_back(WEST); - p->stepsCapture.push_back(EAST); - return p; - } - 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; - } - PieceInfo* dragon_horse_piece() { - PieceInfo* p = bishop_piece(); - p->name = "dragonHorse"; - p->betza = "BW"; - PieceInfo* p2 = wazir_piece(); - p->merge(p2); - delete p2; - return p; - } - PieceInfo* clobber_piece() { - PieceInfo* p = wazir_piece(); - p->name = "clobber"; - p->betza = "cW"; - p->stepsQuiet.clear(); - 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; - } - PieceInfo* immobile_piece() { - PieceInfo* p = new PieceInfo(); - p->name = "immobile"; - return p; - } - PieceInfo* ataxx_piece() { - PieceInfo* p = new PieceInfo(); - p->name = "ataxx"; - p->betza = "mDNA"; - p->stepsQuiet = {2 * NORTH_WEST, 2 * NORTH + WEST, 2 * NORTH, 2 * NORTH + EAST, 2 * NORTH_EAST, - NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * WEST, 2 * EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, - 2 * SOUTH_WEST, 2 * SOUTH + WEST, 2 * SOUTH, 2 * SOUTH + EAST, 2 * SOUTH_EAST}; - return p; - } - PieceInfo* quiet_queen_piece() { - PieceInfo* p = queen_piece(); - p->name = "quietQueen"; - p->betza = "mQ"; - p->sliderCapture.clear(); - return p; - } - 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; - } - PieceInfo* janggi_cannon_piece() { - PieceInfo* p = new PieceInfo(); - p->name = "janggiCannon"; - p->betza = "pR"; - p->hopperQuiet = {NORTH, EAST, SOUTH, WEST}; - p->hopperCapture = {NORTH, EAST, SOUTH, WEST}; - return p; - } - 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; - } - 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; - } + std::map>> leaperAtoms = { + {'W', {std::make_pair(1, 0)}}, + {'F', {std::make_pair(1, 1)}}, + {'D', {std::make_pair(2, 0)}}, + {'N', {std::make_pair(2, 1)}}, + {'A', {std::make_pair(2, 2)}}, + {'H', {std::make_pair(3, 0)}}, + {'L', {std::make_pair(3, 1)}}, + {'C', {std::make_pair(3, 1)}}, + {'J', {std::make_pair(3, 2)}}, + {'Z', {std::make_pair(3, 2)}}, + {'G', {std::make_pair(3, 3)}}, + {'K', {std::make_pair(1, 0), std::make_pair(1, 1)}}, + }; + std::map>> riderAtoms = { + {'R', {std::make_pair(1, 0)}}, + {'B', {std::make_pair(1, 1)}}, + {'Q', {std::make_pair(1, 0), std::make_pair(1, 1)}}, + }; + const std::string verticals = "fbvh"; + const std::string horizontals = "rlsh"; + // from_betza creates a piece by parsing Betza notation + // https://en.wikipedia.org/wiki/Betza%27s_funny_notation + PieceInfo* from_betza(const std::string& betza, const std::string& name) { + PieceInfo* p = new PieceInfo(); + p->name = name; + p->betza = betza; + std::vector moveTypes = {}; + bool hopper = false; + bool rider = false; + std::vector prelimDirections = {}; + for (std::string::size_type i = 0; i < betza.size(); i++) + { + char c = betza[i]; + // Move or capture + if (c == 'm' || c == 'c') + moveTypes.push_back(c); + // Hopper + else if (c == 'p') + hopper = true; + // Lame leaper + else if (c == 'n') + p->lameLeaper = true; + // Directional modifiers + else if (verticals.find(c) != std::string::npos || horizontals.find(c) != std::string::npos) + { + if (i + 1 < betza.size()) + { + char c2 = betza[i+1]; + // Can modifiers be combined? + if ( c2 == c + || (verticals.find(c) != std::string::npos && horizontals.find(c2) != std::string::npos) + || (horizontals.find(c) != std::string::npos && verticals.find(c2) != std::string::npos)) + { + prelimDirections.push_back(std::string(1, c) + c2); + i++; + continue; + } + } + prelimDirections.push_back(std::string(2, c)); + } + // Move atom + else if (leaperAtoms.find(c) != leaperAtoms.end() || riderAtoms.find(c) != riderAtoms.end()) + { + const auto& atoms = riderAtoms.find(c) != riderAtoms.end() ? riderAtoms.find(c)->second + : leaperAtoms.find(c)->second; + // Check for rider + if (riderAtoms.find(c) != riderAtoms.end()) + rider = true; + if (i + 1 < betza.size() && (isdigit(betza[i+1]) || betza[i+1] == c)) + { + rider = true; + // limited distance riders + if (isdigit(betza[i+1])) + { + // TODO: not supported + } + i++; + } + // No type qualifier means m+c + if (moveTypes.size() == 0) + { + moveTypes.push_back('m'); + moveTypes.push_back('c'); + } + // Define moves + for (const auto& atom : atoms) + { + std::vector directions = {}; + // Split directions for orthogonal pieces + // This is required e.g. to correctly interpret fsW for soldiers + for (auto s : prelimDirections) + if (atoms.size() == 1 && atom.second == 0 && s[0] != s[1]) + { + directions.push_back(std::string(2, s[0])); + directions.push_back(std::string(2, s[1])); + } + else + directions.push_back(s); + // Add moves + for (char mt : moveTypes) + { + std::vector& v = hopper ? (mt == 'c' ? p->hopperCapture : p->hopperQuiet) + : rider ? (mt == 'c' ? p->sliderCapture : p->sliderQuiet) + : (mt == 'c' ? p->stepsCapture : p->stepsQuiet); + auto has_dir = [&](std::string s) { + return std::find(directions.begin(), directions.end(), s) != directions.end(); + }; + if (directions.size() == 0 || has_dir("ff") || has_dir("vv") || has_dir("rf") || has_dir("rv") || has_dir("fh") || has_dir("rh") || has_dir("hr")) + v.push_back(Direction(atom.first * FILE_NB + atom.second)); + if (directions.size() == 0 || has_dir("bb") || has_dir("vv") || has_dir("lb") || has_dir("lv") || has_dir("bh") || has_dir("lh") || has_dir("hr")) + v.push_back(Direction(-atom.first * FILE_NB - atom.second)); + if (directions.size() == 0 || has_dir("rr") || has_dir("ss") || has_dir("br") || has_dir("bs") || has_dir("bh") || has_dir("lh") || has_dir("hr")) + v.push_back(Direction(-atom.second * FILE_NB + atom.first)); + if (directions.size() == 0 || has_dir("ll") || has_dir("ss") || has_dir("fl") || has_dir("fs") || has_dir("fh") || has_dir("rh") || has_dir("hr")) + v.push_back(Direction(atom.second * FILE_NB - atom.first)); + if (directions.size() == 0 || has_dir("rr") || has_dir("ss") || has_dir("fr") || has_dir("fs") || has_dir("fh") || has_dir("rh") || has_dir("hl")) + v.push_back(Direction(atom.second * FILE_NB + atom.first)); + if (directions.size() == 0 || has_dir("ll") || has_dir("ss") || has_dir("bl") || has_dir("bs") || has_dir("bh") || has_dir("lh") || has_dir("hl")) + v.push_back(Direction(-atom.second * FILE_NB - atom.first)); + if (directions.size() == 0 || has_dir("bb") || has_dir("vv") || has_dir("rb") || has_dir("rv") || has_dir("bh") || has_dir("rh") || has_dir("hl")) + v.push_back(Direction(-atom.first * FILE_NB + atom.second)); + if (directions.size() == 0 || has_dir("ff") || has_dir("vv") || has_dir("lf") || has_dir("lv") || has_dir("fh") || has_dir("lh") || has_dir("hl")) + v.push_back(Direction(atom.first * FILE_NB - atom.second)); + } + } + // Reset state + moveTypes.clear(); + prelimDirections.clear(); + hopper = false; + rider = false; + } + } + return p; + } + // Special multi-leg betza description for Janggi elephant PieceInfo* janggi_elephant_piece() { PieceInfo* p = new PieceInfo(); p->name = "janggiElephant"; @@ -359,69 +178,49 @@ namespace { 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; - p->hopperCapture = {NORTH, EAST, SOUTH, WEST}; - p->lameLeaper = true; - return p; - } - PieceInfo* centaur_piece() { - PieceInfo* p = commoner_piece(); - p->name = "centaur"; - p->betza = "KN"; - PieceInfo* p2 = knight_piece(); - p->merge(p2); - delete p2; - return p; - } } void PieceMap::init() { - add(PAWN, pawn_piece()); - add(KNIGHT, knight_piece()); - add(BISHOP, bishop_piece()); - add(ROOK, rook_piece()); - add(QUEEN, queen_piece()); - add(FERS, fers_piece()); - add(ALFIL, alfil_piece()); - add(FERS_ALFIL, fers_alfil_piece()); - add(SILVER, silver_piece()); - add(AIWOK, aiwok_piece()); - add(BERS, bers_piece()); - add(ARCHBISHOP, archbishop_piece()); - add(CHANCELLOR, chancellor_piece()); - add(AMAZON, amazon_piece()); - add(KNIBIS, knibis_piece()); - add(BISKNI, biskni_piece()); - add(KNIROO, kniroo_piece()); - add(ROOKNI, rookni_piece()); - add(SHOGI_PAWN, shogi_pawn_piece()); - add(LANCE, lance_piece()); - add(SHOGI_KNIGHT, shogi_knight_piece()); - add(EUROSHOGI_KNIGHT, euroshogi_knight_piece()); - add(GOLD, gold_piece()); - add(DRAGON_HORSE, dragon_horse_piece()); - add(CLOBBER_PIECE, clobber_piece()); - add(BREAKTHROUGH_PIECE, breakthrough_piece()); - add(IMMOBILE_PIECE, immobile_piece()); - add(ATAXX_PIECE, ataxx_piece()); - add(QUIET_QUEEN, quiet_queen_piece()); - add(CANNON, cannon_piece()); - add(JANGGI_CANNON, janggi_cannon_piece()); - add(SOLDIER, soldier_piece()); - add(HORSE, horse_piece()); - add(ELEPHANT, elephant_piece()); + add(PAWN, from_betza("fmWfceF", "pawn")); + add(KNIGHT, from_betza("N", "knight")); + add(BISHOP, from_betza("B", "bishop")); + add(ROOK, from_betza("R", "rook")); + add(QUEEN, from_betza("Q", "queen")); + add(FERS, from_betza("F", "fers")); + add(ALFIL, from_betza("A", "alfil")); + add(FERS_ALFIL, from_betza("FA", "fersAlfil")); + add(SILVER, from_betza("FfW", "silver")); + add(AIWOK, from_betza("RNF", "aiwok")); + add(BERS, from_betza("RF", "bers")); + add(ARCHBISHOP, from_betza("BN", "archbishop")); + add(CHANCELLOR, from_betza("RN", "chancellor")); + add(AMAZON, from_betza("QN", "amazon")); + add(KNIBIS, from_betza("mNcB", "knibis")); + add(BISKNI, from_betza("mBcN", "biskni")); + add(KNIROO, from_betza("mNcR", "kniroo")); + add(ROOKNI, from_betza("mRcN", "rookni")); + add(SHOGI_PAWN, from_betza("fW", "shogiPawn")); + add(LANCE, from_betza("fR", "lance")); + add(SHOGI_KNIGHT, from_betza("fN", "shogiKnight")); + add(EUROSHOGI_KNIGHT, from_betza("fNsW", "euroshogiKnight")); + add(GOLD, from_betza("WfF", "gold")); + add(DRAGON_HORSE, from_betza("BW", "dragonHorse")); + add(CLOBBER_PIECE, from_betza("cW", "clobber")); + add(BREAKTHROUGH_PIECE, from_betza("fWfFcF", "breakthrough")); + add(IMMOBILE_PIECE, from_betza("", "immobile")); + add(ATAXX_PIECE, from_betza("mDmNmA", "ataxx")); + add(QUIET_QUEEN, from_betza("mQ", "quietQueen")); + add(CANNON, from_betza("mRcpR", "cannon")); + add(JANGGI_CANNON, from_betza("pR", "janggiCannon")); + add(SOLDIER, from_betza("fsW", "soldier")); + add(HORSE, from_betza("nN", "horse")); + add(ELEPHANT, from_betza("nA", "elephant")); add(JANGGI_ELEPHANT, janggi_elephant_piece()); - add(BANNER, banner_piece()); - add(WAZIR, wazir_piece()); - add(COMMONER, commoner_piece()); - add(CENTAUR, centaur_piece()); - add(KING, king_piece()); + add(BANNER, from_betza("RcpRnN", "banner")); + add(WAZIR, from_betza("W", "wazir")); + add(COMMONER, from_betza("K", "commoner")); + add(CENTAUR, from_betza("KN", "centaur")); + add(KING, from_betza("K", "king")); } void PieceMap::add(PieceType pt, const PieceInfo* p) { diff --git a/src/piece.h b/src/piece.h index 61670bc..66fa36f 100644 --- a/src/piece.h +++ b/src/piece.h @@ -38,8 +38,6 @@ struct PieceInfo { std::vector hopperQuiet = {}; std::vector hopperCapture = {}; bool lameLeaper = false; - - void merge(const PieceInfo* pi); }; struct PieceMap : public std::map {