Support Nightrider
authorFabian Fichter <ianfab@users.noreply.github.com>
Fri, 30 Apr 2021 19:42:40 +0000 (21:42 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Fri, 30 Apr 2021 20:29:29 +0000 (22:29 +0200)
src/bitboard.cpp
src/bitboard.h
src/magic.h
src/types.h
src/variant.cpp
src/variants.ini
tests/js/package.json
tests/perft.sh

index d00eb51..139823f 100644 (file)
@@ -46,9 +46,10 @@ Magic HorseMagics[SQUARE_NB];
 Magic ElephantMagics[SQUARE_NB];
 Magic JanggiElephantMagics[SQUARE_NB];
 Magic CannonDiagMagics[SQUARE_NB];
+Magic NightriderMagics[SQUARE_NB];
 
 Magic* magics[] = {BishopMagics, RookMagicsH, RookMagicsV, CannonMagicsH, CannonMagicsV,
-                   HorseMagics, ElephantMagics, JanggiElephantMagics, CannonDiagMagics};
+                   HorseMagics, ElephantMagics, JanggiElephantMagics, CannonDiagMagics, NightriderMagics};
 
 namespace {
 
@@ -64,6 +65,7 @@ namespace {
   Bitboard ElephantTable[0x400];  // To store elephant attacks
   Bitboard JanggiElephantTable[0x1C000];  // To store janggi elephant attacks
   Bitboard CannonDiagTable[0x33C00]; // To store diagonal cannon attacks
+  Bitboard NightriderTable[0x70200]; // To store nightrider attacks
 #else
   Bitboard RookTableH[0xA00];  // To store horizontal rook attacks
   Bitboard RookTableV[0xA00];  // To store vertical rook attacks
@@ -74,6 +76,7 @@ namespace {
   Bitboard ElephantTable[0x1A0];  // To store elephant attacks
   Bitboard JanggiElephantTable[0x5C00];  // To store janggi elephant attacks
   Bitboard CannonDiagTable[0x1480]; // To store diagonal cannon attacks
+  Bitboard NightriderTable[0x1840]; // To store nightrider attacks
 #endif
 
   // Rider directions
@@ -107,7 +110,7 @@ namespace {
     {
         bool hurdle = false;
         for (Square s = sq + (c == WHITE ? d : -d);
-             is_ok(s) && distance(s, s - (c == WHITE ? d : -d)) == 1;
+             is_ok(s) && distance(s, s - (c == WHITE ? d : -d)) <= 2;
              s += (c == WHITE ? d : -d))
         {
             if (MT != HOPPER || hurdle)
@@ -239,6 +242,8 @@ void Bitboards::init_pieces() {
               AttackRiderTypes[pt] |= RIDER_ROOK_H;
           if (std::find(RookDirectionsV.begin(), RookDirectionsV.end(), d) != RookDirectionsV.end())
               AttackRiderTypes[pt] |= RIDER_ROOK_V;
+          if (std::find(HorseDirections.begin(), HorseDirections.end(), d) != HorseDirections.end())
+              AttackRiderTypes[pt] |= RIDER_NIGHTRIDER;
       }
       for (Direction d : pi->sliderQuiet)
       {
@@ -248,6 +253,8 @@ void Bitboards::init_pieces() {
               MoveRiderTypes[pt] |= RIDER_ROOK_H;
           if (std::find(RookDirectionsV.begin(), RookDirectionsV.end(), d) != RookDirectionsV.end())
               MoveRiderTypes[pt] |= RIDER_ROOK_V;
+          if (std::find(HorseDirections.begin(), HorseDirections.end(), d) != HorseDirections.end())
+              MoveRiderTypes[pt] |= RIDER_NIGHTRIDER;
       }
       for (Direction d : pi->hopperCapture)
       {
@@ -328,6 +335,7 @@ void Bitboards::init() {
   init_magics<LAME_LEAPER>(ElephantTable, ElephantMagics, ElephantDirections, ElephantMagicInit);
   init_magics<LAME_LEAPER>(JanggiElephantTable, JanggiElephantMagics, JanggiElephantDirections, JanggiElephantMagicInit);
   init_magics<HOPPER>(CannonDiagTable, CannonDiagMagics, BishopDirections, CannonDiagMagicInit);
+  init_magics<RIDER>(NightriderTable, NightriderMagics, HorseDirections, NightriderMagicInit);
 #else
   init_magics<RIDER>(RookTableH, RookMagicsH, RookDirectionsH);
   init_magics<RIDER>(RookTableV, RookMagicsV, RookDirectionsV);
@@ -338,6 +346,7 @@ void Bitboards::init() {
   init_magics<LAME_LEAPER>(ElephantTable, ElephantMagics, ElephantDirections);
   init_magics<LAME_LEAPER>(JanggiElephantTable, JanggiElephantMagics, JanggiElephantDirections);
   init_magics<HOPPER>(CannonDiagTable, CannonDiagMagics, BishopDirections);
+  init_magics<RIDER>(NightriderTable, NightriderMagics, HorseDirections);
 #endif
 
   init_pieces();
index 1c105de..232c4f5 100644 (file)
@@ -148,6 +148,7 @@ extern Magic HorseMagics[SQUARE_NB];
 extern Magic ElephantMagics[SQUARE_NB];
 extern Magic JanggiElephantMagics[SQUARE_NB];
 extern Magic CannonDiagMagics[SQUARE_NB];
+extern Magic NightriderMagics[SQUARE_NB];
 
 extern Magic* magics[];
 
@@ -383,7 +384,7 @@ template<RiderType R>
 inline Bitboard rider_attacks_bb(Square s, Bitboard occupied) {
 
   assert(R == RIDER_BISHOP || R == RIDER_ROOK_H || R == RIDER_ROOK_V || R == RIDER_CANNON_H || R == RIDER_CANNON_V
-         || R == RIDER_HORSE || R == RIDER_ELEPHANT || R == RIDER_JANGGI_ELEPHANT || R == RIDER_CANNON_DIAG);
+         || R == RIDER_HORSE || R == RIDER_ELEPHANT || R == RIDER_JANGGI_ELEPHANT || R == RIDER_CANNON_DIAG || R == RIDER_NIGHTRIDER);
   const Magic& m =  R == RIDER_ROOK_H ? RookMagicsH[s]
                   : R == RIDER_ROOK_V ? RookMagicsV[s]
                   : R == RIDER_CANNON_H ? CannonMagicsH[s]
@@ -392,6 +393,7 @@ inline Bitboard rider_attacks_bb(Square s, Bitboard occupied) {
                   : R == RIDER_ELEPHANT ? ElephantMagics[s]
                   : R == RIDER_JANGGI_ELEPHANT ? JanggiElephantMagics[s]
                   : R == RIDER_CANNON_DIAG ? CannonDiagMagics[s]
+                  : R == RIDER_NIGHTRIDER ? NightriderMagics[s]
                   : BishopMagics[s];
   return m.attacks[m.index(occupied)];
 }
@@ -401,7 +403,7 @@ inline Square lsb(Bitboard b);
 inline Bitboard rider_attacks_bb(RiderType R, Square s, Bitboard occupied) {
 
   assert(R == RIDER_BISHOP || R == RIDER_ROOK_H || R == RIDER_ROOK_V || R == RIDER_CANNON_H || R == RIDER_CANNON_V
-         || R == RIDER_HORSE || R == RIDER_ELEPHANT || R == RIDER_JANGGI_ELEPHANT || R == RIDER_CANNON_DIAG);
+         || R == RIDER_HORSE || R == RIDER_ELEPHANT || R == RIDER_JANGGI_ELEPHANT || R == RIDER_CANNON_DIAG || R == RIDER_NIGHTRIDER);
   const Magic& m = magics[lsb(R)][s]; // re-use Bitboard lsb for riders
   return m.attacks[m.index(occupied)];
 }
index 33649ab..e12eb46 100644 (file)
       B(0x20012C2400880082, 0x7000880020C03200),
       B(0x204040300004, 0x840800041101002),
   };
+  Bitboard NightriderMagicInit[SQUARE_NB] = {
+      B(0x8008100800020052, 0x8001440000000000),
+      B(0x24028400210090, 0x4200000000021),
+      B(0x22002020A0200800, 0x100820120000082),
+      B(0x424009020002200, 0x84810D4100002A),
+      B(0x404008020000600, 0x1000202000000081),
+      B(0x21020001000680, 0x2140200000000000),
+      B(0x2060021100000608, 0x8080020040000C8),
+      B(0x910C20408001200, 0x80A4030800000500),
+      B(0x2C40100010400009, 0x40400000200000C),
+      B(0x4090210034400004, 0x2104008000000),
+      B(0x1082008040840180, 0x140082080000000F),
+      B(0x8041001002101002, 0x8C002000000),
+      B(0x102205086800080, 0x84400030020D600),
+      B(0x2120080A32044E0, 0x400A02000016000),
+      B(0x6040003021040A0, 0x8000200206040040),
+      B(0x8001000008104082, 0x4002104202000114),
+      B(0x100400081080000, 0x201020020000020),
+      B(0x203000090010040, 0x140040010000000C),
+      B(0x9140000108100040, 0x4004004C08450010),
+      B(0x4402A12120020000, 0x450C002C000040C),
+      B(0x2028000200120800, 0x100100401001000),
+      B(0x800890081000, 0x10700A080180048),
+      B(0x41040C4008400, 0x8080001000080020),
+      B(0x2404000001060401, 0x10800116C0009110),
+      B(0x2001810020400110, 0xA0100800000480E2),
+      B(0x4081400120200218, 0x8800410800000000),
+      B(0x4C020020300E00, 0x810800000000808),
+      B(0xC8002200100108, 0x4860040380000100),
+      B(0x8000E0000804080, 0x4C800000000000),
+      B(0x211880010934041, 0x31000040000188),
+      B(0x4800801000003140, 0x80000000028),
+      B(0x61240410840004, 0x230100050000002),
+      B(0x61240410840004, 0x230100050000002),
+      B(0x4020008000C04C42, 0x3000021000000804),
+      B(0x829808040040840, 0x288010000002200),
+      B(0xA0420002040084, 0x1008604002000048),
+      B(0x10200004980, 0x2010410028000000),
+      B(0x4900200420100010, 0x1000A00401001898),
+      B(0x20000801600134, 0xC0002400000021C),
+      B(0x200040021010001, 0x8800000400000088),
+      B(0x88000824, 0x8800000040010000),
+      B(0x40000000200000D0, 0x8200004000AA84),
+      B(0x1002000000812002, 0x4000001C1008480),
+      B(0xC00010420003, 0x400002C00000004),
+      B(0x208400008008040, 0x111004280000C0),
+      B(0x60004000E800241, 0x202001000010040),
+      B(0x200004800061, 0x1109100480045800),
+      B(0x52880000200001, 0x608204100012DA0),
+      B(0x1000429008100800, 0x2008001000006018),
+      B(0x8490024200123001, 0x1041400080020),
+      B(0x810001020200014, 0x2C50500220000020),
+      B(0x20234B8000A0080, 0x4091200200000020),
+      B(0x400401010012600, 0xE00200000000020),
+      B(0x8040C00804004000, 0x8208014000000083),
+      B(0x102000410001044, 0x8200000000000),
+      B(0x102000410001044, 0x8200000000000),
+      B(0x242E00508040001, 0x80028000000000),
+      B(0x40810368002080, 0x4008080000224),
+      B(0x48200010208800, 0x1020800C000022),
+      B(0x220C4018008000, 0x282100130000211),
+      B(0x8008004400100, 0xC128208200020400),
+      B(0x44C004100020, 0x4008004000011000),
+      B(0x1008000000600008, 0x41C00180480183),
+      B(0x10080000, 0x404090018800020A),
+      B(0x4500000000004200, 0x45200200A0140),
+      B(0x2040000000240003, 0x8020080288000600),
+      B(0x2040000000240003, 0x8020080288000600),
+      B(0x2040000000240003, 0x8020080288000600),
+      B(0x48000000020A0080, 0x1000020200088),
+      B(0xA00000008404200, 0x4204010101001004),
+      B(0x10008030082, 0x2002800200100104),
+      B(0x44080002460010, 0x8007804100082D00),
+      B(0x98400040001802, 0x913002002020301),
+      B(0xA0400501040028, 0x8040481824002024),
+      B(0x4C0A0600100080A0, 0x8005000080008200),
+      B(0x802124000860008, 0x1009081800100080),
+      B(0x4000110040011000, 0x4080422200001081),
+      B(0x422008008000080, 0x4001020C00000202),
+      B(0x8000202008002101, 0xA008010000040),
+      B(0x804200020000020, 0xE0B0008010000001),
+      B(0x14040200002, 0x2000000006000004),
+      B(0x45000002010020, 0xA4040008400000),
+      B(0x800040020204184A, 0x10000402000006),
+      B(0x908000080400004, 0x5040100038400050),
+      B(0x3100002000040014, 0x804008008120000),
+      B(0x6002200000020008, 0xC011409081008881),
+      B(0xC02004060280001, 0x2003004010220254),
+      B(0x16410101, 0x100040108600000),
+      B(0x100000000200000, 0x201200010800200),
+      B(0xC400000004090002, 0x808808010224000A),
+      B(0xC400000004090002, 0x808808010224000A),
+      B(0x1000000000890001, 0x4050002001040),
+      B(0x618000000008484, 0x40000A0150000D4),
+      B(0x500000400009004, 0x1100200204100A1),
+      B(0x6006000008080480, 0x100254800C00904),
+      B(0x6006000008080480, 0x100254800C00904),
+      B(0x404808040044040, 0x4202020040000200),
+      B(0x2000080440810, 0x9044008844920000),
+      B(0x40204418040, 0x412000204080010),
+      B(0x88400820040248, 0x408040010C040800),
+      B(0x8110084000803, 0x102000000000),
+      B(0x4000040140001100, 0x80808102002),
+      B(0x100480044020008, 0x4601000100084488),
+      B(0x6200204420840, 0x41802043B0000),
+      B(0x540000010091010, 0x409004800A01208),
+      B(0x300040008000008, 0x2030080800010000),
+      B(0x408804010400090, 0x4008100800004000),
+      B(0x401600A0000080, 0x8400200201002200),
+      B(0x44000000100000, 0x1140040210000001),
+      B(0xC6000000D00804, 0x1050020C0081090C),
+      B(0x4098002, 0x900000C045008300),
+      B(0x245190008020, 0x2000C00100041000),
+      B(0x1000000A100046, 0x88000084800004),
+      B(0x1000000220240002, 0x400000401001088),
+      B(0x1000000220240002, 0x400000401001088),
+      B(0x820000118808000, 0x8000048161004A),
+      B(0x1100000000071A02, 0x500146102000048),
+      B(0x610000, 0x10010080040641),
+      B(0x2000010441A0044, 0x500800502020188),
+      B(0xA80000000180000, 0x234402012110080),
+  };
 #undef B
 #endif
 
index 38de559..c3df461 100644 (file)
@@ -417,10 +417,11 @@ enum RiderType : int {
   RIDER_ELEPHANT = 1 << 6,
   RIDER_JANGGI_ELEPHANT = 1 << 7,
   RIDER_CANNON_DIAG = 1 << 8,
+  RIDER_NIGHTRIDER = 1 << 9,
   HOPPING_RIDERS = RIDER_CANNON_H | RIDER_CANNON_V | RIDER_CANNON_DIAG,
   LAME_LEAPERS = RIDER_HORSE | RIDER_ELEPHANT | RIDER_JANGGI_ELEPHANT,
   ASYMMETRICAL_RIDERS = RIDER_HORSE | RIDER_JANGGI_ELEPHANT,
-  NON_SLIDING_RIDERS = HOPPING_RIDERS | LAME_LEAPERS,
+  NON_SLIDING_RIDERS = HOPPING_RIDERS | LAME_LEAPERS | RIDER_NIGHTRIDER,
 };
 
 extern Value PieceValue[PHASE_NB][PIECE_NB];
index e08ed17..8287d61 100644 (file)
@@ -192,6 +192,17 @@ namespace {
         v->promotionPieceTypes = {AMAZON, ROOK, BISHOP, KNIGHT};
         return v;
     }
+    // Nightrider chess
+    // Knights are replaced by nightriders.
+    // https://en.wikipedia.org/wiki/Nightrider_(chess)
+    Variant* nightrider_variant() {
+        Variant* v = chess_variant_base();
+        v->remove_piece(KNIGHT);
+        v->customPiece[0] = "NN";
+        v->add_piece(CUSTOM_PIECES, 'n');
+        v->promotionPieceTypes = {QUEEN, ROOK, BISHOP, CUSTOM_PIECES};
+        return v;
+    }
     // Hoppel-Poppel
     // A variant from Germany where knights capture like bishops and vice versa
     // https://www.chessvariants.com/diffmove.dir/hoppel-poppel.html
@@ -1273,6 +1284,7 @@ void VariantMap::init() {
     add("shatranj", shatranj_variant()->conclude());
     add("chaturanga", chaturanga_variant()->conclude());
     add("amazon", amazon_variant()->conclude());
+    add("nightrider", nightrider_variant()->conclude());
     add("hoppelpoppel", hoppelpoppel_variant()->conclude());
     add("newzealand", newzealand_variant()->conclude());
     add("kingofthehill", kingofthehill_variant()->conclude());
index 0f70dbc..fe04d55 100644 (file)
@@ -95,7 +95,7 @@
 # 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 for W/R and F/B directions
+# - 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
 
index 896e22d..0c2b43e 100644 (file)
@@ -4,7 +4,7 @@
   "description": "A high performance WebAssembly chess variant library based on Fairy-Stockfish",
   "main": "ffish.js",
   "scripts": {
-    "test": "mocha --timeout 40000",
+    "test": "mocha --timeout 80000",
     "dev": "node index"
   },
   "author": [
index 4979416..fab2ab8 100755 (executable)
@@ -52,6 +52,7 @@ if [[ $1 == "" || $1 == "variant" ]]; then
   expect perft.exp sittuyin "fen 8/6s1/5P2/3n4/pR2K2S/1P6/1k4p1/8[] w - - 1 50" 4 268869 > /dev/null
   expect perft.exp shatranj startpos 4 68122 > /dev/null
   expect perft.exp amazon startpos 4 318185 > /dev/null
+  expect perft.exp nightrider startpos 4 419019 > /dev/null
   expect perft.exp hoppelpoppel startpos 4 202459 > /dev/null
   expect perft.exp newzealand startpos 4 200310 > /dev/null
   # alternative goals