From 32795fb239fea9f2e78b8c53b77315b3c5138137 Mon Sep 17 00:00:00 2001 From: H.G.Muller Date: Sat, 3 Jan 2026 21:39:15 +0100 Subject: [PATCH] Derive new magics from existing sliders dynamically The infra-structure is provided for adding new magic attack getters from those for Rook and Bishop. These use the same attacks tables as the one they are copied from, but mask away some squares from teh original masks. This is controlled by the 16 high-order bits of the range code passed from the Betza parser to the bitboard-creating routines, which then do for the masks what the 16 low-order bits do for the pseudoAttacks: remove those squares from the slider path for which the corresponding bit was set. This is a memory-efficient way for creating new types of rides in the 8 principal directions, such as Dabbaba- or Alfilrider, or even those with still larger strides, such as the Threeleaperrider (HH). It can in principle also be used for defining (non-lame) ski-sliders or a Panda. --- src/bitboard.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++++++---- src/types.h | 2 ++ 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index da2f98d..970fe3b 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -54,11 +54,16 @@ Magic NightriderMagics[SQUARE_NB]; Magic GrasshopperMagicsH[SQUARE_NB]; Magic GrasshopperMagicsV[SQUARE_NB]; Magic GrasshopperMagicsD[SQUARE_NB]; +Magic CustomMagics[MAX_RIDE - CUSTOM_RIDES][SQUARE_NB]; -Magic* magics[] = {BishopMagics, RookMagicsH, RookMagicsV, CannonMagicsH, CannonMagicsV, +Magic* magics[MAX_RIDE] = {BishopMagics, RookMagicsH, RookMagicsV, CannonMagicsH, CannonMagicsV, LameDabbabaMagics, HorseMagics, ElephantMagics, JanggiElephantMagics, CannonDiagMagics, NightriderMagics, GrasshopperMagicsH, GrasshopperMagicsV, GrasshopperMagicsD}; +int nrOfRides; +int riderBaseType[MAX_RIDE]; +int riderRangeMask[MAX_RIDE]; + namespace { // Some magics need to be split in order to reduce memory consumption. @@ -112,6 +117,8 @@ namespace { const std::map GrasshopperDirectionsD { {step(1, 1), 0xFFFE}, {step(-1, 1), 0xFFFE}, {step(-1, -1), 0xFFFE}, {step(1, -1), 0xFFFE} }; + const std::map allDirections[] { BishopDirections, RookDirectionsH, RookDirectionsV }; + enum MovementType { RIDER, HOPPER, LAME_LEAPER, HOPPER_RANGE }; template @@ -242,6 +249,40 @@ std::string Bitboards::pretty(Bitboard b) { return s; } +/// Derive a new RiderType from a sliding one, (if it did not exist yet) +/// by removing squares to be skipped from the masks of the latter + +RiderType assign_magic(RiderType r, int limit) { + + int n = lsb(r); + int i; + limit >>= 16; + + for(i = 0; i < nrOfRides; i++) + if(riderBaseType[i] == n && riderRangeMask[i] == limit) return RiderType(1 << i); + + if(nrOfRides == MAX_RIDE) return r; // use standard mask if capacity exceeded + + i = nrOfRides++; // allocate new magic + riderBaseType[i] = n; + riderRangeMask[i] = limit; + Magic* m = CustomMagics[i - CUSTOM_RIDES]; + magics[i] = m; + + for(Square s = SQ_A1; s < SQUARE_NB; ++s) + { + Bitboard b = 0; + m[s] = magics[n][s]; + + for (auto const& [v, limit2] : allDirections[n]) { + b |= one_ride(v, limit, s, 0, WHITE); + } + m[s].mask &= b; // restrict mask according to high bits of limit + } + + return RiderType(1 << i); +} + /// Bitboards::init_pieces() initializes piece move/attack bitboards and rider types void Bitboards::init_pieces() { @@ -274,11 +315,11 @@ void Bitboards::init_pieces() { for (auto const& [d, limit] : pi->slider[initial][modality]) { if (BishopDirections.find(d) != BishopDirections.end()) - riderTypes |= RIDER_BISHOP; + riderTypes |= assign_magic(RIDER_BISHOP, limit); if (RookDirectionsH.find(d) != RookDirectionsH.end()) - riderTypes |= RIDER_ROOK_H; + riderTypes |= assign_magic(RIDER_ROOK_H, limit); if (RookDirectionsV.find(d) != RookDirectionsV.end()) - riderTypes |= RIDER_ROOK_V; + riderTypes |= assign_magic(RIDER_ROOK_V, limit); if (HorseDirections.find(d) != HorseDirections.end()) riderTypes |= RIDER_NIGHTRIDER; } @@ -377,6 +418,9 @@ void Bitboards::init() { init_magics(GrasshopperTableD, GrasshopperMagicsD, GrasshopperDirectionsD); #endif + nrOfRides = CUSTOM_RIDES; + for(int i = 0; i < CUSTOM_RIDES; i++) riderBaseType[i] = i; + init_pieces(); for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1) diff --git a/src/types.h b/src/types.h index e271faf..aac1085 100644 --- a/src/types.h +++ b/src/types.h @@ -472,6 +472,8 @@ enum RiderType : int { ASYMMETRICAL_RIDERS = RIDER_HORSE | RIDER_JANGGI_ELEPHANT | RIDER_GRASSHOPPER_H | RIDER_GRASSHOPPER_V | RIDER_GRASSHOPPER_D, NON_SLIDING_RIDERS = HOPPING_RIDERS | LAME_LEAPERS | RIDER_NIGHTRIDER, + CUSTOM_RIDES = 20, + MAX_RIDE = 32 }; extern Value PieceValue[PHASE_NB][PIECE_NB]; -- 1.7.0.4