Value mg = mg_value(score);
Value eg = eg_value(score);
- int outflanking = distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK))
- - distance<Rank>(pos.square<KING>(WHITE), pos.square<KING>(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<KING>(WHITE) || !pos.count<KING>(BLACK) ? 0
+ : distance<File>(pos.square<KING>(WHITE), pos.square<KING>(BLACK))
+ - distance<Rank>(pos.square<KING>(WHITE), pos.square<KING>(BLACK));
- bool infiltration = rank_of(pos.square<KING>(WHITE)) > RANK_4
- || rank_of(pos.square<KING>(BLACK)) < RANK_5;
++ bool infiltration = (pos.count<KING>(WHITE) && rank_of(pos.square<KING>(WHITE)) > RANK_4)
++ || (pos.count<KING>(BLACK) && rank_of(pos.square<KING>(BLACK)) < RANK_5);
+
bool pawnsOnBothFlanks = (pos.pieces(PAWN) & QueenSide)
&& (pos.pieces(PAWN) & KingSide);
// Compute the initiative bonus for the attacking side
int complexity = 9 * pe->passed_count()
+ 11 * pos.count<PAWN>()
+ + 15 * pos.count<SOLDIER>()
+ 9 * outflanking
+ + 12 * infiltration
+ 21 * pawnsOnBothFlanks
+ 51 * !pos.non_pawn_material()
- 43 * almostUnwinnable
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#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
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <string>
+#include <sstream>
+
+#include "parser.h"
+#include "piece.h"
+#include "types.h"
+
+namespace {
+
+ template <typename T> 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 <class T> 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;
+}
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PARSER_H_INCLUDED
+#define PARSER_H_INCLUDED
+
+#include <iostream>
+
+#include "variant.h"
+
+class Config : public std::map<std::string, std::string> {
+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<std::string, std::string>::find(s);
+ }
+};
+
+class VariantParser {
+public:
+ VariantParser(const Config& c) : config (c) {};
+ Variant* parse();
+ Variant* parse(Variant* v);
+
+private:
+ Config config;
+ template <class T> 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
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#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;
+ }
+}
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PARTNER_H_INCLUDED
+#define PARTNER_H_INCLUDED
+
+#include <atomic>
+#include <sstream>
+
+#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<bool> isFairy;
+ std::atomic<bool> sitRequested;
+ Move moveRequested;
+};
+
+extern PartnerHandler Partner;
+
+#endif // #ifndef PARTNER_H_INCLUDED
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <string>
+
+#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<PieceType, const PieceInfo*>(pt, p));
+}
+
+void PieceMap::clear_all() {
+ for (auto const& element : *this)
+ delete element.second;
+ clear();
+}
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PIECE_H_INCLUDED
+#define PIECE_H_INCLUDED
+
+#include <string>
+#include <map>
+#include <vector>
+
+#include "types.h"
+
+
+/// PieceInfo struct stores information about the piece movements.
+
+struct PieceInfo {
+ std::string name = "";
+ std::string betza = "";
+ std::vector<Direction> stepsQuiet = {};
+ std::vector<Direction> stepsCapture = {};
+ std::vector<Direction> sliderQuiet = {};
+ std::vector<Direction> sliderCapture = {};
+ std::vector<Direction> hopperQuiet = {};
+ std::vector<Direction> hopperCapture = {};
+ bool lameLeaper = false;
+
+ void merge(const PieceInfo* pi);
+};
+
+struct PieceMap : public std::map<PieceType, const PieceInfo*> {
+ void init();
+ void add(PieceType pt, const PieceInfo* v);
+ void clear_all();
+};
+
+extern PieceMap pieceMap;
+
+#endif // #ifndef PIECE_H_INCLUDED
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;
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;
if ((swap = QueenValueMg - swap) < res)
break;
- occ ^= lsb(bb);
- attackers |= (attacks_bb<BISHOP>(to, occ) & pieces(BISHOP, QUEEN))
- | (attacks_bb<ROOK >(to, occ) & pieces(ROOK , QUEEN));
+ occupied ^= lsb(bb);
+ attackers |= (attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN))
+ | (attacks_bb<ROOK >(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<LEGAL>(*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<LEGAL>(*this).size()))
+ // counting rules
+ if ( counting_rule()
+ && st->countingLimit
+ && st->countingPly >= st->countingLimit
+ && (!checkers() || MoveList<LEGAL>(*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<ALL_PIECES>(sideToMove) == 2
+ && count<PAWN>(sideToMove) == 1
+ && !checkers())
+ {
+ bool promotionsOnly = true;
+ for (const auto& m : MoveList<LEGAL>(*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<ALL_PIECES>(sideToMove) - count<KING>(sideToMove)))
+ {
+ result = bare_king_value(ply);
+ return true;
+ }
+ if ( bare_king_value() != VALUE_NONE
+ && bare_king_move()
+ && !(count<ALL_PIECES>(~sideToMove) - count<KING>(~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<KING>(~sideToMove) && count<KING>(sideToMove) && !checkers() && Options["TsumeMode"])
+ {
+ result = mate_in(ply);
return true;
+ }
return false;
}
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;
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
// 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;
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<NT>(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<CAPTURES>(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);
}
}
- // 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<NT>(pos, ss, alpha, beta, depth - 7, cutNode);
+ search<NT>(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;
// 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
// 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;
}
if (singularLMR)
r -= 2;
- if (!captureOrPromotion)
+ if (!captureOrPromotion && !(pos.must_capture() && MoveList<CAPTURES>(pos).size()))
{
- // Increase reduction if ttMove is a capture (~0 Elo)
+ // Increase reduction if ttMove is a capture (~5 Elo)
if (ttCapture)
r++;
// 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
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;
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<uint64_t> Thread::* member) const {
uint64_t sum = 0;
// 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;
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#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 == "<empty>")
+ 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<std::string, const Variant*>(s, v));
+}
+
+void VariantMap::clear_all() {
+ for (auto const& element : *this)
+ delete element.second;
+ clear();
+}
+
+std::vector<std::string> VariantMap::get_keys() {
+ std::vector<std::string> keys;
+ for (auto const& element : *this)
+ keys.push_back(element.first);
+ return keys;
+}
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef VARIANT_H_INCLUDED
+#define VARIANT_H_INCLUDED
+
+#include <set>
+#include <map>
+#include <vector>
+#include <string>
+#include <functional>
+
+#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<PieceType> 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<PieceType, std::greater<PieceType> > 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<PieceType> 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<std::string, const Variant*> {
+public:
+ void init();
+ void parse(std::string path);
+ void clear_all();
+ std::vector<std::string> get_keys();
+
+private:
+ void add(std::string s, const Variant* v);
+};
+
+extern VariantMap variants;
+
+#endif // #ifndef VARIANT_H_INCLUDED
--- /dev/null
+# 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 <http://www.gnu.org/licenses/>.
+
+# 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: <none>)
+# promotedPieceType: mapping between unpromoted and promoted non-pawn piece types, e.g., p:g s:g (default: <none>)
+# 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: <none>)
+# extinctionValue: result when one of extinctionPieceTypes is extinct [Value] (default: <none>)
+# 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: <none>)
+# flagPiece: piece type for capture the flag win rule [PieceType] (default: <none>)
+# whiteFlag: white's target region for capture the flag win rule [Bitboard] (default: <none>)
+# blackFlag: black's target region for capture the flag win rule [Bitboard] (default: <none>)
+# 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: <none>)
+
+################################################
+### 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
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <iostream>
+#include <string>
+
+#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<StateInfo>(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<Move>& 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<Move>& 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 [<white>] [<black>] <color><piece>
+ 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
--- /dev/null
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef XBOARD_H_INCLUDED
+#define XBOARD_H_INCLUDED
+
+#include <sstream>
+#include <string>
+
+#include "types.h"
+
+class Position;
+
+namespace XBoard {
+
+/// StateMachine class maintains the states required by XBoard protocol
+
+class StateMachine {
+public:
+ StateMachine() {
+ moveList = std::deque<Move>();
+ moveAfterSearch = false;
+ playColor = COLOR_NB;
+ }
+ void process_command(Position& pos, std::string token, std::istringstream& is, StateListPtr& states);
+
+private:
+ std::deque<Move> moveList;
+ Search::LimitsType limits;
+ bool moveAfterSearch;
+ Color playColor;
+};
+
+} // namespace XBoard
+
+#endif // #ifndef XBOARD_H_INCLUDED