From 7ab21a670339358be5a03baf5b42c31373bedde6 Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Fri, 30 Apr 2021 21:42:40 +0200 Subject: [PATCH] Support Nightrider --- src/bitboard.cpp | 13 ++++- src/bitboard.h | 6 ++- src/magic.h | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ src/types.h | 3 +- src/variant.cpp | 12 +++++ src/variants.ini | 2 +- tests/js/package.json | 2 +- tests/perft.sh | 1 + 8 files changed, 154 insertions(+), 7 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index d00eb51..139823f 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -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(ElephantTable, ElephantMagics, ElephantDirections, ElephantMagicInit); init_magics(JanggiElephantTable, JanggiElephantMagics, JanggiElephantDirections, JanggiElephantMagicInit); init_magics(CannonDiagTable, CannonDiagMagics, BishopDirections, CannonDiagMagicInit); + init_magics(NightriderTable, NightriderMagics, HorseDirections, NightriderMagicInit); #else init_magics(RookTableH, RookMagicsH, RookDirectionsH); init_magics(RookTableV, RookMagicsV, RookDirectionsV); @@ -338,6 +346,7 @@ void Bitboards::init() { init_magics(ElephantTable, ElephantMagics, ElephantDirections); init_magics(JanggiElephantTable, JanggiElephantMagics, JanggiElephantDirections); init_magics(CannonDiagTable, CannonDiagMagics, BishopDirections); + init_magics(NightriderTable, NightriderMagics, HorseDirections); #endif init_pieces(); diff --git a/src/bitboard.h b/src/bitboard.h index 1c105de..232c4f5 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -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 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)]; } diff --git a/src/magic.h b/src/magic.h index 33649ab..e12eb46 100644 --- a/src/magic.h +++ b/src/magic.h @@ -1121,6 +1121,128 @@ 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 diff --git a/src/types.h b/src/types.h index 38de559..c3df461 100644 --- a/src/types.h +++ b/src/types.h @@ -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]; diff --git a/src/variant.cpp b/src/variant.cpp index e08ed17..8287d61 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -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()); diff --git a/src/variants.ini b/src/variants.ini index 0f70dbc..fe04d55 100644 --- a/src/variants.ini +++ b/src/variants.ini @@ -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 diff --git a/tests/js/package.json b/tests/js/package.json index 896e22d..0c2b43e 100644 --- a/tests/js/package.json +++ b/tests/js/package.json @@ -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": [ diff --git a/tests/perft.sh b/tests/perft.sh index 4979416..fab2ab8 100755 --- a/tests/perft.sh +++ b/tests/perft.sh @@ -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 -- 1.7.0.4