From: Fabian Fichter Date: Wed, 29 May 2019 14:02:04 +0000 (+0200) Subject: Support Shako X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=0619e184c38d3e17d284302b2752b79df4293651;p=fairystockfish.git Support Shako https://www.chessvariants.com/large.dir/shako.html - Support cannon - Generalize pawn double steps - Generalize castling bench: 3713921 --- diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 6aef4f2..47c969e 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -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 #ifdef PRECOMPUTED_MAGICS void init_magics(Bitboard table[], Magic magics[], std::vector directions, Bitboard magicsInit[]); #else void init_magics(Bitboard table[], Magic magics[], std::vector directions); #endif + template Bitboard sliding_attack(std::vector 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 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(RookTableH, RookMagicsH, RookDirectionsH, RookMagicHInit); + init_magics(RookTableV, RookMagicsV, RookDirectionsV, RookMagicVInit); + init_magics(BishopTable, BishopMagics, BishopDirections, BishopMagicInit); + init_magics(CannonTableH, CannonMagicsH, RookDirectionsH, CannonMagicHInit); + init_magics(CannonTableV, CannonMagicsV, RookDirectionsV, CannonMagicVInit); #else - init_magics(RookTableH, RookMagicsH, RookDirectionsH); - init_magics(RookTableV, RookMagicsV, RookDirectionsV); - init_magics(BishopTable, BishopMagics, BishopDirections); + init_magics(RookTableH, RookMagicsH, RookDirectionsH); + init_magics(RookTableV, RookMagicsV, RookDirectionsV); + init_magics(BishopTable, BishopMagics, BishopDirections); + init_magics(CannonTableH, CannonMagicsH, RookDirectionsH); + init_magics(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(pi->sliderCapture, s, 0, c); + PseudoAttacks[c][pt][s] |= sliding_attack(pi->hopperCapture, s, 0, c); + PseudoMoves[c][pt][s] |= sliding_attack(pi->sliderQuiet, s, 0, c); + PseudoMoves[c][pt][s] |= sliding_attack(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 #ifdef PRECOMPUTED_MAGICS void init_magics(Bitboard table[], Magic magics[], std::vector 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(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(directions, s, b); if (HasPext) m.attacks[pext(b, m.mask)] = reference[size]; diff --git a/src/bitboard.h b/src/bitboard.h index 3987999..63a38a1 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -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 constexpr const T& clamp(const T& v, const T& lo, const T& hi template 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(s, occupied); if (AttackRiderTypes[pt] & RIDER_ROOK_V) b |= rider_attacks_bb(s, occupied); + if (AttackRiderTypes[pt] & RIDER_ROOK_H) + b |= rider_attacks_bb(s, occupied); + if (AttackRiderTypes[pt] & RIDER_CANNON_V) + b |= rider_attacks_bb(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(s, occupied); if (MoveRiderTypes[pt] & RIDER_ROOK_V) b |= rider_attacks_bb(s, occupied); + if (MoveRiderTypes[pt] & RIDER_CANNON_H) + b |= rider_attacks_bb(s, occupied); + if (MoveRiderTypes[pt] & RIDER_CANNON_V) + b |= rider_attacks_bb(s, occupied); return b & PseudoMoves[c][pt][s]; } diff --git a/src/magic.h b/src/magic.h index 5610b19..1fae2e3 100644 --- a/src/magic.h +++ b/src/magic.h @@ -389,6 +389,250 @@ 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 diff --git a/src/movegen.cpp b/src/movegen.cpp index b326233..6cb35f2 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -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(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(from, pos.castling_rook_square(OO)); diff --git a/src/piece.cpp b/src/piece.cpp index b510bb0..aea82e0 100644 --- a/src/piece.cpp +++ b/src/piece.cpp @@ -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()); diff --git a/src/piece.h b/src/piece.h index a6404e5..bd4809e 100644 --- a/src/piece.h +++ b/src/piece.h @@ -32,6 +32,8 @@ struct PieceInfo { std::vector stepsCapture = {}; std::vector sliderQuiet = {}; std::vector sliderCapture = {}; + std::vector hopperQuiet = {}; + std::vector hopperCapture = {}; void merge(const PieceInfo* pi); }; diff --git a/src/position.cpp b/src/position.cpp index aee2cc9..931e346 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -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(c) ? square(c) : make_square(FILE_E, c == WHITE ? RANK_1 : max_rank()); + Square kfrom = count(c) ? square(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(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(~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(~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(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(WHITE) && piece_on(square(WHITE)) != make_piece(WHITE, KING)) || (count(BLACK) && piece_on(square(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) diff --git a/src/position.h b/src/position.h index 793fdb3..6e75dd0 100644 --- a/src/position.h +++ b/src/position.h @@ -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; diff --git a/src/psqt.cpp b/src/psqt.cpp index 0f91f16..9f9f1af 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -25,15 +25,15 @@ 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 { diff --git a/src/types.h b/src/types.h index 2c7899b..22d3075 100644 --- a/src/types.h +++ b/src/types.h @@ -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]; diff --git a/src/variant.cpp b/src/variant.cpp index b27e00a..fd35e6c 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -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 } diff --git a/src/variant.h b/src/variant.h index 2527ccb..caa5638 100644 --- a/src/variant.h +++ b/src/variant.h @@ -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;