From: Fabian Fichter Date: Sun, 26 Jan 2020 18:39:38 +0000 (+0100) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=d1a1c7b157e59e4344ad2ab478b16c790d708cb3;p=fairystockfish.git Merge official-stockfish/master bench: 4794966 --- d1a1c7b157e59e4344ad2ab478b16c790d708cb3 diff --cc src/evaluate.cpp index fe6b986,7c7ce95..f5e88d1 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@@ -956,14 -701,12 +955,17 @@@ namespace Value mg = mg_value(score); Value eg = eg_value(score); - int outflanking = distance(pos.square(WHITE), pos.square(BLACK)) - - distance(pos.square(WHITE), pos.square(BLACK)); + // No initiative bonus for extinction variants + if (pos.extinction_value() != VALUE_NONE || pos.captures_to_hand() || pos.connect_n()) + return SCORE_ZERO; + + int outflanking = !pos.count(WHITE) || !pos.count(BLACK) ? 0 + : distance(pos.square(WHITE), pos.square(BLACK)) + - distance(pos.square(WHITE), pos.square(BLACK)); - bool infiltration = rank_of(pos.square(WHITE)) > RANK_4 - || rank_of(pos.square(BLACK)) < RANK_5; ++ bool infiltration = (pos.count(WHITE) && rank_of(pos.square(WHITE)) > RANK_4) ++ || (pos.count(BLACK) && rank_of(pos.square(BLACK)) < RANK_5); + bool pawnsOnBothFlanks = (pos.pieces(PAWN) & QueenSide) && (pos.pieces(PAWN) & KingSide); @@@ -975,8 -717,8 +977,9 @@@ // Compute the initiative bonus for the attacking side int complexity = 9 * pe->passed_count() + 11 * pos.count() + + 15 * pos.count() + 9 * outflanking + + 12 * infiltration + 21 * pawnsOnBothFlanks + 51 * !pos.non_pawn_material() - 43 * almostUnwinnable diff --cc src/magic.h index 7dd0dfe,0000000..478f3f7 mode 100644,000000..100644 --- a/src/magic.h +++ b/src/magic.h @@@ -1,883 -1,0 +1,883 @@@ +/* + Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish - Copyright (C) 2018-2019 Fabian Fichter ++ Copyright (C) 2018-2020 Fabian Fichter + + Fairy-Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Fairy-Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef MAGIC_H_INCLUDED +#define MAGIC_H_INCLUDED + +#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 RookMagicHInit[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(0xC010220920198, 0x85000A08000), + 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 RookMagicVInit[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) + }; + 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) + }; + 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), + }; + Bitboard HorseMagicInit[SQUARE_NB] = { + B(0x3C080482A592000C, 0x540104000020000), + B(0x2802C40008000420, 0x4A00000001818009), + B(0x1083040280804000, 0x120004C20100880), + B(0x6840940880000892, 0x2014A01080800C2), + B(0x8401489004000180, 0x2000800000400000), + B(0x820161C800000110, 0x8000100000204020), + B(0x610011A122000109, 0x1000004020008004), + B(0x83282004023000, 0xE000020004848446), + B(0x6840940880000892, 0x2014A01080800C2), + B(0x4020120800800002, 0x88008000010020), + B(0x30025B140A1000, 0x3141801401000040), + B(0x41104D1810100050, 0x8141002010910), + B(0x4200828A298400, 0x400340001040C000), + B(0x8016A4900110040, 0x844812001068020), + B(0x2250035820400A2, 0x8012010080900), + B(0x820080083A009000, 0x880404091080110), + B(0x80401500AF0020, 0x240000082201A04), + B(0x668020020C081005, 0x4008001004100021), + B(0x240100910000000, 0x82000A0030454000), + B(0xA24091400008, 0x200014880004A921), + B(0x840110042200410, 0x100080000A400000), + B(0x40024024102000, 0x1000000002180404), + B(0x92828423000530, 0x118800020110), + B(0x1122404A1C90A8, 0x822040280020D00), + B(0x41201A40900A000, 0x80C0480040605100), + B(0x2504A85005488280, 0x3028112120022800), + B(0x210180080626B048, 0x8000401000014000), + B(0x1000410401040200, 0x41014000050C0106), + B(0x1040650210802200, 0x80C0041000000), + B(0x4020C10110900002, 0x2140C2001050009), + B(0x191180092200022, 0x6010008400400800), + B(0x8010821088080202, 0xCA240011008208), + B(0x8C0488120024214, 0x8414880202291), + B(0x8C0488120024214, 0x8414880202291), + B(0x22080C8A0161401, 0x200C10004C002002), + B(0x8430818023034080, 0x210090800000801), + B(0x4845087008200, 0x40661480000), + B(0x1202804428812050, 0x100022038020000), + B(0x400016001201080, 0x24002200402060), + B(0x680E041300800800, 0xE00130080004000), + B(0x3409080200, 0x282840210000000), + B(0x803310108400, 0x85200000080100A0), + B(0xE180008A04162104, 0x9088240412404), + B(0x20080100920020, 0x2002248010242052), + B(0x8A000400C2410, 0x1000024086014300), + B(0x1821040024663, 0x100000100010009), + B(0x4000822310611, 0x120280406014008), + B(0x1004008010818D08, 0x800000141892000), + B(0x8010800004024042, 0x44B106008800896), + B(0xA0063423444, 0x41002C15811008), + B(0x2040012381001282, 0x4804080104A4000), + B(0x10840101820880, 0xA800008000020020), + B(0x10840101820880, 0xA800008000020020), + B(0x60201D8300408190, 0x2010020920200000), + B(0x4048100200090090, 0x2008090100000900), + B(0x24200000280210, 0xD440050008004000), + B(0x1280001000580020, 0x2200040089000A4), + B(0x10208018C1020A20, 0x84C0432240610014), + B(0x10208018C1020A20, 0x84C0432240610014), + B(0x4108000010209089, 0x913000000024840), + B(0x410C208008008E02, 0xE8000000000001), + B(0x802208004005, 0x94206000022080), + B(0xC00290018902002, 0x4204100000000000), + B(0x2102801400093816, 0x9810004001000202), + B(0x8008304000015800, 0x4A5C000000020000), + B(0x1020108380800514, 0x1144210000000080), + B(0xC0001000008090, 0x2812060000204000), + B(0x1001100200003100, 0x246240060A004004), + B(0xA00020A008002030, 0x2440C40000110B00), + B(0x80502104000C008, 0x8222200042100010), + B(0xC020200088014, 0x422094000000480), + B(0x1029002000001030, 0x8105841120000210), + B(0x49040D, 0x2310808A14042C0), + B(0x200040200080A02C, 0xB890290400080000), + B(0x2240180C0800002, 0x4151050280000100), + B(0x2240180C0800002, 0x4151050280000100), + B(0x8220224180420006, 0x4024501212011000), + B(0x1806810A0881000, 0x802002048400080), + B(0x400400A080842, 0x9305000401180000), + B(0x10008001444110, 0x4420401040041833), + B(0x2000002C02010E00, 0x400408D08009804), + B(0x69D008200020100, 0x100842240049021), + B(0x42C24450020000, 0xD38400880090884), + B(0x485800800100001, 0x2484086522018840), + B(0x900200020820042, 0x22302421400040C0), + B(0x50B0413001818000, 0x452014040800C40), + B(0x8004040021008, 0x20088A08000290), + B(0x600C000801000004, 0x8015084010200020), + B(0x208000C00, 0xE004804021100100), + B(0x20001000040204, 0x948110C0B2081), + B(0x268502400100021, 0x80A201840802080), + B(0x408C000008, 0x8822102408014), + B(0x1182080410100000, 0x608002046A0100), + B(0x100820A083C00002, 0x3100100410A00), + B(0x8401040000400124, 0x2000081288202200), + B(0xB014040003000800, 0x11960D1101210), + B(0x10040001900C000, 0x85603C1001280), + B(0x2000844000000100, 0x2000024C60800800), + B(0x120004234800900, 0x210010841040), + B(0x8010300040000002, 0x4200008222104100), + B(0x1000120402200100, 0x209080CC040108B4), + B(0x110049A00000800, 0x80000420022180A8), + B(0x80001C00080384, 0x1400101111081001), + B(0x8011200008100428, 0x2020000880800922), + B(0x10001000000204C8, 0x280C11104240), + B(0x50100C82C000500, 0x28000280618DD1), + B(0x8800498020000, 0x20500A0200320128), + B(0x20010104000860, 0x8021720186008), + B(0x4000000000100080, 0x35040084270C04), + B(0x4500080000800, 0x280100002482C842), + B(0x10400000000000, 0x20080051100130C2), + B(0x10400000000000, 0x20080051100130C2), + B(0x2000002110202014, 0x121004004004681), + B(0x400202001006D40, 0x82240082202424), + B(0x4500080000800, 0x280100002482C842), + B(0xC6000000D00804, 0x1050020C0081090C), + B(0x200080000000042, 0x10800661), + B(0x2000001011200200, 0x2A420000802A0222), + B(0x802020001202412, 0x2400404148426), + B(0x8000440801040002, 0x444002800010052A), + }; + Bitboard ElephantMagicInit[SQUARE_NB] = { + B(0x64D2990200008, 0x4401880001C000), + B(0x29BAA00010020, 0x200000400800600), + B(0x3024240000000, 0x4100400010080), + B(0xA490A00480020, 0x20084001041010A4), + B(0x328C021008042, 0x100000000C10204), + B(0x1964090001018, 0x7002040148001205), + B(0x800302098404080, 0x4983020000000001), + B(0x8812244630A02080, 0x8200006204003C08), + B(0x41120231008000, 0x240441401020), + B(0x840091030C00040, 0x1400008200023400), + B(0x8001040E77030200, 0x100040090022000), + B(0x602022139D835040, 0x101002010025900), + B(0x405707C48400, 0x40010000008001), + B(0x982003456A82050, 0x60800820040030), + B(0x204184849200088, 0x101800004006), + B(0x300222470949200, 0x2A0800200200800), + B(0x400001211914000, 0x8200001407001), + B(0x2000008614831020, 0x4000020001404000), + B(0x84000024A2048048, 0x1200102000042), + B(0x424010A58422008, 0x88440242212A0110), + B(0x20020812C0C4408, 0x4121400000080010), + B(0x680200062042420, 0x2001100000800000), + B(0x200010060AEC855, 0x8083002040200000), + B(0x4000008BAA85810, 0x82000805C0200A90), + B(0x81450B200A025400, 0x4400101050000040), + B(0x820A2241409010, 0x888420030000), + B(0x909203000028, 0xC000004C00200041), + B(0x8021400A84880240, 0x100180002010020), + B(0x8001A20061410000, 0x14008499A000000), + B(0x8201444800A00080, 0x402010040588120), + B(0x100C06280020, 0x60010104840130), + B(0x520040800080044, 0x8220000080001402), + B(0x102021410040202, 0x2004400410006000), + B(0x5401832090020400, 0x300010020001), + B(0x180003105A84C108, 0x1012008800081000), + B(0x480C10210026904, 0xA006000004200418), + B(0x48050820210843A6, 0x108001004000C00), + B(0x1030101182206324, 0x4401008921502002), + B(0x40281060800800, 0x406000201260022), + B(0xC29002440040C820, 0x400001002008020), + B(0x40000400800241, 0xC220000000400280), + B(0x40880126014208, 0x2A8004C008940000), + B(0x121028100114080, 0x5010280481100082), + B(0x4000088280442, 0x908420140008041), + B(0x808C42400C0020, 0x3028100840801000), + B(0x4000000410078488, 0x501000000620000), + B(0x90080001421020A4, 0x4118400101060406), + B(0x280420004855, 0xD200100400820000), + B(0xA0063423444, 0x41002C15811008), + B(0x200061201808102, 0x4286969000200002), + B(0x10208018C1020A20, 0x84C0432240610014), + B(0x4001A04880402000, 0x8100824080000001), + B(0x60201D8300408190, 0x2010020920200000), + B(0x20018C04908019, 0x2010884002002040), + B(0x800000000C40810, 0x680100081150000D), + B(0x2002002000040040, 0x8810049000010600), + B(0x41618A0300040040, 0x21200200A421801), + B(0x10208018C1020A20, 0x84C0432240610014), + B(0x10208018C1020A20, 0x84C0432240610014), + B(0x5A04001400412854, 0x8A44006000010002), + B(0x13000C0810072432, 0x50049001021104), + B(0x400048801142130, 0x4C1204100226010C), + B(0x80001048, 0x408800104000080), + B(0x8104868204040412, 0x22244202000081), + B(0x8104868204040412, 0x22244202000081), + B(0x4140001000240440, 0x80209004410004E), + B(0x800800000100, 0xB111820100000002), + B(0x404240004220, 0x2110402802050080), + B(0x284010400004040, 0x100245002502020), + B(0x14880A100114010, 0x400208080010024), + B(0x4100004040440648, 0x10030D838041A80), + B(0x32004000210, 0x4010225C88014000), + B(0x2240180C0800002, 0x4151050280000100), + B(0x2010A12002000042, 0x189051442010000), + B(0x4060050080121883, 0x8250C10001000141), + B(0x10000000044100, 0x8401084010261009), + B(0xA00028040000, 0x2003224000002000), + B(0x2060009001000020, 0x1000432022020228), + B(0x404200000883080, 0x1080800848245000), + B(0x240000402080, 0xCA0820814210502), + B(0x200040200080A02C, 0xB890290400080000), + B(0x800000000300482, 0x9203008100100013), + B(0x8000210202042000, 0x22642104004C2400), + B(0x1040400805000401, 0x2A0300102C80010), + B(0x8010A01088020000, 0x122106105A06A030), + B(0x8000C00001010494, 0x130A1A20404120), + B(0x4B084010844290, 0x10A08008900840), + B(0x1180001802460000, 0xB08000034C82004), + B(0x4001880060028029, 0x204040002401000), + B(0x8021A0001308002A, 0x97001822040040), + B(0xC00000009A020AC1, 0x1000080900400), + B(0x60010110001990, 0x4000880900400000), + B(0x10290402401200, 0x230080402C08), + B(0x4220000219012000, 0x140204804100008), + B(0x1400200100002, 0x8E62200414128), + B(0x402808502004403, 0x20049100C0284520), + B(0xB30041004280280, 0x10020464DB200308), + B(0x440010800808, 0xA0102E295812100), + B(0x10008000B000, 0x2000058583220200), + B(0x2000844000000100, 0x2000024C60800800), + B(0x110000400100028, 0x24052304508004), + B(0x8458000000840004, 0x118006463400001), + B(0x804008000040050, 0x41044890228000), + B(0x20000050000400, 0x80A101824A00086), + B(0x600080404000020, 0x100007322480005), + B(0xD082200020020008, 0x642000630120001), + B(0x10000100040230, 0x8048114733320002), + B(0x20200442002A880A, 0x8200002CB4B8052), + B(0x290080000000, 0xA41297838F40D), + B(0x800205000080, 0xF221232039874400), + B(0x1444002004880C20, 0xC4100049144200), + B(0x4500080000800, 0x280100002482C842), + B(0x281240881008, 0x204084004C101900), + B(0x1444002004880C20, 0xC4100049144200), + B(0x4500080000800, 0x280100002482C842), + B(0xC0010928430540, 0x92041902180), + B(0x1051001208A, 0x4900064800C20640), + B(0x882020418C00000, 0x30004040092A821), + B(0x224404002004268C, 0x202500204C7D254), + B(0x290080000000, 0xA41297838F40D), + }; +#undef B +#endif + +#endif // #ifndef MAGIC_H_INCLUDED diff --cc src/parser.cpp index 996f562,0000000..0d0ffb2 mode 100644,000000..100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@@ -1,235 -1,0 +1,235 @@@ +/* + Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish - Copyright (C) 2018-2019 Fabian Fichter ++ Copyright (C) 2018-2020 Fabian Fichter + + Fairy-Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Fairy-Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include + +#include "parser.h" +#include "piece.h" +#include "types.h" + +namespace { + + template void set(const std::string& value, T& target) + { + std::stringstream ss(value); + ss >> target; + } + + template <> void set(const std::string& value, Rank& target) { + std::stringstream ss(value); + int i; + ss >> i; + target = Rank(i - 1); + } + + template <> void set(const std::string& value, File& target) { + std::stringstream ss(value); + if (isdigit(ss.peek())) + { + int i; + ss >> i; + target = File(i - 1); + } + else + { + char c; + ss >> c; + target = File(c - 'a'); + } + } + + template <> void set(const std::string& value, std::string& target) { + target = value; + } + + template <> void set(const std::string& value, bool& target) { + target = value == "true"; + } + + template <> void set(const std::string& value, Value& target) { + target = value == "win" ? VALUE_MATE + : value == "loss" ? -VALUE_MATE + : VALUE_DRAW; + } + + template <> void set(const std::string& value, CountingRule& target) { + target = value == "makruk" ? MAKRUK_COUNTING + : value == "asean" ? ASEAN_COUNTING + : NO_COUNTING; + } + + template <> void set(const std::string& value, Bitboard& target) { + char file; + int rank; + std::stringstream ss(value); + target = 0; + while (ss >> file && ss >> rank) + target |= file == '*' ? rank_bb(Rank(rank - 1)) : square_bb(make_square(File(tolower(file) - 'a'), Rank(rank - 1))); + } + +} // namespace + +template void VariantParser::parse_attribute(const std::string& key, T& target) { + const auto& it = config.find(key); + if (it != config.end()) + set(it->second, target); +} + +void VariantParser::parse_attribute(const std::string& key, PieceType& target, std::string pieceToChar) { + const auto& it = config.find(key); + if (it != config.end()) + { + char token; + size_t idx; + std::stringstream ss(it->second); + if (ss >> token && (idx = pieceToChar.find(toupper(token))) != std::string::npos) + target = PieceType(idx); + } +} + +Variant* VariantParser::parse() { + Variant* v = new Variant(); + v->reset_pieces(); + v->promotionPieceTypes = {}; + return parse(v); +} + +Variant* VariantParser::parse(Variant* v) { + // piece types + for (const auto& pieceInfo : pieceMap) + { + const auto& keyValue = config.find(pieceInfo.second->name); + if (keyValue != config.end() && !keyValue->second.empty()) + { + if (isalpha(keyValue->second.at(0))) + v->add_piece(pieceInfo.first, keyValue->second.at(0)); + else + v->remove_piece(pieceInfo.first); + } + } + parse_attribute("variantTemplate", v->variantTemplate); + parse_attribute("pieceToCharTable", v->pieceToCharTable); + parse_attribute("pocketSize", v->pocketSize); + parse_attribute("maxRank", v->maxRank); + parse_attribute("maxFile", v->maxFile); + parse_attribute("chess960", v->chess960); + parse_attribute("twoBoards", v->twoBoards); + parse_attribute("startFen", v->startFen); + parse_attribute("promotionRank", v->promotionRank); + // promotion piece types + const auto& it_prom = config.find("promotionPieceTypes"); + if (it_prom != config.end()) + { + v->promotionPieceTypes = {}; + char token; + size_t idx; + std::stringstream ss(it_prom->second); + while (ss >> token && ((idx = v->pieceToChar.find(toupper(token))) != std::string::npos)) + v->promotionPieceTypes.insert(PieceType(idx)); + } + parse_attribute("sittuyinPromotion", v->sittuyinPromotion); + // promotion limit + const auto& it_prom_limit = config.find("promotionLimit"); + if (it_prom_limit != config.end()) + { + char token; + size_t idx; + std::stringstream ss(it_prom_limit->second); + while (ss >> token && (idx = v->pieceToChar.find(toupper(token))) != std::string::npos && ss >> token && ss >> v->promotionLimit[idx]) {} + } + // promoted piece types + const auto& it_prom_pt = config.find("promotedPieceType"); + if (it_prom_pt != config.end()) + { + char token; + size_t idx, idx2; + std::stringstream ss(it_prom_pt->second); + while ( ss >> token && (idx = v->pieceToChar.find(toupper(token))) != std::string::npos && ss >> token + && ss >> token && (idx2 = (token == '-' ? 0 : v->pieceToChar.find(toupper(token)))) != std::string::npos) + v->promotedPieceType[idx] = PieceType(idx2); + } + parse_attribute("piecePromotionOnCapture", v->piecePromotionOnCapture); + parse_attribute("mandatoryPawnPromotion", v->mandatoryPawnPromotion); + parse_attribute("mandatoryPiecePromotion", v->mandatoryPiecePromotion); + parse_attribute("pieceDemotion", v->pieceDemotion); + parse_attribute("endgameEval", v->endgameEval); + parse_attribute("doubleStep", v->doubleStep); + parse_attribute("doubleStepRank", v->doubleStepRank); + parse_attribute("firstRankDoubleSteps", v->firstRankDoubleSteps); + parse_attribute("castling", v->castling); + parse_attribute("castlingDroppedPiece", v->castlingDroppedPiece); + parse_attribute("castlingKingsideFile", v->castlingKingsideFile); + parse_attribute("castlingQueensideFile", v->castlingQueensideFile); + parse_attribute("castlingRank", v->castlingRank); + parse_attribute("castlingRookPiece", v->castlingRookPiece, v->pieceToChar); + parse_attribute("kingType", v->kingType, v->pieceToChar); + parse_attribute("checking", v->checking); + parse_attribute("mustCapture", v->mustCapture); + parse_attribute("mustDrop", v->mustDrop); + parse_attribute("pieceDrops", v->pieceDrops); + parse_attribute("dropLoop", v->dropLoop); + parse_attribute("capturesToHand", v->capturesToHand); + parse_attribute("firstRankPawnDrops", v->firstRankPawnDrops); + parse_attribute("promotionZonePawnDrops", v->promotionZonePawnDrops); + parse_attribute("dropOnTop", v->dropOnTop); + parse_attribute("whiteDropRegion", v->whiteDropRegion); + parse_attribute("blackDropRegion", v->blackDropRegion); + parse_attribute("sittuyinRookDrop", v->sittuyinRookDrop); + parse_attribute("dropOppositeColoredBishop", v->dropOppositeColoredBishop); + parse_attribute("dropPromoted", v->dropPromoted); + parse_attribute("shogiDoubledPawn", v->shogiDoubledPawn); + parse_attribute("immobilityIllegal", v->immobilityIllegal); + parse_attribute("gating", v->gating); + parse_attribute("seirawanGating", v->seirawanGating); + parse_attribute("cambodianMoves", v->cambodianMoves); + parse_attribute("flyingGeneral", v->flyingGeneral); + parse_attribute("xiangqiSoldier", v->xiangqiSoldier); + // game end + parse_attribute("nMoveRule", v->nMoveRule); + parse_attribute("nFoldRule", v->nFoldRule); + parse_attribute("nFoldValue", v->nFoldValue); + parse_attribute("nFoldValueAbsolute", v->nFoldValueAbsolute); + parse_attribute("perpetualCheckIllegal", v->perpetualCheckIllegal); + parse_attribute("stalemateValue", v->stalemateValue); + parse_attribute("checkmateValue", v->checkmateValue); + parse_attribute("shogiPawnDropMateIllegal", v->shogiPawnDropMateIllegal); + parse_attribute("shatarMateRule", v->shatarMateRule); + parse_attribute("bareKingValue", v->bareKingValue); + parse_attribute("extinctionValue", v->extinctionValue); + parse_attribute("bareKingMove", v->bareKingMove); + // extinction piece types + const auto& it_ext = config.find("extinctionPieceTypes"); + if (it_ext != config.end()) + { + v->extinctionPieceTypes = {}; + char token; + size_t idx; + std::stringstream ss(it_ext->second); + while (ss >> token && ((idx = v->pieceToChar.find(toupper(token))) != std::string::npos || token == '*')) + v->extinctionPieceTypes.insert(PieceType(token == '*' ? 0 : idx)); + } + parse_attribute("flagPiece", v->flagPiece, v->pieceToChar); + parse_attribute("whiteFlag", v->whiteFlag); + parse_attribute("blackFlag", v->blackFlag); + parse_attribute("flagMove", v->flagMove); + parse_attribute("checkCounting", v->checkCounting); + parse_attribute("connectN", v->connectN); + parse_attribute("countingRule", v->countingRule); + return v; +} diff --cc src/parser.h index 310a81e,0000000..2e6c234 mode 100644,000000..100644 --- a/src/parser.h +++ b/src/parser.h @@@ -1,48 -1,0 +1,48 @@@ +/* + Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish - Copyright (C) 2018-2019 Fabian Fichter ++ Copyright (C) 2018-2020 Fabian Fichter + + Fairy-Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Fairy-Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PARSER_H_INCLUDED +#define PARSER_H_INCLUDED + +#include + +#include "variant.h" + +class Config : public std::map { +public: + Config::iterator find (const std::string& s) { + constexpr bool PrintOptions = false; // print config options? + if (PrintOptions) + std::cout << s << std::endl; + return std::map::find(s); + } +}; + +class VariantParser { +public: + VariantParser(const Config& c) : config (c) {}; + Variant* parse(); + Variant* parse(Variant* v); + +private: + Config config; + template void parse_attribute(const std::string& key, T& target); + void parse_attribute(const std::string& key, PieceType& target, std::string pieceToChar); +}; + +#endif // #ifndef PARSER_H_INCLUDED diff --cc src/partner.cpp index c1f533e,0000000..4eb3120 mode 100644,000000..100644 --- a/src/partner.cpp +++ b/src/partner.cpp @@@ -1,85 -1,0 +1,85 @@@ +/* + Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish - Copyright (C) 2018-2019 Fabian Fichter ++ Copyright (C) 2018-2020 Fabian Fichter + + Fairy-Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Fairy-Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include + +#include "partner.h" +#include "thread.h" +#include "uci.h" + +PartnerHandler Partner; // Global object + +void PartnerHandler::parse_partner(std::istringstream& is) { + std::string token; + if (is >> token) + sync_cout << "tellics ptell partner Fairy-Stockfish is an engine. Ask it 'help' for supported commands." << sync_endl; + else + isFairy = false; +} + +void PartnerHandler::parse_ptell(std::istringstream& is, const Position& pos) { + std::string token; + is >> token; + if (token == "partner") + { + if (is >> token && token == "Fairy-Stockfish") + isFairy = true; + } + else if (token == "help") + { + if (!(is >> token)) + sync_cout << "tellics ptell I listen to the commands help, sit, go, and move. Ptell 'help sit', etc. for details." << sync_endl; + else if (token == "sit") + sync_cout << "tellics ptell After receiving 'sit', I stop moving. Also see 'go'." << sync_endl; + else if (token == "go") + sync_cout << "tellics ptell After receiving 'go', I will no longer sit." << sync_endl; + else if (token == "move") + { + sync_cout << "tellics ptell After receiving 'move', I will move immediately." << sync_endl; + sync_cout << "tellics ptell If you specify a valid move, e.g., 'move e2e4', I will play it." << sync_endl; + } + } + else if (!pos.two_boards()) + return; + else if (token == "sit") + { + sitRequested = true; + sync_cout << "tellics ptell I sit, tell me 'go' to continue" << sync_endl; + } + else if (token == "go") + { + sitRequested = false; + Threads.stop = true; + } + else if (token == "move") + { + if (is >> token) + { + // if the given move is valid and we can still abort the search, play it + Move move = UCI::to_move(pos, token); + if (move && !Threads.abort.exchange(true)) + moveRequested = move; + else + sync_cout << "tellics ptell sorry, not possible" << sync_endl; + } + else + Threads.stop = true; + } +} diff --cc src/partner.h index def5797,0000000..1b378ad mode 100644,000000..100644 --- a/src/partner.h +++ b/src/partner.h @@@ -1,41 -1,0 +1,41 @@@ +/* + Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish - Copyright (C) 2018-2019 Fabian Fichter ++ Copyright (C) 2018-2020 Fabian Fichter + + Fairy-Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Fairy-Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PARTNER_H_INCLUDED +#define PARTNER_H_INCLUDED + +#include +#include + +#include "position.h" + +/// PartnerHandler manages the communication with the partner +/// in games played on two boards, such as bughouse. + +struct PartnerHandler { + void parse_partner(std::istringstream& is); + void parse_ptell(std::istringstream& is, const Position& pos); + + std::atomic isFairy; + std::atomic sitRequested; + Move moveRequested; +}; + +extern PartnerHandler Partner; + +#endif // #ifndef PARTNER_H_INCLUDED diff --cc src/piece.cpp index 3b9a789,0000000..82f938c mode 100644,000000..100644 --- a/src/piece.cpp +++ b/src/piece.cpp @@@ -1,392 -1,0 +1,392 @@@ +/* + Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish - Copyright (C) 2018-2019 Fabian Fichter ++ Copyright (C) 2018-2020 Fabian Fichter + + Fairy-Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Fairy-Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include + +#include "types.h" +#include "piece.h" + +PieceMap pieceMap; // Global object + +void PieceInfo::merge(const PieceInfo* pi) { + stepsQuiet.insert(stepsQuiet.end(), pi->stepsQuiet.begin(), pi->stepsQuiet.end()); + stepsCapture.insert(stepsCapture.end(), pi->stepsCapture.begin(), pi->stepsCapture.end()); + sliderQuiet.insert(sliderQuiet.end(), pi->sliderQuiet.begin(), pi->sliderQuiet.end()); + sliderCapture.insert(sliderCapture.end(), pi->sliderCapture.begin(), pi->sliderCapture.end()); +} + +namespace { + PieceInfo* pawn_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "pawn"; + p->betza = "fmWfceF"; + p->stepsQuiet = {NORTH}; + p->stepsCapture = {NORTH_WEST, NORTH_EAST}; + return p; + } + PieceInfo* knight_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "knight"; + p->betza = "N"; + p->stepsQuiet = {2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }; + p->stepsCapture = {2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }; + return p; + } + PieceInfo* bishop_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "bishop"; + p->betza = "B"; + p->sliderQuiet = {NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST}; + p->sliderCapture = {NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST}; + return p; + } + PieceInfo* rook_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "rook"; + p->betza = "R"; + p->sliderQuiet = {NORTH, EAST, SOUTH, WEST}; + p->sliderCapture = {NORTH, EAST, SOUTH, WEST}; + return p; + } + PieceInfo* queen_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "queen"; + p->betza = "RB"; + p->sliderQuiet = {NORTH, EAST, SOUTH, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST}; + p->sliderCapture = {NORTH, EAST, SOUTH, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST}; + return p; + } + PieceInfo* king_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "king"; + p->betza = "K"; + p->stepsQuiet = {SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST}; + p->stepsCapture = {SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST}; + return p; + } + PieceInfo* commoner_piece() { + PieceInfo* p = king_piece(); + p->name = "commoner"; + return p; + } + PieceInfo* fers_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "fers"; + p->betza = "F"; + p->stepsQuiet = {SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST}; + p->stepsCapture = {SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST}; + return p; + } + PieceInfo* wazir_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "wazir"; + p->betza = "W"; + p->stepsQuiet = {SOUTH, WEST, EAST, NORTH}; + p->stepsCapture = {SOUTH, WEST, EAST, NORTH}; + return p; + } + PieceInfo* alfil_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "alfil"; + p->betza = "A"; + p->stepsQuiet = {2 * SOUTH_WEST, 2 * SOUTH_EAST, 2 * NORTH_WEST, 2 * NORTH_EAST}; + p->stepsCapture = {2 * SOUTH_WEST, 2 * SOUTH_EAST, 2 * NORTH_WEST, 2 * NORTH_EAST}; + return p; + } + PieceInfo* fers_alfil_piece() { + PieceInfo* p = fers_piece(); + p->name = "fers_alfil"; + p->betza = "FA"; + PieceInfo* p2 = alfil_piece(); + p->merge(p2); + delete p2; + return p; + } + PieceInfo* silver_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "silver"; + p->betza = "FfW"; + p->stepsQuiet = {SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH, NORTH_EAST}; + p->stepsCapture = {SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH, NORTH_EAST}; + return p; + } + PieceInfo* aiwok_piece() { + PieceInfo* p = rook_piece(); + p->name = "aiwok"; + p->betza = "RNF"; + PieceInfo* p2 = knight_piece(); + PieceInfo* p3 = fers_piece(); + p->merge(p2); + p->merge(p3); + delete p2; + delete p3; + return p; + } + PieceInfo* bers_piece() { + PieceInfo* p = rook_piece(); + p->name = "bers"; + p->betza = "RF"; + PieceInfo* p2 = fers_piece(); + p->merge(p2); + delete p2; + return p; + } + PieceInfo* archbishop_piece() { + PieceInfo* p = bishop_piece(); + p->name = "archbishop"; + p->betza = "BN"; + PieceInfo* p2 = knight_piece(); + p->merge(p2); + delete p2; + return p; + } + PieceInfo* chancellor_piece() { + PieceInfo* p = rook_piece(); + p->name = "chancellor"; + p->betza = "RN"; + PieceInfo* p2 = knight_piece(); + p->merge(p2); + delete p2; + return p; + } + PieceInfo* amazon_piece() { + PieceInfo* p = queen_piece(); + p->name = "amazon"; + p->betza = "RBN"; + PieceInfo* p2 = knight_piece(); + p->merge(p2); + delete p2; + return p; + } + PieceInfo* knibis_piece() { + PieceInfo* p = bishop_piece(); + p->name = "knibis"; + p->betza = "mNcB"; + PieceInfo* p2 = knight_piece(); + p->merge(p2); + delete p2; + p->stepsCapture = {}; + p->sliderQuiet = {}; + return p; + } + PieceInfo* biskni_piece() { + PieceInfo* p = bishop_piece(); + p->name = "biskni"; + p->betza = "mBcN"; + PieceInfo* p2 = knight_piece(); + p->merge(p2); + delete p2; + p->stepsQuiet = {}; + p->sliderCapture = {}; + return p; + } + PieceInfo* kniroo_piece() { + PieceInfo* p = rook_piece(); + p->name = "kniroo"; + p->betza = "mNcR"; + PieceInfo* p2 = knight_piece(); + p->merge(p2); + delete p2; + p->stepsCapture = {}; + p->sliderQuiet = {}; + return p; + } + PieceInfo* rookni_piece() { + PieceInfo* p = rook_piece(); + p->name = "rookni"; + p->betza = "mRcN"; + PieceInfo* p2 = knight_piece(); + p->merge(p2); + delete p2; + p->stepsQuiet = {}; + p->sliderCapture = {}; + return p; + } + PieceInfo* shogi_pawn_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "shogi_pawn"; + p->betza = "fW"; + p->stepsQuiet = {NORTH}; + p->stepsCapture = {NORTH}; + return p; + } + PieceInfo* lance_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "lance"; + p->betza = "fR"; + p->sliderQuiet = {NORTH}; + p->sliderCapture = {NORTH}; + return p; + } + PieceInfo* shogi_knight_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "shogi_knight"; + p->betza = "fN"; + p->stepsQuiet = {2 * NORTH + WEST, 2 * NORTH + EAST}; + p->stepsCapture = {2 * NORTH + WEST, 2 * NORTH + EAST}; + return p; + } + PieceInfo* euroshogi_knight_piece() { + PieceInfo* p = shogi_knight_piece(); + p->name = "euroshogi_knight"; + p->betza = "fNsW"; + p->stepsQuiet.push_back(WEST); + p->stepsQuiet.push_back(EAST); + p->stepsCapture.push_back(WEST); + p->stepsCapture.push_back(EAST); + return p; + } + PieceInfo* gold_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "gold"; + p->betza = "WfF"; + p->stepsQuiet = {SOUTH, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST}; + p->stepsCapture = {SOUTH, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST}; + return p; + } + PieceInfo* dragon_horse_piece() { + PieceInfo* p = bishop_piece(); + p->name = "dragon_horse"; + p->betza = "BW"; + PieceInfo* p2 = wazir_piece(); + p->merge(p2); + delete p2; + return p; + } + PieceInfo* clobber_piece() { + PieceInfo* p = wazir_piece(); + p->name = "clobber"; + p->betza = "cW"; + p->stepsQuiet = {}; + return p; + } + PieceInfo* breakthrough_piece() { + PieceInfo* p = pawn_piece(); + p->name = "breakthrough"; + p->betza = "fWfFcF"; + p->stepsQuiet.push_back(NORTH_WEST); + p->stepsQuiet.push_back(NORTH_EAST); + return p; + } + PieceInfo* immobile_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "immobile"; + return p; + } + PieceInfo* cannon_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "cannon"; + p->betza = "mRcpR"; + p->sliderQuiet = {NORTH, EAST, SOUTH, WEST}; + p->hopperCapture = {NORTH, EAST, SOUTH, WEST}; + return p; + } + PieceInfo* soldier_piece() { + PieceInfo* p = new PieceInfo(); + p->name = "soldier"; + p->betza = "fsW"; + p->stepsQuiet = {NORTH, WEST, EAST}; + p->stepsCapture = {NORTH, WEST, EAST}; + return p; + } + PieceInfo* horse_piece() { + PieceInfo* p = knight_piece(); + p->name = "horse"; + p->betza = "nN"; + p->lameLeaper = true; + return p; + } + PieceInfo* elephant_piece() { + PieceInfo* p = alfil_piece(); + p->name = "elephant"; + p->betza = "nA"; + p->lameLeaper = true; + return p; + } + PieceInfo* banner_piece() { + PieceInfo* p = rook_piece(); + p->name = "banner"; + p->betza = "RcpRnN"; + PieceInfo* p2 = horse_piece(); + p->merge(p2); + delete p2; + p->hopperCapture = {NORTH, EAST, SOUTH, WEST}; + p->lameLeaper = true; + return p; + } + PieceInfo* centaur_piece() { + PieceInfo* p = commoner_piece(); + p->name = "centaur"; + p->betza = "KN"; + PieceInfo* p2 = knight_piece(); + p->merge(p2); + delete p2; + return p; + } +} + +void PieceMap::init() { + add(PAWN, pawn_piece()); + add(KNIGHT, knight_piece()); + add(BISHOP, bishop_piece()); + add(ROOK, rook_piece()); + 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()); + add(ARCHBISHOP, archbishop_piece()); + add(CHANCELLOR, chancellor_piece()); + add(AMAZON, amazon_piece()); + add(KNIBIS, knibis_piece()); + add(BISKNI, biskni_piece()); + add(KNIROO, kniroo_piece()); + add(ROOKNI, rookni_piece()); + add(SHOGI_PAWN, shogi_pawn_piece()); + add(LANCE, lance_piece()); + add(SHOGI_KNIGHT, shogi_knight_piece()); + add(EUROSHOGI_KNIGHT, euroshogi_knight_piece()); + add(GOLD, gold_piece()); + add(DRAGON_HORSE, dragon_horse_piece()); + add(CLOBBER_PIECE, clobber_piece()); + add(BREAKTHROUGH_PIECE, breakthrough_piece()); + add(IMMOBILE_PIECE, immobile_piece()); + add(CANNON, cannon_piece()); + add(SOLDIER, soldier_piece()); + add(HORSE, horse_piece()); + add(ELEPHANT, elephant_piece()); + add(BANNER, banner_piece()); + add(WAZIR, wazir_piece()); + add(COMMONER, commoner_piece()); + add(CENTAUR, centaur_piece()); + add(KING, king_piece()); +} + +void PieceMap::add(PieceType pt, const PieceInfo* p) { + insert(std::pair(pt, p)); +} + +void PieceMap::clear_all() { + for (auto const& element : *this) + delete element.second; + clear(); +} diff --cc src/piece.h index 70df241,0000000..c93e1d5 mode 100644,000000..100644 --- a/src/piece.h +++ b/src/piece.h @@@ -1,53 -1,0 +1,53 @@@ +/* + Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish - Copyright (C) 2018-2019 Fabian Fichter ++ Copyright (C) 2018-2020 Fabian Fichter + + Fairy-Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Fairy-Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef PIECE_H_INCLUDED +#define PIECE_H_INCLUDED + +#include +#include +#include + +#include "types.h" + + +/// PieceInfo struct stores information about the piece movements. + +struct PieceInfo { + std::string name = ""; + std::string betza = ""; + std::vector stepsQuiet = {}; + std::vector stepsCapture = {}; + std::vector sliderQuiet = {}; + std::vector sliderCapture = {}; + std::vector hopperQuiet = {}; + std::vector hopperCapture = {}; + bool lameLeaper = false; + + void merge(const PieceInfo* pi); +}; + +struct PieceMap : public std::map { + void init(); + void add(PieceType pt, const PieceInfo* v); + void clear_all(); +}; + +extern PieceMap pieceMap; + +#endif // #ifndef PIECE_H_INCLUDED diff --cc src/position.cpp index b33a787,53d9b64..ac581e4 --- a/src/position.cpp +++ b/src/position.cpp @@@ -1289,11 -817,8 +1289,8 @@@ void Position::do_move(Move m, StateInf st->nonPawnMaterial[us] += PieceValue[MG][promotion]; } - // Update pawn hash key and prefetch access to pawnsTable - if (type_of(m) == DROP) - st->pawnKey ^= Zobrist::psq[pc][to]; - else - st->pawnKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to]; + // Update pawn hash key - st->pawnKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to]; ++ st->pawnKey ^= (type_of(m) != DROP ? Zobrist::psq[pc][from] : 0) ^ Zobrist::psq[pc][to]; // Reset rule 50 draw counter st->rule50 = 0; @@@ -1666,21 -1027,12 +1663,21 @@@ bool Position::see_ge(Move m, Value thr if (swap <= 0) return true; - Bitboard occ = (type_of(m) != DROP ? pieces() ^ from : pieces()) ^ to; - Bitboard occupied = pieces() ^ from ^ to; - Color stm = color_of(piece_on(from)); ++ Bitboard occupied = (type_of(m) != DROP ? pieces() ^ from : pieces()) ^ to; + Color stm = color_of(moved_piece(m)); - Bitboard attackers = attackers_to(to, occ); + Bitboard attackers = attackers_to(to, occupied); Bitboard stmAttackers, bb; int res = 1; + // Flying general rule + if (var->flyingGeneral) + { + if (attackers & pieces(stm, KING)) - attackers |= attacks_bb(stm, ROOK, to, occ & ~pieces(ROOK)) & pieces(~stm, KING); ++ attackers |= attacks_bb(stm, ROOK, to, occupied & ~pieces(ROOK)) & pieces(~stm, KING); + if (attackers & pieces(~stm, KING)) - attackers |= attacks_bb(~stm, ROOK, to, occ & ~pieces(ROOK)) & pieces(stm, KING); ++ attackers |= attacks_bb(~stm, ROOK, to, occupied & ~pieces(ROOK)) & pieces(stm, KING); + } + while (true) { stm = ~stm; @@@ -1742,185 -1094,32 +1739,185 @@@ if ((swap = QueenValueMg - swap) < res) break; - occ ^= lsb(bb); - attackers |= (attacks_bb(to, occ) & pieces(BISHOP, QUEEN)) - | (attacks_bb(to, occ) & pieces(ROOK , QUEEN)); + occupied ^= lsb(bb); + attackers |= (attacks_bb(to, occupied) & pieces(BISHOP, QUEEN)) + | (attacks_bb(to, occupied) & pieces(ROOK , QUEEN)); } + // fairy pieces + // pick next piece without considering value + else if ((bb = stmAttackers & ~pieces(KING))) + { + if ((swap = PieceValue[MG][piece_on(lsb(bb))] - swap) < res) + break; + - occ ^= lsb(bb); ++ occupied ^= lsb(bb); + } + else // KING // If we "capture" with the king but opponent still has attackers, // reverse the result. return (attackers & ~pieces(stm)) ? res ^ 1 : res; } - return res; + return bool(res); } -/// Position::is_draw() tests whether the position is drawn by 50-move rule -/// or by repetition. It does not detect stalemates. +/// Position::is_optinal_game_end() tests whether the position may end the game by +/// 50-move rule, by repetition, or a variant rule that allows a player to claim a game result. + +bool Position::is_optional_game_end(Value& result, int ply) const { + + // n-move rule + if (n_move_rule() && st->rule50 > (2 * n_move_rule() - 1) && (!checkers() || MoveList(*this).size())) + { + result = VALUE_DRAW; + return true; + } + + // n-fold repetition + if (n_fold_rule()) + { + int end = captures_to_hand() ? st->pliesFromNull : std::min(st->rule50, st->pliesFromNull); + + if (end >= 4) + { + StateInfo* stp = st->previous->previous; + int cnt = 0; + bool perpetualThem = st->checkersBB && stp->checkersBB; + bool perpetualUs = st->previous->checkersBB && stp->previous->checkersBB; + + for (int i = 4; i <= end; i += 2) + { + stp = stp->previous->previous; + perpetualThem &= bool(stp->checkersBB); + + // Return a draw score if a position repeats once earlier but strictly + // after the root, or repeats twice before or at the root. + if ( stp->key == st->key + && ++cnt + 1 == (ply > i ? 2 : n_fold_rule())) + { + result = convert_mate_value( var->perpetualCheckIllegal && perpetualThem ? VALUE_MATE + : var->perpetualCheckIllegal && perpetualUs ? -VALUE_MATE + : var->nFoldValueAbsolute && sideToMove == BLACK ? -var->nFoldValue + : var->nFoldValue, ply); + return true; + } -bool Position::is_draw(int ply) const { + if (i + 1 <= end) + perpetualUs &= bool(stp->previous->checkersBB); + } + } + } - if (st->rule50 > 99 && (!checkers() || MoveList(*this).size())) + // counting rules + if ( counting_rule() + && st->countingLimit + && st->countingPly >= st->countingLimit + && (!checkers() || MoveList(*this).size())) + { + result = VALUE_DRAW; return true; + } - // Return a draw score if a position repeats once earlier but strictly - // after the root, or repeats twice before or at the root. - if (st->repetition && st->repetition < ply) + // sittuyin stalemate due to optional promotion (3.9 c.7) + if ( sittuyin_promotion() + && count(sideToMove) == 2 + && count(sideToMove) == 1 + && !checkers()) + { + bool promotionsOnly = true; + for (const auto& m : MoveList(*this)) + if (type_of(m) != PROMOTION) + { + promotionsOnly = false; + break; + } + if (promotionsOnly) + { + result = VALUE_DRAW; + return true; + } + } + + return false; +} + +/// Position::is_immediate_game_end() tests whether the position ends the game +/// immediately by a variant rule, i.e., there are no more legal moves. +/// It does not not detect stalemates. + +bool Position::is_immediate_game_end(Value& result, int ply) const { + + // bare king rule + if ( bare_king_value() != VALUE_NONE + && !bare_king_move() + && !(count(sideToMove) - count(sideToMove))) + { + result = bare_king_value(ply); + return true; + } + if ( bare_king_value() != VALUE_NONE + && bare_king_move() + && !(count(~sideToMove) - count(~sideToMove))) + { + result = -bare_king_value(ply); + return true; + } + // extinction + if (extinction_value() != VALUE_NONE) + { + for (PieceType pt : extinction_piece_types()) + if (!count(WHITE, pt) || !count(BLACK, pt)) + { + result = !count(sideToMove, pt) ? extinction_value(ply) : -extinction_value(ply); + return true; + } + } + // capture the flag + if ( capture_the_flag_piece() + && !flag_move() + && (capture_the_flag(~sideToMove) & pieces(~sideToMove, capture_the_flag_piece()))) + { + result = mated_in(ply); + return true; + } + if ( capture_the_flag_piece() + && flag_move() + && (capture_the_flag(sideToMove) & pieces(sideToMove, capture_the_flag_piece()))) + { + result = (capture_the_flag(~sideToMove) & pieces(~sideToMove, capture_the_flag_piece())) + && sideToMove == WHITE ? VALUE_DRAW : mate_in(ply); + return true; + } + // nCheck + if (check_counting() && checks_remaining(~sideToMove) == 0) + { + result = mated_in(ply); + return true; + } + // Connect-n + if (connect_n() > 0) + { + Bitboard b; + for (Direction d : {NORTH, NORTH_EAST, EAST, SOUTH_EAST}) + { + b = pieces(~sideToMove); + for (int i = 1; i < connect_n() && b; i++) + b &= shift(d, b); + if (b) + { + result = mated_in(ply); + return true; + } + } + } + // Tsume mode: Assume that side with king wins when not in check + if (!count(~sideToMove) && count(sideToMove) && !checkers() && Options["TsumeMode"]) + { + result = mate_in(ply); return true; + } return false; } diff --cc src/position.h index f900a34,6791455..7aeb414 --- a/src/position.h +++ b/src/position.h @@@ -45,14 -43,9 +45,13 @@@ struct StateInfo int castlingRights; int rule50; int pliesFromNull; + int countingPly; + int countingLimit; + CheckCount checksRemaining[COLOR_NB]; Square epSquare; + Bitboard gatesBB[COLOR_NB]; // Not copied when making a move (will be recomputed anyhow) - int repetition; Key key; Bitboard checkersBB; Piece capturedPiece; @@@ -61,8 -53,7 +60,9 @@@ Bitboard blockersForKing[COLOR_NB]; Bitboard pinners[COLOR_NB]; Bitboard checkSquares[PIECE_TYPE_NB]; + bool capturedpromoted; + bool shak; + int repetition; }; /// A list to keep track of the position states along the setup moves (from the diff --cc src/search.cpp index c68080d,0eea412..759036c --- a/src/search.cpp +++ b/src/search.cpp @@@ -575,9 -560,15 +580,15 @@@ void Thread::search() // keep pondering until the GUI sends "ponderhit" or "stop". if (mainThread->ponder) mainThread->stopOnPonderhit = true; - else + else if (!(rootPos.two_boards() && (Partner.sitRequested || bestValue <= VALUE_MATED_IN_MAX_PLY))) Threads.stop = true; } + else if ( Threads.increaseDepth + && !mainThread->ponder + && Time.elapsed() > Time.optimum() * fallingEval * reduction * bestMoveInstability * 0.6) + Threads.increaseDepth = false; + else + Threads.increaseDepth = true; } mainThread->iterValue[iterIdx] = bestValue; @@@ -830,43 -819,31 +843,43 @@@ namespace tte->save(posKey, VALUE_NONE, ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval); } - // Step 7. Razoring (~2 Elo) + // Step 7. Razoring (~1 Elo) if ( !rootNode // The required rootNode PV handling is not available in qsearch && depth < 2 + && !pos.must_capture() + && !pos.capture_the_flag_piece() + && !pos.check_counting() && eval <= alpha - RazorMargin) return qsearch(pos, ss, alpha, beta); improving = (ss-2)->staticEval == VALUE_NONE ? (ss->staticEval >= (ss-4)->staticEval || (ss-4)->staticEval == VALUE_NONE) : ss->staticEval >= (ss-2)->staticEval; + // Skip early pruning in case of mandatory capture + if (pos.must_capture() && MoveList(pos).size()) + goto moves_loop; + - // Step 8. Futility pruning: child node (~30 Elo) + // Step 8. Futility pruning: child node (~50 Elo) if ( !PvNode && depth < 6 - && eval - futility_margin(depth, improving) >= beta + && !( pos.extinction_value() == -VALUE_MATE + && pos.extinction_piece_types().find(ALL_PIECES) == pos.extinction_piece_types().end()) + && (pos.checking_permitted() || !pos.capture_the_flag_piece()) + && eval - futility_margin(depth, improving) * (1 + pos.check_counting()) >= beta && eval < VALUE_KNOWN_WIN) // Do not return unproven wins return eval; // Step 9. Null move search with verification search (~40 Elo) if ( !PvNode && (ss-1)->currentMove != MOVE_NULL - && (ss-1)->statScore < 23405 + && (ss-1)->statScore < 23397 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 32 * depth + 317 - improving * 30 + && ss->staticEval >= beta - 32 * depth + 292 - improving * 30 && !excludedMove && pos.non_pawn_material(us) + && (pos.pieces(~us) ^ pos.pieces(~us, PAWN)) + && (pos.pieces() ^ pos.pieces(BREAKTHROUGH_PIECE) ^ pos.pieces(CLOBBER_PIECE)) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) { assert(eval - beta >= 0); @@@ -952,10 -928,10 +965,10 @@@ } } - // Step 11. Internal iterative deepening (~2 Elo) + // Step 11. Internal iterative deepening (~1 Elo) - if (depth >= 7 && !ttMove) + if (depth >= (7 - 2 * pos.captures_to_hand()) && !ttMove) { - search(pos, ss, alpha, beta, depth - 7, cutNode); + search(pos, ss, alpha, beta, depth - (7 - 2 * pos.captures_to_hand()), cutNode); tte = TT.probe(posKey, ttHit); ttValue = ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE; @@@ -1017,9 -993,9 +1030,9 @@@ moves_loop: // When in check, search st // Calculate new depth for this move newDepth = depth - 1; - // Step 13. Pruning at shallow depth (~170 Elo) + // Step 13. Pruning at shallow depth (~200 Elo) if ( !rootNode - && pos.non_pawn_material(us) + && (pos.non_pawn_material(us) || !(pos.pieces(us) ^ pos.pieces(us, PAWN))) && bestValue > VALUE_MATED_IN_MAX_PLY) { // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold @@@ -1035,24 -1009,25 +1048,28 @@@ // Countermoves based pruning (~20 Elo) if ( lmrDepth < 4 + ((ss-1)->statScore > 0 || (ss-1)->moveCount == 1) - && (*contHist[0])[movedPiece][to_sq(move)] < CounterMovePruneThreshold - && (*contHist[1])[movedPiece][to_sq(move)] < CounterMovePruneThreshold) + && (*contHist[0])[history_slot(movedPiece)][to_sq(move)] < CounterMovePruneThreshold + && (*contHist[1])[history_slot(movedPiece)][to_sq(move)] < CounterMovePruneThreshold) continue; - // Futility pruning: parent node (~2 Elo) + // Futility pruning: parent node (~5 Elo) if ( lmrDepth < 6 && !inCheck + && !( pos.extinction_value() == -VALUE_MATE + && pos.extinction_piece_types().find(ALL_PIECES) == pos.extinction_piece_types().end()) - && ss->staticEval + 255 + 182 * lmrDepth <= alpha) + && ss->staticEval + 235 + 172 * lmrDepth <= alpha + && thisThread->mainHistory[us][from_to(move)] - + (*contHist[0])[movedPiece][to_sq(move)] - + (*contHist[1])[movedPiece][to_sq(move)] - + (*contHist[3])[movedPiece][to_sq(move)] < 25000) ++ + (*contHist[0])[history_slot(movedPiece)][to_sq(move)] ++ + (*contHist[1])[history_slot(movedPiece)][to_sq(move)] ++ + (*contHist[3])[history_slot(movedPiece)][to_sq(move)] < 25000) continue; - // Prune moves with negative SEE (~10 Elo) + // Prune moves with negative SEE (~20 Elo) - if (!pos.see_ge(move, Value(-(32 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) + if (!pos.must_capture() && !pos.see_ge(move, Value(-(32 - std::min(lmrDepth, 18)) * lmrDepth * lmrDepth))) continue; } - else if (!pos.see_ge(move, Value(-194) * depth)) // (~25 Elo) + else if ( !pos.must_capture() - && !pos.see_ge(move, Value(-194 - 120 * pos.captures_to_hand()) * depth)) // (~20 Elo) ++ && !pos.see_ge(move, Value(-194 - 120 * pos.captures_to_hand()) * depth)) // (~25 Elo) continue; } @@@ -1177,9 -1145,9 +1194,9 @@@ if (singularLMR) r -= 2; - if (!captureOrPromotion) + if (!captureOrPromotion && !(pos.must_capture() && MoveList(pos).size())) { - // Increase reduction if ttMove is a capture (~0 Elo) + // Increase reduction if ttMove is a capture (~5 Elo) if (ttCapture) r++; diff --cc src/syzygy/tbprobe.cpp index d617a13,721a0ef..90c53aa --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@@ -683,8 -682,8 +683,8 @@@ Ret do_probe_table(const Position& pos // flip the squares before to lookup. bool blackStronger = (pos.material_key() != entry->key); - int flipColor = (symmetricBlackToMove || blackStronger) * 8; + int flipColor = (symmetricBlackToMove || blackStronger) * PIECE_TYPE_NB; - int flipSquares = (symmetricBlackToMove || blackStronger) * 070; + int flipSquares = (symmetricBlackToMove || blackStronger) * 56; int stm = (symmetricBlackToMove || blackStronger) ^ pos.side_to_move(); // For pawns, TB files store 4 separate tables according if leading pawn is on diff --cc src/thread.cpp index 88437f6,615d482..c4dfaeb --- a/src/thread.cpp +++ b/src/thread.cpp @@@ -178,7 -178,8 +178,8 @@@ void ThreadPool::start_thinking(Positio main()->wait_for_search_finished(); - main()->stopOnPonderhit = stop = false; + main()->stopOnPonderhit = stop = abort = false; + increaseDepth = true; main()->ponder = ponderMode; Search::Limits = limits; Search::RootMoves rootMoves; diff --cc src/thread.h index 876336b,aea86fd..a7d9f57 --- a/src/thread.h +++ b/src/thread.h @@@ -110,13 -109,11 +110,12 @@@ struct ThreadPool : public std::vector< uint64_t nodes_searched() const { return accumulate(&Thread::nodes); } uint64_t tb_hits() const { return accumulate(&Thread::tbHits); } - std::atomic_bool stop; - std::atomic_bool abort; - std::atomic_bool sit; + std::atomic_bool stop, increaseDepth; ++ std::atomic_bool abort, sit; -private: StateListPtr setupStates; +private: uint64_t accumulate(std::atomic Thread::* member) const { uint64_t sum = 0; diff --cc src/uci.cpp index 4d78d41,8b35e6f..2b4054f --- a/src/uci.cpp +++ b/src/uci.cpp @@@ -276,11 -235,11 +276,12 @@@ void UCI::loop(int argc, char* argv[]) // Additional custom non-UCI commands, mainly for debugging. // Do not use these commands during a search! - else if (token == "flip") pos.flip(); - else if (token == "bench") bench(pos, is, states); - else if (token == "d") sync_cout << pos << sync_endl; - else if (token == "eval") sync_cout << Eval::trace(pos) << sync_endl; - else if (token == "load") { load(is); argc = 1; } // continue reading stdin + else if (token == "flip") pos.flip(); + else if (token == "bench") bench(pos, is, states); + else if (token == "d") sync_cout << pos << sync_endl; + else if (token == "eval") sync_cout << Eval::trace(pos) << sync_endl; + else if (token == "compiler") sync_cout << compiler_info() << sync_endl; ++ else if (token == "load") { load(is); argc = 1; } // continue reading stdin else sync_cout << "Unknown command: " << cmd << sync_endl; diff --cc src/variant.cpp index 960ee4e,0000000..f5e39d0 mode 100644,000000..100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@@ -1,964 -1,0 +1,964 @@@ +/* + Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish - Copyright (C) 2018-2019 Fabian Fichter ++ Copyright (C) 2018-2020 Fabian Fichter + + Fairy-Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Fairy-Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include + +#include "parser.h" +#include "piece.h" +#include "variant.h" + +using std::string; + +VariantMap variants; // Global object + +namespace { + // Define variant rules + Variant* fairy_variant_base() { + Variant* v = new Variant(); + v->pieceToCharTable = "PNBRQ................Kpnbrq................k"; + v->endgameEval = false; + return v; + } + Variant* chess_variant() { + Variant* v = fairy_variant_base(); + v->endgameEval = true; + return v; + } + Variant* chess960_variant() { + Variant* v = chess_variant(); + v->chess960 = true; + return v; + } + Variant* nocastle_variant() { + Variant* v = chess_variant(); + v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w - - 0 1"; + v->castling = false; + return v; + } + Variant* fairy_variant() { + Variant* v = chess_variant(); + v->add_piece(SILVER, 's'); + v->add_piece(FERS, 'f'); + return v; + } + Variant* makruk_variant() { + Variant* v = chess_variant(); + v->variantTemplate = "makruk"; + v->pieceToCharTable = "PN.R.M....SKpn.r.m....sk"; + v->remove_piece(BISHOP); + v->remove_piece(QUEEN); + v->add_piece(KHON, 's'); + v->add_piece(MET, 'm'); + v->startFen = "rnsmksnr/8/pppppppp/8/8/PPPPPPPP/8/RNSKMSNR w - - 0 1"; + v->promotionRank = RANK_6; + v->promotionPieceTypes = {MET}; + v->doubleStep = false; + v->castling = false; + v->nMoveRule = 0; + v->countingRule = MAKRUK_COUNTING; + return v; + } + Variant* cambodian_variant() { + Variant* v = makruk_variant(); + v->startFen = "rnsmksnr/8/pppppppp/8/8/PPPPPPPP/8/RNSKMSNR w DEde - 0 1"; + v->gating = true; + v->cambodianMoves = true; + return v; + } + Variant* karouk_variant() { + Variant* v = cambodian_variant(); + v->checkCounting = true; + return v; + } + Variant* asean_variant() { + Variant* v = chess_variant(); + v->remove_piece(BISHOP); + v->remove_piece(QUEEN); + v->add_piece(KHON, 'b'); + v->add_piece(MET, 'q'); + v->startFen = "rnbqkbnr/8/pppppppp/8/8/PPPPPPPP/8/RNBQKBNR w - - 0 1"; + v->promotionPieceTypes = {ROOK, KNIGHT, KHON, MET}; + v->doubleStep = false; + v->castling = false; + v->countingRule = ASEAN_COUNTING; + return v; + } + Variant* aiwok_variant() { + Variant* v = makruk_variant(); + v->pieceToCharTable = "PN.R...A..SKpn.r...a..sk"; + v->remove_piece(MET); + v->add_piece(AIWOK, 'a'); + v->startFen = "rnsaksnr/8/pppppppp/8/8/PPPPPPPP/8/RNSKASNR w - - 0 1"; + v->promotionPieceTypes = {AIWOK}; + return v; + } + Variant* shatranj_variant() { + Variant* v = fairy_variant_base(); + v->variantTemplate = "shatranj"; + v->remove_piece(BISHOP); + v->remove_piece(QUEEN); + v->add_piece(ALFIL, 'b'); + v->add_piece(FERS, 'q'); + v->startFen = "rnbkqbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBKQBNR w - - 0 1"; + v->promotionPieceTypes = {FERS}; + v->doubleStep = false; + v->castling = false; + v->bareKingValue = -VALUE_MATE; + v->bareKingMove = true; + v->stalemateValue = -VALUE_MATE; + v->nMoveRule = 70; + return v; + } + Variant* amazon_variant() { + Variant* v = chess_variant(); + v->pieceToCharTable = "PNBR..............AKpnbr..............ak"; + v->remove_piece(QUEEN); + v->add_piece(AMAZON, 'a'); + v->startFen = "rnbakbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBAKBNR w KQkq - 0 1"; + v->promotionPieceTypes = {AMAZON, ROOK, BISHOP, KNIGHT}; + return v; + } + Variant* hoppelpoppel_variant() { + Variant* v = chess_variant(); + v->remove_piece(KNIGHT); + v->remove_piece(BISHOP); + v->add_piece(KNIBIS, 'n'); + v->add_piece(BISKNI, 'b'); + v->promotionPieceTypes = {QUEEN, ROOK, BISKNI, KNIBIS}; + return v; + } + Variant* newzealand_variant() { + Variant* v = chess_variant(); + v->remove_piece(ROOK); + v->remove_piece(KNIGHT); + v->add_piece(ROOKNI, 'r'); + v->add_piece(KNIROO, 'n'); + v->castlingRookPiece = ROOKNI; + v->promotionPieceTypes = {QUEEN, ROOKNI, BISHOP, KNIROO}; + return v; + } + Variant* kingofthehill_variant() { + Variant* v = fairy_variant_base(); + v->flagPiece = KING; + v->whiteFlag = make_bitboard(SQ_D4, SQ_E4, SQ_D5, SQ_E5); + v->blackFlag = make_bitboard(SQ_D4, SQ_E4, SQ_D5, SQ_E5); + v->flagMove = false; + return v; + } + Variant* racingkings_variant() { + Variant* v = fairy_variant_base(); + v->startFen = "8/8/8/8/8/8/krbnNBRK/qrbnNBRQ w - - 0 1"; + v->flagPiece = KING; + v->whiteFlag = Rank8BB; + v->blackFlag = Rank8BB; + v->flagMove = true; + v->castling = false; + v->checking = false; + return v; + } + Variant* knightmate_variant() { + Variant* v = fairy_variant_base(); + v->add_piece(COMMONER, 'm'); + v->remove_piece(KNIGHT); + v->startFen = "rmbqkbmr/pppppppp/8/8/8/8/PPPPPPPP/RMBQKBMR w KQkq - 0 1"; + v->kingType = KNIGHT; + v->promotionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP}; + return v; + } + Variant* losers_variant() { + Variant* v = fairy_variant_base(); + v->checkmateValue = VALUE_MATE; + v->stalemateValue = VALUE_MATE; + v->bareKingValue = VALUE_MATE; + v->bareKingMove = false; + v->mustCapture = true; + return v; + } + Variant* giveaway_variant() { + Variant* v = fairy_variant_base(); + v->variantTemplate = "giveaway"; + v->remove_piece(KING); + v->add_piece(COMMONER, 'k'); + v->promotionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT}; + v->stalemateValue = VALUE_MATE; + v->extinctionValue = VALUE_MATE; + v->extinctionPieceTypes = {ALL_PIECES}; + v->mustCapture = true; + return v; + } + Variant* antichess_variant() { + Variant* v = giveaway_variant(); + v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w - - 0 1"; + v->castling = false; + return v; + } + Variant* suicide_variant() { + Variant* v = antichess_variant(); + v->stalematePieceCount = true; + return v; + } + Variant* codrus_variant() { + Variant* v = giveaway_variant(); + v->promotionPieceTypes = {QUEEN, ROOK, BISHOP, KNIGHT}; + v->extinctionPieceTypes = {COMMONER}; + return v; + } + Variant* extinction_variant() { + Variant* v = fairy_variant_base(); + v->remove_piece(KING); + v->add_piece(COMMONER, 'k'); + v->promotionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT}; + v->extinctionValue = -VALUE_MATE; + v->extinctionPieceTypes = {COMMONER, QUEEN, ROOK, BISHOP, KNIGHT, PAWN}; + return v; + } + Variant* kinglet_variant() { + Variant* v = extinction_variant(); + v->promotionPieceTypes = {COMMONER}; + v->extinctionPieceTypes = {PAWN}; + return v; + } + Variant* horde_variant() { + Variant* v = fairy_variant_base(); + v->startFen = "rnbqkbnr/pppppppp/8/1PP2PP1/PPPPPPPP/PPPPPPPP/PPPPPPPP/PPPPPPPP w kq - 0 1"; + v->firstRankDoubleSteps = true; + v->extinctionValue = -VALUE_MATE; + v->extinctionPieceTypes = {ALL_PIECES}; + return v; + } + Variant* threecheck_variant() { + Variant* v = fairy_variant_base(); + v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 3+3 0 1"; + v->checkCounting = true; + return v; + } + Variant* fivecheck_variant() { + Variant* v = threecheck_variant(); + v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 5+5 0 1"; + return v; + } + Variant* crazyhouse_variant() { + Variant* v = fairy_variant_base(); + v->variantTemplate = "crazyhouse"; + v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR[] w KQkq - 0 1"; + v->pieceDrops = true; + v->capturesToHand = true; + return v; + } + Variant* loop_variant() { + Variant* v = crazyhouse_variant(); + v->dropLoop = true; + return v; + } + Variant* chessgi_variant() { + Variant* v = loop_variant(); + v->firstRankPawnDrops = true; + return v; + } + Variant* bughouse_variant() { + Variant* v = crazyhouse_variant(); + v->variantTemplate = "bughouse"; + v->twoBoards = true; + v->capturesToHand = false; + return v; + } + Variant* pocketknight_variant() { + Variant* v = chess_variant(); + v->variantTemplate = "bughouse"; + v->pocketSize = 2; + v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR[Nn] w KQkq - 0 1"; + v->pieceDrops = true; + v->capturesToHand = false; + return v; + } + Variant* placement_variant() { + Variant* v = chess_variant(); + v->variantTemplate = "bughouse"; + v->startFen = "8/pppppppp/8/8/8/8/PPPPPPPP/8[KQRRBBNNkqrrbbnn] w - - 0 1"; + v->mustDrop = true; + v->pieceDrops = true; + v->capturesToHand = false; + v->whiteDropRegion = Rank1BB; + v->blackDropRegion = Rank8BB; + v->dropOppositeColoredBishop = true; + v->castlingDroppedPiece = true; + return v; + } + Variant* sittuyin_variant() { + Variant* v = makruk_variant(); + v->variantTemplate = "bughouse"; + v->pieceToCharTable = "PN.R.F....SKpn.r.f....sk"; + v->startFen = "8/8/4pppp/pppp4/4PPPP/PPPP4/8/8[KFRRSSNNkfrrssnn] w - - 0 1"; + v->remove_piece(MET); + v->add_piece(MET, 'f'); + v->mustDrop = true; + v->pieceDrops = true; + v->capturesToHand = false; + v->whiteDropRegion = Rank1BB | Rank2BB | Rank3BB; + v->blackDropRegion = Rank8BB | Rank7BB | Rank6BB; + v->sittuyinRookDrop = true; + v->promotionRank = RANK_1; // no regular promotions + v->sittuyinPromotion = true; + v->promotionLimit[FERS] = 1; + v->immobilityIllegal = false; + v->countingRule = ASEAN_COUNTING; + v->nMoveRule = 50; + return v; + } + Variant* seirawan_variant() { + Variant* v = chess_variant(); + v->variantTemplate = "seirawan"; + v->pieceToCharTable = "PNBRQ.E..........H...Kpnbrq.e..........h...k"; + v->add_piece(ARCHBISHOP, 'h'); + v->add_piece(CHANCELLOR, 'e'); + v->startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR[HEhe] w KQBCDFGkqbcdfg - 0 1"; + v->gating = true; + v->seirawanGating = true; + v->promotionPieceTypes = {ARCHBISHOP, CHANCELLOR, QUEEN, ROOK, BISHOP, KNIGHT}; + return v; + } + Variant* shouse_variant() { + Variant* v = seirawan_variant(); + v->variantTemplate = "crazyhouse"; + v->pieceDrops = true; + v->capturesToHand = true; + return v; + } + Variant* minishogi_variant_base() { + Variant* v = fairy_variant_base(); + v->variantTemplate = "shogi"; + v->maxRank = RANK_5; + v->maxFile = FILE_E; + v->reset_pieces(); + v->add_piece(SHOGI_PAWN, 'p'); + v->add_piece(SILVER, 's'); + v->add_piece(GOLD, 'g'); + v->add_piece(BISHOP, 'b'); + v->add_piece(DRAGON_HORSE, 'h'); + v->add_piece(ROOK, 'r'); + v->add_piece(DRAGON, 'd'); + v->add_piece(KING, 'k'); + v->startFen = "rbsgk/4p/5/P4/KGSBR[-] w 0 1"; + v->pieceDrops = true; + v->capturesToHand = true; + v->promotionRank = RANK_5; + v->promotionPieceTypes = {}; + v->doubleStep = false; + v->castling = false; + v->promotedPieceType[SHOGI_PAWN] = GOLD; + v->promotedPieceType[SILVER] = GOLD; + v->promotedPieceType[BISHOP] = DRAGON_HORSE; + v->promotedPieceType[ROOK] = DRAGON; + v->shogiDoubledPawn = false; + v->immobilityIllegal = true; + v->shogiPawnDropMateIllegal = true; + v->stalemateValue = -VALUE_MATE; + v->nFoldRule = 4; + v->nMoveRule = 0; + v->perpetualCheckIllegal = true; + return v; + } + Variant* minishogi_variant() { + Variant* v = minishogi_variant_base(); + v->pieceToCharTable = "P.BR.S...G.+.++.+Kp.br.s...g.+.++.+k"; + v->pocketSize = 5; + v->nFoldValue = -VALUE_MATE; + v->nFoldValueAbsolute = true; + return v; + } + Variant* kyotoshogi_variant() { + Variant* v = minishogi_variant_base(); + v->add_piece(LANCE, 'l'); + v->add_piece(SHOGI_KNIGHT, 'n'); + v->startFen = "p+nks+l/5/5/5/+LSK+NP[-] w 0 1"; + v->promotionRank = RANK_1; + v->mandatoryPiecePromotion = true; + v->pieceDemotion = true; + v->dropPromoted = true; + v->promotedPieceType[LANCE] = GOLD; + v->promotedPieceType[SILVER] = BISHOP; + v->promotedPieceType[SHOGI_KNIGHT] = GOLD; + v->promotedPieceType[SHOGI_PAWN] = ROOK; + v->promotedPieceType[GOLD] = NO_PIECE_TYPE; + v->promotedPieceType[BISHOP] = NO_PIECE_TYPE; + v->promotedPieceType[ROOK] = NO_PIECE_TYPE; + v->immobilityIllegal = false; + v->shogiPawnDropMateIllegal = false; + v->shogiDoubledPawn = true; + return v; + } + Variant* microshogi_variant() { + Variant* v = kyotoshogi_variant(); + v->maxFile = FILE_D; + v->startFen = "kb+r+l/p3/4/3P/+L+RBK[-] w 0 1"; + v->promotionRank = RANK_1; + v->piecePromotionOnCapture = true; + v->promotedPieceType[LANCE] = SILVER; + v->promotedPieceType[BISHOP] = GOLD; + v->promotedPieceType[ROOK] = GOLD; + v->promotedPieceType[SHOGI_PAWN] = SHOGI_KNIGHT; + v->promotedPieceType[SILVER] = NO_PIECE_TYPE; + v->promotedPieceType[GOLD] = NO_PIECE_TYPE; + v->promotedPieceType[SHOGI_KNIGHT] = NO_PIECE_TYPE; + return v; + } + Variant* dobutsu_variant() { + Variant* v = minishogi_variant_base(); + v->pieceToCharTable = "C....E...G.+.....Lc....e...g.+.....l"; + v->pocketSize = 3; + v->maxRank = RANK_4; + v->maxFile = FILE_C; + v->reset_pieces(); + v->add_piece(SHOGI_PAWN, 'c'); + v->add_piece(GOLD, 'h'); + v->add_piece(FERS, 'e'); + v->add_piece(WAZIR, 'g'); + v->add_piece(KING, 'l'); + v->startFen = "gle/1c1/1C1/ELG[-] w 0 1"; + v->promotionRank = RANK_4; + v->immobilityIllegal = false; + v->shogiPawnDropMateIllegal = false; + v->flagPiece = KING; + v->whiteFlag = Rank4BB; + v->blackFlag = Rank1BB; + v->shogiDoubledPawn = true; + return v; + } + Variant* gorogoroshogi_variant() { + Variant* v = minishogi_variant_base(); + v->pieceToCharTable = "P....S...G.+....+Kp....s...g.+....+k"; + v->pocketSize = 3; + v->maxRank = RANK_6; + v->maxFile = FILE_E; + v->startFen = "sgkgs/5/1ppp1/1PPP1/5/SGKGS[-] w 0 1"; + v->promotionRank = RANK_5; + return v; + } + Variant* judkinsshogi_variant() { + Variant* v = minishogi_variant_base(); + v->pieceToCharTable = "PNBR.S...G.++++.+Kpnbr.s...g.++++.+k"; + v->maxRank = RANK_6; + v->maxFile = FILE_F; + v->add_piece(SHOGI_KNIGHT, 'n'); + v->startFen = "rbnsgk/5p/6/6/P5/KGSNBR[-] w 0 1"; + v->promotionRank = RANK_5; + v->promotedPieceType[SHOGI_KNIGHT] = GOLD; + return v; + } + Variant* euroshogi_variant() { + Variant* v = minishogi_variant_base(); + v->pieceToCharTable = "PNBR.....G.++++Kpnbr.....g.++++k"; + v->maxRank = RANK_8; + v->maxFile = FILE_H; + v->add_piece(EUROSHOGI_KNIGHT, 'n'); + v->startFen = "1nbgkgn1/1r4b1/pppppppp/8/8/PPPPPPPP/1B4R1/1NGKGBN1[-] w 0 1"; + v->promotionRank = RANK_6; + v->promotedPieceType[EUROSHOGI_KNIGHT] = GOLD; + v->mandatoryPiecePromotion = true; + return v; + } + Variant* losalamos_variant() { + Variant* v = fairy_variant_base(); + v->pieceToCharTable = "PN.RQ................Kpn.rq................k"; + v->maxRank = RANK_6; + v->maxFile = FILE_F; + v->remove_piece(BISHOP); + v->startFen = "rnqknr/pppppp/6/6/PPPPPP/RNQKNR w - - 0 1"; + v->promotionRank = RANK_6; + v->promotionPieceTypes = {QUEEN, ROOK, KNIGHT}; + v->doubleStep = false; + v->castling = false; + return v; + } + Variant* gardner_variant() { + Variant* v = fairy_variant_base(); + v->maxRank = RANK_5; + v->maxFile = FILE_E; + v->startFen = "rnbqk/ppppp/5/PPPPP/RNBQK w - - 0 1"; + v->promotionRank = RANK_5; + v->doubleStep = false; + v->castling = false; + return v; + } + Variant* almost_variant() { + Variant* v = chess_variant(); + v->pieceToCharTable = "PNBR............CKpnbr............ck"; + v->remove_piece(QUEEN); + v->add_piece(CHANCELLOR, 'c'); + v->startFen = "rnbckbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBCKBNR w KQkq - 0 1"; + v->promotionPieceTypes = {CHANCELLOR, ROOK, BISHOP, KNIGHT}; + return v; + } + Variant* chigorin_variant() { + Variant* v = chess_variant(); + v->pieceToCharTable = "PNBR............CKpnbrq............k"; + v->add_piece(CHANCELLOR, 'c'); + v->startFen = "rbbqkbbr/pppppppp/8/8/8/8/PPPPPPPP/RNNCKNNR w KQkq - 0 1"; + v->promotionPieceTypes = {QUEEN, CHANCELLOR, ROOK, BISHOP, KNIGHT}; + return v; + } + Variant* shatar_variant() { + Variant* v = chess_variant(); + v->pieceToCharTable = "PNBR..........J......Kpnbr..........j......k"; + v->remove_piece(QUEEN); + v->add_piece(BERS, 'j'); + v->startFen = "rnbjkbnr/ppp1pppp/8/3p4/3P4/8/PPP1PPPP/RNBJKBNR w - - 0 1"; + v->promotionPieceTypes = {BERS}; + v->doubleStep = false; + v->castling = false; + v->bareKingValue = VALUE_DRAW; // Robado + v->shatarMateRule = true; + return v; + } + Variant* clobber_variant() { + Variant* v = fairy_variant_base(); + v->pieceToCharTable = "P.................p................."; + v->maxRank = RANK_6; + v->maxFile = FILE_E; + v->reset_pieces(); + v->add_piece(CLOBBER_PIECE, 'p'); + v->startFen = "PpPpP/pPpPp/PpPpP/pPpPp/PpPpP/pPpPp w 0 1"; + v->promotionPieceTypes = {}; + v->doubleStep = false; + v->castling = false; + v->stalemateValue = -VALUE_MATE; + v->immobilityIllegal = false; + return v; + } + Variant* breakthrough_variant() { + Variant* v = fairy_variant_base(); + v->pieceToCharTable = "P.................p................."; + v->reset_pieces(); + v->add_piece(BREAKTHROUGH_PIECE, 'p'); + v->startFen = "pppppppp/pppppppp/8/8/8/8/PPPPPPPP/PPPPPPPP w 0 1"; + v->promotionPieceTypes = {}; + v->firstRankDoubleSteps = false; + v->castling = false; + v->stalemateValue = -VALUE_MATE; + v->flagPiece = BREAKTHROUGH_PIECE; + v->whiteFlag = Rank8BB; + v->blackFlag = Rank1BB; + return v; + } + Variant* minixiangqi_variant() { + Variant* v = fairy_variant_base(); + v->variantTemplate = "xiangqi"; + v->pieceToCharTable = "PN.R.....K.C.pn.r.....k.c."; + v->maxRank = RANK_7; + v->maxFile = FILE_G; + v->reset_pieces(); + v->add_piece(ROOK, 'r'); + v->add_piece(HORSE, 'n', 'h'); + v->add_piece(KING, 'k'); + v->add_piece(CANNON, 'c'); + v->add_piece(SOLDIER, 'p'); + v->startFen = "rcnkncr/p1ppp1p/7/7/7/P1PPP1P/RCNKNCR w - - 0 1"; + Bitboard white_castle = make_bitboard(SQ_C1, SQ_D1, SQ_E1, + SQ_C2, SQ_D2, SQ_E2, + SQ_C3, SQ_D3, SQ_E3); + Bitboard black_castle = make_bitboard(SQ_C5, SQ_D5, SQ_E5, + SQ_C6, SQ_D6, SQ_E6, + SQ_C7, SQ_D7, SQ_E7); + v->mobilityRegion[WHITE][KING] = white_castle; + v->mobilityRegion[BLACK][KING] = black_castle; + v->kingType = WAZIR; + v->promotionPieceTypes = {}; + v->doubleStep = false; + v->castling = false; + v->stalemateValue = -VALUE_MATE; + //v->nFoldValue = VALUE_MATE; + v->perpetualCheckIllegal = true; + v->flyingGeneral = true; + return v; + } +#ifdef LARGEBOARDS + Variant* shogi_variant() { + Variant* v = minishogi_variant_base(); + v->maxRank = RANK_9; + v->maxFile = FILE_I; + v->add_piece(LANCE, 'l'); + v->add_piece(SHOGI_KNIGHT, 'n'); + v->startFen = "lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL[-] w 0 1"; + v->promotionRank = RANK_7; + v->promotedPieceType[LANCE] = GOLD; + v->promotedPieceType[SHOGI_KNIGHT] = GOLD; + return v; + } + Variant* capablanca_variant() { + Variant* v = chess_variant(); + v->pieceToCharTable = "PNBRQ..AC............Kpnbrq..ac............k"; + v->maxRank = RANK_8; + v->maxFile = FILE_J; + v->castlingKingsideFile = FILE_I; + v->castlingQueensideFile = FILE_C; + v->add_piece(ARCHBISHOP, 'a'); + v->add_piece(CHANCELLOR, 'c'); + v->startFen = "rnabqkbcnr/pppppppppp/10/10/10/10/PPPPPPPPPP/RNABQKBCNR w KQkq - 0 1"; + v->promotionPieceTypes = {ARCHBISHOP, CHANCELLOR, QUEEN, ROOK, BISHOP, KNIGHT}; + return v; + } + Variant* capahouse_variant() { + Variant* v = capablanca_variant(); + v->startFen = "rnabqkbcnr/pppppppppp/10/10/10/10/PPPPPPPPPP/RNABQKBCNR[] w KQkq - 0 1"; + v->pieceDrops = true; + v->capturesToHand = true; + v->endgameEval = false; + return v; + } + Variant* caparandom_variant() { + Variant* v = capablanca_variant(); + v->chess960 = true; + return v; + } + Variant* gothic_variant() { + Variant* v = capablanca_variant(); + v->startFen = "rnbqckabnr/pppppppppp/10/10/10/10/PPPPPPPPPP/RNBQCKABNR w KQkq - 0 1"; + return v; + } + Variant* janus_variant() { + Variant* v = chess_variant(); + v->pieceToCharTable = "PNBRQ............J...Kpnbrq............J...k"; + v->maxRank = RANK_8; + v->maxFile = FILE_J; + v->castlingKingsideFile = FILE_I; + v->castlingQueensideFile = FILE_B; + v->add_piece(ARCHBISHOP, 'j'); + v->startFen = "rjnbkqbnjr/pppppppppp/10/10/10/10/PPPPPPPPPP/RJNBKQBNJR w KQkq - 0 1"; + v->promotionPieceTypes = {ARCHBISHOP, QUEEN, ROOK, BISHOP, KNIGHT}; + return v; + } + Variant* modern_variant() { + Variant* v = chess_variant(); + v->pieceToCharTable = "PNBRQ..M.............Kpnbrq..m.............k"; + v->maxRank = RANK_9; + v->maxFile = FILE_I; + v->promotionRank = RANK_9; + v->castlingKingsideFile = FILE_G; + v->castlingQueensideFile = FILE_C; + v->add_piece(ARCHBISHOP, 'm'); + v->startFen = "rnbqkmbnr/ppppppppp/9/9/9/9/9/PPPPPPPPP/RNBMKQBNR w KQkq - 0 1"; + v->promotionPieceTypes = {ARCHBISHOP, QUEEN, ROOK, BISHOP, KNIGHT}; + return v; + } + Variant* chancellor_variant() { + Variant* v = chess_variant(); + v->pieceToCharTable = "PNBRQ...........CKpnbrq...........ck"; + v->maxRank = RANK_9; + v->maxFile = FILE_I; + v->promotionRank = RANK_9; + v->castlingKingsideFile = FILE_G; + v->castlingQueensideFile = FILE_C; + v->add_piece(CHANCELLOR, 'c'); + v->startFen = "rnbqkcnbr/ppppppppp/9/9/9/9/9/PPPPPPPPP/RNBQKCNBR w KQkq - 0 1"; + v->promotionPieceTypes = {CHANCELLOR, QUEEN, ROOK, BISHOP, KNIGHT}; + return v; + } + Variant* embassy_variant() { + Variant* v = capablanca_variant(); + v->castlingKingsideFile = FILE_H; + v->castlingQueensideFile = FILE_B; + v->startFen = "rnbqkcabnr/pppppppppp/10/10/10/10/PPPPPPPPPP/RNBQKCABNR w KQkq - 0 1"; + return v; + } + Variant* centaur_variant() { + Variant* v = chess_variant(); + v->pieceToCharTable = "PNBRQ...............CKpnbrq...............ck"; + v->maxRank = RANK_8; + v->maxFile = FILE_J; + v->castlingKingsideFile = FILE_I; + v->castlingQueensideFile = FILE_C; + v->add_piece(CENTAUR, 'c'); + v->startFen = "rcnbqkbncr/pppppppppp/10/10/10/10/PPPPPPPPPP/RCNBQKBNCR w KQkq - 0 1"; + v->promotionPieceTypes = {CENTAUR, QUEEN, ROOK, BISHOP, KNIGHT}; + return v; + } + Variant* jesonmor_variant() { + Variant* v = fairy_variant_base(); + v->maxRank = RANK_9; + v->maxFile = FILE_I; + v->reset_pieces(); + v->add_piece(KNIGHT, 'n'); + v->startFen = "nnnnnnnnn/9/9/9/9/9/9/9/NNNNNNNNN w - - 0 1"; + v->promotionPieceTypes = {}; + v->doubleStep = false; + v->castling = false; + v->stalemateValue = -VALUE_MATE; + v->flagPiece = KNIGHT; + v->whiteFlag = make_bitboard(SQ_E5); + v->blackFlag = make_bitboard(SQ_E5); + v->flagMove = true; + return v; + } + Variant* courier_variant() { + Variant* v = fairy_variant_base(); + v->maxRank = RANK_8; + v->maxFile = FILE_L; + v->remove_piece(QUEEN); + v->add_piece(ALFIL, 'e'); + v->add_piece(FERS, 'f'); + v->add_piece(COMMONER, 'm'); + v->add_piece(WAZIR, 'w'); + v->startFen = "rnebmk1wbenr/1ppppp1pppp1/6f5/p5p4p/P5P4P/6F5/1PPPPP1PPPP1/RNEBMK1WBENR w - - 0 1"; + v->promotionPieceTypes = {FERS}; + v->doubleStep = false; + v->castling = false; + v->bareKingValue = -VALUE_MATE; + v->bareKingMove = true; + v->stalemateValue = -VALUE_MATE; + return v; + } + Variant* grand_variant() { + Variant* v = fairy_variant_base(); + v->maxRank = RANK_10; + v->maxFile = FILE_J; + v->add_piece(ARCHBISHOP, 'a'); + v->add_piece(CHANCELLOR, 'c'); + v->startFen = "r8r/1nbqkcabn1/pppppppppp/10/10/10/10/PPPPPPPPPP/1NBQKCABN1/R8R w - - 0 1"; + v->promotionPieceTypes = {ARCHBISHOP, CHANCELLOR, QUEEN, ROOK, BISHOP, KNIGHT}; + v->promotionRank = RANK_8; + v->promotionLimit[ARCHBISHOP] = 1; + v->promotionLimit[CHANCELLOR] = 1; + v->promotionLimit[QUEEN] = 1; + v->promotionLimit[ROOK] = 2; + v->promotionLimit[BISHOP] = 2; + v->promotionLimit[KNIGHT] = 2; + v->mandatoryPawnPromotion = false; + v->immobilityIllegal = true; + v->doubleStepRank = RANK_3; + v->castling = false; + return v; + } + Variant* shako_variant() { + Variant* v = fairy_variant_base(); + v->pieceToCharTable = "PNBRQ.E....C.........Kpnbrq.e....c.........k"; + 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; + v->maxFile = FILE_J; + v->startFen = "PpPpPpPpPp/pPpPpPpPpP/PpPpPpPpPp/pPpPpPpPpP/PpPpPpPpPp/" + "pPpPpPpPpP/PpPpPpPpPp/pPpPpPpPpP/PpPpPpPpPp/pPpPpPpPpP w 0 1"; + return v; + } + Variant* xiangqi_variant() { + Variant* v = minixiangqi_variant(); + v->pieceToCharTable = "PN.R.AB..K.C..........pn.r.ab..k.c.........."; + v->maxRank = RANK_10; + v->maxFile = FILE_I; + v->add_piece(ELEPHANT, 'b', 'e'); + v->add_piece(FERS, 'a'); + v->startFen = "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - - 0 1"; + Bitboard white_castle = make_bitboard(SQ_D1, SQ_E1, SQ_F1, + SQ_D2, SQ_E2, SQ_F2, + SQ_D3, SQ_E3, SQ_F3); + Bitboard black_castle = make_bitboard(SQ_D8, SQ_E8, SQ_F8, + SQ_D9, SQ_E9, SQ_F9, + SQ_D10, SQ_E10, SQ_F10); + v->mobilityRegion[WHITE][KING] = white_castle; + v->mobilityRegion[BLACK][KING] = black_castle; + v->mobilityRegion[WHITE][FERS] = white_castle; + v->mobilityRegion[BLACK][FERS] = black_castle; + v->mobilityRegion[WHITE][ELEPHANT] = Rank1BB | Rank2BB | Rank3BB | Rank4BB | Rank5BB; + v->mobilityRegion[BLACK][ELEPHANT] = Rank6BB | Rank7BB | Rank8BB | Rank9BB | Rank10BB; + v->xiangqiSoldier = true; + return v; + } + // Manchu/Yitong chess + // https://en.wikipedia.org/wiki/Manchu_chess + Variant* manchu_variant() { + Variant* v = xiangqi_variant(); + v->pieceToCharTable = "PN.R.AB..K.C....M.....pn.r.ab..k.c.........."; + v->add_piece(BANNER, 'm'); + v->startFen = "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/9/9/M1BAKAB2 w - - 0 1"; + return v; + } + // Supply chess + // https://en.wikipedia.org/wiki/Xiangqi#Variations + Variant* supply_variant() { + Variant* v = xiangqi_variant(); + v->variantTemplate = "bughouse"; + v->startFen = "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR[] w - - 0 1"; + v->twoBoards = true; + v->pieceDrops = true; + v->dropChecks = false; + v->whiteDropRegion = v->mobilityRegion[WHITE][ELEPHANT]; + v->blackDropRegion = v->mobilityRegion[BLACK][ELEPHANT]; + return v; + } +#endif + +} // namespace + + +/// VariantMap::init() is called at startup to initialize all predefined variants + +void VariantMap::init() { + // Add to UCI_Variant option + add("chess", chess_variant()); + add("normal", chess_variant()); + add("fischerandom", chess960_variant()); + add("nocastle", nocastle_variant()); + add("fairy", fairy_variant()); // fairy variant used for endgame code initialization + add("makruk", makruk_variant()); + add("cambodian", cambodian_variant()); + add("karouk", karouk_variant()); + add("asean", asean_variant()); + add("ai-wok", aiwok_variant()); + add("shatranj", shatranj_variant()); + add("amazon", amazon_variant()); + add("hoppelpoppel", hoppelpoppel_variant()); + add("newzealand", newzealand_variant()); + add("kingofthehill", kingofthehill_variant()); + add("racingkings", racingkings_variant()); + add("knightmate", knightmate_variant()); + add("losers", losers_variant()); + add("giveaway", giveaway_variant()); + add("antichess", antichess_variant()); + add("suicide", suicide_variant()); + add("codrus", codrus_variant()); + add("extinction", extinction_variant()); + add("kinglet", kinglet_variant()); + add("horde", horde_variant()); + add("3check", threecheck_variant()); + add("5check", fivecheck_variant()); + add("crazyhouse", crazyhouse_variant()); + add("loop", loop_variant()); + add("chessgi", chessgi_variant()); + add("bughouse", bughouse_variant()); + add("pocketknight", pocketknight_variant()); + add("placement", placement_variant()); + add("sittuyin", sittuyin_variant()); + add("seirawan", seirawan_variant()); + add("shouse", shouse_variant()); + add("minishogi", minishogi_variant()); + add("mini", minishogi_variant()); + add("kyotoshogi", kyotoshogi_variant()); + add("micro", microshogi_variant()); + add("dobutsu", dobutsu_variant()); + add("gorogoro", gorogoroshogi_variant()); + add("judkins", judkinsshogi_variant()); + add("euroshogi", euroshogi_variant()); + add("losalamos", losalamos_variant()); + add("gardner", gardner_variant()); + add("almost", almost_variant()); + add("chigorin", chigorin_variant()); + add("shatar", shatar_variant()); + add("clobber", clobber_variant()); + add("breakthrough", breakthrough_variant()); + add("minixiangqi", minixiangqi_variant()); +#ifdef LARGEBOARDS + add("shogi", shogi_variant()); + add("capablanca", capablanca_variant()); + add("capahouse", capahouse_variant()); + add("caparandom", caparandom_variant()); + add("gothic", gothic_variant()); + add("janus", janus_variant()); + add("modern", modern_variant()); + add("chancellor", chancellor_variant()); + add("embassy", embassy_variant()); + add("centaur", centaur_variant()); + add("jesonmor", jesonmor_variant()); + add("courier", courier_variant()); + add("grand", grand_variant()); + add("shako", shako_variant()); + add("clobber10", clobber10_variant()); + add("xiangqi", xiangqi_variant()); + add("manchu", manchu_variant()); + add("supply", supply_variant()); +#endif +} + + +/// VariantMap::parse reads variants from an INI-style configuration file. + +void VariantMap::parse(std::string path) { + if (path.empty() || path == "") + return; + std::ifstream file(path); + if (!file.is_open()) + { + std::cerr << "Unable to open file " << path << std::endl; + return; + } + std::string variant, variant_template, key, value, input; + while (file.peek() != '[' && std::getline(file, input)) {} + + while (file.get() && std::getline(std::getline(file, variant, ']'), input)) + { + // Extract variant template, if specified + if (!std::getline(std::getline(std::stringstream(variant), variant, ':'), variant_template)) + variant_template = ""; + + // Read variant rules + Config attribs = {}; + while (file.peek() != '[' && std::getline(file, input)) + { + std::stringstream ss(input); + if (ss.peek() != '#' && std::getline(std::getline(ss, key, '=') >> std::ws, value) && !key.empty()) + attribs[key.erase(key.find_last_not_of(" ") + 1)] = value; + } + + // Create variant + if (variants.find(variant) != variants.end()) + std::cerr << "Variant '" << variant << "' already exists." << std::endl; + else if (!variant_template.empty() && variants.find(variant_template) == variants.end()) + std::cerr << "Variant template '" << variant_template << "' does not exist." << std::endl; + else + { + Variant* v = !variant_template.empty() ? VariantParser(attribs).parse(new Variant(*variants.find(variant_template)->second)) + : VariantParser(attribs).parse(); + if (v->maxFile <= FILE_MAX && v->maxRank <= RANK_MAX) + add(variant, v); + else + delete v; + } + } + file.close(); +} + +void VariantMap::add(std::string s, const Variant* v) { + insert(std::pair(s, v)); +} + +void VariantMap::clear_all() { + for (auto const& element : *this) + delete element.second; + clear(); +} + +std::vector VariantMap::get_keys() { + std::vector keys; + for (auto const& element : *this) + keys.push_back(element.first); + return keys; +} diff --cc src/variant.h index fc5d370,0000000..6464d3f mode 100644,000000..100644 --- a/src/variant.h +++ b/src/variant.h @@@ -1,149 -1,0 +1,149 @@@ +/* + Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish - Copyright (C) 2018-2019 Fabian Fichter ++ Copyright (C) 2018-2020 Fabian Fichter + + Fairy-Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Fairy-Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef VARIANT_H_INCLUDED +#define VARIANT_H_INCLUDED + +#include +#include +#include +#include +#include + +#include "types.h" +#include "bitboard.h" + + +/// Variant struct stores information needed to determine the rules of a variant. + +struct Variant { + std::string variantTemplate = "fairy"; + std::string pieceToCharTable = "-"; + int pocketSize = 0; + Rank maxRank = RANK_8; + File maxFile = FILE_H; + bool chess960 = false; + bool twoBoards = false; + std::set pieceTypes = { PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING }; + std::string pieceToChar = " PNBRQ" + std::string(KING - QUEEN - 1, ' ') + "K" + std::string(PIECE_TYPE_NB - KING - 1, ' ') + + " pnbrq" + std::string(KING - QUEEN - 1, ' ') + "k" + std::string(PIECE_TYPE_NB - KING - 1, ' '); + std::string pieceToCharSynonyms = std::string(PIECE_NB, ' '); + std::string startFen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; + Bitboard mobilityRegion[COLOR_NB][PIECE_TYPE_NB] = {}; + Rank promotionRank = RANK_8; + std::set > promotionPieceTypes = { QUEEN, ROOK, BISHOP, KNIGHT }; + bool sittuyinPromotion = false; + int promotionLimit[PIECE_TYPE_NB] = {}; // 0 means unlimited + PieceType promotedPieceType[PIECE_TYPE_NB] = {}; + bool piecePromotionOnCapture = false; + bool mandatoryPawnPromotion = true; + bool mandatoryPiecePromotion = false; + 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; + PieceType castlingRookPiece = ROOK; + PieceType kingType = KING; + bool checking = true; + bool dropChecks = true; + bool mustCapture = false; + bool mustDrop = false; + bool pieceDrops = false; + bool dropLoop = false; + bool capturesToHand = false; + bool firstRankPawnDrops = false; + bool promotionZonePawnDrops = false; + bool dropOnTop = false; + Bitboard whiteDropRegion = AllSquares; + Bitboard blackDropRegion = AllSquares; + bool sittuyinRookDrop = false; + bool dropOppositeColoredBishop = false; + bool dropPromoted = false; + bool shogiDoubledPawn = true; + bool immobilityIllegal = false; + bool gating = false; + bool seirawanGating = false; + bool cambodianMoves = false; + bool flyingGeneral = false; + bool xiangqiSoldier = false; + // game end + int nMoveRule = 50; + int nFoldRule = 3; + Value nFoldValue = VALUE_DRAW; + bool nFoldValueAbsolute = false; + bool perpetualCheckIllegal = false; + Value stalemateValue = VALUE_DRAW; + bool stalematePieceCount = false; // multiply stalemate value by sign(count(~stm) - count(stm)) + Value checkmateValue = -VALUE_MATE; + bool shogiPawnDropMateIllegal = false; + bool shatarMateRule = false; + Value bareKingValue = VALUE_NONE; + Value extinctionValue = VALUE_NONE; + bool bareKingMove = false; + std::set extinctionPieceTypes = {}; + PieceType flagPiece = NO_PIECE_TYPE; + Bitboard whiteFlag = 0; + Bitboard blackFlag = 0; + bool flagMove = false; + bool checkCounting = false; + int connectN = 0; + CountingRule countingRule = NO_COUNTING; + + void add_piece(PieceType pt, char c, char c2 = ' ') { + pieceToChar[make_piece(WHITE, pt)] = toupper(c); + pieceToChar[make_piece(BLACK, pt)] = tolower(c); + pieceToCharSynonyms[make_piece(WHITE, pt)] = toupper(c2); + pieceToCharSynonyms[make_piece(BLACK, pt)] = tolower(c2); + pieceTypes.insert(pt); + } + + void remove_piece(PieceType pt) { + pieceToChar[make_piece(WHITE, pt)] = ' '; + pieceToChar[make_piece(BLACK, pt)] = ' '; + pieceToCharSynonyms[make_piece(WHITE, pt)] = ' '; + pieceToCharSynonyms[make_piece(BLACK, pt)] = ' '; + pieceTypes.erase(pt); + } + + void reset_pieces() { + pieceToChar = std::string(PIECE_NB, ' '); + pieceToCharSynonyms = std::string(PIECE_NB, ' '); + pieceTypes.clear(); + } +}; + +class VariantMap : public std::map { +public: + void init(); + void parse(std::string path); + void clear_all(); + std::vector get_keys(); + +private: + void add(std::string s, const Variant* v); +}; + +extern VariantMap variants; + +#endif // #ifndef VARIANT_H_INCLUDED diff --cc src/variants.ini index 13d790c,0000000..fbc7c2b mode 100644,000000..100644 --- a/src/variants.ini +++ b/src/variants.ini @@@ -1,302 -1,0 +1,302 @@@ +# Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish - # Copyright (C) 2018-2019 Fabian Fichter ++# Copyright (C) 2018-2020 Fabian Fichter +# +# Fairy-Stockfish is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Fairy-Stockfish is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This is a configuration file to add user-defined variants to Fairy-Stockfish. + +################################################ +### Usage: +# Add "load" and the file path to the SF call (e.g., "./stockfish load variants.ini") +# or set the UCI option "VariantPath" to the path of this file in order to load it. + +################################################ +### Variant configuration: +# The variant name needs to be specified as a section in square brackets, +# followed by its rule configurations as key-value pairs as described below. +# If you encounter problems configuring variants, please report them at: +# https://github.com/ianfab/Fairy-Stockfish/issues + +### Inheritance +# If a variant is similar to a previously defined variant, +# inheritance can be used to simplify the definition. To inherit from the +# configuration of an existing variant, specify the parent variant after the child +# variant name separated by a colon, e.g., [gothic:capablanca]. +# When inheritance is used, only the differences to the parent variant need to be defined, +# see the examples in this file, e.g., 3check-crazyhouse. +# When no inheritance is used, the default template applies, +# which is basically standard chess but without any predefined pieces. + +### Piece types +# Firstly, the piece types for a variant need to be defined. +# For that, specify the letter used for each piece type, e.g.: +# pawn = p +# +# See the list below for all available piece types: +# pawn +# knight +# bishop +# rook +# queen +# fers +# alfil +# fers_alfil (=fers+alfil) +# silver +# aiwok (=rook+knight+fers) +# bers (=rook+fers) +# archbishop (=bishop+knight) +# chancellor (=rook+knight) +# amazon (=queen+knight) +# knibis +# biskni +# kniroo +# rookni +# shogi_pawn +# lance +# shogi_knight +# euroshogi_knight +# gold +# dragon_horse +# clobber +# breakthrough +# immobile (piece without moves) +# cannon +# soldier +# horse +# elephant +# banner (=rook+cannon+horse) +# wazir +# commoner (non-royal king) +# centaur (=knight+commoner) +# king + +### Option types +# [bool]: boolean flag to enable/disable a feature [true, false] +# [Rank]: denotes a rank of the board [1-10] +# [File]: denotes a file of the board [1-12, a-i] +# [int]: any natural number [0, 1, ...] +# [PieceType]: a piece type [letters defined for pieces, e.g., p] +# [Bitboard]: list of squares [e.g., d4 e4 d5 e5]. * can be used as wildcard for files (e.g., *1 is the first rank) +# [Value]: game result for the side to move [win, loss, draw] +# [CountingRule]: makruk or ASEAN counting rules [makruk, asean, none] + +### Rule definition options +# variantTemplate: only relevant for usage in XBoard/WinBoard GUI [values: fairy, shogi] (default: fairy) +# pieceToCharTable: mapping of piece characters to images for XBoard/WinBoard GUI (default: -) +# pocketSize: number of pockets shown by XBoard/WinBoard for drop variants [int] (default: 0) +# maxRank: maximum rank [Rank] (default: 8) +# maxFile: maximum file [File] (default: 8) +# chess960: allow chess960 castling [bool] (default: false) +# twoBoards: the game is influenced by a second board (e.g., bughouse) [bool] (default: false) +# startFen: FEN of starting position (default: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1) +# promotionRank: relative rank required to reach for promotion [Rank] (default: 8) +# promotionPieceTypes: pawn promotion options using their one-letter representations (default: nbrq) +# sittuyinPromotion: enable Sittuyin-style pawn promotion [bool] (default: false) +# promotionLimit: maximum number of pieces of a type, e.g., q:1 r:2 (default: ) +# promotedPieceType: mapping between unpromoted and promoted non-pawn piece types, e.g., p:g s:g (default: ) +# piecePromotionOnCapture: piece promotion only allowed on captures (e.g., micro shogi) [bool] (default: false) +# mandatoryPawnPromotion: pawn promotion is mandatory [bool] (default: true) +# mandatoryPiecePromotion: piece promotion (and demotion if enabled) is mandatory [bool] (default: false) +# pieceDemotion: enable demotion of pieces (e.g., Kyoto shogi) [bool] (default: false) +# endgameEval: enable special endgame evaluation (for very chess-like variants only) [bool] (default: false) +# doubleStep: enable pawn double step [bool] (default: true) +# doubleStepRank: relative rank from where pawn double steps are allowed [Rank] (default: 2) +# firstRankDoubleSteps: enable pawn double steps from first rank [bool] (default: false) +# castling: enable castling [bool] (default: true) +# castlingDroppedPiece: enable castling with dropped rooks/kings [bool] (default: false) +# castlingKingsideFile: destination file of king after kingside castling [File] (default: g) +# castlingQueensideFile: destination file of king after queenside castling [File] (default: c) +# castlingRank: relative rank of castling [Rank] (default: 1) +# castlingRookPiece: piece type that participates in castling [PieceType] (default: r) +# kingType: piece type defining moves of king/royal piece (default: k) +# checking: allow checks [bool] (default: true) +# dropChecks: allow checks by piece drops [bool] (default: true) +# mustCapture: captures are mandatory (check evasion still takes precedence) [bool] (default: false) +# mustDrop: drops are mandatory (e.g., for Sittuyin setup phase) [bool] (default: false) +# pieceDrops: enable piece drops [bool] (default: false) +# dropLoop: captures promoted pieces are not demoted [bool] (default: false) +# capturesToHand: captured pieces are go to opponent's hand [bool] (default: false) +# firstRankPawnDrops: allow pawn drops to first rank [bool] (default: false) +# promotionZonePawnDrops: allow pawn drops in promotion zone [bool] (default: false) +# dropOnTop: piece drops need to be on top of pieces on board (e.g., for connect4) [bool] (default: false) +# whiteDropRegion: restrict region for piece drops of all white pieces [Bitboard] +# blackDropRegion: restrict region for piece drops of all black pieces [Bitboard] +# sittuyinRookDrop: restrict region of rook drops to first rank [bool] (default: false) +# dropOppositeColoredBishop: dropped bishops have to be on opposite-colored squares [bool] (default: false) +# dropPromoted: pieces may be dropped in promoted state [bool] (default: false) +# shogiDoubledPawn: allow shogi pawns to be doubled [bool] (default: true) +# immobilityIllegal: pieces may not move to squares where they can never move from [bool] (default: false) +# gating: maintain squares on backrank with extra rights in castling field of FEN [bool] (default: false) +# seirawanGating: allow gating of pieces in hand like in S-Chess, requires "gating = true" [bool] (default: false) +# cambodianMoves: enable special moves of cambodian chess, requires "gating = true" [bool] (default: false) +# flyingGeneral: disallow general face-off like in xiangqi [bool] (default: false) +# xiangqiSoldier: restrict soldier to shogi pawn movements on first five ranks [bool] (default: false) +# nMoveRule: move count for 50/n-move rule [int] (default: 50) +# nFoldRule: move count for 3/n-fold repetition rule [int] (default: 3) +# nFoldValue: result in case of 3/n-fold repetition [Value] (default: draw) +# nFoldValueAbsolute: result in case of 3/n-fold repetition is from white's point of view [bool] (default: false) +# perpetualCheckIllegal: prohibit perpetual checks [bool] (default: false) +# stalemateValue: result in case of stalemate [Value] (default: draw) +# checkmateValue: result in case of checkmate [Value] (default: loss) +# shogiPawnDropMateIllegal: prohibit checkmate via shogi pawn drops [bool] (default: false) +# shatarMateRule: enable shatar mating rules [bool] (default: false) +# bareKingValue: result when player only has a lone/bare king [Value] (default: ) +# extinctionValue: result when one of extinctionPieceTypes is extinct [Value] (default: ) +# bareKingMove: allow additional move by opponent after lone/bare king position [bool] (default: false) +# extinctionPieceTypes: list of piece types for extinction rules, e.g., pnbrq (* means all) (default: ) +# flagPiece: piece type for capture the flag win rule [PieceType] (default: ) +# whiteFlag: white's target region for capture the flag win rule [Bitboard] (default: ) +# blackFlag: black's target region for capture the flag win rule [Bitboard] (default: ) +# flagMove: black gets one more move after white captures the flag [bool] (default: false) +# checkCounting: enable check count win rule (check count is communicated via FEN, see 3check) [bool] (default: false) +# connectN: number of aligned pieces for win [int] (default: 0) +# countingRule: enable counting rules [CountingRule] (default: ) + +################################################ +### Example for minishogi configuration that would be equivalent to the built-in variant: + +# [minishogi] +# variantTemplate = shogi +# maxRank = 5 +# maxFile = 5 +# shogi_pawn = p +# silver = s +# gold = g +# bishop = b +# horse = h +# rook = r +# bers = d +# king = k +# startFen = rbsgk/4p/5/P4/KGSBR[-] w 0 1 +# pieceDrops = true +# capturesToHand = true +# promotionRank = 5 +# doubleStep = false +# castling = false +# promotedPieceType = p:g s:g b:h r:d +# shogiDoubledPawn = false +# immobilityIllegal = true +# shogiPawnDropMateIllegal = true +# stalemateValue = loss +# nFoldRule = 4 +# nMoveRule = 0 +# perpetualCheckIllegal = true +# pocketSize = 5 +# nFoldValue = loss +# nFoldValueAbsolute = true + +# Hybrid variant of three-check chess and crazyhouse, using crazyhouse as a template +[3check-crazyhouse:crazyhouse] +startFen = rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR[] w KQkq - 3+3 0 1 +checkCounting = true + +# Crazyhouse with mandatory captures, using crazyhouse as a template +[coffeehouse:crazyhouse] +mustCapture = true + +# Hybrid variant of makruk and crazyhouse +[makrukhouse:makruk] +pieceDrops = true +capturesToHand = true + +# Hybrid variant of xiangqi and crazyhouse +[xiangqihouse:xiangqi] +pieceDrops = true +capturesToHand = true +dropChecks = false +whiteDropRegion = *1 *2 *3 *4 *5 +blackDropRegion = *6 *7 *8 *9 *10 + +# Hybrid variant of antichess and losalamos +[anti-losalamos:losalamos] +king = - +commoner = k +promotionPieceTypes = nrqk +mustCapture = true +stalemateValue = win +extinctionValue = win +extinctionPieceTypes = * + +# Indian great chess +# https://www.chessvariants.com/historic.dir/indiangr1.html +[indiangreat] +pieceToCharTable = PNBRQ..VW.........G..Kpnbrq..vw.........g..k +pawn = p +knight = n +bishop = b +rook = r +queen = q +king = k +archbishop = v +chancellor = w +amazon = g +maxRank = 10 +maxFile = 10 +startFen = rnbqkgvbnr/ppppwwpppp/4pp4/10/10/10/10/4PP4/PPPPWWPPPP/RNBVGKQBNR w - - 0 1 +promotionRank = 10 +promotionPieceTypes = q +doubleStep = false +castling = false + +# Peasant revolt +# https://www.chessvariants.com/large.dir/peasantrevolt.html +[peasant:chess] +startFen = 1nn1k1n1/4p3/8/8/8/8/PPPPPPPP/4K3 w - - 0 1 + +[tictactoe] +maxRank = 3 +maxFile = 3 +immobile = p +startFen = 3/3/3[PPPPPpppp] w - - 0 1 +pieceDrops = true +doubleStep = false +castling = false +stalemateValue = draw +immobilityIllegal = false +connectN = 3 + +[connect4] +maxRank = 6 +maxFile = 7 +immobile = p +startFen = 7/7/7/7/7/7[PPPPPPPPPPPPPPPPPPPPPppppppppppppppppppppp] w - - 0 1 +pieceDrops = true +dropOnTop = true +doubleStep = false +castling = false +stalemateValue = draw +immobilityIllegal = false +connectN = 4 +nMoveRule = 0 + +[shogun:crazyhouse] +variantTemplate = shogi +pieceToCharTable = PNBR.D.....++++.+Kpnbr.d.....++++.+k +pocketSize = 8 +startFen = rnb+dkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNB+DKBNR w KQkq - 0 1 +commoner = c +centaur = g +archbishop = a +chancellor = m +fers = d +promotionRank = 6 +promotionLimit = g:1 a:1 m:1 q:1 +promotionPieceTypes = - +promotedPieceType = p:c n:g b:a r:m d:q +mandatoryPawnPromotion = false +firstRankPawnDrops = true +promotionZonePawnDrops = true +whiteDropRegion = *1 *2 *3 *4 *5 +blackDropRegion = *4 *5 *6 *7 *8 +immobilityIllegal = true diff --cc src/xboard.cpp index 2e2b378,0000000..0b18e2b mode 100644,000000..100644 --- a/src/xboard.cpp +++ b/src/xboard.cpp @@@ -1,306 -1,0 +1,306 @@@ +/* + Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish - Copyright (C) 2018-2019 Fabian Fichter ++ Copyright (C) 2018-2020 Fabian Fichter + + Fairy-Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Fairy-Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include + +#include "evaluate.h" +#include "partner.h" +#include "search.h" +#include "thread.h" +#include "types.h" +#include "uci.h" +#include "xboard.h" + +namespace { + + const Search::LimitsType analysisLimits = []{ + Search::LimitsType limits; + limits.infinite = 1; + return limits; + }(); + + // go() starts the search for game play, analysis, or perft. + + void go(Position& pos, Search::LimitsType limits, StateListPtr& states) { + + limits.startTime = now(); // As early as possible! + + Threads.start_thinking(pos, states, limits, false); + } + + // setboard() is called when engine receives the "setboard" XBoard command. + + void setboard(Position& pos, StateListPtr& states, std::string fen = "") { + + if (fen.empty()) + fen = variants.find(Options["UCI_Variant"])->second->startFen; + + states = StateListPtr(new std::deque(1)); // Drop old and create a new one + pos.set(variants.find(Options["UCI_Variant"])->second, fen, Options["UCI_Chess960"], &states->back(), Threads.main()); + } + + // do_move() is called when engine needs to apply a move when using XBoard protocol. + + void do_move(Position& pos, std::deque& moveList, StateListPtr& states, Move m) { + + // transfer states back + if (Threads.setupStates.get()) + states = std::move(Threads.setupStates); + + if (m == MOVE_NONE) + return; + moveList.push_back(m); + states->emplace_back(); + pos.do_move(m, states->back()); + } + + // undo_move() is called when the engine receives the undo command in XBoard protocol. + + void undo_move(Position& pos, std::deque& moveList, StateListPtr& states) { + + // transfer states back + if (Threads.setupStates.get()) + states = std::move(Threads.setupStates); + + pos.undo_move(moveList.back()); + states->pop_back(); + moveList.pop_back(); + } + +} // namespace + +namespace XBoard { + +/// StateMachine::process_command() processes commands of the XBoard protocol. + +void StateMachine::process_command(Position& pos, std::string token, std::istringstream& is, StateListPtr& states) { + if (moveAfterSearch && token != "ptell") + { + // abort search in bughouse when receiving "holding" command + bool doMove = token != "holding" || Threads.abort.exchange(true); + Threads.stop = true; + Threads.main()->wait_for_search_finished(); + if (doMove) + { + do_move(pos, moveList, states, Threads.main()->bestThread->rootMoves[0].pv[0]); + moveAfterSearch = false; + } + } + if (token == "protover") + { + std::string vars = "chess"; + for (std::string v : variants.get_keys()) + if (v != "chess") + vars += "," + v; + sync_cout << "feature setboard=1 usermove=1 time=1 memory=1 smp=1 colors=0 draw=0 name=0 sigint=0 ping=1 myname=Fairy-Stockfish variants=\"" + << vars << "\"" + << Options << sync_endl + << "feature done=1" << sync_endl; + } + else if (token == "accepted" || token == "rejected" || token == "result" || token == "?") {} + else if (token == "ping") + { + if (!(is >> token)) + token = ""; + sync_cout << "pong " << token << sync_endl; + } + else if (token == "new") + { + setboard(pos, states); + // play second by default + playColor = ~pos.side_to_move(); + Threads.sit = false; + } + else if (token == "variant") + { + if (is >> token) + Options["UCI_Variant"] = token; + setboard(pos, states); + } + else if (token == "force") + playColor = COLOR_NB; + else if (token == "go") + { + playColor = pos.side_to_move(); + go(pos, limits, states); + moveAfterSearch = true; + } + else if (token == "level" || token == "st" || token == "sd" || token == "time" || token == "otim") + { + int num; + if (token == "level") + { + // moves to go + is >> limits.movestogo; + // base time + is >> token; + size_t idx = token.find(":"); + if (idx != std::string::npos) + num = std::stoi(token.substr(0, idx)) * 60 + std::stoi(token.substr(idx + 1)); + else + num = std::stoi(token) * 60; + limits.time[WHITE] = num * 1000; + limits.time[BLACK] = num * 1000; + // increment + is >> num; + limits.inc[WHITE] = num * 1000; + limits.inc[BLACK] = num * 1000; + } + else if (token == "sd") + is >> limits.depth; + else if (token == "st") + is >> limits.movetime; + // Note: time/otim are in centi-, not milliseconds + else if (token == "time") + { + is >> num; + limits.time[playColor != COLOR_NB ? playColor : pos.side_to_move()] = num * 10; + } + else if (token == "otim") + { + is >> num; + limits.time[playColor != COLOR_NB ? ~playColor : ~pos.side_to_move()] = num * 10; + } + } + else if (token == "setboard") + { + std::string fen; + std::getline(is >> std::ws, fen); + setboard(pos, states, fen); + } + else if (token == "cores") + { + if (is >> token) + Options["Threads"] = token; + } + else if (token == "memory") + { + if (is >> token) + Options["Hash"] = token; + } + else if (token == "hard" || token == "easy") + Options["Ponder"] = token == "hard"; + else if (token == "option") + { + std::string name, value; + is.get(); + std::getline(is, name, '='); + std::getline(is, value); + if (Options.count(name)) + { + if (Options[name].get_type() == "check") + value = value == "1" ? "true" : "false"; + Options[name] = value; + } + } + else if (token == "analyze") + { + Options["UCI_AnalyseMode"] = std::string("true"); + go(pos, analysisLimits, states); + } + else if (token == "exit") + { + Threads.stop = true; + Threads.main()->wait_for_search_finished(); + Options["UCI_AnalyseMode"] = std::string("false"); + } + else if (token == "undo") + { + if (moveList.size()) + { + if (Options["UCI_AnalyseMode"]) + { + Threads.stop = true; + Threads.main()->wait_for_search_finished(); + } + undo_move(pos, moveList, states); + if (Options["UCI_AnalyseMode"]) + go(pos, analysisLimits, states); + } + } + // Bughouse commands + else if (token == "partner") + Partner.parse_partner(is); + else if (token == "ptell") + { + Partner.parse_ptell(is, pos); + // play move requested by partner + if (moveAfterSearch && Partner.moveRequested) + { + Threads.stop = true; + Threads.main()->wait_for_search_finished(); + sync_cout << "move " << UCI::move(pos, Partner.moveRequested) << sync_endl; + do_move(pos, moveList, states, Partner.moveRequested); + moveAfterSearch = false; + Partner.moveRequested = MOVE_NONE; + } + } + else if (token == "holding") + { + // holding [] [] + std::string white_holdings, black_holdings; + if ( std::getline(is, token, '[') && std::getline(is, white_holdings, ']') + && std::getline(is, token, '[') && std::getline(is, black_holdings, ']')) + { + std::transform(black_holdings.begin(), black_holdings.end(), black_holdings.begin(), ::tolower); + std::string fen = pos.fen(false, white_holdings + black_holdings); + setboard(pos, states, fen); + } + // restart search + if (moveAfterSearch) + go(pos, limits, states); + } + // Additional custom non-XBoard commands + else if (token == "perft") + { + Search::LimitsType perft_limits; + is >> perft_limits.perft; + go(pos, perft_limits, states); + } + else if (token == "d") + sync_cout << pos << sync_endl; + else if (token == "eval") + sync_cout << Eval::trace(pos) << sync_endl; + // Move strings and unknown commands + else + { + // process move string + if (token == "usermove") + is >> token; + if (Options["UCI_AnalyseMode"]) + { + Threads.stop = true; + Threads.main()->wait_for_search_finished(); + } + Move m; + if ((m = UCI::to_move(pos, token)) != MOVE_NONE) + do_move(pos, moveList, states, m); + else + sync_cout << "Error (unkown command): " << token << sync_endl; + if (Options["UCI_AnalyseMode"]) + go(pos, analysisLimits, states); + else if (pos.side_to_move() == playColor) + { + go(pos, limits, states); + moveAfterSearch = true; + } + } +} + +} // namespace XBoard diff --cc src/xboard.h index ab3a3d6,0000000..5821394 mode 100644,000000..100644 --- a/src/xboard.h +++ b/src/xboard.h @@@ -1,51 -1,0 +1,51 @@@ +/* + Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish - Copyright (C) 2018-2019 Fabian Fichter ++ Copyright (C) 2018-2020 Fabian Fichter + + Fairy-Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Fairy-Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef XBOARD_H_INCLUDED +#define XBOARD_H_INCLUDED + +#include +#include + +#include "types.h" + +class Position; + +namespace XBoard { + +/// StateMachine class maintains the states required by XBoard protocol + +class StateMachine { +public: + StateMachine() { + moveList = std::deque(); + moveAfterSearch = false; + playColor = COLOR_NB; + } + void process_command(Position& pos, std::string token, std::istringstream& is, StateListPtr& states); + +private: + std::deque moveList; + Search::LimitsType limits; + bool moveAfterSearch; + Color playColor; +}; + +} // namespace XBoard + +#endif // #ifndef XBOARD_H_INCLUDED