Implement Griffon piece type
authorH.G.Muller <hgm@hgm-xboard.(none)>
Sat, 3 Jan 2026 21:46:41 +0000 (22:46 +0100)
committerH.G.Muller <hgm@hgm-xboard.(none)>
Mon, 5 Jan 2026 08:28:25 +0000 (09:28 +0100)
Four new RiderTypes are added, using 'tableless magics'. Thai is, they
use the attacks tables of the Rook, but shifted by one file or rank.
The Betza parser in extended to recognize two-leg moves of teh type yafs...,
where yafsF is recognized as the Griffon. It then generates the (fake)
large leap that is used to indicate these type of bent slides, omitting
moves to the first square of the ride. (Because this is what yafsF means).
  Unbent moves of the type yaf... are recognized as lame ski-sliders.

src/bitboard.cpp
src/piece.cpp
src/piece.h
src/types.h

index 970fe3b..c85dd04 100644 (file)
@@ -54,11 +54,16 @@ Magic NightriderMagics[SQUARE_NB];
 Magic GrasshopperMagicsH[SQUARE_NB];
 Magic GrasshopperMagicsV[SQUARE_NB];
 Magic GrasshopperMagicsD[SQUARE_NB];
+Magic RookMagicsHT[SQUARE_NB];
+Magic RookMagicsHB[SQUARE_NB];
+Magic RookMagicsVL[SQUARE_NB];
+Magic RookMagicsVR[SQUARE_NB];
 Magic CustomMagics[MAX_RIDE - CUSTOM_RIDES][SQUARE_NB];
 
 Magic* magics[MAX_RIDE] = {BishopMagics, RookMagicsH, RookMagicsV, CannonMagicsH, CannonMagicsV,
                    LameDabbabaMagics, HorseMagics, ElephantMagics, JanggiElephantMagics, CannonDiagMagics, NightriderMagics,
-                   GrasshopperMagicsH, GrasshopperMagicsV, GrasshopperMagicsD};
+                   GrasshopperMagicsH, GrasshopperMagicsV, GrasshopperMagicsD,
+                   RookMagicsHT, RookMagicsHB, RookMagicsVL, RookMagicsVR };
 
 int nrOfRides;
 int riderBaseType[MAX_RIDE];
@@ -116,6 +121,10 @@ namespace {
   const std::map<DirectionCode, int> GrasshopperDirectionsH { {step(0, 1), 0xFFFE}, {step(0, -1), 0xFFFE} };
   const std::map<DirectionCode, int> GrasshopperDirectionsD { {step(1, 1), 0xFFFE}, {step(-1, 1), 0xFFFE},
                                                               {step(-1, -1), 0xFFFE}, {step(1, -1), 0xFFFE} };
+  const std::map<DirectionCode, int> RookDirectionsHT { {step(1, -BENT), 0}, {step(1, BENT), 0} };
+  const std::map<DirectionCode, int> RookDirectionsHB { {step(-1, -BENT), 0}, {step(-1, BENT), 0} };
+  const std::map<DirectionCode, int> RookDirectionsVL { {step(-BENT, -1), 0}, {step(BENT, -1), 0} };
+  const std::map<DirectionCode, int> RookDirectionsVR { {step(-BENT, 1), 0}, {step(BENT, 1), 0} };
 
   const std::map<DirectionCode, int> allDirections[] { BishopDirections, RookDirectionsH, RookDirectionsV };
 
@@ -133,13 +142,23 @@ namespace {
 
         bool hurdle = false;
         Direction d = board_step(v);
+        Direction x = h_step(v);
+        Direction y = v_step(v);
         int lim = limit;
+        Square ss = sq;
         Bitboard attack = 0;
 
         if(c != WHITE) d = -d;
         if(MT == HOPPER_RANGE && limit == 0xFFFE) lim = 0; // give grasshopper unlimited total range
 
-        for (Square s = sq + d;
+        if(std::abs(x) == BENT) { // bent slider
+          d = x/BENT; ss += y*FILE_NB;
+        } else
+        if(std::abs(y) == BENT) { // bent slider
+          d = y*FILE_NB/BENT; ss += x;
+        }
+
+        for (Square s = ss + d;
              is_ok(s) && distance(s, s - d) <= 2;
              s += d)
         {
@@ -322,6 +341,14 @@ void Bitboards::init_pieces() {
                       riderTypes |= assign_magic(RIDER_ROOK_V, limit);
                   if (HorseDirections.find(d) != HorseDirections.end())
                       riderTypes |= RIDER_NIGHTRIDER;
+                  if (RookDirectionsHT.find(d) != RookDirectionsHT.end())
+                      riderTypes |= RIDER_ROOK_HT;
+                  if (RookDirectionsVR.find(d) != RookDirectionsVR.end())
+                      riderTypes |= RIDER_ROOK_VR;
+                  if (RookDirectionsHB.find(d) != RookDirectionsHB.end())
+                      riderTypes |= RIDER_ROOK_HB;
+                  if (RookDirectionsVL.find(d) != RookDirectionsVL.end())
+                      riderTypes |= RIDER_ROOK_VL;
               }
               for (auto const& [d, limit] : pi->hopper[initial][modality])
               {
@@ -420,6 +447,15 @@ void Bitboards::init() {
 
   nrOfRides = CUSTOM_RIDES;
   for(int i = 0; i < CUSTOM_RIDES; i++) riderBaseType[i] = i;
++
+  // Magics that can use attacks tables from others
+  for(Square s = SQ_A1; s <= SQ_MAX; ++s)
+  {
+    RookMagicsHT[s] = RookMagicsH[rank_of(s) < RANK_NB - 1 ? s + FILE_NB : s - FILE_NB];
+    RookMagicsHB[s] = RookMagicsH[rank_of(s) > 0 ? s - FILE_NB : s + FILE_NB];
+    RookMagicsVR[s] = RookMagicsV[file_of(s) < FILE_NB - 1 ? s + 1 : s - 1];
+    RookMagicsVL[s] = RookMagicsV[file_of(s) > 0 ? s - 1 : s + 1];
+  }
 
   init_pieces();
 
index 82a4117..851bbc8 100644 (file)
@@ -64,6 +64,7 @@ namespace {
       int distance = 0;
       int fExtension = 0;
       int fsExtension = 0;
+      BentType bent = SINGLE_LEG;
       std::vector<std::string> prelimDirections = {};
       for (std::string::size_type i = 0; i < betza.size(); i++)
       {
@@ -103,6 +104,17 @@ namespace {
               }
               prelimDirections.push_back(std::string(2, c));
           }
+          // Multi-leg
+          else if(betza.size() > i + 3 && (c == 'a' || (c == 'y' && betza[++i] == 'a'))) // detect yaf(s)
+          {
+              if(betza[i+1] == 'f' && c == 'y')
+              {
+                  if(betza[i+2] == 's') { i++; bent = BENT_SLIDER; }
+                  else bent = SKI_SLIDER;
+                  i++; distance |= 1; // suppress 1-step moves
+                  moveModalities.clear();
+              }
+          }
           // Move atom
           else if (leaperAtoms.find(c) != leaperAtoms.end() || riderAtoms.find(c) != riderAtoms.end())
           {
@@ -141,6 +153,10 @@ namespace {
                   int y = atom.first + 3*fExtension + 2*fsExtension;
                   int x = atom.second + 2*fsExtension;
                   std::vector<std::string> directions = {};
+                  if(bent != SINGLE_LEG) {
+                      if(bent == BENT_SLIDER && c == 'F') y = BENT; // yafsF = griffon
+                      rider = true;
+                  }
                   if(rider && y > 1 && (x == 0 || x == y)) { // radial true rider
                       for(int n = distance; ~n & 1; n >>= 1) distance <<= y - 1; // adapt range to larger stride
                       distance &= 0xFFFF;
@@ -197,6 +213,7 @@ namespace {
               distance = 0;
               fExtension = 0;
               fsExtension = 0;
+              bent = SINGLE_LEG;
           }
       }
       return p;
index 38fdcc9..d83e5d3 100644 (file)
@@ -27,6 +27,8 @@
 
 namespace Stockfish {
 
+const int BENT = 9; // kludge for indicating bent slider as leap
+
 enum MoveModality {MODALITY_QUIET, MODALITY_CAPTURE, MOVE_MODALITY_NB};
 
 /// PieceInfo struct stores information about the piece movements.
index aac1085..620e99b 100644 (file)
@@ -450,6 +450,10 @@ enum PieceSet : uint64_t {
   COMMON_STEP_PIECES = (1ULL << COMMONER) | (1ULL << FERS) | (1ULL << WAZIR) | (1ULL << BREAKTHROUGH_PIECE),
 };
 
+enum BentType : int {
+  SINGLE_LEG, SKI_SLIDER, BENT_SLIDER, HOOK_MOVER
+};
+
 enum RiderType : int {
   NO_RIDER = 0,
   RIDER_BISHOP = 1 << 0,
@@ -466,10 +470,15 @@ enum RiderType : int {
   RIDER_GRASSHOPPER_H = 1 << 11,
   RIDER_GRASSHOPPER_V = 1 << 12,
   RIDER_GRASSHOPPER_D = 1 << 13,
+  RIDER_ROOK_HT = 1 << 14,
+  RIDER_ROOK_HB = 1 << 15,
+  RIDER_ROOK_VL = 1 << 16,
+  RIDER_ROOK_VR = 1 << 17,
+  RIDER_GRIFFON = RIDER_ROOK_HT | RIDER_ROOK_HB | RIDER_ROOK_VL | RIDER_ROOK_VR,
   HOPPING_RIDERS =  RIDER_CANNON_H | RIDER_CANNON_V | RIDER_CANNON_DIAG
                   | RIDER_GRASSHOPPER_H | RIDER_GRASSHOPPER_V | RIDER_GRASSHOPPER_D,
   LAME_LEAPERS = RIDER_LAME_DABBABA | RIDER_HORSE | RIDER_ELEPHANT | RIDER_JANGGI_ELEPHANT,
-  ASYMMETRICAL_RIDERS =  RIDER_HORSE | RIDER_JANGGI_ELEPHANT
+  ASYMMETRICAL_RIDERS =  RIDER_HORSE | RIDER_JANGGI_ELEPHANT | GRIFFON
                        | RIDER_GRASSHOPPER_H | RIDER_GRASSHOPPER_V | RIDER_GRASSHOPPER_D,
   NON_SLIDING_RIDERS = HOPPING_RIDERS | LAME_LEAPERS | RIDER_NIGHTRIDER,
   CUSTOM_RIDES = 20,