From 955cf1db9501a35d9e490c0dfa620822e6e1700c Mon Sep 17 00:00:00 2001 From: Fabian Fichter Date: Thu, 27 Sep 2018 22:18:34 +0200 Subject: [PATCH] Add support for large-board variants (#6) Add compile-time option for enabling a 12x10 board representation with 128 bit bitboards to enable support for chess variants with large boards. Support shogi as first variant with board size >8x8. Open issues for large board version: - Evaluation needs to be consolidated (esp. PSQT) - Endgame evaluation is disabled and requires to be fixed before reenabling it. - Memory consumption of history tables needs to be reduced. No functional change for normal version. --- src/Makefile | 21 +++- src/bitboard.cpp | 482 ++++++++++++++++++++++++++++++++++++++++++++---------- src/bitboard.h | 98 ++++++++--- src/endgame.cpp | 4 +- src/evaluate.cpp | 4 + src/material.cpp | 5 + src/movegen.cpp | 2 +- src/pawns.cpp | 2 +- src/position.cpp | 60 +++++-- src/position.h | 2 +- src/psqt.cpp | 2 +- src/types.h | 118 ++++++++++---- src/uci.cpp | 12 ++ src/variant.cpp | 38 +++++ 14 files changed, 685 insertions(+), 165 deletions(-) diff --git a/src/Makefile b/src/Makefile index 862bdb5..67d153b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -70,6 +70,8 @@ endif # at the end of the line for flag values. ### 2.1. General and architecture defaults +largeboards = no +precomputedmagics = yes optimize = yes debug = no sanitize = no @@ -122,6 +124,7 @@ ifeq ($(ARCH),x86-64-bmi2) popcnt = yes sse = yes pext = yes + precomputedmagics = no endif ifeq ($(ARCH),armv7) @@ -149,6 +152,15 @@ CXXFLAGS += -Wall -Wcast-qual -fno-exceptions -std=c++11 $(EXTRACXXFLAGS) DEPENDFLAGS += -std=c++11 LDFLAGS += $(EXTRALDFLAGS) +# Compile version with support for large board variants +# Use precomputed magics by default if pext is not available +ifneq ($(largeboards),no) + CXXFLAGS += -DLARGEBOARDS + ifeq ($(precomputedmagics),yes) + CXXFLAGS += -DPRECOMPUTED_MAGICS + endif +endif + ifeq ($(COMP),) COMP=gcc endif @@ -156,7 +168,10 @@ endif ifeq ($(COMP),gcc) comp=gcc CXX=g++ - CXXFLAGS += -pedantic -Wextra -Wshadow + CXXFLAGS += -Wextra -Wshadow + ifeq ($(largeboards),no) + CXXFLAGS += -pedantic + endif ifeq ($(ARCH),armv7) ifeq ($(OS),Android) @@ -403,6 +418,10 @@ help: @echo "make build ARCH=x86-64 COMP=clang" @echo "make profile-build ARCH=x86-64-modern COMP=gcc COMPCXX=g++-4.8" @echo "" + @echo "Version for large boards (only GCC and mingw, 64-bit required): " + @echo "" + @echo "make build ARCH=x86-64 COMP=gcc largeboards=yes" + @echo "" .PHONY: help build profile-build strip install clean objclean profileclean help \ diff --git a/src/bitboard.cpp b/src/bitboard.cpp index ec90623..7ba1783 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -34,7 +34,7 @@ Bitboard AdjacentFilesBB[FILE_NB]; Bitboard ForwardRanksBB[COLOR_NB][RANK_NB]; Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; Bitboard LineBB[SQUARE_NB][SQUARE_NB]; -Bitboard DistanceRingBB[SQUARE_NB][8]; +Bitboard DistanceRingBB[SQUARE_NB][FILE_NB]; Bitboard ForwardFileBB[COLOR_NB][SQUARE_NB]; Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB]; Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB]; @@ -48,10 +48,270 @@ Magic BishopMagics[SQUARE_NB]; namespace { +#ifdef LARGEBOARDS + Bitboard RookTable[0xA80000]; // To store rook attacks + Bitboard BishopTable[0x33C00]; // To store bishop attacks +#else Bitboard RookTable[0x19000]; // To store rook attacks Bitboard BishopTable[0x1480]; // To store bishop attacks +#endif + +#ifdef PRECOMPUTED_MAGICS +#define B(a, b) (Bitboard(a) << 64) ^ Bitboard(b) + // Use precomputed magics if pext is not avaible, + // since the magics generation is very slow. + Bitboard RookMagicInit[SQUARE_NB] = { + B(0x4068000028000894, 0x20006051028), + B(0x2004000042000004, 0x2810000008004000), + B(0x1020000220004000, 0x8004290180020200), + B(0x4310000101000020, 0x8020100004002000), + B(0x38000080211108, 0x118000104000000), + B(0x4050000080400004, 0x2011040500118010), + B(0x4010000048100200, 0x100000840204000), + B(0x4020000820000100, 0x410106024000804), + B(0x910000008D00021, 0x800004400100010), + B(0x6830000821080004, 0x80C00010100000), + B(0x8040000040500008, 0x200031840804901), + B(0x4018000042201000, 0x8300002D80000841), + B(0x100008000044000, 0x1980020094A89400), + B(0x1000004000082000, 0x4408540710000181), + B(0x1206010001100802, 0x40004100048), + B(0x984010000410001, 0x208080028AE), + B(0x411210000261014, 0x8000414100011208), + B(0x8200100000B0002, 0x1082008404000008), + B(0x5004090000400096, 0x10004020001000E2), + B(0x8899220000020001, 0x8401004904082000), + B(0x801720000080040, 0x101000200082020), + B(0x800060000102411, 0xA8200008808400), + B(0x30C0000081004, 0x1004200082100418), + B(0x1018010000020102, 0x4100000040014082), + B(0x24000008000001, 0x4080041809020000), + B(0x3011200814000104, 0x2110004020000000), + B(0x1814410050000800, 0x4041010220000400), + B(0x20B002010000211, 0x100104188808), + B(0x821020000114, 0x22080A0200304020), + B(0xC0E0020000082, 0x1004108210042000), + B(0x9010010000084, 0x2000011014020406), + B(0x400208018000040, 0x20D000052800018), + B(0x108008000080, 0x240400000104), + B(0x8012001080004400, 0x102010420201000), + B(0x1000000C0001210, 0x821000080441200), + B(0x1C500000200004D0, 0x20042084400410), + B(0x4000284000108000, 0x1809420810080140), + B(0x40804004000, 0x2220005410000000), + B(0x4007080A1020000, 0x8004020D41200020), + B(0x1080000800008000, 0x4080210000002002), + B(0x400000400250000, 0x8000001100410000), + B(0xC8010090010001, 0x2004000068009022), + B(0x8300200008210000, 0x410804100111004), + B(0x42150008210000, 0x81100004A400200), + B(0x2C1410001810001, 0x8200800000411020), + B(0x28420004020000, 0x409002880830900), + B(0x200028000008000, 0x8100000040200004), + B(0x4001030120000, 0x41008A020140404), + B(0x288000004240804, 0x2410020000090), + B(0x104202000004004, 0x2008010000040), + B(0x800A020008022020, 0x4112108040400), + B(0x90044001082420, 0x239806020040A), + B(0x4018000414800030, 0x2001100010000), + B(0x102820010088120, 0x8002004090008), + B(0x280100200000410, 0x840441100000), + B(0x4A020000040020, 0x10820040C0881), + B(0x20000010020, 0x21000800402010), + B(0x161A0400212C80, 0x42000400203002), + B(0xAB00800181208440, 0x3120A01004040), + B(0x261100084025060, 0x81800A2100400), + B(0x1008000000A02000, 0x940000010040910), + B(0x1406400004A010, 0x100011080188C05), + B(0x400002000011000, 0x2080005008080002), + B(0x402C1004012, 0x600004200488003), + B(0x1800080802000409, 0x200012061200104), + B(0x843020018100800, 0xE2000040100E0A04), + B(0xA0010200005048, 0x80000851000012), + B(0x20000900041, 0x200006904002024), + B(0x20010000080002, 0x100000490211000), + B(0x1000018070C, 0x4100008200400010), + B(0x40000004101060, 0x40000109A800112), + B(0x44000908010404, 0x2200000420010409), + B(0x169D042288081204, 0x18000040A000), + B(0x1000041002000, 0x6040040001208000), + B(0x130040088200DA, 0x81600004010300), + B(0x3000062004000220, 0x8404200010200020), + B(0xC000102000020A, 0x108200004001000), + B(0x2000008606120000, 0xC010200008010821), + B(0x80040200000100, 0x80080000800440), + B(0x508028000040100, 0x4280000800124), + B(0x5AA422000B810100, 0xA802200002004404), + B(0x10000A0000012100, 0x8080200000400802), + B(0x240048004008102, 0x200400010800100), + B(0x4140030108004, 0x8C012000024909A0), + B(0x1400018A0A8000, 0x90841080008200), + B(0xA500120088001010, 0x4040020200008042), + B(0x5008024008888001, 0x1A0200A00005000), + B(0x4004D13000026, 0x800008008000A012), + B(0x201501022901000E, 0x8000024100001102), + B(0xE80010140000800C, 0x20004B1080000820), + B(0x8011010100046A00, 0x90010000C021), + B(0x1008020008401440, 0x80900020000E088), + B(0x100088000040000, 0x8124800080002200), + B(0x12C04120401200, 0x410500E80004040B), + B(0x9904A0100020008, 0x800108400020040), + B(0x4000842405D0004, 0x10220200000080), + B(0x4000001080802010, 0x4040880A00200001), + B(0x4000001080802010, 0x4040880A00200001), + B(0x800002021008000, 0xA04000420020000C), + B(0x12A6020000304, 0x8290144200000), + B(0x102803020008, 0x40824014A0200000), + B(0x1400020080210008, 0x8001004000500000), + B(0x120000148212, 0x801C001003A00000), + B(0x2020002908040, 0x2000804140200000), + B(0x820000010080, 0x10A2020420200000), + B(0x508200022440, 0xB004001108800040), + B(0x8202004084010C81, 0xC081A03000400008), + B(0xB04080040204050, 0x1810028080200000), + B(0xAA20014010120001, 0x80308004022200), + B(0xAA20014010120001, 0x80308004022200), + B(0x208018020814020, 0x2004020200410A00), + B(0x6000801000002800, 0xC80121082004080), + B(0x84002080140202, 0x8000004100090100), + B(0x3100114050000, 0x2000818014000100), + B(0x280805000008A400, 0x401042000000300), + B(0x245A20000040401, 0x1000850102080200), + B(0x4010430000D00240, 0xD0800001201100), + B(0x20000080040, 0x9053000880500600), + B(0x1840000610021088, 0x440801002428400), + B(0x448814040010, 0x8410085020500600) + }; + Bitboard BishopMagicInit[SQUARE_NB] = { + B(0x2001040305000010, 0x830200040400082), + B(0x1042400080E01200, 0x2004904010811400), + B(0x400010120200, 0x880080D080018000), + B(0x240190C00100040, 0x100A020140044404), + B(0x1018010404010004, 0x1001010018081E0), + B(0x41200A804C0904, 0x40000322000008), + B(0x4001180A004, 0x8000001106000000), + B(0x6006020020030600, 0x1840002100004841), + B(0x4200200100, 0x4001041808002000), + B(0x4100020050124600, 0x1001802902400CA0), + B(0x448C0081440161, 0x200206010008000), + B(0x400008008008408, 0x1000080210100080), + B(0x200280C01008200, 0x210200813000080), + B(0x1A000204400, 0x222200401023000), + B(0x10081040640A00, 0x8410021881400000), + B(0x1840400318080008, 0x800800840080000), + B(0x4204050C040, 0x6500600200140000), + B(0x1012100040204, 0x402404444400000), + B(0x6000012680008240, 0x410140000004220), + B(0x1000020810040008, 0x2D0011000060000), + B(0x1020020400, 0x400108059001001), + B(0x400020001100808, 0x480204800200000B), + B(0x10000010030084, 0x2042000848900022), + B(0x10000010030084, 0x2042000848900022), + B(0x100D801402400, 0x1512404009000400), + B(0x8000208005112400, 0xA02040401000000), + B(0x1000420002800200, 0x4CA000183020000), + B(0x800811480020, 0x408801010224001), + B(0xC805200810900100, 0x9000084204004020), + B(0x8200160204100004, 0x8040004004002022), + B(0x104514013080080, 0x146410040001000), + B(0x140844000080002, 0x1008102020040001), + B(0x4040400041A2002, 0x8040000A8802510), + B(0x801014041008002, 0x80068008025200), + B(0xA00540A414040, 0x4101040010A0000), + B(0x6484008010810002, 0x1100506884024000), + B(0x2800401008006000, 0x1005420884029020), + B(0x6822091010004421, 0x2000458080480), + B(0x40101000200101, 0x10020100001C4E0), + B(0x100400008C42, 0x4000100009008000), + B(0x851220018800400, 0x1681800040080080), + B(0x64200002010, 0x900020200040002), + B(0x20800080000022, 0x80040810002010), + B(0xA88408000802080, 0x20808001000000), + B(0x200000400C005040, 0x100140020290108), + B(0x224100000800408, 0x4204802004400020), + B(0x80080620010210, 0x91080088804040), + B(0x4008002100010, 0x80AC201001000001), + B(0x10008200902C046, 0x8080D03004000010), + B(0x3002100081000180, 0x2210002121528408), + B(0x8C101800804420, 0x1019880200043008), + B(0x200022000920D0, 0x8000800081300020), + B(0x1D40800880000, 0x400040001400050), + B(0x2020004100040, 0x200008040008008), + B(0x4840800040100001, 0x100100040203040), + B(0x40084001105, 0x8800080088000089), + B(0x4000128008020008, 0x4004200200440020), + B(0x210040008520000, 0x820219001080022), + B(0x1494040018002116, 0x400101047020008), + B(0x510008001910C224, 0x80200148118000), + B(0xC0301002301000, 0x4211A08004801), + B(0x50008E0C01001080, 0x100C004102845100), + B(0x400600020060400, 0x88024100250050), + B(0x8202920002002040, 0x810012000003), + B(0x800004208800200, 0x18AA00201000048), + B(0x402100800100002, 0x411000081000400), + B(0x101000022004044, 0x9000100040000), + B(0x41068001001, 0xC00400010001), + B(0x310210001040, 0x1A1200020010000), + B(0xA082409200004048, 0x490040800124101), + B(0x18844820E0040212, 0x1000404420D10000), + B(0x802908A40003348, 0x20200040104140), + B(0x1800404028205003, 0xC020010401089020), + B(0x802100044D01000, 0x8C41888000800040), + B(0x1D0161011410081, 0x10008000100200), + B(0x401000480040100, 0x286800404002212), + B(0x821030000100009, 0x2000090200A00000), + B(0x200020800200800, 0x2000480900841012), + B(0x80A000048030080, 0x200000120200008), + B(0x40B1400008020020, 0x148000200008004), + B(0xA021700002002010, 0x3040E400040100), + B(0x400242C200200640, 0x20440210200281), + B(0x80AC140040206240, 0x120000102801401), + B(0x2020340040832040, 0x10402100A44000), + B(0x420100400040220, 0x80014C8004000106), + B(0x504300822421120, 0x8004004008400100), + B(0x2001100008040, 0x2020104302000000), + B(0xA500802000A, 0x2008008000114100), + B(0x8A0020000200, 0x9C00101001002408), + B(0x104000001001008, 0x9001000204040060), + B(0x1000820080108200, 0xA401000008100001), + B(0x2008600009000480, 0x9008020001400000), + B(0x4000800200040200, 0xA00030400308082), + B(0x4004300202004709, 0x1000100180010020), + B(0xC014800100440010, 0x402020280002C010), + B(0x220208010884680, 0x1040280000042110), + B(0x40B0018019202801, 0x1008408000100040), + B(0x8269010206080044, 0x8001810000000040), + B(0x4000020880081040, 0x208A44000028000), + B(0x4004004E9004220A, 0x2104004001400024), + B(0x8035006008C0904, 0x402002001080120), + B(0x1800884002, 0x404400820000000), + B(0x8088000004008910, 0x8024100401000000), + B(0x142200086000100, 0x28021040020002E), + B(0x1000409141004018, 0x100410820080040A), + B(0x1800801800140, 0x810801060C0801), + B(0x1000C00100402220, 0x808023420000000), + B(0x8A0A202414305008, 0x100040200000021), + B(0xC0208024050, 0x8003088008020401), + B(0x8044004201440101, 0x400820080C024022), + B(0x406018884120099, 0xB00088018002000), + B(0x2000800010403010, 0xC5A002002010010), + B(0x800020040840, 0x201800202800200), + B(0x201280120020008D, 0x258809001000040), + B(0x9100002020181, 0x80400082204000), + B(0x104010080201001, 0x40080080181080), + B(0x8440248092000430, 0xA200804900100000), + B(0x2031010C01000C20, 0x200310A560082008), + B(0x400202081811400, 0x40081802050000C), + B(0x1011002100821300, 0x2400825040804100) + }; +#undef B +#endif +#ifdef PRECOMPUTED_MAGICS + void init_magics(Bitboard table[], Magic magics[], Direction directions[], Bitboard magicsInit[]); +#else void init_magics(Bitboard table[], Magic magics[], Direction directions[]); +#endif // popcount16() counts the non-zero bits using SWAR-Popcount algorithm @@ -62,14 +322,14 @@ namespace { return (u * 0x0101U) >> 8; } - Bitboard sliding_attack(Direction directions[], Square sq, Bitboard occupied, int maxDist = 7) { + Bitboard sliding_attack(Direction directions[], Square sq, Bitboard occupied, int maxDist = FILE_MAX, Color c = WHITE) { Bitboard attack = 0; for (int i = 0; directions[i]; ++i) - for (Square s = sq + directions[i]; - is_ok(s) && distance(s, s - directions[i]) == 1 && distance(s, sq) <= maxDist; - s += directions[i]) + for (Square s = sq + (c == WHITE ? directions[i] : -directions[i]); + is_ok(s) && distance(s, s - (c == WHITE ? directions[i] : -directions[i])) == 1 && distance(s, sq) <= maxDist; + s += (c == WHITE ? directions[i] : -directions[i])) { attack |= s; @@ -89,9 +349,9 @@ const std::string Bitboards::pretty(Bitboard b) { std::string s = "+---+---+---+---+---+---+---+---+\n"; - for (Rank r = RANK_8; r >= RANK_1; --r) + for (Rank r = RANK_MAX; r >= RANK_1; --r) { - for (File f = FILE_A; f <= FILE_H; ++f) + for (File f = FILE_A; f <= FILE_MAX; ++f) s += b & make_square(f, r) ? "| X " : "| "; s += "|\n+---+---+---+---+---+---+---+---+\n"; @@ -109,35 +369,35 @@ void Bitboards::init() { for (unsigned i = 0; i < (1 << 16); ++i) PopCnt16[i] = (uint8_t) popcount16(i); - for (Square s = SQ_A1; s <= SQ_H8; ++s) + for (Square s = SQ_A1; s <= SQ_MAX; ++s) SquareBB[s] = make_bitboard(s); - for (File f = FILE_A; f <= FILE_H; ++f) + for (File f = FILE_A; f <= FILE_MAX; ++f) FileBB[f] = f > FILE_A ? FileBB[f - 1] << 1 : FileABB; - for (Rank r = RANK_1; r <= RANK_8; ++r) - RankBB[r] = r > RANK_1 ? RankBB[r - 1] << 8 : Rank1BB; + for (Rank r = RANK_1; r <= RANK_MAX; ++r) + RankBB[r] = r > RANK_1 ? RankBB[r - 1] << FILE_NB : Rank1BB; - for (File f = FILE_A; f <= FILE_H; ++f) - AdjacentFilesBB[f] = (f > FILE_A ? FileBB[f - 1] : 0) | (f < FILE_H ? FileBB[f + 1] : 0); + for (File f = FILE_A; f <= FILE_MAX; ++f) + AdjacentFilesBB[f] = (f > FILE_A ? FileBB[f - 1] : 0) | (f < FILE_MAX ? FileBB[f + 1] : 0); - for (Rank r = RANK_1; r < RANK_8; ++r) + for (Rank r = RANK_1; r < RANK_MAX; ++r) ForwardRanksBB[WHITE][r] = ~(ForwardRanksBB[BLACK][r + 1] = ForwardRanksBB[BLACK][r] | RankBB[r]); for (Color c = WHITE; c <= BLACK; ++c) - for (Square s = SQ_A1; s <= SQ_H8; ++s) + for (Square s = SQ_A1; s <= SQ_MAX; ++s) { ForwardFileBB [c][s] = ForwardRanksBB[c][rank_of(s)] & FileBB[file_of(s)]; PawnAttackSpan[c][s] = ForwardRanksBB[c][rank_of(s)] & AdjacentFilesBB[file_of(s)]; PassedPawnMask[c][s] = ForwardFileBB [c][s] | PawnAttackSpan[c][s]; } - for (File f = FILE_A; f <= FILE_H; ++f) - for (Rank r = RANK_1; r <= RANK_8; ++r) + for (File f = FILE_A; f <= FILE_MAX; ++f) + for (Rank r = RANK_1; r <= RANK_MAX; ++r) BoardSizeBB[f][r] = ForwardFileBB[BLACK][make_square(f, r)] | SquareBB[make_square(f, r)] | (f > FILE_A ? BoardSizeBB[f - 1][r] : 0); - for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) - for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) + for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1) + for (Square s2 = SQ_A1; s2 <= SQ_MAX; ++s2) if (s1 != s2) { SquareDistance[s1][s2] = std::max(distance(s1, s2), distance(s1, s2)); @@ -148,64 +408,79 @@ void Bitboards::init() { Direction RookDirections[5] = { NORTH, EAST, SOUTH, WEST }; Direction BishopDirections[5] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }; +#ifdef PRECOMPUTED_MAGICS + init_magics(RookTable, RookMagics, RookDirections, RookMagicInit); + init_magics(BishopTable, BishopMagics, BishopDirections, BishopMagicInit); +#else init_magics(RookTable, RookMagics, RookDirections); init_magics(BishopTable, BishopMagics, BishopDirections); +#endif int stepsCapture[][13] = { {}, // NO_PIECE_TYPE - { 7, 9 }, // pawn - { -17, -15, -10, -6, 6, 10, 15, 17 }, // knight + { NORTH_WEST, NORTH_EAST }, // pawn + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // knight {}, // bishop {}, // rook {}, // queen - { -9, -7, 7, 9 }, // fers/met - { -18, -14, 14, 18 }, // alfil - { -9, -7, 7, 8, 9 }, // silver/khon - { -17, -15, -10, -9, -7, -6, 6, 7, 9, 10, 15, 17 }, // aiwok - { -9, -7, 7, 9 }, // bers/dragon - { -17, -15, -10, -6, 6, 10, 15, 17 }, // chancellor - { -17, -15, -10, -6, 6, 10, 15, 17 }, // amazon + { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // fers/met + { 2 * SOUTH_WEST, 2 * SOUTH_EAST, 2 * NORTH_WEST, 2 * NORTH_EAST }, // alfil + { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH, NORTH_EAST }, // silver/khon + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH_WEST, SOUTH_EAST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH_WEST, NORTH_EAST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // aiwok + { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // bers/dragon + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // chancellor + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // amazon {}, // knibis - { -17, -15, -10, -6, 6, 10, 15, 17 }, // biskni - { 8 }, // shogi pawn + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // biskni + { NORTH }, // shogi pawn {}, // lance - { 15, 17 }, // shogi knight - { -1, 1, 15, 17 }, // euroshogi knight - { -8, -1, 1, 7, 8, 9 }, // gold - { -8, -1, 1, 8 }, // horse - { -8, -1, 1, 8 }, // clobber - { 7, 9 }, // breakthrough + { 2 * NORTH + WEST, 2 * NORTH + EAST }, // shogi knight + { WEST, EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // euroshogi knight + { SOUTH, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST }, // gold + { SOUTH, WEST, EAST, NORTH }, // horse + { SOUTH, WEST, EAST, NORTH }, // clobber + { NORTH_WEST, NORTH_EAST }, // breakthrough {}, // immobile - { -9, -8, -7, -1, 1, 7, 8, 9 }, // commoner - { -9, -8, -7, -1, 1, 7, 8, 9 } // king + { SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST }, // commoner + { SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST } // king }; int stepsQuiet[][13] = { {}, // NO_PIECE_TYPE - { 8 }, // pawn - { -17, -15, -10, -6, 6, 10, 15, 17 }, // knight + { NORTH }, // pawn + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // knight {}, // bishop {}, // rook {}, // queen - { -9, -7, 7, 9 }, // fers/met - { -18, -14, 14, 18 }, // alfil - { -9, -7, 7, 8, 9 }, // silver/khon - { -17, -15, -10, -9, -7, -6, 6, 7, 9, 10, 15, 17 }, // aiwok - { -9, -7, 7, 9 }, // bers/dragon - { -17, -15, -10, -6, 6, 10, 15, 17 }, // chancellor - { -17, -15, -10, -6, 6, 10, 15, 17 }, // amazon - { -17, -15, -10, -6, 6, 10, 15, 17 }, // knibis + { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // fers/met + { 2 * SOUTH_WEST, 2 * SOUTH_EAST, 2 * NORTH_WEST, 2 * NORTH_EAST }, // alfil + { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH, NORTH_EAST }, // silver/khon + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH_WEST, SOUTH_EAST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH_WEST, NORTH_EAST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // aiwok + { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // bers/dragon + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // chancellor + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // amazon + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // knibis {}, // biskni - { 8 }, // shogi pawn + { NORTH }, // shogi pawn {}, // lance - { 15, 17 }, // shogi knight - { -1, 1, 15, 17 }, // euroshogi knight - { -8, -1, 1, 7, 8, 9 }, // gold - { -8, -1, 1, 8 }, // horse + { 2 * NORTH + WEST, 2 * NORTH + EAST }, // shogi knight + { WEST, EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // euroshogi knight + { SOUTH, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST }, // gold + { SOUTH, WEST, EAST, NORTH }, // horse {}, // clobber - { 7, 8, 9 }, // breakthrough + { NORTH_WEST, NORTH, NORTH_EAST }, // breakthrough {}, // immobile - { -9, -8, -7, -1, 1, 7, 8, 9 }, // commoner - { -9, -8, -7, -1, 1, 7, 8, 9 } // king + { SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST }, // commoner + { SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST } // king }; Direction sliderCapture[][9] = { {}, // NO_PIECE_TYPE @@ -267,24 +542,24 @@ void Bitboards::init() { 0, // NO_PIECE_TYPE 0, // pawn 0, // knight - 7, // bishop - 7, // rook - 7, // queen + FILE_MAX, // bishop + FILE_MAX, // rook + FILE_MAX, // queen 0, // fers/met 0, // alfil 0, // silver/khon - 7, // aiwok - 7, // bers/dragon - 7, // chancellor - 7, // amazon - 7, // knibis + FILE_MAX, // aiwok + FILE_MAX, // bers/dragon + FILE_MAX, // chancellor + FILE_MAX, // amazon + FILE_MAX, // knibis 0, // biskni 0, // shogi pawn - 7, // lance + FILE_MAX, // lance 0, // shogi knight 0, // euroshogi knight 0, // gold - 7, // horse + FILE_MAX, // horse 0, // clobber 0, // breakthrough 0, // immobile @@ -295,24 +570,24 @@ void Bitboards::init() { 0, // NO_PIECE_TYPE 0, // pawn 0, // knight - 7, // bishop - 7, // rook - 7, // queen + FILE_MAX, // bishop + FILE_MAX, // rook + FILE_MAX, // queen 0, // fers/met 0, // alfil 0, // silver/khon - 7, // aiwok - 7, // bers/dragon - 7, // chancellor - 7, // amazon + FILE_MAX, // aiwok + FILE_MAX, // bers/dragon + FILE_MAX, // chancellor + FILE_MAX, // amazon 0, // knibis - 7, // biskni + FILE_MAX, // biskni 0, // shogi pawn - 7, // lance + FILE_MAX, // lance 0, // shogi knight 0, // euroshogi knight 0, // gold - 7, // horse + FILE_MAX, // horse 0, // clobber 0, // breakthrough 0, // immobile @@ -322,7 +597,7 @@ void Bitboards::init() { for (Color c = WHITE; c <= BLACK; ++c) for (PieceType pt = PAWN; pt <= KING; ++pt) - for (Square s = SQ_A1; s <= SQ_H8; ++s) + for (Square s = SQ_A1; s <= SQ_MAX; ++s) { for (int i = 0; stepsCapture[pt][i]; ++i) { @@ -344,14 +619,14 @@ void Bitboards::init() { LeaperMoves[c][pt][s] |= to; } } - PseudoAttacks[c][pt][s] |= sliding_attack(sliderCapture[pt], s, 0, sliderDistCapture[pt]); - PseudoMoves[c][pt][s] |= sliding_attack(sliderQuiet[pt], s, 0, sliderDistQuiet[pt]); + PseudoAttacks[c][pt][s] |= sliding_attack(sliderCapture[pt], s, 0, sliderDistCapture[pt], c); + PseudoMoves[c][pt][s] |= sliding_attack(sliderQuiet[pt], s, 0, sliderDistQuiet[pt], c); } - for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) + for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1) { for (PieceType pt : { BISHOP, ROOK }) - for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) + for (Square s2 = SQ_A1; s2 <= SQ_MAX; ++s2) { if (!(PseudoAttacks[WHITE][pt][s1] & s2)) continue; @@ -370,19 +645,34 @@ namespace { // chessprogramming.wikispaces.com/Magic+Bitboards. In particular, here we // use the so called "fancy" approach. +#ifdef PRECOMPUTED_MAGICS + void init_magics(Bitboard table[], Magic magics[], Direction directions[], Bitboard magicsInit[]) { +#else void init_magics(Bitboard table[], Magic magics[], Direction directions[]) { +#endif // Optimal PRNG seeds to pick the correct magics in the shortest time +#ifndef PRECOMPUTED_MAGICS +#ifdef LARGEBOARDS + int seeds[][RANK_NB] = { {}, + { 734, 10316, 55013, 32803, 12281, 15100, 16645, 255, 346, 89123} }; +#else int seeds[][RANK_NB] = { { 8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020 }, { 728, 10316, 55013, 32803, 12281, 15100, 16645, 255 } }; +#endif +#endif + + Bitboard* occupancy = new Bitboard[1 << (FILE_NB + RANK_NB - 4)]; + Bitboard* reference = new Bitboard[1 << (FILE_NB + RANK_NB - 4)]; + Bitboard edges, b; + int* epoch = new int[1 << (FILE_NB + RANK_NB - 4)](); + int cnt = 0, size = 0; - Bitboard occupancy[4096], reference[4096], edges, b; - int epoch[4096] = {}, cnt = 0, size = 0; - for (Square s = SQ_A1; s <= SQ_H8; ++s) + for (Square s = SQ_A1; s <= SQ_MAX; ++s) { // Board edges are not considered in the relevant occupancies - edges = ((Rank1BB | Rank8BB) & ~rank_bb(s)) | ((FileABB | FileHBB) & ~file_bb(s)); + edges = ((Rank1BB | rank_bb(RANK_MAX)) & ~rank_bb(s)) | ((FileABB | file_bb(FILE_MAX)) & ~file_bb(s)); // Given a square 's', the mask is the bitboard of sliding attacks from // 's' computed on an empty board. The index must be big enough to contain @@ -391,7 +681,11 @@ namespace { // apply to the 64 or 32 bits word to get the index. Magic& m = magics[s]; m.mask = sliding_attack(directions, s, 0) & ~edges; +#ifdef LARGEBOARDS + m.shift = 128 - popcount(m.mask); +#else m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask); +#endif // Set the offset for the attacks table of the square. We have individual // table sizes for each square with "Fancy Magic Bitboards". @@ -414,14 +708,26 @@ namespace { if (HasPext) continue; +#ifndef PRECOMPUTED_MAGICS PRNG rng(seeds[Is64Bit][rank_of(s)]); +#endif // Find a magic for square 's' picking up an (almost) random number // until we find the one that passes the verification test. for (int i = 0; i < size; ) { - for (m.magic = 0; popcount((m.magic * m.mask) >> 56) < 6; ) + for (m.magic = 0; popcount(((m.magic * m.mask) & AllSquares) >> (SQUARE_NB - FILE_NB)) < FILE_NB - 2; ) + { +#ifdef LARGEBOARDS +#ifdef PRECOMPUTED_MAGICS + m.magic = magicsInit[s]; +#else + m.magic = (rng.sparse_rand() << 64) ^ rng.sparse_rand(); +#endif +#else m.magic = rng.sparse_rand(); +#endif + } // A good magic must map every possible occupancy to an index that // looks up the correct sliding attack in the attacks[s] database. @@ -443,5 +749,9 @@ namespace { } } } + + delete[] occupancy; + delete[] reference; + delete[] epoch; } } diff --git a/src/bitboard.h b/src/bitboard.h index 9f3819d..35ee1cb 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -39,10 +39,22 @@ const std::string pretty(Bitboard b); } +#ifdef LARGEBOARDS +constexpr Bitboard AllSquares = ((~Bitboard(0)) >> 8); +#else constexpr Bitboard AllSquares = ~Bitboard(0); +#endif +#ifdef LARGEBOARDS +constexpr Bitboard DarkSquares = (Bitboard(0xAAA555AAA555AAULL) << 64) ^ Bitboard(0xA555AAA555AAA555ULL); +#else constexpr Bitboard DarkSquares = 0xAA55AA55AA55AA55ULL; +#endif +#ifdef LARGEBOARDS +constexpr Bitboard FileABB = (Bitboard(0x00100100100100ULL) << 64) ^ Bitboard(0x1001001001001001ULL); +#else constexpr Bitboard FileABB = 0x0101010101010101ULL; +#endif constexpr Bitboard FileBBB = FileABB << 1; constexpr Bitboard FileCBB = FileABB << 2; constexpr Bitboard FileDBB = FileABB << 3; @@ -50,15 +62,30 @@ constexpr Bitboard FileEBB = FileABB << 4; constexpr Bitboard FileFBB = FileABB << 5; constexpr Bitboard FileGBB = FileABB << 6; constexpr Bitboard FileHBB = FileABB << 7; +#ifdef LARGEBOARDS +constexpr Bitboard FileIBB = FileABB << 8; +constexpr Bitboard FileJBB = FileABB << 9; +constexpr Bitboard FileKBB = FileABB << 10; +constexpr Bitboard FileLBB = FileABB << 11; +#endif + +#ifdef LARGEBOARDS +constexpr Bitboard Rank1BB = 0xFFF; +#else constexpr Bitboard Rank1BB = 0xFF; -constexpr Bitboard Rank2BB = Rank1BB << (8 * 1); -constexpr Bitboard Rank3BB = Rank1BB << (8 * 2); -constexpr Bitboard Rank4BB = Rank1BB << (8 * 3); -constexpr Bitboard Rank5BB = Rank1BB << (8 * 4); -constexpr Bitboard Rank6BB = Rank1BB << (8 * 5); -constexpr Bitboard Rank7BB = Rank1BB << (8 * 6); -constexpr Bitboard Rank8BB = Rank1BB << (8 * 7); +#endif +constexpr Bitboard Rank2BB = Rank1BB << (FILE_NB * 1); +constexpr Bitboard Rank3BB = Rank1BB << (FILE_NB * 2); +constexpr Bitboard Rank4BB = Rank1BB << (FILE_NB * 3); +constexpr Bitboard Rank5BB = Rank1BB << (FILE_NB * 4); +constexpr Bitboard Rank6BB = Rank1BB << (FILE_NB * 5); +constexpr Bitboard Rank7BB = Rank1BB << (FILE_NB * 6); +constexpr Bitboard Rank8BB = Rank1BB << (FILE_NB * 7); +#ifdef LARGEBOARDS +constexpr Bitboard Rank9BB = Rank1BB << (FILE_NB * 8); +constexpr Bitboard Rank10BB = Rank1BB << (FILE_NB * 9); +#endif extern int SquareDistance[SQUARE_NB][SQUARE_NB]; @@ -70,7 +97,7 @@ extern Bitboard AdjacentFilesBB[FILE_NB]; extern Bitboard ForwardRanksBB[COLOR_NB][RANK_NB]; extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; extern Bitboard LineBB[SQUARE_NB][SQUARE_NB]; -extern Bitboard DistanceRingBB[SQUARE_NB][8]; +extern Bitboard DistanceRingBB[SQUARE_NB][FILE_NB]; extern Bitboard ForwardFileBB[COLOR_NB][SQUARE_NB]; extern Bitboard PassedPawnMask[COLOR_NB][SQUARE_NB]; extern Bitboard PawnAttackSpan[COLOR_NB][SQUARE_NB]; @@ -79,6 +106,9 @@ extern Bitboard PseudoMoves[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB]; extern Bitboard LeaperAttacks[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB]; extern Bitboard LeaperMoves[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB]; +#ifdef LARGEBOARDS +int popcount(Bitboard b); // required for 128 bit pext +#endif /// Magic holds all magic bitboards relevant data for a single square struct Magic { @@ -110,37 +140,37 @@ extern Magic BishopMagics[SQUARE_NB]; /// whether a given bit is set in a bitboard, and for setting and clearing bits. inline Bitboard operator&(Bitboard b, Square s) { - assert(s >= SQ_A1 && s <= SQ_H8); + assert(s >= SQ_A1 && s <= SQ_MAX); return b & SquareBB[s]; } inline Bitboard operator|(Bitboard b, Square s) { - assert(s >= SQ_A1 && s <= SQ_H8); + assert(s >= SQ_A1 && s <= SQ_MAX); return b | SquareBB[s]; } inline Bitboard operator^(Bitboard b, Square s) { - assert(s >= SQ_A1 && s <= SQ_H8); + assert(s >= SQ_A1 && s <= SQ_MAX); return b ^ SquareBB[s]; } inline Bitboard operator-(Bitboard b, Square s) { - assert(s >= SQ_A1 && s <= SQ_H8); + assert(s >= SQ_A1 && s <= SQ_MAX); return b & ~SquareBB[s]; } inline Bitboard& operator|=(Bitboard& b, Square s) { - assert(s >= SQ_A1 && s <= SQ_H8); + assert(s >= SQ_A1 && s <= SQ_MAX); return b |= SquareBB[s]; } inline Bitboard& operator^=(Bitboard& b, Square s) { - assert(s >= SQ_A1 && s <= SQ_H8); + assert(s >= SQ_A1 && s <= SQ_MAX); return b ^= SquareBB[s]; } inline Bitboard& operator-=(Bitboard& b, Square s) { - assert(s >= SQ_A1 && s <= SQ_H8); + assert(s >= SQ_A1 && s <= SQ_MAX); return b &= ~SquareBB[s]; } @@ -183,7 +213,7 @@ constexpr Bitboard make_bitboard() { return 0; } template constexpr Bitboard make_bitboard(Square s, Squares... squares) { - return (1ULL << s) | make_bitboard(squares...); + return (Bitboard(1) << s) | make_bitboard(squares...); } @@ -191,10 +221,10 @@ constexpr Bitboard make_bitboard(Square s, Squares... squares) { template constexpr Bitboard shift(Bitboard b) { - return D == NORTH ? b << 8 : D == SOUTH ? b >> 8 - : D == EAST ? (b & ~FileHBB) << 1 : D == WEST ? (b & ~FileABB) >> 1 - : D == NORTH_EAST ? (b & ~FileHBB) << 9 : D == NORTH_WEST ? (b & ~FileABB) << 7 - : D == SOUTH_EAST ? (b & ~FileHBB) >> 7 : D == SOUTH_WEST ? (b & ~FileABB) >> 9 + return D == NORTH ? b << NORTH : D == SOUTH ? b >> NORTH + : D == EAST ? (b & ~file_bb(FILE_MAX)) << EAST : D == WEST ? (b & ~FileABB) >> EAST + : D == NORTH_EAST ? (b & ~file_bb(FILE_MAX)) << NORTH_EAST : D == NORTH_WEST ? (b & ~FileABB) << NORTH_WEST + : D == SOUTH_EAST ? (b & ~file_bb(FILE_MAX)) >> NORTH_WEST : D == SOUTH_WEST ? (b & ~FileABB) >> NORTH_EAST : 0; } @@ -202,10 +232,10 @@ constexpr Bitboard shift(Bitboard b) { /// shift() moves a bitboard one step along direction D (mainly for pawns) constexpr Bitboard shift(Direction D, Bitboard b) { - return D == NORTH ? b << 8 : D == SOUTH ? b >> 8 - : D == EAST ? (b & ~FileHBB) << 1 : D == WEST ? (b & ~FileABB) >> 1 - : D == NORTH_EAST ? (b & ~FileHBB) << 9 : D == NORTH_WEST ? (b & ~FileABB) << 7 - : D == SOUTH_EAST ? (b & ~FileHBB) >> 7 : D == SOUTH_WEST ? (b & ~FileABB) >> 9 + return D == NORTH ? b << NORTH : D == SOUTH ? b >> NORTH + : D == EAST ? (b & ~file_bb(FILE_MAX)) << EAST : D == WEST ? (b & ~FileABB) >> EAST + : D == NORTH_EAST ? (b & ~file_bb(FILE_MAX)) << NORTH_EAST : D == NORTH_WEST ? (b & ~FileABB) << NORTH_WEST + : D == SOUTH_EAST ? (b & ~file_bb(FILE_MAX)) >> NORTH_WEST : D == SOUTH_WEST ? (b & ~FileABB) >> NORTH_EAST : 0; } @@ -330,8 +360,14 @@ inline int popcount(Bitboard b) { #ifndef USE_POPCNT extern uint8_t PopCnt16[1 << 16]; +#ifdef LARGEBOARDS + union { Bitboard bb; uint16_t u[8]; } v = { b }; + return PopCnt16[v.u[0]] + PopCnt16[v.u[1]] + PopCnt16[v.u[2]] + PopCnt16[v.u[3]] + + PopCnt16[v.u[4]] + PopCnt16[v.u[5]] + PopCnt16[v.u[6]] + PopCnt16[v.u[7]]; +#else union { Bitboard bb; uint16_t u[4]; } v = { b }; return PopCnt16[v.u[0]] + PopCnt16[v.u[1]] + PopCnt16[v.u[2]] + PopCnt16[v.u[3]]; +#endif #elif defined(_MSC_VER) || defined(__INTEL_COMPILER) @@ -339,7 +375,11 @@ inline int popcount(Bitboard b) { #else // Assumed gcc or compatible compiler +#ifdef LARGEBOARDS + return __builtin_popcountll(b >> 64) + __builtin_popcountll(b); +#else return __builtin_popcountll(b); +#endif #endif } @@ -351,12 +391,20 @@ inline int popcount(Bitboard b) { inline Square lsb(Bitboard b) { assert(b); +#ifdef LARGEBOARDS + if (!(b << 64)) + return Square(__builtin_ctzll(b >> 64) + 64); +#endif return Square(__builtin_ctzll(b)); } inline Square msb(Bitboard b) { assert(b); - return Square(63 ^ __builtin_clzll(b)); +#ifdef LARGEBOARDS + if (b >> 64) + return Square(SQUARE_BIT_MASK ^ (__builtin_clzll(b >> 64) + 64)); +#endif + return Square(SQUARE_BIT_MASK ^ __builtin_clzll(b)); } #elif defined(_MSC_VER) // MSVC diff --git a/src/endgame.cpp b/src/endgame.cpp index 3cd5e5b..6cf3aee 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -56,8 +56,8 @@ namespace { }; // Tables used to drive a piece towards or away from another piece - constexpr int PushClose[8] = { 0, 0, 100, 80, 60, 40, 20, 10 }; - constexpr int PushAway [8] = { 0, 5, 20, 40, 60, 80, 90, 100 }; + constexpr int PushClose[FILE_NB] = { 0, 0, 100, 80, 60, 40, 20, 10 }; + constexpr int PushAway [FILE_NB] = { 0, 5, 20, 40, 60, 80, 90, 100 }; // Pawn Rank based scaling factors used in KRPPKRP endgame constexpr int KRPPKRPScaleFactors[RANK_NB] = { 0, 9, 10, 14, 21, 44, 0, 0 }; diff --git a/src/evaluate.cpp b/src/evaluate.cpp index bf5372e..e6772fb 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -100,7 +100,11 @@ namespace { // MobilityBonus[PieceType-2][attacked] contains bonuses for middle and end game, // indexed by piece type and number of attacked squares in the mobility area. +#ifdef LARGEBOARDS + constexpr Score MobilityBonus[][38] = { +#else constexpr Score MobilityBonus[][32] = { +#endif { S(-75,-76), S(-57,-54), S( -9,-28), S( -2,-10), S( 6, 5), S( 14, 12), // Knights S( 22, 26), S( 29, 29), S( 36, 29) }, { S(-48,-59), S(-20,-23), S( 16, -3), S( 26, 13), S( 38, 24), S( 51, 42), // Bishops diff --git a/src/material.cpp b/src/material.cpp index 2585d47..45d2741 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -137,7 +137,12 @@ Entry* probe(const Position& pos) { // Map total non-pawn material into [PHASE_ENDGAME, PHASE_MIDGAME] e->gamePhase = Phase(((npm - EndgameLimit) * PHASE_MIDGAME) / (MidgameLimit - EndgameLimit)); +#ifdef LARGEBOARDS + // Disable endgame evaluation until it works independent of board size + if (false) +#else if (pos.endgame_eval()) +#endif { // Let's look if we have a specialized evaluation function for this particular // material configuration. Firstly we look for a fixed configuration one, then diff --git a/src/movegen.cpp b/src/movegen.cpp index 4c095de..f9ccf24 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -222,7 +222,7 @@ namespace { if (pos.ep_square() != SQ_NONE) { - assert(rank_of(pos.ep_square()) == relative_rank(Us, RANK_6)); + assert(rank_of(pos.ep_square()) == relative_rank(Them, RANK_3)); // 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 diff --git a/src/pawns.cpp b/src/pawns.cpp index 5ee3165..d2d9a6b 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -164,7 +164,7 @@ void init() { for (int opposed = 0; opposed <= 1; ++opposed) for (int phalanx = 0; phalanx <= 1; ++phalanx) for (int support = 0; support <= 2; ++support) - for (Rank r = RANK_1; r < RANK_8; ++r) + for (Rank r = RANK_1; r < RANK_MAX; ++r) { int v = 17 * support; v += (Seed[r] + (phalanx ? (Seed[r + 1] - Seed[r]) / 2 : 0)) >> opposed; diff --git a/src/position.cpp b/src/position.cpp index 4e07e75..eef10b2 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -46,7 +46,7 @@ namespace Zobrist { Key enpassant[FILE_NB]; Key castling[CASTLING_RIGHT_NB]; Key side, noPawns; - Key inHand[PIECE_NB][17]; + Key inHand[PIECE_NB][SQUARE_NB]; Key checks[COLOR_NB][CHECKS_NB]; } @@ -138,12 +138,22 @@ std::ostream& operator<<(std::ostream& os, const Position& pos) { // https://marcelk.net/2013-04-06/paper/upcoming-rep-v2.pdf // First and second hash functions for indexing the cuckoo tables +#ifdef LARGEBOARDS +inline int H1(Key h) { return h & 0x7fff; } +inline int H2(Key h) { return (h >> 16) & 0x7fff; } +#else inline int H1(Key h) { return h & 0x1fff; } inline int H2(Key h) { return (h >> 16) & 0x1fff; } +#endif // Cuckoo tables with Zobrist hashes of valid reversible moves, and the moves themselves +#ifdef LARGEBOARDS +Key cuckoo[65536]; +Move cuckooMove[65536]; +#else Key cuckoo[8192]; Move cuckooMove[8192]; +#endif /// Position::init() initializes at startup the various arrays used to compute @@ -155,10 +165,10 @@ void Position::init() { for (Color c = WHITE; c <= BLACK; ++c) for (PieceType pt = PAWN; pt <= KING; ++pt) - for (Square s = SQ_A1; s <= SQ_H8; ++s) + for (Square s = SQ_A1; s <= SQ_MAX; ++s) Zobrist::psq[make_piece(c, pt)][s] = rng.rand(); - for (File f = FILE_A; f <= FILE_H; ++f) + for (File f = FILE_A; f <= FILE_MAX; ++f) Zobrist::enpassant[f] = rng.rand(); for (int cr = NO_CASTLING; cr <= ANY_CASTLING; ++cr) @@ -181,7 +191,7 @@ void Position::init() { for (Color c = WHITE; c <= BLACK; ++c) for (PieceType pt = PAWN; pt <= KING; ++pt) - for (int n = 0; n < 17; ++n) + for (int n = 0; n < SQUARE_NB; ++n) Zobrist::inHand[make_piece(c, pt)][n] = rng.rand(); // Prepare the cuckoo tables @@ -190,8 +200,8 @@ void Position::init() { for (PieceType pt = KNIGHT; pt <= QUEEN || pt == KING; pt != QUEEN ? ++pt : pt = KING) { Piece pc = make_piece(c, pt); - for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) - for (Square s2 = Square(s1 + 1); s2 <= SQ_H8; ++s2) + for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1) + for (Square s2 = Square(s1 + 1); s2 <= SQ_MAX; ++s2) if (PseudoAttacks[WHITE][type_of(pc)][s1] & s2) { Move move = make_move(s1, s2); @@ -208,7 +218,11 @@ void Position::init() { count++; } } +#ifdef LARGEBOARDS + assert(count == 9344); +#else assert(count == 3668); +#endif } @@ -264,16 +278,27 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960, ss >> std::noskipws; - Square sq = SQ_A8 + (RANK_8 - max_rank()) * SOUTH; + Square sq = SQ_A1 + max_rank() * NORTH; // 1. Piece placement while ((ss >> token) && !isspace(token)) { if (isdigit(token)) + { +#ifdef LARGEBOARDS + if (isdigit(ss.peek())) + { + sq += 10 * (token - '0') * EAST; + ss >> token; + sq += (token - '0') * EAST; + } + else +#endif sq += (token - '0') * EAST; // Advance the given number of files + } else if (token == '/') - sq += 2 * SOUTH + (FILE_H - max_file()) * EAST; + sq += 2 * SOUTH + (FILE_MAX - max_file()) * EAST; else if ((idx = piece_to_char().find(token)) != string::npos) { @@ -348,8 +373,8 @@ Position& Position::set(const Variant* v, const string& fenStr, bool isChess960, } // 4. En passant square. Ignore if no pawn capture is possible - if ( ((ss >> col) && (col >= 'a' && col <= 'h')) - && ((ss >> row) && (row == '3' || row == '6'))) + if ( ((ss >> col) && (col >= 'a' && col <= 'a' + max_file())) + && ((ss >> row) && (row >= '1' && row <= '1' + max_rank()))) { st->epSquare = make_square(File(col - 'a'), Rank(row - '1')); @@ -533,8 +558,9 @@ Position& Position::set(const string& code, Color c, StateInfo* si) { std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower); - string fenStr = "8/" + sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/" - + sides[1] + char(8 - sides[1].length() + '0') + "/8 w - - 0 10"; + string n = std::to_string(FILE_NB); + string fenStr = n + "/" + sides[0] + char(FILE_NB - sides[0].length() + '0') + "/" + n + "/" + n + "/" + n + "/" + + n + "/" + sides[1] + char(FILE_NB - sides[1].length() + '0') + "/" + n + " w - - 0 10"; return set(variants.find("chess")->second, fenStr, false, si, nullptr); } @@ -952,7 +978,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) == RANK_6); + assert(relative_rank(~us, to, max_rank()) == RANK_3); assert(piece_on(to) == NO_PIECE); assert(piece_on(capsq) == make_piece(them, PAWN)); @@ -1032,7 +1058,7 @@ void Position::do_move(Move m, StateInfo& newSt, bool givesCheck) { if (type_of(pc) == PAWN) { // Set en-passant square if the moved pawn can be captured - if ( (int(to) ^ int(from)) == 16 + if ( std::abs(int(to) - int(from)) == 2 * NORTH && relative_rank(us, rank_of(from), max_rank()) == RANK_2 && (attacks_from(us, to - pawn_push(us)) & pieces(them, PAWN))) { @@ -1197,7 +1223,7 @@ void Position::undo_move(Move m) { assert(type_of(pc) == PAWN); assert(to == st->previous->epSquare); - assert(relative_rank(us, to) == RANK_6); + assert(relative_rank(~us, to, max_rank()) == RANK_3); assert(piece_on(capsq) == NO_PIECE); assert(st->capturedPiece == make_piece(~us, PAWN)); } @@ -1533,7 +1559,7 @@ void Position::flip() { string f, token; std::stringstream ss(fen()); - for (Rank r = RANK_8; r >= RANK_1; --r) // Piece placement + for (Rank r = RANK_MAX; r >= RANK_1; --r) // Piece placement { std::getline(ss, token, r > RANK_1 ? '/' : ' '); f.insert(0, token + (f.empty() ? " " : "/")); @@ -1572,7 +1598,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_6)) + && relative_rank(~sideToMove, ep_square()) != RANK_3)) assert(0 && "pos_is_ok: Default"); if (Fast) diff --git a/src/position.h b/src/position.h index 25ee85c..04f5bb9 100644 --- a/src/position.h +++ b/src/position.h @@ -655,7 +655,7 @@ inline bool Position::pawn_passed(Color c, Square s) const { inline bool Position::advanced_pawn_push(Move m) const { return type_of(moved_piece(m)) == PAWN - && relative_rank(sideToMove, from_sq(m)) > RANK_4; + && relative_rank(sideToMove, from_sq(m), max_rank()) > (max_rank() + 1) / 2 - 1; } inline Key Position::key() const { diff --git a/src/psqt.cpp b/src/psqt.cpp index 7e6a501..3fef593 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -125,7 +125,7 @@ void init() { Score score = make_score(PieceValue[MG][pc], PieceValue[EG][pc]); - for (Square s = SQ_A1; s <= SQ_H8; ++s) + for (Square s = SQ_A1; s <= SQ_MAX; ++s) { File f = std::min(file_of(s), ~file_of(s)); psq[ pc][ s] = score + (pt == KING ? KingBonus[rank_of(s)][f] : Bonus[pc][rank_of(s)][f]); diff --git a/src/types.h b/src/types.h index 800414c..d9818a5 100644 --- a/src/types.h +++ b/src/types.h @@ -74,7 +74,11 @@ #if defined(USE_PEXT) # include // Header for _pext_u64() intrinsic -# define pext(b, m) _pext_u64(b, m) +# ifdef LARGEBOARDS +# define pext(b, m) (_pext_u64(b, m) ^ (_pext_u64(b >> 64, m >> 64) << popcount((m << 64) >> 64))) +# else +# define pext(b, m) _pext_u64(b, m) +# endif #else # define pext(b, m) 0 #endif @@ -98,7 +102,13 @@ constexpr bool Is64Bit = false; #endif typedef uint64_t Key; +#ifdef LARGEBOARDS +typedef unsigned __int128 Bitboard; +constexpr int SQUARE_BITS = 7; +#else typedef uint64_t Bitboard; +constexpr int SQUARE_BITS = 6; +#endif constexpr int MAX_MOVES = 512; constexpr int MAX_PLY = 128; @@ -117,16 +127,16 @@ constexpr int MAX_PLY = 128; enum Move : int { MOVE_NONE, - MOVE_NULL = 65 + MOVE_NULL = 1 + (1 << SQUARE_BITS) }; -enum MoveType { +enum MoveType : int { NORMAL, - ENPASSANT = 1 << 12, - CASTLING = 2 << 12, - PROMOTION = 3 << 12, - DROP = 4 << 12, - PIECE_PROMOTION = 5 << 12, + ENPASSANT = 1 << (2 * SQUARE_BITS), + CASTLING = 2 << (2 * SQUARE_BITS), + PROMOTION = 3 << (2 * SQUARE_BITS), + DROP = 4 << (2 * SQUARE_BITS), + PIECE_PROMOTION = 5 << (2 * SQUARE_BITS), }; enum Color { @@ -254,6 +264,18 @@ enum Depth : int { static_assert(!(ONE_PLY & (ONE_PLY - 1)), "ONE_PLY is not a power of 2"); enum Square : int { +#ifdef LARGEBOARDS + SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1, SQ_I1, SQ_J1, SQ_K1, SQ_L1, + SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2, SQ_I2, SQ_J2, SQ_K2, SQ_L2, + SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3, SQ_I3, SQ_J3, SQ_K3, SQ_L3, + SQ_A4, SQ_B4, SQ_C4, SQ_D4, SQ_E4, SQ_F4, SQ_G4, SQ_H4, SQ_I4, SQ_J4, SQ_K4, SQ_L4, + SQ_A5, SQ_B5, SQ_C5, SQ_D5, SQ_E5, SQ_F5, SQ_G5, SQ_H5, SQ_I5, SQ_J5, SQ_K5, SQ_L5, + SQ_A6, SQ_B6, SQ_C6, SQ_D6, SQ_E6, SQ_F6, SQ_G6, SQ_H6, SQ_I6, SQ_J6, SQ_K6, SQ_L6, + SQ_A7, SQ_B7, SQ_C7, SQ_D7, SQ_E7, SQ_F7, SQ_G7, SQ_H7, SQ_I7, SQ_J7, SQ_K7, SQ_L7, + SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8, SQ_I8, SQ_J8, SQ_K8, SQ_L8, + SQ_A9, SQ_B9, SQ_C9, SQ_D9, SQ_E9, SQ_F9, SQ_G9, SQ_H9, SQ_I9, SQ_J9, SQ_K9, SQ_L9, + SQ_A10, SQ_B10, SQ_C10, SQ_D10, SQ_E10, SQ_F10, SQ_G10, SQ_H10, SQ_I10, SQ_J10, SQ_K10, SQ_L10, +#else SQ_A1, SQ_B1, SQ_C1, SQ_D1, SQ_E1, SQ_F1, SQ_G1, SQ_H1, SQ_A2, SQ_B2, SQ_C2, SQ_D2, SQ_E2, SQ_F2, SQ_G2, SQ_H2, SQ_A3, SQ_B3, SQ_C3, SQ_D3, SQ_E3, SQ_F3, SQ_G3, SQ_H3, @@ -262,13 +284,25 @@ enum Square : int { SQ_A6, SQ_B6, SQ_C6, SQ_D6, SQ_E6, SQ_F6, SQ_G6, SQ_H6, SQ_A7, SQ_B7, SQ_C7, SQ_D7, SQ_E7, SQ_F7, SQ_G7, SQ_H7, SQ_A8, SQ_B8, SQ_C8, SQ_D8, SQ_E8, SQ_F8, SQ_G8, SQ_H8, +#endif SQ_NONE, - SQUARE_NB = 64 +#ifdef LARGEBOARDS + SQUARE_NB = 120, + SQUARE_BIT_MASK = 127, +#else + SQUARE_NB = 64, + SQUARE_BIT_MASK = 63, +#endif + SQ_MAX = SQUARE_NB - 1 }; enum Direction : int { +#ifdef LARGEBOARDS + NORTH = 12, +#else NORTH = 8, +#endif EAST = 1, SOUTH = -NORTH, WEST = -EAST, @@ -280,11 +314,23 @@ enum Direction : int { }; enum File : int { - FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, FILE_NB +#ifdef LARGEBOARDS + FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, FILE_I, FILE_J, FILE_K, FILE_L, +#else + FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H, +#endif + FILE_NB, + FILE_MAX = FILE_NB - 1 }; enum Rank : int { - RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, RANK_NB +#ifdef LARGEBOARDS + RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, RANK_9, RANK_10, +#else + RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8, +#endif + RANK_NB, + RANK_MAX = RANK_NB - 1 }; @@ -388,15 +434,19 @@ constexpr Color operator~(Color c) { } constexpr Square operator~(Square s) { +#ifdef LARGEBOARDS + return Square(s - FILE_NB * (s / FILE_NB * 2 - RANK_MAX)); // Vertical flip SQ_A1 -> SQ_A10 +#else return Square(s ^ SQ_A8); // Vertical flip SQ_A1 -> SQ_A8 +#endif } constexpr File operator~(File f) { - return File(f ^ FILE_H); // Horizontal flip FILE_A -> FILE_H + return File(FILE_MAX - f); // Horizontal flip FILE_A -> FILE_H } constexpr Rank operator~(Rank r) { - return Rank(r ^ RANK_8); // Vertical flip Rank_1 -> Rank_8 + return Rank(RANK_MAX - r); // Vertical flip Rank_1 -> Rank_8 } constexpr Piece operator~(Piece pc) { @@ -422,7 +472,7 @@ constexpr Value convert_mate_value(Value v, int ply) { } constexpr Square make_square(File f, Rank r) { - return Square((r << 3) + f); + return Square(r * FILE_NB + f); } constexpr Piece make_piece(Color c, PieceType pt) { @@ -439,19 +489,15 @@ inline Color color_of(Piece pc) { } constexpr bool is_ok(Square s) { - return s >= SQ_A1 && s <= SQ_H8; + return s >= SQ_A1 && s <= SQ_MAX; } constexpr File file_of(Square s) { - return File(s & 7); + return File(s % FILE_NB); } constexpr Rank rank_of(Square s) { - return Rank(s >> 3); -} - -constexpr Square relative_square(Color c, Square s) { - return Square(s ^ (c * 56)); + return Rank(s / FILE_NB); } constexpr Rank relative_rank(Color c, Rank r, Rank maxRank = RANK_8) { @@ -462,9 +508,21 @@ constexpr Rank relative_rank(Color c, Square s, Rank maxRank = RANK_8) { return relative_rank(c, rank_of(s), maxRank); } +constexpr Square relative_square(Color c, Square s) { +#ifdef LARGEBOARDS + return make_square(file_of(s), relative_rank(c, s)); +#else + return Square(s ^ (c * 56)); +#endif +} + inline bool opposite_colors(Square s1, Square s2) { +#ifdef LARGEBOARDS + return int(s1 - (s1 % FILE_NB)) ^ int(s2 - (s2 % FILE_NB)); +#else int s = int(s1) ^ int(s2); return ((s >> 3) ^ s) & 1; +#endif } constexpr Direction pawn_push(Color c) { @@ -472,42 +530,42 @@ constexpr Direction pawn_push(Color c) { } inline MoveType type_of(Move m) { - return MoveType(m & (15 << 12)); + return MoveType(m & (15 << (2 * SQUARE_BITS))); } constexpr Square to_sq(Move m) { - return Square(m & 0x3F); + return Square(m & SQUARE_BIT_MASK); } inline Square from_sq(Move m) { if (type_of(m) == DROP) return SQ_NONE; - return Square((m >> 6) & 0x3F); + return Square((m >> SQUARE_BITS) & SQUARE_BIT_MASK); } inline int from_to(Move m) { - return to_sq(m) + (from_sq(m) << 6); + return to_sq(m) + (from_sq(m) << SQUARE_BITS); } inline PieceType promotion_type(Move m) { - return type_of(m) == PROMOTION ? PieceType((m >> 16) & 63) : NO_PIECE_TYPE; + return type_of(m) == PROMOTION ? PieceType((m >> (2 * SQUARE_BITS + 4)) & (PIECE_TYPE_NB - 1)) : NO_PIECE_TYPE; } inline Move make_move(Square from, Square to) { - return Move((from << 6) + to); + return Move((from << SQUARE_BITS) + to); } template inline Move make(Square from, Square to, PieceType pt = NO_PIECE_TYPE) { - return Move((pt << 16) + T + (from << 6) + to); + return Move((pt << (2 * SQUARE_BITS + 4)) + T + (from << SQUARE_BITS) + to); } constexpr Move make_drop(Square to, PieceType pt) { - return Move(DROP + (pt << 16) + to); + return Move((pt << (2 * SQUARE_BITS + 4)) + DROP + to); } constexpr PieceType dropped_piece_type(Move m) { - return PieceType((m >> 16) & 63); + return PieceType((m >> (2 * SQUARE_BITS + 4)) & (PIECE_TYPE_NB - 1)); } inline bool is_ok(Move m) { diff --git a/src/uci.cpp b/src/uci.cpp index ec8c044..6ae8105 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -273,8 +273,20 @@ string UCI::value(Value v) { /// UCI::square() converts a Square to a string in algebraic notation (g1, a7, etc.) std::string UCI::square(const Position& pos, Square s) { +#ifdef LARGEBOARDS + if (Options["Protocol"] == "usi") + return rank_of(s) < RANK_10 ? std::string{ char('1' + pos.max_file() - file_of(s)), char('a' + pos.max_rank() - rank_of(s)) } + : std::string{ char('0' + (pos.max_file() - file_of(s) + 1) / 10), + char('0' + (pos.max_file() - file_of(s) + 1) % 10), + char('a' + pos.max_rank() - rank_of(s)) }; + else + return rank_of(s) < RANK_10 ? std::string{ char('a' + file_of(s)), char('1' + (rank_of(s) % 10)) } + : std::string{ char('a' + file_of(s)), char('0' + ((rank_of(s) + 1) / 10)), + char('0' + ((rank_of(s) + 1) % 10)) }; +#else return Options["Protocol"] == "usi" ? std::string{ char('1' + pos.max_file() - file_of(s)), char('a' + pos.max_rank() - rank_of(s)) } : std::string{ char('a' + file_of(s)), char('1' + rank_of(s)) }; +#endif } diff --git a/src/variant.cpp b/src/variant.cpp index f97c024..90f3c49 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -431,6 +431,41 @@ void VariantMap::init() { v->connectN = 3; return v; } (); +#ifdef LARGEBOARDS + const Variant* shogi = [&]{ + Variant* v = new Variant(); + v->maxRank = RANK_9; + v->maxFile = FILE_I; + v->reset_pieces(); + v->add_piece(SHOGI_PAWN, 'p'); + v->add_piece(LANCE, 'l'); + v->add_piece(SHOGI_KNIGHT, 'n'); + v->add_piece(SILVER, 's'); + v->add_piece(GOLD, 'g'); + v->add_piece(BISHOP, 'b'); + v->add_piece(HORSE, 'h'); + v->add_piece(ROOK, 'r'); + v->add_piece(KING, 'k'); + v->add_piece(DRAGON, 'd'); + v->startFen = "lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL[-] w 0 1"; + v->pieceDrops = true; + v->capturesToHand = true; + v->promotionRank = RANK_7; + v->promotionPieceTypes = {}; + v->doubleStep = false; + v->castling = false; + v->promotedPieceType[SHOGI_PAWN] = GOLD; + v->promotedPieceType[LANCE] = GOLD; + v->promotedPieceType[SHOGI_KNIGHT] = GOLD; + v->promotedPieceType[SILVER] = GOLD; + v->promotedPieceType[BISHOP] = HORSE; + v->promotedPieceType[ROOK] = DRAGON; + v->mandatoryPiecePromotion = false; + v->immobilityIllegal = true; + v->shogiPawnDropMateIllegal = true; + return v; + } (); +#endif // Add to UCI_Variant option add("chess", chess); @@ -467,6 +502,9 @@ void VariantMap::init() { add("breakthrough", breakthrough); add("connect4", connect4); add("tictactoe", tictactoe); +#ifdef LARGEBOARDS + add("shogi", shogi); +#endif } void VariantMap::add(std::string s, const Variant* v) { -- 1.7.0.4