Merge official-stockfish/master
authorFabian Fichter <ianfab@users.noreply.github.com>
Sun, 26 Jan 2020 18:39:38 +0000 (19:39 +0100)
committerFabian Fichter <ianfab@users.noreply.github.com>
Sun, 26 Jan 2020 18:39:38 +0000 (19:39 +0100)
bench: 4794966

44 files changed:
1  2 
Readme.md
src/benchmark.cpp
src/bitbase.cpp
src/bitboard.cpp
src/bitboard.h
src/endgame.cpp
src/endgame.h
src/evaluate.cpp
src/evaluate.h
src/magic.h
src/main.cpp
src/material.cpp
src/misc.cpp
src/movegen.cpp
src/movepick.cpp
src/movepick.h
src/parser.cpp
src/parser.h
src/partner.cpp
src/partner.h
src/pawns.cpp
src/piece.cpp
src/piece.h
src/position.cpp
src/position.h
src/psqt.cpp
src/search.cpp
src/search.h
src/syzygy/tbprobe.cpp
src/thread.cpp
src/thread.h
src/timeman.cpp
src/timeman.h
src/tt.cpp
src/tt.h
src/types.h
src/uci.cpp
src/uci.h
src/ucioption.cpp
src/variant.cpp
src/variant.h
src/variants.ini
src/xboard.cpp
src/xboard.h

diff --cc Readme.md
Simple merge
Simple merge
diff --cc src/bitbase.cpp
Simple merge
Simple merge
diff --cc src/bitboard.h
Simple merge
diff --cc src/endgame.cpp
Simple merge
diff --cc src/endgame.h
Simple merge
@@@ -956,14 -701,12 +955,17 @@@ namespace 
      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
diff --cc src/evaluate.h
Simple merge
diff --cc src/magic.h
index 7dd0dfe,0000000..478f3f7
mode 100644,000000..100644
--- /dev/null
@@@ -1,883 -1,0 +1,883 @@@
 +/*
 +  Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
-   Copyright (C) 2018-2019 Fabian Fichter
++  Copyright (C) 2018-2020 Fabian Fichter
 +
 +  Fairy-Stockfish is free software: you can redistribute it and/or modify
 +  it under the terms of the GNU General Public License as published by
 +  the Free Software Foundation, either version 3 of the License, or
 +  (at your option) any later version.
 +
 +  Fairy-Stockfish is distributed in the hope that it will be useful,
 +  but WITHOUT ANY WARRANTY; without even the implied warranty of
 +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +  GNU General Public License for more details.
 +
 +  You should have received a copy of the GNU General Public License
 +  along with this program.  If not, see <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
diff --cc src/main.cpp
Simple merge
Simple merge
diff --cc src/misc.cpp
Simple merge
diff --cc src/movegen.cpp
Simple merge
Simple merge
diff --cc src/movepick.h
Simple merge
diff --cc src/parser.cpp
index 996f562,0000000..0d0ffb2
mode 100644,000000..100644
--- /dev/null
@@@ -1,235 -1,0 +1,235 @@@
 +/*
 +  Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
-   Copyright (C) 2018-2019 Fabian Fichter
++  Copyright (C) 2018-2020 Fabian Fichter
 +
 +  Fairy-Stockfish is free software: you can redistribute it and/or modify
 +  it under the terms of the GNU General Public License as published by
 +  the Free Software Foundation, either version 3 of the License, or
 +  (at your option) any later version.
 +
 +  Fairy-Stockfish is distributed in the hope that it will be useful,
 +  but WITHOUT ANY WARRANTY; without even the implied warranty of
 +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +  GNU General Public License for more details.
 +
 +  You should have received a copy of the GNU General Public License
 +  along with this program.  If not, see <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;
 +}
diff --cc src/parser.h
index 310a81e,0000000..2e6c234
mode 100644,000000..100644
--- /dev/null
@@@ -1,48 -1,0 +1,48 @@@
 +/*
 +  Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
-   Copyright (C) 2018-2019 Fabian Fichter
++  Copyright (C) 2018-2020 Fabian Fichter
 +
 +  Fairy-Stockfish is free software: you can redistribute it and/or modify
 +  it under the terms of the GNU General Public License as published by
 +  the Free Software Foundation, either version 3 of the License, or
 +  (at your option) any later version.
 +
 +  Fairy-Stockfish is distributed in the hope that it will be useful,
 +  but WITHOUT ANY WARRANTY; without even the implied warranty of
 +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +  GNU General Public License for more details.
 +
 +  You should have received a copy of the GNU General Public License
 +  along with this program.  If not, see <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
diff --cc src/partner.cpp
index c1f533e,0000000..4eb3120
mode 100644,000000..100644
--- /dev/null
@@@ -1,85 -1,0 +1,85 @@@
 +/*
 +  Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
-   Copyright (C) 2018-2019 Fabian Fichter
++  Copyright (C) 2018-2020 Fabian Fichter
 +
 +  Fairy-Stockfish is free software: you can redistribute it and/or modify
 +  it under the terms of the GNU General Public License as published by
 +  the Free Software Foundation, either version 3 of the License, or
 +  (at your option) any later version.
 +
 +  Fairy-Stockfish is distributed in the hope that it will be useful,
 +  but WITHOUT ANY WARRANTY; without even the implied warranty of
 +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +  GNU General Public License for more details.
 +
 +  You should have received a copy of the GNU General Public License
 +  along with this program.  If not, see <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;
 +    }
 +}
diff --cc src/partner.h
index def5797,0000000..1b378ad
mode 100644,000000..100644
--- /dev/null
@@@ -1,41 -1,0 +1,41 @@@
 +/*
 +  Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
-   Copyright (C) 2018-2019 Fabian Fichter
++  Copyright (C) 2018-2020 Fabian Fichter
 +
 +  Fairy-Stockfish is free software: you can redistribute it and/or modify
 +  it under the terms of the GNU General Public License as published by
 +  the Free Software Foundation, either version 3 of the License, or
 +  (at your option) any later version.
 +
 +  Fairy-Stockfish is distributed in the hope that it will be useful,
 +  but WITHOUT ANY WARRANTY; without even the implied warranty of
 +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +  GNU General Public License for more details.
 +
 +  You should have received a copy of the GNU General Public License
 +  along with this program.  If not, see <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
diff --cc src/pawns.cpp
Simple merge
diff --cc src/piece.cpp
index 3b9a789,0000000..82f938c
mode 100644,000000..100644
--- /dev/null
@@@ -1,392 -1,0 +1,392 @@@
 +/*
 +  Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
-   Copyright (C) 2018-2019 Fabian Fichter
++  Copyright (C) 2018-2020 Fabian Fichter
 +
 +  Fairy-Stockfish is free software: you can redistribute it and/or modify
 +  it under the terms of the GNU General Public License as published by
 +  the Free Software Foundation, either version 3 of the License, or
 +  (at your option) any later version.
 +
 +  Fairy-Stockfish is distributed in the hope that it will be useful,
 +  but WITHOUT ANY WARRANTY; without even the implied warranty of
 +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +  GNU General Public License for more details.
 +
 +  You should have received a copy of the GNU General Public License
 +  along with this program.  If not, see <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();
 +}
diff --cc src/piece.h
index 70df241,0000000..c93e1d5
mode 100644,000000..100644
--- /dev/null
@@@ -1,53 -1,0 +1,53 @@@
 +/*
 +  Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
-   Copyright (C) 2018-2019 Fabian Fichter
++  Copyright (C) 2018-2020 Fabian Fichter
 +
 +  Fairy-Stockfish is free software: you can redistribute it and/or modify
 +  it under the terms of the GNU General Public License as published by
 +  the Free Software Foundation, either version 3 of the License, or
 +  (at your option) any later version.
 +
 +  Fairy-Stockfish is distributed in the hope that it will be useful,
 +  but WITHOUT ANY WARRANTY; without even the implied warranty of
 +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +  GNU General Public License for more details.
 +
 +  You should have received a copy of the GNU General Public License
 +  along with this program.  If not, see <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
@@@ -1289,11 -817,8 +1289,8 @@@ void Position::do_move(Move m, StateInf
            st->nonPawnMaterial[us] += PieceValue[MG][promotion];
        }
  
-       // Update pawn hash key and prefetch access to pawnsTable
-       if (type_of(m) == DROP)
-           st->pawnKey ^= Zobrist::psq[pc][to];
-       else
-           st->pawnKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
+       // Update pawn hash key
 -      st->pawnKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to];
++      st->pawnKey ^= (type_of(m) != DROP ? Zobrist::psq[pc][from] : 0) ^ Zobrist::psq[pc][to];
  
        // Reset rule 50 draw counter
        st->rule50 = 0;
@@@ -1666,21 -1027,12 +1663,21 @@@ bool Position::see_ge(Move m, Value thr
    if (swap <= 0)
        return true;
  
-   Bitboard occ = (type_of(m) != DROP ? pieces() ^ from : pieces()) ^ to;
 -  Bitboard occupied = pieces() ^ from ^ to;
 -  Color stm = color_of(piece_on(from));
++  Bitboard occupied = (type_of(m) != DROP ? pieces() ^ from : pieces()) ^ to;
 +  Color stm = color_of(moved_piece(m));
-   Bitboard attackers = attackers_to(to, occ);
+   Bitboard attackers = attackers_to(to, occupied);
    Bitboard stmAttackers, bb;
    int res = 1;
  
 +  // Flying general rule
 +  if (var->flyingGeneral)
 +  {
 +      if (attackers & pieces(stm, KING))
-           attackers |= attacks_bb(stm, ROOK, to, occ & ~pieces(ROOK)) & pieces(~stm, KING);
++          attackers |= attacks_bb(stm, ROOK, to, occupied & ~pieces(ROOK)) & pieces(~stm, KING);
 +      if (attackers & pieces(~stm, KING))
-           attackers |= attacks_bb(~stm, ROOK, to, occ & ~pieces(ROOK)) & pieces(stm, KING);
++          attackers |= attacks_bb(~stm, ROOK, to, occupied & ~pieces(ROOK)) & pieces(stm, KING);
 +  }
 +
    while (true)
    {
        stm = ~stm;
            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;
  }
diff --cc src/position.h
@@@ -45,14 -43,9 +45,13 @@@ struct StateInfo 
    int    castlingRights;
    int    rule50;
    int    pliesFromNull;
 +  int    countingPly;
 +  int    countingLimit;
 +  CheckCount checksRemaining[COLOR_NB];
    Square epSquare;
 +  Bitboard gatesBB[COLOR_NB];
  
    // Not copied when making a move (will be recomputed anyhow)
-   int repetition;
    Key        key;
    Bitboard   checkersBB;
    Piece      capturedPiece;
@@@ -61,8 -53,7 +60,9 @@@
    Bitboard   blockersForKing[COLOR_NB];
    Bitboard   pinners[COLOR_NB];
    Bitboard   checkSquares[PIECE_TYPE_NB];
 +  bool       capturedpromoted;
 +  bool       shak;
+   int        repetition;
  };
  
  /// A list to keep track of the position states along the setup moves (from the
diff --cc src/psqt.cpp
Simple merge
diff --cc src/search.cpp
@@@ -575,9 -560,15 +580,15 @@@ void Thread::search() 
                // keep pondering until the GUI sends "ponderhit" or "stop".
                if (mainThread->ponder)
                    mainThread->stopOnPonderhit = true;
 -              else
 +              else if (!(rootPos.two_boards() && (Partner.sitRequested || bestValue <= VALUE_MATED_IN_MAX_PLY)))
                    Threads.stop = true;
            }
+           else if (   Threads.increaseDepth
+                    && !mainThread->ponder
+                    && Time.elapsed() > Time.optimum() * fallingEval * reduction * bestMoveInstability * 0.6)
+                    Threads.increaseDepth = false;
+           else
+                    Threads.increaseDepth = true;
        }
  
        mainThread->iterValue[iterIdx] = bestValue;
@@@ -830,43 -819,31 +843,43 @@@ namespace 
          tte->save(posKey, VALUE_NONE, ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval);
      }
  
-     // Step 7. Razoring (~2 Elo)
+     // Step 7. Razoring (~1 Elo)
      if (   !rootNode // The required rootNode PV handling is not available in qsearch
          &&  depth < 2
 +        && !pos.must_capture()
 +        && !pos.capture_the_flag_piece()
 +        && !pos.check_counting()
          &&  eval <= alpha - RazorMargin)
          return qsearch<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;
@@@ -1017,9 -993,9 +1030,9 @@@ moves_loop: // When in check, search st
        // Calculate new depth for this move
        newDepth = depth - 1;
  
-       // Step 13. Pruning at shallow depth (~170 Elo)
+       // Step 13. Pruning at shallow depth (~200 Elo)
        if (  !rootNode
 -          && pos.non_pawn_material(us)
 +          && (pos.non_pawn_material(us) || !(pos.pieces(us) ^ pos.pieces(us, PAWN)))
            && bestValue > VALUE_MATED_IN_MAX_PLY)
        {
            // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold
  
                // 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++;
  
diff --cc src/search.h
Simple merge
@@@ -683,8 -682,8 +683,8 @@@ Ret do_probe_table(const Position& pos
      // flip the squares before to lookup.
      bool blackStronger = (pos.material_key() != entry->key);
  
 -    int flipColor   = (symmetricBlackToMove || blackStronger) * 8;
 +    int flipColor   = (symmetricBlackToMove || blackStronger) * PIECE_TYPE_NB;
-     int flipSquares = (symmetricBlackToMove || blackStronger) * 070;
+     int flipSquares = (symmetricBlackToMove || blackStronger) * 56;
      int stm         = (symmetricBlackToMove || blackStronger) ^ pos.side_to_move();
  
      // For pawns, TB files store 4 separate tables according if leading pawn is on
diff --cc src/thread.cpp
@@@ -178,7 -178,8 +178,8 @@@ void ThreadPool::start_thinking(Positio
  
    main()->wait_for_search_finished();
  
 -  main()->stopOnPonderhit = stop = false;
 +  main()->stopOnPonderhit = stop = abort = false;
+   increaseDepth = true;
    main()->ponder = ponderMode;
    Search::Limits = limits;
    Search::RootMoves rootMoves;
diff --cc src/thread.h
@@@ -110,13 -109,11 +110,12 @@@ struct ThreadPool : public std::vector<
    uint64_t nodes_searched() const { return accumulate(&Thread::nodes); }
    uint64_t tb_hits()        const { return accumulate(&Thread::tbHits); }
  
-   std::atomic_bool stop;
-   std::atomic_bool abort;
-   std::atomic_bool sit;
+   std::atomic_bool stop, increaseDepth;
++  std::atomic_bool abort, sit;
  
 -private:
    StateListPtr setupStates;
  
 +private:
    uint64_t accumulate(std::atomic<uint64_t> Thread::* member) const {
  
      uint64_t sum = 0;
diff --cc src/timeman.cpp
Simple merge
diff --cc src/timeman.h
Simple merge
diff --cc src/tt.cpp
Simple merge
diff --cc src/tt.h
Simple merge
diff --cc src/types.h
Simple merge
diff --cc src/uci.cpp
@@@ -276,11 -235,11 +276,12 @@@ void UCI::loop(int argc, char* argv[]) 
  
        // Additional custom non-UCI commands, mainly for debugging.
        // Do not use these commands during a search!
-       else if (token == "flip")  pos.flip();
-       else if (token == "bench") bench(pos, is, states);
-       else if (token == "d")     sync_cout << pos << sync_endl;
-       else if (token == "eval")  sync_cout << Eval::trace(pos) << sync_endl;
-       else if (token == "load")  { load(is); argc = 1; } // continue reading stdin
+       else if (token == "flip")     pos.flip();
+       else if (token == "bench")    bench(pos, is, states);
+       else if (token == "d")        sync_cout << pos << sync_endl;
+       else if (token == "eval")     sync_cout << Eval::trace(pos) << sync_endl;
+       else if (token == "compiler") sync_cout << compiler_info() << sync_endl;
++      else if (token == "load")     { load(is); argc = 1; } // continue reading stdin
        else
            sync_cout << "Unknown command: " << cmd << sync_endl;
  
diff --cc src/uci.h
Simple merge
Simple merge
diff --cc src/variant.cpp
index 960ee4e,0000000..f5e39d0
mode 100644,000000..100644
--- /dev/null
@@@ -1,964 -1,0 +1,964 @@@
 +/*
 +  Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
-   Copyright (C) 2018-2019 Fabian Fichter
++  Copyright (C) 2018-2020 Fabian Fichter
 +
 +  Fairy-Stockfish is free software: you can redistribute it and/or modify
 +  it under the terms of the GNU General Public License as published by
 +  the Free Software Foundation, either version 3 of the License, or
 +  (at your option) any later version.
 +
 +  Fairy-Stockfish is distributed in the hope that it will be useful,
 +  but WITHOUT ANY WARRANTY; without even the implied warranty of
 +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +  GNU General Public License for more details.
 +
 +  You should have received a copy of the GNU General Public License
 +  along with this program.  If not, see <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;
 +}
diff --cc src/variant.h
index fc5d370,0000000..6464d3f
mode 100644,000000..100644
--- /dev/null
@@@ -1,149 -1,0 +1,149 @@@
 +/*
 +  Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
-   Copyright (C) 2018-2019 Fabian Fichter
++  Copyright (C) 2018-2020 Fabian Fichter
 +
 +  Fairy-Stockfish is free software: you can redistribute it and/or modify
 +  it under the terms of the GNU General Public License as published by
 +  the Free Software Foundation, either version 3 of the License, or
 +  (at your option) any later version.
 +
 +  Fairy-Stockfish is distributed in the hope that it will be useful,
 +  but WITHOUT ANY WARRANTY; without even the implied warranty of
 +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +  GNU General Public License for more details.
 +
 +  You should have received a copy of the GNU General Public License
 +  along with this program.  If not, see <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
index 13d790c,0000000..fbc7c2b
mode 100644,000000..100644
--- /dev/null
@@@ -1,302 -1,0 +1,302 @@@
 +# Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
- # Copyright (C) 2018-2019 Fabian Fichter
++# Copyright (C) 2018-2020 Fabian Fichter
 +#
 +# Fairy-Stockfish is free software: you can redistribute it and/or modify
 +# it under the terms of the GNU General Public License as published by
 +# the Free Software Foundation, either version 3 of the License, or
 +# (at your option) any later version.
 +#
 +# Fairy-Stockfish is distributed in the hope that it will be useful,
 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +# GNU General Public License for more details.
 +#
 +# You should have received a copy of the GNU General Public License
 +# along with this program.  If not, see <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
diff --cc src/xboard.cpp
index 2e2b378,0000000..0b18e2b
mode 100644,000000..100644
--- /dev/null
@@@ -1,306 -1,0 +1,306 @@@
 +/*
 +  Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
-   Copyright (C) 2018-2019 Fabian Fichter
++  Copyright (C) 2018-2020 Fabian Fichter
 +
 +  Fairy-Stockfish is free software: you can redistribute it and/or modify
 +  it under the terms of the GNU General Public License as published by
 +  the Free Software Foundation, either version 3 of the License, or
 +  (at your option) any later version.
 +
 +  Fairy-Stockfish is distributed in the hope that it will be useful,
 +  but WITHOUT ANY WARRANTY; without even the implied warranty of
 +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +  GNU General Public License for more details.
 +
 +  You should have received a copy of the GNU General Public License
 +  along with this program.  If not, see <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
diff --cc src/xboard.h
index ab3a3d6,0000000..5821394
mode 100644,000000..100644
--- /dev/null
@@@ -1,51 -1,0 +1,51 @@@
 +/*
 +  Fairy-Stockfish, a UCI chess variant playing engine derived from Stockfish
-   Copyright (C) 2018-2019 Fabian Fichter
++  Copyright (C) 2018-2020 Fabian Fichter
 +
 +  Fairy-Stockfish is free software: you can redistribute it and/or modify
 +  it under the terms of the GNU General Public License as published by
 +  the Free Software Foundation, either version 3 of the License, or
 +  (at your option) any later version.
 +
 +  Fairy-Stockfish is distributed in the hope that it will be useful,
 +  but WITHOUT ANY WARRANTY; without even the implied warranty of
 +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +  GNU General Public License for more details.
 +
 +  You should have received a copy of the GNU General Public License
 +  along with this program.  If not, see <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