From: Fabian Fichter Date: Fri, 30 Apr 2021 22:36:54 +0000 (+0200) Subject: Support limited distance sliders X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=7e9956b96c1cea51434741eccf00f9fb46c78a4f;p=fairystockfish.git Support limited distance sliders --- diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 139823f..010381d 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -80,41 +80,46 @@ namespace { #endif // Rider directions - const std::set RookDirectionsV { NORTH, SOUTH}; - const std::set RookDirectionsH { EAST, WEST }; - const std::set BishopDirections { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }; - const std::set HorseDirections { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, - NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }; - const std::set ElephantDirections { 2 * NORTH_EAST, 2 * SOUTH_EAST, 2 * SOUTH_WEST, 2 * NORTH_WEST }; - const std::set JanggiElephantDirections { NORTH + 2 * NORTH_EAST, EAST + 2 * NORTH_EAST, - EAST + 2 * SOUTH_EAST, SOUTH + 2 * SOUTH_EAST, - SOUTH + 2 * SOUTH_WEST, WEST + 2 * SOUTH_WEST, - WEST + 2 * NORTH_WEST, NORTH + 2 * NORTH_WEST }; + const std::map RookDirectionsV { {NORTH, 0}, {SOUTH, 0}}; + const std::map RookDirectionsH { {EAST, 0}, {WEST, 0} }; + const std::map BishopDirections { {NORTH_EAST, 0}, {SOUTH_EAST, 0}, {SOUTH_WEST, 0}, {NORTH_WEST, 0} }; + const std::map HorseDirections { {2 * SOUTH + WEST, 0}, {2 * SOUTH + EAST, 0}, {SOUTH + 2 * WEST, 0}, {SOUTH + 2 * EAST, 0}, + {NORTH + 2 * WEST, 0}, {NORTH + 2 * EAST, 0}, {2 * NORTH + WEST, 0}, {2 * NORTH + EAST, 0} }; + const std::map ElephantDirections { {2 * NORTH_EAST, 0}, {2 * SOUTH_EAST, 0}, {2 * SOUTH_WEST, 0}, {2 * NORTH_WEST, 0} }; + const std::map JanggiElephantDirections { {NORTH + 2 * NORTH_EAST, 0}, {EAST + 2 * NORTH_EAST, 0}, + {EAST + 2 * SOUTH_EAST, 0}, {SOUTH + 2 * SOUTH_EAST, 0}, + {SOUTH + 2 * SOUTH_WEST, 0}, {WEST + 2 * SOUTH_WEST, 0}, + {WEST + 2 * NORTH_WEST, 0}, {NORTH + 2 * NORTH_WEST, 0} }; enum MovementType { RIDER, HOPPER, LAME_LEAPER }; template #ifdef PRECOMPUTED_MAGICS - void init_magics(Bitboard table[], Magic magics[], std::set directions, Bitboard magicsInit[]); + void init_magics(Bitboard table[], Magic magics[], std::map directions, Bitboard magicsInit[]); #else - void init_magics(Bitboard table[], Magic magics[], std::set directions); + void init_magics(Bitboard table[], Magic magics[], std::map directions); #endif template - Bitboard sliding_attack(std::set directions, Square sq, Bitboard occupied, Color c = WHITE) { + Bitboard sliding_attack(std::map directions, Square sq, Bitboard occupied, Color c = WHITE) { assert(MT != LAME_LEAPER); Bitboard attack = 0; - for (Direction d : directions) + for (auto const& [d, limit] : directions) { + int count = 0; bool hurdle = false; for (Square s = sq + (c == WHITE ? d : -d); is_ok(s) && distance(s, s - (c == WHITE ? d : -d)) <= 2; s += (c == WHITE ? d : -d)) { if (MT != HOPPER || hurdle) + { attack |= s; + if (limit && ++count >= limit) + break; + } if (occupied & s) { @@ -152,19 +157,19 @@ namespace { return b; } - Bitboard lame_leaper_path(std::set directions, Square s) { + Bitboard lame_leaper_path(std::map directions, Square s) { Bitboard b = 0; - for (Direction d : directions) - b |= lame_leaper_path(d, s); + for (const auto& i : directions) + b |= lame_leaper_path(i.first, s); return b; } - Bitboard lame_leaper_attack(std::set directions, Square s, Bitboard occupied) { + Bitboard lame_leaper_attack(std::map directions, Square s, Bitboard occupied) { Bitboard b = 0; - for (Direction d : directions) + for (const auto& i : directions) { - Square to = s + d; - if (is_ok(to) && distance(s, to) < 4 && !(lame_leaper_path(d, s) & occupied)) + Square to = s + i.first; + if (is_ok(to) && distance(s, to) < 4 && !(lame_leaper_path(i.first, s) & occupied)) b |= to; } return b; @@ -213,65 +218,62 @@ void Bitboards::init_pieces() { AttackRiderTypes[pt] = NO_RIDER; MoveRiderTypes[pt] = NO_RIDER; - if (pi->lameLeaper) + for (auto const& [d, limit] : pi->stepsCapture) { - for (Direction d : pi->stepsCapture) - { - if (std::find(HorseDirections.begin(), HorseDirections.end(), d) != HorseDirections.end()) - AttackRiderTypes[pt] |= RIDER_HORSE; - if (std::find(ElephantDirections.begin(), ElephantDirections.end(), d) != ElephantDirections.end()) - AttackRiderTypes[pt] |= RIDER_ELEPHANT; - if (std::find(JanggiElephantDirections.begin(), JanggiElephantDirections.end(), d) != JanggiElephantDirections.end()) - AttackRiderTypes[pt] |= RIDER_JANGGI_ELEPHANT; - } - for (Direction d : pi->stepsQuiet) - { - if (std::find(HorseDirections.begin(), HorseDirections.end(), d) != HorseDirections.end()) - MoveRiderTypes[pt] |= RIDER_HORSE; - if (std::find(ElephantDirections.begin(), ElephantDirections.end(), d) != ElephantDirections.end()) - MoveRiderTypes[pt] |= RIDER_ELEPHANT; - if (std::find(JanggiElephantDirections.begin(), JanggiElephantDirections.end(), d) != JanggiElephantDirections.end()) - MoveRiderTypes[pt] |= RIDER_JANGGI_ELEPHANT; - } + if (limit && HorseDirections.find(d) != HorseDirections.end()) + AttackRiderTypes[pt] |= RIDER_HORSE; + if (limit && ElephantDirections.find(d) != ElephantDirections.end()) + AttackRiderTypes[pt] |= RIDER_ELEPHANT; + if (limit && JanggiElephantDirections.find(d) != JanggiElephantDirections.end()) + AttackRiderTypes[pt] |= RIDER_JANGGI_ELEPHANT; + } + for (auto const& [d, limit] : pi->stepsQuiet) + { + if (limit && HorseDirections.find(d) != HorseDirections.end()) + MoveRiderTypes[pt] |= RIDER_HORSE; + if (limit && ElephantDirections.find(d) != ElephantDirections.end()) + MoveRiderTypes[pt] |= RIDER_ELEPHANT; + if (limit && JanggiElephantDirections.find(d) != JanggiElephantDirections.end()) + MoveRiderTypes[pt] |= RIDER_JANGGI_ELEPHANT; } - for (Direction d : pi->sliderCapture) + for (auto const& [d, limit] : pi->sliderCapture) { - if (std::find(BishopDirections.begin(), BishopDirections.end(), d) != BishopDirections.end()) + if (BishopDirections.find(d) != BishopDirections.end()) AttackRiderTypes[pt] |= RIDER_BISHOP; - if (std::find(RookDirectionsH.begin(), RookDirectionsH.end(), d) != RookDirectionsH.end()) + if (RookDirectionsH.find(d) != RookDirectionsH.end()) AttackRiderTypes[pt] |= RIDER_ROOK_H; - if (std::find(RookDirectionsV.begin(), RookDirectionsV.end(), d) != RookDirectionsV.end()) + if (RookDirectionsV.find(d) != RookDirectionsV.end()) AttackRiderTypes[pt] |= RIDER_ROOK_V; - if (std::find(HorseDirections.begin(), HorseDirections.end(), d) != HorseDirections.end()) + if (HorseDirections.find(d) != HorseDirections.end()) AttackRiderTypes[pt] |= RIDER_NIGHTRIDER; } - for (Direction d : pi->sliderQuiet) + for (auto const& [d, limit] : pi->sliderQuiet) { - if (std::find(BishopDirections.begin(), BishopDirections.end(), d) != BishopDirections.end()) + if (BishopDirections.find(d) != BishopDirections.end()) MoveRiderTypes[pt] |= RIDER_BISHOP; - if (std::find(RookDirectionsH.begin(), RookDirectionsH.end(), d) != RookDirectionsH.end()) + if (RookDirectionsH.find(d) != RookDirectionsH.end()) MoveRiderTypes[pt] |= RIDER_ROOK_H; - if (std::find(RookDirectionsV.begin(), RookDirectionsV.end(), d) != RookDirectionsV.end()) + if (RookDirectionsV.find(d) != RookDirectionsV.end()) MoveRiderTypes[pt] |= RIDER_ROOK_V; - if (std::find(HorseDirections.begin(), HorseDirections.end(), d) != HorseDirections.end()) + if (HorseDirections.find(d) != HorseDirections.end()) MoveRiderTypes[pt] |= RIDER_NIGHTRIDER; } - for (Direction d : pi->hopperCapture) + for (auto const& [d, limit] : pi->hopperCapture) { - if (std::find(RookDirectionsH.begin(), RookDirectionsH.end(), d) != RookDirectionsH.end()) + if (!limit && RookDirectionsH.find(d) != RookDirectionsH.end()) AttackRiderTypes[pt] |= RIDER_CANNON_H; - if (std::find(RookDirectionsV.begin(), RookDirectionsV.end(), d) != RookDirectionsV.end()) + if (!limit && RookDirectionsV.find(d) != RookDirectionsV.end()) AttackRiderTypes[pt] |= RIDER_CANNON_V; - if (std::find(BishopDirections.begin(), BishopDirections.end(), d) != BishopDirections.end()) + if (!limit && BishopDirections.find(d) != BishopDirections.end()) AttackRiderTypes[pt] |= RIDER_CANNON_DIAG; } - for (Direction d : pi->hopperQuiet) + for (auto const& [d, limit] : pi->hopperQuiet) { - if (std::find(RookDirectionsH.begin(), RookDirectionsH.end(), d) != RookDirectionsH.end()) + if (!limit && RookDirectionsH.find(d) != RookDirectionsH.end()) MoveRiderTypes[pt] |= RIDER_CANNON_H; - if (std::find(RookDirectionsV.begin(), RookDirectionsV.end(), d) != RookDirectionsV.end()) + if (!limit && RookDirectionsV.find(d) != RookDirectionsV.end()) MoveRiderTypes[pt] |= RIDER_CANNON_V; - if (std::find(BishopDirections.begin(), BishopDirections.end(), d) != BishopDirections.end()) + if (!limit && BishopDirections.find(d) != BishopDirections.end()) MoveRiderTypes[pt] |= RIDER_CANNON_DIAG; } @@ -284,16 +286,16 @@ void Bitboards::init_pieces() { PseudoMoves[c][pt][s] = 0; LeaperAttacks[c][pt][s] = 0; LeaperMoves[c][pt][s] = 0; - for (Direction d : pi->stepsCapture) + for (auto const& [d, limit] : pi->stepsCapture) { PseudoAttacks[c][pt][s] |= safe_destination(s, c == WHITE ? d : -d); - if (!pi->lameLeaper) + if (!limit) LeaperAttacks[c][pt][s] |= safe_destination(s, c == WHITE ? d : -d); } - for (Direction d : pi->stepsQuiet) + for (auto const& [d, limit] : pi->stepsQuiet) { PseudoMoves[c][pt][s] |= safe_destination(s, c == WHITE ? d : -d); - if (!pi->lameLeaper) + if (!limit) LeaperMoves[c][pt][s] |= safe_destination(s, c == WHITE ? d : -d); } PseudoAttacks[c][pt][s] |= sliding_attack(pi->sliderCapture, s, 0, c); @@ -370,9 +372,9 @@ namespace { template #ifdef PRECOMPUTED_MAGICS - void init_magics(Bitboard table[], Magic magics[], std::set directions, Bitboard magicsInit[]) { + void init_magics(Bitboard table[], Magic magics[], std::map directions, Bitboard magicsInit[]) { #else - void init_magics(Bitboard table[], Magic magics[], std::set directions) { + void init_magics(Bitboard table[], Magic magics[], std::map directions) { #endif // Optimal PRNG seeds to pick the correct magics in the shortest time diff --git a/src/parser.cpp b/src/parser.cpp index ed1762f..85a5fd9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -418,7 +418,8 @@ Variant* VariantParser::parse(Variant* v) { if (v->flipEnclosedPieces) std::cerr << "Can not use kings with flipEnclosedPieces." << std::endl; const PieceInfo* pi = pieceMap.find(v->kingType)->second; - if (pi->lameLeaper || pi->hopperQuiet.size() || pi->hopperCapture.size()) + if (pi->hopperQuiet.size() || pi->hopperCapture.size() + || std::any_of(pi->stepsCapture.begin(), pi->stepsCapture.end(), [](const std::pair& d) { return d.second; })) std::cerr << pi->name << " is not supported as kingType." << std::endl; } } diff --git a/src/piece.cpp b/src/piece.cpp index 6fc719b..e52e195 100644 --- a/src/piece.cpp +++ b/src/piece.cpp @@ -57,6 +57,8 @@ namespace { std::vector moveTypes = {}; bool hopper = false; bool rider = false; + bool lame = false; + int distance = 0; std::vector prelimDirections = {}; for (std::string::size_type i = 0; i < betza.size(); i++) { @@ -65,11 +67,15 @@ namespace { if (c == 'm' || c == 'c') moveTypes.push_back(c); // Hopper - else if (c == 'p') + else if (c == 'p' || c == 'g') + { hopper = true; + if (c == 'g') + distance = 1; + } // Lame leaper else if (c == 'n') - p->lameLeaper = true; + lame = true; // Directional modifiers else if (verticals.find(c) != std::string::npos || horizontals.find(c) != std::string::npos) { @@ -101,11 +107,11 @@ namespace { rider = true; // limited distance riders if (isdigit(betza[i+1])) - { - // TODO: not supported - } + distance = betza[i+1] - '0'; i++; } + if (!rider && lame) + distance = -1; // No type qualifier means m+c if (moveTypes.size() == 0) { @@ -129,28 +135,28 @@ namespace { // Add moves for (char mt : moveTypes) { - std::set& v = hopper ? (mt == 'c' ? p->hopperCapture : p->hopperQuiet) - : rider ? (mt == 'c' ? p->sliderCapture : p->sliderQuiet) - : (mt == 'c' ? p->stepsCapture : p->stepsQuiet); + auto& 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.insert(Direction(atom.first * FILE_NB + atom.second)); + v[Direction(atom.first * FILE_NB + atom.second)] = distance; 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.insert(Direction(-atom.first * FILE_NB - atom.second)); + v[Direction(-atom.first * FILE_NB - atom.second)] = distance; 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.insert(Direction(-atom.second * FILE_NB + atom.first)); + v[Direction(-atom.second * FILE_NB + atom.first)] = distance; 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.insert(Direction(atom.second * FILE_NB - atom.first)); + v[Direction(atom.second * FILE_NB - atom.first)] = distance; 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.insert(Direction(atom.second * FILE_NB + atom.first)); + v[Direction(atom.second * FILE_NB + atom.first)] = distance; 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.insert(Direction(-atom.second * FILE_NB - atom.first)); + v[Direction(-atom.second * FILE_NB - atom.first)] = distance; 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.insert(Direction(-atom.first * FILE_NB + atom.second)); + v[Direction(-atom.first * FILE_NB + atom.second)] = distance; 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.insert(Direction(atom.first * FILE_NB - atom.second)); + v[Direction(atom.first * FILE_NB - atom.second)] = distance; } } // Reset state @@ -164,18 +170,8 @@ namespace { } // Special multi-leg betza description for Janggi elephant PieceInfo* janggi_elephant_piece() { - PieceInfo* p = new PieceInfo(); - p->name = "janggiElephant"; - p->betza = "mafsmafW"; - p->stepsQuiet = {SOUTH + 2 * SOUTH_WEST, SOUTH + 2 * SOUTH_EAST, - WEST + 2 * SOUTH_WEST, EAST + 2 * SOUTH_EAST, - WEST + 2 * NORTH_WEST, EAST + 2 * NORTH_EAST, - NORTH + 2 * NORTH_WEST, NORTH + 2 * NORTH_EAST}; - p->stepsCapture = {SOUTH + 2 * SOUTH_WEST, SOUTH + 2 * SOUTH_EAST, - WEST + 2 * SOUTH_WEST, EAST + 2 * SOUTH_EAST, - WEST + 2 * NORTH_WEST, EAST + 2 * NORTH_EAST, - NORTH + 2 * NORTH_WEST, NORTH + 2 * NORTH_EAST}; - p->lameLeaper = true; + PieceInfo* p = from_betza("nZ", ""); + p->betza = "mafsmafW"; // for compatiblity with XBoard/Winboard return p; } } diff --git a/src/piece.h b/src/piece.h index 2ce4a7e..8f8479c 100644 --- a/src/piece.h +++ b/src/piece.h @@ -21,7 +21,6 @@ #include #include -#include #include "types.h" #include "variant.h" @@ -32,13 +31,12 @@ struct PieceInfo { std::string name = ""; std::string betza = ""; - std::set stepsQuiet = {}; - std::set stepsCapture = {}; - std::set sliderQuiet = {}; - std::set sliderCapture = {}; - std::set hopperQuiet = {}; - std::set hopperCapture = {}; - bool lameLeaper = false; + std::map stepsQuiet = {}; + std::map stepsCapture = {}; + std::map sliderQuiet = {}; + std::map sliderCapture = {}; + std::map hopperQuiet = {}; + std::map hopperCapture = {}; }; struct PieceMap : public std::map { diff --git a/src/psqt.cpp b/src/psqt.cpp index f8ba11d..026883f 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -161,8 +161,8 @@ Value piece_value(Phase phase, PieceType pt) + (phase == MG ? 100 : 80) * pi->hopperCapture.size() + (phase == MG ? 80 : 60) * pi->hopperQuiet.size() // Rook sliding directions are more valuable, especially in endgame - + (phase == MG ? 10 : 30) * std::count_if(pi->sliderCapture.begin(), pi->sliderCapture.end(), [](Direction d) { return std::abs(d) == NORTH || std::abs(d) == 1; }) - + (phase == MG ? 30 : 45) * std::count_if(pi->sliderQuiet.begin(), pi->sliderQuiet.end(), [](Direction d) { return std::abs(d) == NORTH || std::abs(d) == 1; }); + + (phase == MG ? 10 : 30) * std::count_if(pi->sliderCapture.begin(), pi->sliderCapture.end(), [](const std::pair& d) { return std::abs(d.first) == NORTH || std::abs(d.first) == 1; }) + + (phase == MG ? 30 : 45) * std::count_if(pi->sliderQuiet.begin(), pi->sliderQuiet.end(), [](const std::pair& d) { return std::abs(d.first) == NORTH || std::abs(d.first) == 1; }); return Value(v0 * exp(double(v0) / 10000)); } @@ -212,8 +212,8 @@ void init(const Variant* v) { const PieceInfo* pi = pieceMap.find(pt)->second; bool isSlider = pi->sliderQuiet.size() || pi->sliderCapture.size() || pi->hopperQuiet.size() || pi->hopperCapture.size(); - bool isPawn = !isSlider && pi->stepsQuiet.size() && !std::any_of(pi->stepsQuiet.begin(), pi->stepsQuiet.end(), [](Direction d) { return d < SOUTH / 2; }); - bool isSlowLeaper = !isSlider && !std::any_of(pi->stepsQuiet.begin(), pi->stepsQuiet.end(), [](Direction d) { return dist(d) > 1; }); + bool isPawn = !isSlider && pi->stepsQuiet.size() && !std::any_of(pi->stepsQuiet.begin(), pi->stepsQuiet.end(), [](const std::pair& d) { return d.first < SOUTH / 2; }); + bool isSlowLeaper = !isSlider && !std::any_of(pi->stepsQuiet.begin(), pi->stepsQuiet.end(), [](const std::pair& d) { return dist(d.first) > 1; }); // Scale slider piece values with board size if (isSlider) @@ -246,8 +246,7 @@ void init(const Variant* v) { // Increase leapers' value in makpong else if (v->makpongRule) { - if (std::any_of(pi->stepsCapture.begin(), pi->stepsCapture.end(), [](Direction d) { return dist(d) > 1; }) - && !pi->lameLeaper) + if (std::any_of(pi->stepsCapture.begin(), pi->stepsCapture.end(), [](const std::pair& d) { return dist(d.first) > 1 && !d.second; })) score = make_score(mg_value(score) * 4200 / (3500 + mg_value(score)), eg_value(score) * 4700 / (3500 + mg_value(score))); } diff --git a/src/variants.ini b/src/variants.ini index fe04d55..9ec87e3 100644 --- a/src/variants.ini +++ b/src/variants.ini @@ -95,9 +95,9 @@ # In Fairy-Stockfish only a subset of Betza notation can be used. The supported features are: # - all base moves/atoms (W, F, etc.) # - all directional modifiers (f, b, etc.) -# - unlimited distance sliders/riders for W/R, F/B, and N directions +# - limited and unlimited distance sliders/riders for W/R, F/B, and N directions # - hoppers for W/R and F/B directions, i.e., pR and pB -# - lame leapers (n) for N and A directions, i.e., nN and nA +# - lame leapers (n) for N, A, and Z directions, i.e., nN, nA, and nZ ### Piece values # The predefined and precalculated piece values can be overriden