Support diagonal cannon movements
authorFabian Fichter <ianfab@users.noreply.github.com>
Fri, 30 Apr 2021 14:50:29 +0000 (16:50 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Fri, 30 Apr 2021 17:02:38 +0000 (19:02 +0200)
src/bitboard.cpp
src/bitboard.h
src/magic.h
src/position.cpp
src/position.h
src/types.h
src/variants.ini
tests/js/package.json

index cf7a45e..d00eb51 100644 (file)
@@ -45,9 +45,10 @@ Magic CannonMagicsV[SQUARE_NB];
 Magic HorseMagics[SQUARE_NB];
 Magic ElephantMagics[SQUARE_NB];
 Magic JanggiElephantMagics[SQUARE_NB];
+Magic CannonDiagMagics[SQUARE_NB];
 
 Magic* magics[] = {BishopMagics, RookMagicsH, RookMagicsV, CannonMagicsH, CannonMagicsV,
-                   HorseMagics, ElephantMagics, JanggiElephantMagics};
+                   HorseMagics, ElephantMagics, JanggiElephantMagics, CannonDiagMagics};
 
 namespace {
 
@@ -62,6 +63,7 @@ namespace {
   Bitboard HorseTable[0x500];  // To store horse attacks
   Bitboard ElephantTable[0x400];  // To store elephant attacks
   Bitboard JanggiElephantTable[0x1C000];  // To store janggi elephant attacks
+  Bitboard CannonDiagTable[0x33C00]; // To store diagonal cannon attacks
 #else
   Bitboard RookTableH[0xA00];  // To store horizontal rook attacks
   Bitboard RookTableV[0xA00];  // To store vertical rook attacks
@@ -71,6 +73,7 @@ namespace {
   Bitboard HorseTable[0x240];  // To store horse attacks
   Bitboard ElephantTable[0x1A0];  // To store elephant attacks
   Bitboard JanggiElephantTable[0x5C00];  // To store janggi elephant attacks
+  Bitboard CannonDiagTable[0x1480]; // To store diagonal cannon attacks
 #endif
 
   // Rider directions
@@ -252,6 +255,8 @@ void Bitboards::init_pieces() {
               AttackRiderTypes[pt] |= RIDER_CANNON_H;
           if (std::find(RookDirectionsV.begin(), RookDirectionsV.end(), d) != RookDirectionsV.end())
               AttackRiderTypes[pt] |= RIDER_CANNON_V;
+          if (std::find(BishopDirections.begin(), BishopDirections.end(), d) != BishopDirections.end())
+              AttackRiderTypes[pt] |= RIDER_CANNON_DIAG;
       }
       for (Direction d : pi->hopperQuiet)
       {
@@ -259,6 +264,8 @@ void Bitboards::init_pieces() {
               MoveRiderTypes[pt] |= RIDER_CANNON_H;
           if (std::find(RookDirectionsV.begin(), RookDirectionsV.end(), d) != RookDirectionsV.end())
               MoveRiderTypes[pt] |= RIDER_CANNON_V;
+          if (std::find(BishopDirections.begin(), BishopDirections.end(), d) != BishopDirections.end())
+              MoveRiderTypes[pt] |= RIDER_CANNON_DIAG;
       }
 
       // Initialize move/attack bitboards
@@ -320,6 +327,7 @@ void Bitboards::init() {
   init_magics<LAME_LEAPER>(HorseTable, HorseMagics, HorseDirections, HorseMagicInit);
   init_magics<LAME_LEAPER>(ElephantTable, ElephantMagics, ElephantDirections, ElephantMagicInit);
   init_magics<LAME_LEAPER>(JanggiElephantTable, JanggiElephantMagics, JanggiElephantDirections, JanggiElephantMagicInit);
+  init_magics<HOPPER>(CannonDiagTable, CannonDiagMagics, BishopDirections, CannonDiagMagicInit);
 #else
   init_magics<RIDER>(RookTableH, RookMagicsH, RookDirectionsH);
   init_magics<RIDER>(RookTableV, RookMagicsV, RookDirectionsV);
@@ -329,6 +337,7 @@ void Bitboards::init() {
   init_magics<LAME_LEAPER>(HorseTable, HorseMagics, HorseDirections);
   init_magics<LAME_LEAPER>(ElephantTable, ElephantMagics, ElephantDirections);
   init_magics<LAME_LEAPER>(JanggiElephantTable, JanggiElephantMagics, JanggiElephantDirections);
+  init_magics<HOPPER>(CannonDiagTable, CannonDiagMagics, BishopDirections);
 #endif
 
   init_pieces();
index dd3d2c7..1c105de 100644 (file)
@@ -147,6 +147,7 @@ extern Magic CannonMagicsV[SQUARE_NB];
 extern Magic HorseMagics[SQUARE_NB];
 extern Magic ElephantMagics[SQUARE_NB];
 extern Magic JanggiElephantMagics[SQUARE_NB];
+extern Magic CannonDiagMagics[SQUARE_NB];
 
 extern Magic* magics[];
 
@@ -382,7 +383,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_HORSE || R == RIDER_ELEPHANT || R == RIDER_JANGGI_ELEPHANT || R == RIDER_CANNON_DIAG);
   const Magic& m =  R == RIDER_ROOK_H ? RookMagicsH[s]
                   : R == RIDER_ROOK_V ? RookMagicsV[s]
                   : R == RIDER_CANNON_H ? CannonMagicsH[s]
@@ -390,6 +391,7 @@ inline Bitboard rider_attacks_bb(Square s, Bitboard occupied) {
                   : R == RIDER_HORSE ? HorseMagics[s]
                   : R == RIDER_ELEPHANT ? ElephantMagics[s]
                   : R == RIDER_JANGGI_ELEPHANT ? JanggiElephantMagics[s]
+                  : R == RIDER_CANNON_DIAG ? CannonDiagMagics[s]
                   : BishopMagics[s];
   return m.attacks[m.index(occupied)];
 }
@@ -399,7 +401,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_HORSE || R == RIDER_ELEPHANT || R == RIDER_JANGGI_ELEPHANT || R == RIDER_CANNON_DIAG);
   const Magic& m = magics[lsb(R)][s]; // re-use Bitboard lsb for riders
   return m.attacks[m.index(occupied)];
 }
index d8f305a..33649ab 100644 (file)
       B(0x220400000A80040, 0x806080020810010C),
       B(0xA000200000000080, 0x1040801A0081208),
   };
+  Bitboard CannonDiagMagicInit[SQUARE_NB] = {
+      B(0x811801000400, 0x312260280280202),
+      B(0x44A000402022680, 0x1020224880420005),
+      B(0x8000C80800200880, 0x2000810060080C0),
+      B(0x2010300240428040, 0x40240002C004E30),
+      B(0x1018010404010004, 0x1001010018081E0),
+      B(0x2042040010080090, 0x100000008410300),
+      B(0x400080020102000, 0x4500005300000000),
+      B(0x2D00C80420010200, 0x804003280020008),
+      B(0x8038820024420, 0x6010010080012040),
+      B(0x1202028004200088, 0x50018100004000C6),
+      B(0xA02010F0410081, 0x20013001000009A),
+      B(0x4013002041030588, 0x4802004110000004),
+      B(0x110020802000081, 0x202001800908002),
+      B(0x22010404103, 0x2020882080491200),
+      B(0x60000220400580, 0x85902800100100),
+      B(0x100080800050100, 0x200010220021088),
+      B(0x8088840404200080, 0x140011040104000),
+      B(0x4008508080082015, 0x8010100200580048),
+      B(0x4010400420201001, 0x260002080A80808),
+      B(0xC2002004A0008008, 0x8020082000110840),
+      B(0xA000A0820042400, 0x810408082100420),
+      B(0x80231808100004, 0x204002000800400),
+      B(0x8296144044004900, 0x4A1003008001840),
+      B(0x80A0020A0011008, 0x800104846080810),
+      B(0x803800801041000, 0x1030500102000404),
+      B(0x240C00900800850, 0x1804000108810000),
+      B(0x800400000088800, 0x800021801020000),
+      B(0x84800409300082, 0x1002D40680044000),
+      B(0xA110C0000200010, 0x401010001200260),
+      B(0x8200160204100004, 0x8040004004002022),
+      B(0x10001000000100C0, 0x84002811000200),
+      B(0x2000080020014001, 0x42002020000102),
+      B(0x109040044020018, 0x2020400202001000),
+      B(0x620000CD0108, 0x40040201008000),
+      B(0xA1402200A0020, 0x81400400300912),
+      B(0x20020CF100018020, 0x801A14086404000),
+      B(0x800801844001, 0x11621488425000),
+      B(0x10201004A8080, 0x100A000801000010),
+      B(0x2800411001000800, 0x80224084900020),
+      B(0x40400024028100, 0x501000400230060),
+      B(0x404808010080, 0x1201000400100004),
+      B(0x80802005200, 0x2000200008A0000),
+      B(0x20800080000022, 0x80040810002010),
+      B(0x40016004808240, 0x400114000801100),
+      B(0x8410004204240, 0x20011000604050),
+      B(0x8000C1009008268, 0x201004000209000),
+      B(0x10240C000920, 0xE000A5C14003002),
+      B(0x10184024280008, 0x90240802000000),
+      B(0x40889081081000, 0x8010050008800000),
+      B(0x100008C089000019, 0x802032014020010),
+      B(0x401C1804C00, 0x402501002002020),
+      B(0x200022000920D0, 0x8000800081300020),
+      B(0x801000400011, 0x400100044010226),
+      B(0x4A04010100100000, 0x500400080400000),
+      B(0xA000050200080000, 0x8500090001010000),
+      B(0x40400040001812, 0x4403000400100A0),
+      B(0x20C2250203020004, 0x210001C000080000),
+      B(0x21000408C6020001, 0x4200830012D1001),
+      B(0x840082016080A210, 0x2400080801081008),
+      B(0x40001020000, 0x4041240200083120),
+      B(0x2C04030010C0818, 0xA670002000818100),
+      B(0x4704A07085000510, 0x914001000040),
+      B(0x900210304100100, 0x1010004000281840),
+      B(0x8202920002002040, 0x810012000003),
+      B(0x4001400100050, 0x1144000408002000),
+      B(0x5900200020008100, 0x40200020002004),
+      B(0x301020002000480, 0x202000C0004),
+      B(0x20D000201104040, 0x34840100020010),
+      B(0x800004200080408, 0x40184200100240),
+      B(0x8430080100404020, 0x90042100244500),
+      B(0x3800100010220062, 0x50404030200218),
+      B(0x42E20008002020, 0x2000008200200300),
+      B(0xE488008280A004, 0x200001010CC80000),
+      B(0x6018010041109810, 0x800002000242041A),
+      B(0x40A8002438980, 0x8000810008208009),
+      B(0x401000480040100, 0x286800404002212),
+      B(0x821030000100009, 0x2000090200A00000),
+      B(0x20000100C0008028, 0x5000000100400082),
+      B(0x80A000048030080, 0x200000120200008),
+      B(0x6300280800204003, 0x48000105C0040100),
+      B(0x83008802420C0200, 0x2008020200080100),
+      B(0x1050C3102200042, 0x20103900010008),
+      B(0x8040902021408180, 0x12000021806200A4),
+      B(0x3008204008C10004, 0x680110100010401),
+      B(0x204321100421000, 0x400E204820494000),
+      B(0x8000044022404048, 0x4024010090024021),
+      B(0x140201424050, 0x280A000130008000),
+      B(0x900340808004002, 0x21026008000380),
+      B(0x82808000300444, 0x20002000A2001141),
+      B(0x140180100406002, 0x4004480001000004),
+      B(0x4808420800841900, 0x14008C0041000000),
+      B(0x2008600009000480, 0x9008020001400000),
+      B(0x2000100800100002, 0x2004100820210020),
+      B(0x2062010401A8100, 0x12200108420090),
+      B(0x1403188200032, 0x40048166105000),
+      B(0x410020020140041, 0x4400348102940040),
+      B(0x414040209208041, 0x4402400028B004),
+      B(0x8008010100421202, 0x401418002008800),
+      B(0x4000020010062200, 0xA02009148048000),
+      B(0x4443080082008B, 0x104014022801010),
+      B(0x42B440A0C000800, 0x9001009016111020),
+      B(0x400000214002, 0x8008080209020009),
+      B(0x480C414A001900, 0x3400100400210200),
+      B(0x1006008800604, 0x20240004030A050),
+      B(0x4C022401002A8300, 0x405008400000600),
+      B(0x3104000800A1042, 0x2004800204406200),
+      B(0xA09010280008200C, 0x4004000208C4168),
+      B(0x2800401120C20120, 0x4A00450200022030),
+      B(0x88001800304C0200, 0x204288102080000),
+      B(0x8044004201440101, 0x400820080C024022),
+      B(0xA000100C080, 0x4B40341004008081),
+      B(0x94802001300810, 0x140206008000800),
+      B(0x40002020202820, 0x280680404000040),
+      B(0xA820800004200, 0x80E1401012000491),
+      B(0x804000010020C000, 0x9403020200802000),
+      B(0x8C0001284201400, 0xC000100C01620800),
+      B(0x4010004002200414, 0x403080080200000),
+      B(0x140400A100800101, 0x10054C031080400),
+      B(0x20012C2400880082, 0x7000880020C03200),
+      B(0x204040300004, 0x840800041101002),
+  };
 #undef B
 #endif
 
index 4504b55..dbc3a65 100644 (file)
@@ -890,9 +890,10 @@ Bitboard Position::attackers_to(Square s, Bitboard occupied, Color c, Bitboard j
           diags |= attacks_bb(~c, FERS, s, occupied) & pieces(c, KING);
       diags |= attacks_bb(~c, FERS, s, occupied) & pieces(c, WAZIR);
       diags |= attacks_bb(~c, PAWN, s, occupied) & pieces(c, SOLDIER);
-      diags |= attacks_bb(~c, BISHOP, s, occupied) & pieces(c, ROOK);
-      // TODO: fix for longer diagonals
-      diags |= attacks_bb(~c, ALFIL, s, occupied) & ~attacks_bb(~c, ELEPHANT, s, occupied & ~janggiCannons) & pieces(c, JANGGI_CANNON);
+      diags |= rider_attacks_bb<RIDER_BISHOP>(s, occupied) & pieces(c, ROOK);
+      diags |=  rider_attacks_bb<RIDER_CANNON_DIAG>(s, occupied)
+              & rider_attacks_bb<RIDER_CANNON_DIAG>(s, occupied & ~janggiCannons)
+              & pieces(c, JANGGI_CANNON);
       b |= diags & diagonal_lines();
   }
 
@@ -1256,8 +1257,9 @@ bool Position::gives_check(Move m) const {
       Bitboard occupied = type_of(m) == DROP ? pieces() : pieces() ^ from;
       if (diagType && (attacks_bb(sideToMove, diagType, to, occupied) & square<KING>(~sideToMove)))
           return true;
-      // TODO: fix for longer diagonals
-      else if (pt == JANGGI_CANNON && (attacks_bb(sideToMove, ALFIL, to, occupied) & ~attacks_bb(sideToMove, ELEPHANT, to, occupied) & square<KING>(~sideToMove)))
+      else if (pt == JANGGI_CANNON && (  rider_attacks_bb<RIDER_CANNON_DIAG>(to, occupied)
+                                       & rider_attacks_bb<RIDER_CANNON_DIAG>(to, occupied & ~janggiCannons)
+                                       & square<KING>(~sideToMove)))
           return true;
   }
 
index 8bd3623..f79b80f 100644 (file)
@@ -1031,9 +1031,8 @@ inline Bitboard Position::attacks_from(Color c, PieceType pt, Square s) const {
       if (diagType)
           b |= attacks_bb(c, diagType, s, pieces()) & diagonal_lines();
       else if (movePt == JANGGI_CANNON)
-          // TODO: fix for longer diagonals
-          b |=   attacks_bb(c, ALFIL, s, pieces())
-              & ~attacks_bb(c, ELEPHANT, s, pieces() ^ pieces(pt))
+          b |=  rider_attacks_bb<RIDER_CANNON_DIAG>(s, pieces())
+              & rider_attacks_bb<RIDER_CANNON_DIAG>(s, pieces() ^ pieces(pt))
               & ~pieces(pt)
               & diagonal_lines();
   }
@@ -1062,9 +1061,8 @@ inline Bitboard Position::moves_from(Color c, PieceType pt, Square s) const {
       if (diagType)
           b |= attacks_bb(c, diagType, s, pieces()) & diagonal_lines();
       else if (movePt == JANGGI_CANNON)
-          // TODO: fix for longer diagonals
-          b |=   attacks_bb(c, ALFIL, s, pieces())
-              & ~attacks_bb(c, ELEPHANT, s, pieces() ^ pieces(pt))
+          b |=  rider_attacks_bb<RIDER_CANNON_DIAG>(s, pieces())
+              & rider_attacks_bb<RIDER_CANNON_DIAG>(s, pieces() ^ pieces(pt))
               & ~pieces(pt)
               & diagonal_lines();
   }
index 97aa456..38de559 100644 (file)
@@ -416,7 +416,8 @@ enum RiderType : int {
   RIDER_HORSE = 1 << 5,
   RIDER_ELEPHANT = 1 << 6,
   RIDER_JANGGI_ELEPHANT = 1 << 7,
-  HOPPING_RIDERS = RIDER_CANNON_H | RIDER_CANNON_V,
+  RIDER_CANNON_DIAG = 1 << 8,
+  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,
index b388f2d..0f70dbc 100644 (file)
@@ -96,7 +96,7 @@
 # - all base moves/atoms (W, F, etc.)
 # - all directional modifiers (f, b, etc.)
 # - unlimited distance sliders for W/R and F/B directions
-# - hoppers for W/R directions, i.e., pR
+# - 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
 
 ### Piece values
index 51f076b..896e22d 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 20000",
+    "test": "mocha --timeout 40000",
     "dev": "node index"
   },
   "author": [