Support Shako
authorFabian Fichter <ianfab@users.noreply.github.com>
Wed, 29 May 2019 14:02:04 +0000 (16:02 +0200)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sat, 3 Aug 2019 21:39:48 +0000 (23:39 +0200)
https://www.chessvariants.com/large.dir/shako.html

- Support cannon
- Generalize pawn double steps
- Generalize castling

bench: 3713921

12 files changed:
src/bitboard.cpp
src/bitboard.h
src/magic.h
src/movegen.cpp
src/piece.cpp
src/piece.h
src/position.cpp
src/position.h
src/psqt.cpp
src/types.h
src/variant.cpp
src/variant.h

index 6aef4f2..47c969e 100644 (file)
@@ -42,39 +42,58 @@ RiderType MoveRiderTypes[PIECE_TYPE_NB];
 Magic RookMagicsH[SQUARE_NB];
 Magic RookMagicsV[SQUARE_NB];
 Magic BishopMagics[SQUARE_NB];
+Magic CannonMagicsH[SQUARE_NB];
+Magic CannonMagicsV[SQUARE_NB];
 
 namespace {
 
 #ifdef LARGEBOARDS
-  Bitboard RookTableH[0x11800];  // To store rook attacks
-  Bitboard RookTableV[0x4800];  // To store rook attacks
+  Bitboard RookTableH[0x11800];  // To store horizontalrook attacks
+  Bitboard RookTableV[0x4800];  // To store vertical rook attacks
   Bitboard BishopTable[0x33C00]; // To store bishop attacks
+  Bitboard CannonTableH[0x33C00];  // To store horizontal cannon attacks
+  Bitboard CannonTableV[0x33C00];  // To store vertical cannon attacks
 #else
-  Bitboard RookTableH[0xA00];  // To store rook attacks
-  Bitboard RookTableV[0xA00];  // To store rook attacks
+  Bitboard RookTableH[0xA00];  // To store horizontal rook attacks
+  Bitboard RookTableV[0xA00];  // To store vertical rook attacks
   Bitboard BishopTable[0x1480]; // To store bishop attacks
+  Bitboard CannonTableH[0x11800];  // To store horizontal cannon attacks
+  Bitboard CannonTableV[0x4800];  // To store vertical cannon attacks
 #endif
 
+  enum MovementType { RIDER, HOPPER, LAZY_LEAPER };
+
+  template <MovementType MT>
 #ifdef PRECOMPUTED_MAGICS
   void init_magics(Bitboard table[], Magic magics[], std::vector<Direction> directions, Bitboard magicsInit[]);
 #else
   void init_magics(Bitboard table[], Magic magics[], std::vector<Direction> directions);
 #endif
 
+  template <MovementType MT>
   Bitboard sliding_attack(std::vector<Direction> directions, Square sq, Bitboard occupied, Color c = WHITE) {
 
     Bitboard attack = 0;
 
     for (Direction d : directions)
+    {
+        bool hurdle = false;
         for (Square s = sq + (c == WHITE ? d : -d);
              is_ok(s) && distance(s, s - (c == WHITE ? d : -d)) == 1;
              s += (c == WHITE ? d : -d))
         {
-            attack |= s;
+            if (MT != HOPPER || hurdle)
+                attack |= s;
 
             if (occupied & s)
-                break;
+            {
+                if (MT == HOPPER && !hurdle)
+                    hurdle = true;
+                else
+                    break;
+            }
         }
+    }
 
     return attack;
   }
@@ -128,6 +147,20 @@ void Bitboards::init() {
           if (d == NORTH || d == SOUTH)
               MoveRiderTypes[pt] |= RIDER_ROOK_V;
       }
+      for (Direction d : pi->hopperCapture)
+      {
+          if (d == EAST || d == WEST)
+              AttackRiderTypes[pt] |= RIDER_CANNON_H;
+          if (d == NORTH || d == SOUTH)
+              AttackRiderTypes[pt] |= RIDER_CANNON_V;
+      }
+      for (Direction d : pi->hopperQuiet)
+      {
+          if (d == EAST || d == WEST)
+              MoveRiderTypes[pt] |= RIDER_CANNON_H;
+          if (d == NORTH || d == SOUTH)
+              MoveRiderTypes[pt] |= RIDER_CANNON_V;
+      }
   }
 
   for (unsigned i = 0; i < (1 << 16); ++i)
@@ -150,13 +183,17 @@ void Bitboards::init() {
   std::vector<Direction> BishopDirections = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST };
 
 #ifdef PRECOMPUTED_MAGICS
-  init_magics(RookTableH, RookMagicsH, RookDirectionsH, RookMagicHInit);
-  init_magics(RookTableV, RookMagicsV, RookDirectionsV, RookMagicVInit);
-  init_magics(BishopTable, BishopMagics, BishopDirections, BishopMagicInit);
+  init_magics<RIDER>(RookTableH, RookMagicsH, RookDirectionsH, RookMagicHInit);
+  init_magics<RIDER>(RookTableV, RookMagicsV, RookDirectionsV, RookMagicVInit);
+  init_magics<RIDER>(BishopTable, BishopMagics, BishopDirections, BishopMagicInit);
+  init_magics<HOPPER>(CannonTableH, CannonMagicsH, RookDirectionsH, CannonMagicHInit);
+  init_magics<HOPPER>(CannonTableV, CannonMagicsV, RookDirectionsV, CannonMagicVInit);
 #else
-  init_magics(RookTableH, RookMagicsH, RookDirectionsH);
-  init_magics(RookTableV, RookMagicsV, RookDirectionsV);
-  init_magics(BishopTable, BishopMagics, BishopDirections);
+  init_magics<RIDER>(RookTableH, RookMagicsH, RookDirectionsH);
+  init_magics<RIDER>(RookTableV, RookMagicsV, RookDirectionsV);
+  init_magics<RIDER>(BishopTable, BishopMagics, BishopDirections);
+  init_magics<HOPPER>(CannonTableH, CannonMagicsH, RookDirectionsH);
+  init_magics<HOPPER>(CannonTableV, CannonMagicsV, RookDirectionsV);
 #endif
 
   for (Color c : { WHITE, BLACK })
@@ -186,8 +223,10 @@ void Bitboards::init() {
                       LeaperMoves[c][pt][s] |= to;
                   }
               }
-              PseudoAttacks[c][pt][s] |= sliding_attack(pi->sliderCapture, s, 0, c);
-              PseudoMoves[c][pt][s] |= sliding_attack(pi->sliderQuiet, s, 0, c);
+              PseudoAttacks[c][pt][s] |= sliding_attack<RIDER>(pi->sliderCapture, s, 0, c);
+              PseudoAttacks[c][pt][s] |= sliding_attack<RIDER>(pi->hopperCapture, s, 0, c);
+              PseudoMoves[c][pt][s] |= sliding_attack<RIDER>(pi->sliderQuiet, s, 0, c);
+              PseudoMoves[c][pt][s] |= sliding_attack<RIDER>(pi->hopperQuiet, s, 0, c);
           }
       }
 
@@ -208,6 +247,7 @@ namespace {
   // www.chessprogramming.org/Magic_Bitboards. In particular, here we use the so
   // called "fancy" approach.
 
+  template <MovementType MT>
 #ifdef PRECOMPUTED_MAGICS
   void init_magics(Bitboard table[], Magic magics[], std::vector<Direction> directions, Bitboard magicsInit[]) {
 #else
@@ -243,7 +283,7 @@ namespace {
         // the number of 1s of the mask. Hence we deduce the size of the shift to
         // apply to the 64 or 32 bits word to get the index.
         Magic& m = magics[s];
-        m.mask  = sliding_attack(directions, s, 0) & ~edges;
+        m.mask  = sliding_attack<MT == HOPPER ? RIDER : MT>(directions, s, 0) & ~edges;
 #ifdef LARGEBOARDS
         m.shift = 128 - popcount(m.mask);
 #else
@@ -259,7 +299,7 @@ namespace {
         b = size = 0;
         do {
             occupancy[size] = b;
-            reference[size] = sliding_attack(directions, s, b);
+            reference[size] = sliding_attack<MT>(directions, s, b);
 
             if (HasPext)
                 m.attacks[pext(b, m.mask)] = reference[size];
index 3987999..63a38a1 100644 (file)
@@ -143,6 +143,8 @@ struct Magic {
 extern Magic RookMagicsH[SQUARE_NB];
 extern Magic RookMagicsV[SQUARE_NB];
 extern Magic BishopMagics[SQUARE_NB];
+extern Magic CannonMagicsH[SQUARE_NB];
+extern Magic CannonMagicsV[SQUARE_NB];
 
 inline Bitboard square_bb(Square s) {
   assert(s >= SQ_A1 && s <= SQ_MAX);
@@ -342,9 +344,11 @@ template<class T> constexpr const T& clamp(const T& v, const T& lo, const T&  hi
 template<RiderType R>
 inline Bitboard rider_attacks_bb(Square s, Bitboard occupied) {
 
-  assert(R == RIDER_BISHOP || R == RIDER_ROOK_H || R == RIDER_ROOK_V);
+  assert(R == RIDER_BISHOP || R == RIDER_ROOK_H || R == RIDER_ROOK_V || R == RIDER_CANNON_H || R == RIDER_CANNON_V);
   const Magic& m =  R == RIDER_ROOK_H ? RookMagicsH[s]
                   : R == RIDER_ROOK_V ? RookMagicsV[s]
+                  : R == RIDER_CANNON_H ? CannonMagicsH[s]
+                  : R == RIDER_CANNON_V ? CannonMagicsV[s]
                   : BishopMagics[s];
   return m.attacks[m.index(occupied)];
 }
@@ -368,6 +372,10 @@ inline Bitboard attacks_bb(Color c, PieceType pt, Square s, Bitboard occupied) {
       b |= rider_attacks_bb<RIDER_ROOK_H>(s, occupied);
   if (AttackRiderTypes[pt] & RIDER_ROOK_V)
       b |= rider_attacks_bb<RIDER_ROOK_V>(s, occupied);
+  if (AttackRiderTypes[pt] & RIDER_ROOK_H)
+      b |= rider_attacks_bb<RIDER_ROOK_H>(s, occupied);
+  if (AttackRiderTypes[pt] & RIDER_CANNON_V)
+      b |= rider_attacks_bb<RIDER_CANNON_V>(s, occupied);
   return b & PseudoAttacks[c][pt][s];
 }
 
@@ -379,6 +387,10 @@ inline Bitboard moves_bb(Color c, PieceType pt, Square s, Bitboard occupied) {
       b |= rider_attacks_bb<RIDER_ROOK_H>(s, occupied);
   if (MoveRiderTypes[pt] & RIDER_ROOK_V)
       b |= rider_attacks_bb<RIDER_ROOK_V>(s, occupied);
+  if (MoveRiderTypes[pt] & RIDER_CANNON_H)
+      b |= rider_attacks_bb<RIDER_CANNON_H>(s, occupied);
+  if (MoveRiderTypes[pt] & RIDER_CANNON_V)
+      b |= rider_attacks_bb<RIDER_CANNON_V>(s, occupied);
   return b & PseudoMoves[c][pt][s];
 }
 
index 5610b19..1fae2e3 100644 (file)
       B(0x400202081811400, 0x40081802050000C),
       B(0x1011002100821300, 0x2400825040804100)
   };
+  Bitboard CannonMagicHInit[SQUARE_NB] = {
+      B(0x120000880110000, 0x1008000000020020),
+      B(0x24200C080840A052, 0x2004004000010008),
+      B(0xC030024000228800, 0x4000010400000020),
+      B(0x1A0020802008802, 0x206010208000),
+      B(0x12002000D001024, 0x80100800090138),
+      B(0x4220010000241010, 0x3098000602001500),
+      B(0x401010004801040, 0x8000280480100000),
+      B(0x820082024921836, 0x220028000),
+      B(0x100400502411400, 0x220402120240D14),
+      B(0x880202020010404, 0xA80202510000),
+      B(0x140002801000018, 0x1000346490040),
+      B(0x120000880110000, 0x1008000000020020),
+      B(0xD01004008030400, 0x104000408104420),
+      B(0x8420060100020000, 0x800280400000120),
+      B(0x4010020018010, 0x40A00001100000),
+      B(0x40006A0004000200, 0x40000000110),
+      B(0xD01004008030400, 0x104000408104420),
+      B(0x8908A20028110011, 0x800080000001A114),
+      B(0x200042000080F009, 0x20001000004000),
+      B(0x2820008820100, 0x10002400058000B9),
+      B(0x6083100420008050, 0x4040012600280080),
+      B(0x216020000000446, 0x4080204000000211),
+      B(0x340140003002089, 0x2402008000000911),
+      B(0xD01004008030400, 0x104000408104420),
+      B(0x1404040B20001000, 0x8000824010800011),
+      B(0x8C0488120024214, 0x8414880202291),
+      B(0x1010000060050000, 0x4000004050002602),
+      B(0x4022983A0060000, 0x80000040010400),
+      B(0x1404040B20001000, 0x8000824010800011),
+      B(0x6020101802002840, 0x31000003000004),
+      B(0x9000420008840, 0x4881300000000210),
+      B(0xA200808865, 0x41C0048023000128),
+      B(0x31801100400000, 0x8802DC001221240),
+      B(0x884000080200920, 0x1004002410401001),
+      B(0x2400040000884, 0x421006208040C0),
+      B(0x1404040B20001000, 0x8000824010800011),
+      B(0x24100400060009, 0x112008025042410),
+      B(0x1800040009040200, 0x180000A1004E408A),
+      B(0x24100400060009, 0x112008025042410),
+      B(0x4060402008080, 0xC240080000110000),
+      B(0x20080100920020, 0x2002248010242052),
+      B(0x10001010802050, 0x880000001C98420),
+      B(0x4000800100420022, 0x502022010A00D0),
+      B(0x4C18104500200885, 0x400880800),
+      B(0x8080810081020090, 0x8000000000000),
+      B(0x8000062812080201, 0x8004C8300800),
+      B(0x1800040009040200, 0x180000A1004E408A),
+      B(0x24100400060009, 0x112008025042410),
+      B(0x80102204040, 0x1000000900000000),
+      B(0x2080000004202804, 0x120880003461),
+      B(0x102004090A4030, 0x801020589240),
+      B(0x20001100814000A0, 0x420202000820004),
+      B(0x100800000A000120, 0x208000800010000),
+      B(0x1008205000040802, 0x80002000400040),
+      B(0x1480000098008401, 0xA0010000581010),
+      B(0x30C0008200100820, 0x102800080904834),
+      B(0x4810821884000500, 0x4400000200000212),
+      B(0x1811D00128A0180, 0x2500848803000000),
+      B(0x41618A0300040040, 0x21200200A421801),
+      B(0x80102204040, 0x1000000900000000),
+      B(0xA1808E0100108000, 0x2008000505000002),
+      B(0x8C890020410000A0, 0xA010000048000400),
+      B(0x40006002210044, 0x600008000408000),
+      B(0x1200447220090042, 0x80001000160012),
+      B(0x48410010AB000000, 0x9200600000000100),
+      B(0x2040000000240003, 0x8020080288000600),
+      B(0x9080000088848088, 0x4010210500000041),
+      B(0xA1808E0100108000, 0x2008000505000002),
+      B(0x480100400024, 0x1004800018200000),
+      B(0x808403080080200, 0x802601000000500),
+      B(0x8C890020410000A0, 0xA010000048000400),
+      B(0xA1808E0100108000, 0x2008000505000002),
+      B(0x100A40000004008, 0x2800200400200480),
+      B(0x100A40000004008, 0x2800200400200480),
+      B(0x400014006000000, 0x10006000810001F5),
+      B(0xC410062001414, 0x820080041B01044),
+      B(0x20000800310, 0x430040000201000),
+      B(0xA40010008000008, 0x4002200028000040),
+      B(0xC00102000008021C, 0x10C2000A010E024),
+      B(0x80004200104008, 0x50A00800C400020),
+      B(0x20200080012542, 0x910F0040000402C0),
+      B(0xB040100504000300, 0x24802002000040),
+      B(0x800001000014008, 0x400031004000),
+      B(0x100A40000004008, 0x2800200400200480),
+      B(0x84008002041081C0, 0x8080500200000000),
+      B(0x440090001012001, 0x4020004010),
+      B(0x100A0028088020, 0x80040E00010020),
+      B(0x2180808000810, 0xB018040A00040000),
+      B(0x40C80920304C4001, 0x42800B200800000),
+      B(0x85000425001000, 0x4810048020001100),
+      B(0x600C000801000004, 0x8015084010200020),
+      B(0x20020050000240C0, 0x100202008600800),
+      B(0x38000050001220, 0x9200010200145900),
+      B(0x1042108040005, 0x1402A0802201001),
+      B(0x824240000C20400, 0x1000000400080010),
+      B(0x84008002041081C0, 0x8080500200000000),
+      B(0x400804A1000008, 0x1024104A0200010),
+      B(0x8000402308483, 0x20006020100100),
+      B(0x80880120000080, 0x8000240100084),
+      B(0x5840020004882001, 0x1004528000A00010),
+      B(0x8001018800300002, 0x84010040804),
+      B(0x180D10004000A008, 0xA001080008020004),
+      B(0x400080B, 0x10A0000004010000),
+      B(0x8080000200000, 0x2001000082004E0),
+      B(0x40040001000C2000, 0x2024800001004008),
+      B(0x400804A1000008, 0x1024104A0200010),
+      B(0x8000402308483, 0x20006020100100),
+      B(0x400804A1000008, 0x1024104A0200010),
+      B(0x2000200000, 0x1201011000802),
+      B(0x100100000000C4, 0x208004084048201),
+      B(0x400084000044, 0x100810140300),
+      B(0x29040C0C01010, 0x300204010820080),
+      B(0x1A808000020200, 0x1000000005210040),
+      B(0x20000400150000, 0x85008020),
+      B(0x40C040008184014, 0x8002AA00024010),
+      B(0x202000081B00804, 0x10001002008),
+      B(0x40011000210060, 0x6080C40000021004),
+      B(0x2000200000, 0x1201011000802),
+      B(0x4100480203840, 0x300080100804),
+      B(0x2000200000, 0x1201011000802),
+  };
+  Bitboard CannonMagicVInit[SQUARE_NB] = {
+      B(0x202000812104400, 0x24800B01C0000303),
+      B(0x340020400010D, 0x88060150C00400),
+      B(0x400802040609, 0x49010200501A0002),
+      B(0x8002680301000208, 0x628006C0C020200),
+      B(0x20400209001C0804, 0xA044000800143110),
+      B(0xC400082060010202, 0x4000480401014000),
+      B(0x22500200144040, 0x8204820084704C00),
+      B(0x8C1204009030020, 0x328400805000000),
+      B(0x84800800D0001640, 0x200080040060108),
+      B(0x804810208020040, 0x140010108020000),
+      B(0x1102010B008004, 0x300208006220020),
+      B(0x140080404A0A2428, 0x6308010100080),
+      B(0x20444002120408, 0xA080010508010001),
+      B(0x82011044000D02, 0x4112028620110809),
+      B(0x81010831000C02, 0x408802085000000),
+      B(0x81010831000C02, 0x408802085000000),
+      B(0x920008920600040, 0x8053801004000028),
+      B(0x81140283208300, 0x10040C004200420),
+      B(0x103080022201, 0xC01000081312620),
+      B(0x2200221100008, 0x1000408104000A4),
+      B(0x4402088080042008, 0x210401501040340),
+      B(0x898400202170001, 0x80040404208000),
+      B(0x20080004051012, 0x5100048200081800),
+      B(0x2320020000401018, 0x108501021040210),
+      B(0x21080410A422021, 0x83040180008800),
+      B(0x44E8100000408224, 0x20010008040400),
+      B(0x1800240002810405, 0x23004820000020),
+      B(0x80A0100400110, 0x80104020100C4028),
+      B(0x1002050001222C0, 0x5100818004024020),
+      B(0x104000200040, 0xC010A09800102000),
+      B(0x1020003A058120, 0x450900809000302),
+      B(0x40040045008B1, 0x202800400383010),
+      B(0x4640200220034, 0x8800485420304000),
+      B(0x5001042100084288, 0x110820001240080A),
+      B(0x2002C04004010120, 0xA15008020880001),
+      B(0x2800004080C4190, 0x890808280020080),
+      B(0x40C0401000104000, 0x2020880008002580),
+      B(0x40020C002400802, 0x801104010000000),
+      B(0x44842000040080, 0x2050011084000400),
+      B(0x4110040800000401, 0x2023810029008000),
+      B(0x20884000840, 0x8017102004008000),
+      B(0x10411104000480, 0x1414042000201001),
+      B(0x220040000008, 0x800306021000000),
+      B(0x41400A0008080, 0x501000298ACAD10),
+      B(0x800240012831810, 0x80120004468050E),
+      B(0x800005020801008, 0x20102400240000),
+      B(0x20C00040C114C010, 0x88080820200C00),
+      B(0x1044010100820081, 0x20080841004000),
+      B(0x8041048400022, 0x8020836040005002),
+      B(0x2001004010205, 0x8001002884042009),
+      B(0x128088400087, 0x20008002201002),
+      B(0x8084108040402000, 0x80809000A080400),
+      B(0x408081840880, 0x201002088000040),
+      B(0xA40180010280, 0x241004006000010),
+      B(0x4204100080048140, 0x2002C4F104202020),
+      B(0x100140A10204, 0x980200800840060),
+      B(0x1005140010202048, 0x1442280800202815),
+      B(0x2000082025008600, 0x1108400040600003),
+      B(0x1005050648000, 0x200020240008002),
+      B(0x202010208044000, 0x8210404060008),
+      B(0x8011040402000210, 0xC840180408016004),
+      B(0x404098801028, 0x80020A0001000400),
+      B(0x404098801028, 0x80020A0001000400),
+      B(0x80101002180140, 0x40C2080820000C0),
+      B(0x208202081260800, 0x14090E4C04000050),
+      B(0x4221201084004C2, 0x110480A011060),
+      B(0x8000008421090204, 0x1C01010800024),
+      B(0x8000008421090204, 0x1C01010800024),
+      B(0x200180C840088A0, 0x401100400820000),
+      B(0x10084043A021070, 0x202041600080200),
+      B(0x210E6202001040C, 0x10100800080B0),
+      B(0x848008021204002, 0x801004308100BAD),
+      B(0xC082C0390A000601, 0x4040080189008),
+      B(0x431200240210402D, 0x58102820000),
+      B(0x202020100A0019B0, 0x4010C0D018000000),
+      B(0x800800908402203, 0x102948C84C184),
+      B(0x26801100080845, 0x4009702022A00820),
+      B(0x8880520010401040, 0x1060084832052000),
+      B(0x100100022042081, 0x10000600008C121),
+      B(0x46020384100040, 0x800200320882021),
+      B(0xC0002010148, 0x4200800800040003),
+      B(0x2002208020090040, 0x40820210021410),
+      B(0x9000A41160002004, 0x2A09000100080043),
+      B(0x800004010008001, 0x1108002020104600),
+      B(0x800540C000A4E041, 0x18021180000401),
+      B(0x808200900A900202, 0x8364202140012005),
+      B(0x1DBA52000081010, 0x4008000023000010),
+      B(0x4100110204401481, 0x800040091020001C),
+      B(0x4100110204401481, 0x800040091020001C),
+      B(0x4101100020400482, 0x2000402302100120),
+      B(0x100408000A020212, 0xA000400111000020),
+      B(0x2000010488080104, 0x3000404410208100),
+      B(0x2684220180008DD0, 0x422040200004000A),
+      B(0x2021200C0424, 0x1010100000080200),
+      B(0x8908020020801006, 0x3010800020C2000),
+      B(0x4000030008062044, 0x244010202688000),
+      B(0x242101200408009, 0x8150040000200015),
+      B(0x42004C02180204, 0x210208014241040),
+      B(0x4E1A01C208410804, 0x8890041000012004),
+      B(0x2080200401000080, 0x8001098429008004),
+      B(0xA01400121804104, 0x280200C400000500),
+      B(0xD0080408040420, 0x1006040100224000),
+      B(0x28400205000800C9, 0x6021101401040075),
+      B(0x4000900040020104, 0x88129801100D0C),
+      B(0x8000004002180410, 0x400380200400204),
+      B(0x4002A430043008, 0x400200340100020),
+      B(0x401960004140A42, 0x100880710000464),
+      B(0x58014090102, 0xB8D30004010080),
+      B(0xA004C08000244000, 0x11280100E0000040),
+      B(0x2102008089208804, 0x110001004080040),
+      B(0x700010084E003004, 0x8080864112000D40),
+      B(0x4080881000200C20, 0x30324040880E0600),
+      B(0x2024A40401810820, 0x3000888002000000),
+      B(0x8200100400014, 0x4400340800252844),
+      B(0x24A00804288281, 0x410103002201140),
+      B(0x4080005022A08, 0x1000402200100264),
+      B(0x200080032244040, 0x200502189010001),
+      B(0x28108110404001, 0x400600120008412),
+      B(0xA00002102810020, 0xB1080240015408),
+      B(0x810080200806, 0x410440804080046),
+  };
 #undef B
 #endif
 
index b326233..6cb35f2 100644 (file)
@@ -71,7 +71,7 @@ namespace {
     constexpr Direction UpLeft   = (Us == WHITE ? NORTH_WEST : SOUTH_EAST);
 
     // Define squares a pawn can pass during a double step
-    Bitboard  TRank3BB = rank_bb(relative_rank(Us, RANK_3, pos.max_rank()));
+    Bitboard  TRank3BB = rank_bb(relative_rank(Us, Rank(pos.double_step_rank() + 1), pos.max_rank()));
     if (pos.first_rank_double_steps())
         TRank3BB |= rank_bb(relative_rank(Us, RANK_2, pos.max_rank()));
 
@@ -203,7 +203,7 @@ namespace {
 
         if (pos.ep_square() != SQ_NONE)
         {
-            assert(rank_of(pos.ep_square()) == relative_rank(Them, RANK_3));
+            assert(rank_of(pos.ep_square()) == relative_rank(Them, Rank(pos.double_step_rank() + 1), pos.max_rank()));
 
             // An en passant capture can be an evasion only if the checking piece
             // is the double pushed pawn and so is in the target. Otherwise this
@@ -323,7 +323,7 @@ namespace {
     // Castling with non-king piece
     if (!pos.count<KING>(Us) && Type != CAPTURES && pos.can_castle(CastlingRight(OO | OOO)))
     {
-        Square from = make_square(FILE_E, relative_rank(Us, RANK_1, pos.max_rank()));
+        Square from = make_square(FILE_E, relative_rank(Us, pos.castling_rank(), pos.max_rank()));
         if (!pos.castling_impeded(OO) && pos.can_castle(OO))
             *moveList++ = make<CASTLING>(from, pos.castling_rook_square(OO));
 
index b510bb0..aea82e0 100644 (file)
@@ -87,6 +87,13 @@ namespace {
       p->stepsCapture = {2 * SOUTH_WEST, 2 * SOUTH_EAST, 2 * NORTH_WEST, 2 * NORTH_EAST};
       return p;
   }
+  PieceInfo* fers_alfil_piece() {
+      PieceInfo* p = fers_piece();
+      PieceInfo* p2 = alfil_piece();
+      p->merge(p2);
+      delete p2;
+      return p;
+  }
   PieceInfo* silver_piece() {
       PieceInfo* p = new PieceInfo();
       p->stepsQuiet = {SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH, NORTH_EAST};
@@ -203,6 +210,12 @@ namespace {
       PieceInfo* p = new PieceInfo();
       return p;
   }
+  PieceInfo* cannon_piece() {
+      PieceInfo* p = new PieceInfo();
+      p->sliderQuiet = {NORTH, EAST, SOUTH, WEST};
+      p->hopperCapture = {NORTH, EAST, SOUTH, WEST};
+      return p;
+  }
 }
 
 void PieceMap::init() {
@@ -213,6 +226,7 @@ void PieceMap::init() {
   add(QUEEN, queen_piece());
   add(FERS, fers_piece());
   add(ALFIL, alfil_piece());
+  add(FERS_ALFIL, fers_alfil_piece());
   add(SILVER, silver_piece());
   add(AIWOK, aiwok_piece());
   add(BERS, bers_piece());
@@ -230,6 +244,7 @@ void PieceMap::init() {
   add(CLOBBER_PIECE, clobber_piece());
   add(BREAKTHROUGH_PIECE, breakthrough_piece());
   add(IMMOBILE_PIECE, immobile_piece());
+  add(CANNON, cannon_piece());
   add(WAZIR, wazir_piece());
   add(COMMONER, king_piece());
   add(KING, king_piece());
index a6404e5..bd4809e 100644 (file)
@@ -32,6 +32,8 @@ struct PieceInfo {
   std::vector<Direction> stepsCapture = {};
   std::vector<Direction> sliderQuiet = {};
   std::vector<Direction> sliderCapture = {};
+  std::vector<Direction> hopperQuiet = {};
+  std::vector<Direction> hopperCapture = {};
 
   void merge(const PieceInfo* pi);
 };
index aee2cc9..931e346 100644 (file)
@@ -361,13 +361,13 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960,
           token = char(toupper(token));
 
           if (token == 'K')
-              for (rsq = make_square(FILE_MAX, relative_rank(c, RANK_1, max_rank())); piece_on(rsq) != rook; --rsq) {}
+              for (rsq = make_square(FILE_MAX, relative_rank(c, castling_rank(), max_rank())); piece_on(rsq) != rook; --rsq) {}
 
           else if (token == 'Q')
-              for (rsq = make_square(FILE_A, relative_rank(c, RANK_1, max_rank())); piece_on(rsq) != rook; ++rsq) {}
+              for (rsq = make_square(FILE_A, relative_rank(c, castling_rank(), max_rank())); piece_on(rsq) != rook; ++rsq) {}
 
           else if (token >= 'A' && token <= 'A' + max_file())
-              rsq = make_square(File(token - 'A'), relative_rank(c, RANK_1, max_rank()));
+              rsq = make_square(File(token - 'A'), relative_rank(c, castling_rank(), max_rank()));
 
           else
               continue;
@@ -449,7 +449,7 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960,
 
 void Position::set_castling_right(Color c, Square rfrom) {
 
-  Square kfrom = count<KING>(c) ? square<KING>(c) : make_square(FILE_E, c == WHITE ? RANK_1 : max_rank());
+  Square kfrom = count<KING>(c) ? square<KING>(c) : make_square(FILE_E, relative_rank(c, castling_rank(), max_rank()));
   CastlingSide cs = kfrom < rfrom ? KING_SIDE : QUEEN_SIDE;
   CastlingRight cr = (c | cs);
 
@@ -459,7 +459,7 @@ void Position::set_castling_right(Color c, Square rfrom) {
   castlingRookSquare[cr] = rfrom;
 
   Square kto = make_square(cs == KING_SIDE ? castling_kingside_file() : castling_queenside_file(),
-                           relative_rank(c, RANK_1, max_rank()));
+                           relative_rank(c, castling_rank(), max_rank()));
   Square rto = kto + (cs == KING_SIDE ? WEST : EAST);
 
   castlingPath[cr] =   (between_bb(rfrom, rto) | between_bb(kfrom, kto) | rto | kto)
@@ -809,7 +809,7 @@ bool Position::legal(Move m) const {
 
       // After castling, the rook and king final positions are the same in
       // Chess960 as they would be in standard chess.
-      to = make_square(to > from ? castling_kingside_file() : castling_queenside_file(), relative_rank(us, RANK_1, max_rank()));
+      to = make_square(to > from ? castling_kingside_file() : castling_queenside_file(), relative_rank(us, castling_rank(), max_rank()));
       Direction step = to > from ? WEST : EAST;
 
       for (Square s = to; s != from; s += step)
@@ -888,7 +888,7 @@ bool Position::pseudo_legal(const Move m) const {
       if (   !(attacks_from<PAWN>(us, from) & pieces(~us) & to) // Not a capture
           && !((from + pawn_push(us) == to) && empty(to))       // Not a single push
           && !(   (from + 2 * pawn_push(us) == to)              // Not a double push
-               && (rank_of(from) == relative_rank(us, RANK_2)
+               && (rank_of(from) == relative_rank(us, double_step_rank())
                    || (first_rank_double_steps() && rank_of(from) == relative_rank(us, RANK_1)))
                && empty(to)
                && empty(to - pawn_push(us))
@@ -945,7 +945,7 @@ bool Position::gives_check(Move m) const {
 
   // Is there a discovered check?
   if (   type_of(m) != DROP
-      && (st->blockersForKing[~sideToMove] & from)
+      && ((st->blockersForKing[~sideToMove] & from) || pieces(sideToMove, CANNON))
       && attackers_to(square<KING>(~sideToMove), (pieces() ^ from) | to, sideToMove))
       return true;
 
@@ -980,7 +980,7 @@ bool Position::gives_check(Move m) const {
       Square kfrom = from;
       Square rfrom = to; // Castling is encoded as 'King captures the rook'
       Square kto = make_square(rfrom > kfrom ? castling_kingside_file() : castling_queenside_file(),
-                              relative_rank(sideToMove, RANK_1, max_rank()));
+                              relative_rank(sideToMove, castling_rank(), max_rank()));
       Square rto = kto + (rfrom > kfrom ? WEST : EAST);
 
       return   (PseudoAttacks[sideToMove][ROOK][rto] & square<KING>(~sideToMove))
@@ -1066,7 +1066,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
 
               assert(pc == make_piece(us, PAWN));
               assert(to == st->epSquare);
-              assert(relative_rank(~us, to, max_rank()) == RANK_3);
+              assert(relative_rank(~us, to, max_rank()) == Rank(double_step_rank() + 1));
               assert(piece_on(to) == NO_PIECE);
               assert(piece_on(capsq) == make_piece(them, PAWN));
 
@@ -1136,12 +1136,12 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
       if (type_of(pc) != PAWN)
           st->nonPawnMaterial[us] += PieceValue[MG][pc];
       // Set castling rights for dropped king or rook
-      if (castling_dropped_piece() && relative_rank(us, to, max_rank()) == RANK_1)
+      if (castling_dropped_piece() && relative_rank(us, to, max_rank()) == castling_rank())
       {
           if (type_of(pc) == KING && file_of(to) == FILE_E)
           {
               Bitboard castling_rooks =  pieces(us, ROOK)
-                                       & rank_bb(relative_rank(us, RANK_1, max_rank()))
+                                       & rank_bb(relative_rank(us, castling_rank(), max_rank()))
                                        & (file_bb(FILE_A) | file_bb(max_file()));
               while (castling_rooks)
                   set_castling_right(us, pop_lsb(&castling_rooks));
@@ -1149,7 +1149,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
           else if (type_of(pc) == ROOK)
           {
               if (   (file_of(to) == FILE_A || file_of(to) == max_file())
-                  && piece_on(make_square(FILE_E, relative_rank(us, RANK_1, max_rank()))) == make_piece(us, KING))
+                  && piece_on(make_square(FILE_E, relative_rank(us, castling_rank(), max_rank()))) == make_piece(us, KING))
                   set_castling_right(us, to);
           }
       }
@@ -1162,7 +1162,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) {
   {
       // Set en-passant square if the moved pawn can be captured
       if (   std::abs(int(to) - int(from)) == 2 * NORTH
-          && relative_rank(us, rank_of(from), max_rank()) == RANK_2
+          && relative_rank(us, rank_of(from), max_rank()) == double_step_rank()
           && (attacks_from<PAWN>(us, to - pawn_push(us)) & pieces(them, PAWN)))
       {
           st->epSquare = to - pawn_push(us);
@@ -1377,7 +1377,7 @@ void Position::undo_move(Move m) {
 
               assert(type_of(pc) == PAWN);
               assert(to == st->previous->epSquare);
-              assert(relative_rank(~us, to, max_rank()) == RANK_3);
+              assert(relative_rank(~us, to, max_rank()) == Rank(double_step_rank() + 1));
               assert(piece_on(capsq) == NO_PIECE);
               assert(st->capturedPiece == make_piece(~us, PAWN));
           }
@@ -1412,7 +1412,7 @@ void Position::do_castling(Color us, Square from, Square& to, Square& rfrom, Squ
   bool kingSide = to > from;
   rfrom = to; // Castling is encoded as "king captures friendly rook"
   to = make_square(kingSide ? castling_kingside_file() : castling_queenside_file(),
-                   us == WHITE ? RANK_1 : max_rank());
+                   relative_rank(us, castling_rank(), max_rank()));
   rto = to + (kingSide ? WEST : EAST);
 
   // Remove both pieces first since squares could overlap in Chess960
@@ -1912,7 +1912,7 @@ bool Position::pos_is_ok() const {
       || (count<KING>(WHITE) && piece_on(square<KING>(WHITE)) != make_piece(WHITE, KING))
       || (count<KING>(BLACK) && piece_on(square<KING>(BLACK)) != make_piece(BLACK, KING))
       || (   ep_square() != SQ_NONE
-          && relative_rank(~sideToMove, ep_square()) != RANK_3))
+          && relative_rank(~sideToMove, ep_square(), max_rank()) != Rank(double_step_rank() + 1)))
       assert(0 && "pos_is_ok: Default");
 
   if (Fast)
index 793fdb3..6e75dd0 100644 (file)
@@ -106,11 +106,13 @@ public:
   bool piece_demotion() const;
   bool endgame_eval() const;
   bool double_step_enabled() const;
+  Rank double_step_rank() const;
   bool first_rank_double_steps() const;
   bool castling_enabled() const;
   bool castling_dropped_piece() const;
   File castling_kingside_file() const;
   File castling_queenside_file() const;
+  Rank castling_rank() const;
   bool checking_permitted() const;
   bool must_capture() const;
   bool must_drop() const;
@@ -362,6 +364,11 @@ inline bool Position::double_step_enabled() const {
   return var->doubleStep;
 }
 
+inline Rank Position::double_step_rank() const {
+  assert(var != nullptr);
+  return var->doubleStepRank;
+}
+
 inline bool Position::first_rank_double_steps() const {
   assert(var != nullptr);
   return var->firstRankDoubleSteps;
@@ -387,6 +394,11 @@ inline File Position::castling_queenside_file() const {
   return var->castlingQueensideFile;
 }
 
+inline Rank Position::castling_rank() const {
+  assert(var != nullptr);
+  return var->castlingRank;
+}
+
 inline bool Position::checking_permitted() const {
   assert(var != nullptr);
   return var->checking;
index 0f91f16..9f9f1af 100644 (file)
 
 Value PieceValue[PHASE_NB][PIECE_NB] = {
   { VALUE_ZERO, PawnValueMg, KnightValueMg, BishopValueMg, RookValueMg, QueenValueMg,
-    FersValueMg, AlfilValueMg, SilverValueMg, AiwokValueMg, BersValueMg,
+    FersValueMg, AlfilValueMg, FersAlfilValueMg, SilverValueMg, AiwokValueMg, BersValueMg,
     ArchbishopValueMg, ChancellorValueMg, AmazonValueMg, KnibisValueMg, BiskniValueMg,
     ShogiPawnValueMg, LanceValueMg, ShogiKnightValueMg, EuroShogiKnightValueMg, GoldValueMg, HorseValueMg,
-    ClobberPieceValueMg, BreakthroughPieceValueMg, ImmobilePieceValueMg, WazirValueMg, CommonerValueMg },
+    ClobberPieceValueMg, BreakthroughPieceValueMg, ImmobilePieceValueMg, CannonPieceValueMg, WazirValueMg, CommonerValueMg },
   { VALUE_ZERO, PawnValueEg, KnightValueEg, BishopValueEg, RookValueEg, QueenValueEg,
-    FersValueEg, AlfilValueEg, SilverValueEg, AiwokValueEg, BersValueEg,
+    FersValueEg, AlfilValueEg, FersAlfilValueEg, SilverValueEg, AiwokValueEg, BersValueEg,
     ArchbishopValueMg, ChancellorValueEg, AmazonValueEg, KnibisValueMg, BiskniValueMg,
     ShogiPawnValueEg, LanceValueEg, ShogiKnightValueEg, EuroShogiKnightValueEg, GoldValueEg, HorseValueEg,
-    ClobberPieceValueEg, BreakthroughPieceValueEg, ImmobilePieceValueEg, WazirValueEg, CommonerValueEg }
+    ClobberPieceValueEg, BreakthroughPieceValueEg, ImmobilePieceValueEg, CannonPieceValueEg, WazirValueEg, CommonerValueEg }
 };
 
 namespace PSQT {
index 2c7899b..22d3075 100644 (file)
@@ -316,6 +316,7 @@ enum Value : int {
   QueenValueMg  = 2529,  QueenValueEg  = 2687,
   FersValueMg              = 420,   FersValueEg              = 450,
   AlfilValueMg             = 330,   AlfilValueEg             = 300,
+  FersAlfilValueMg         = 600,   FersAlfilValueEg         = 600,
   SilverValueMg            = 600,   SilverValueEg            = 600,
   AiwokValueMg             = 2500,  AiwokValueEg             = 2500,
   BersValueMg              = 2000,  BersValueEg              = 2000,
@@ -333,6 +334,7 @@ enum Value : int {
   ClobberPieceValueMg      = 300,   ClobberPieceValueEg      = 300,
   BreakthroughPieceValueMg = 300,   BreakthroughPieceValueEg = 300,
   ImmobilePieceValueMg     = 100,   ImmobilePieceValueEg     = 100,
+  CannonPieceValueMg       = 900,   CannonPieceValueEg       = 900,
   WazirValueMg             = 400,   WazirValueEg             = 400,
   CommonerValueMg          = 700,   CommonerValueEg          = 900,
 
@@ -343,10 +345,10 @@ constexpr int PIECE_TYPE_BITS = 5; // PIECE_TYPE_NB = pow(2, PIECE_TYPE_BITS)
 
 enum PieceType {
   NO_PIECE_TYPE, PAWN, KNIGHT, BISHOP, ROOK, QUEEN,
-  FERS, MET = FERS, ALFIL, SILVER, KHON = SILVER, AIWOK, BERS, DRAGON = BERS,
+  FERS, MET = FERS, ALFIL, FERS_ALFIL, SILVER, KHON = SILVER, AIWOK, BERS, DRAGON = BERS,
   ARCHBISHOP, CHANCELLOR, AMAZON, KNIBIS, BISKNI,
   SHOGI_PAWN, LANCE, SHOGI_KNIGHT, EUROSHOGI_KNIGHT, GOLD, HORSE,
-  CLOBBER_PIECE, BREAKTHROUGH_PIECE, IMMOBILE_PIECE, WAZIR, COMMONER, KING,
+  CLOBBER_PIECE, BREAKTHROUGH_PIECE, IMMOBILE_PIECE, CANNON, WAZIR, COMMONER, KING,
   ALL_PIECES = 0,
 
   PIECE_TYPE_NB = 1 << PIECE_TYPE_BITS
@@ -367,6 +369,8 @@ enum RiderType {
   RIDER_BISHOP = 1 << 0,
   RIDER_ROOK_H = 1 << 1,
   RIDER_ROOK_V = 1 << 2,
+  RIDER_CANNON_H = 1 << 3,
+  RIDER_CANNON_V = 1 << 4,
 };
 
 extern Value PieceValue[PHASE_NB][PIECE_NB];
index b27e00a..fd35e6c 100644 (file)
@@ -587,6 +587,21 @@ VariantMap variants; // Global object
         v->stalemateValue = -VALUE_MATE;
         return v;
     }
+    Variant* shako_variant() {
+        Variant* v = fairy_variant_base();
+        v->maxRank = RANK_10;
+        v->maxFile = FILE_J;
+        v->add_piece(FERS_ALFIL, 'e');
+        v->add_piece(CANNON, 'c');
+        v->startFen = "c8c/ernbqkbnre/pppppppppp/10/10/10/10/PPPPPPPPPP/ERNBQKBNRE/C8C w KQkq - 0 1";
+        v->promotionPieceTypes = { QUEEN, ROOK, BISHOP, KNIGHT, CANNON, FERS_ALFIL };
+        v->promotionRank = RANK_10;
+        v->castlingKingsideFile = FILE_H;
+        v->castlingQueensideFile = FILE_D;
+        v->castlingRank = RANK_2;
+        v->doubleStepRank = RANK_3;
+        return v;
+    }
     Variant* clobber10_variant() {
         Variant* v = clobber_variant();
         v->maxRank = RANK_10;
@@ -653,6 +668,7 @@ void VariantMap::init() {
     add("embassy", embassy_variant());
     add("jesonmor", jesonmor_variant());
     add("courier", courier_variant());
+    add("shako", shako_variant());
     add("clobber10", clobber10_variant());
 #endif
 }
index 2527ccb..caa5638 100644 (file)
@@ -50,11 +50,13 @@ struct Variant {
   bool pieceDemotion = false;
   bool endgameEval = false;
   bool doubleStep = true;
+  Rank doubleStepRank = RANK_2;
   bool firstRankDoubleSteps = false;
   bool castling = true;
   bool castlingDroppedPiece = false;
   File castlingKingsideFile = FILE_G;
   File castlingQueensideFile = FILE_C;
+  Rank castlingRank = RANK_1;
   bool checking = true;
   bool mustCapture = false;
   bool mustDrop = false;