From: Fabian Fichter Date: Sat, 30 Mar 2019 15:10:23 +0000 (+0100) Subject: Merge official-stockfish/master X-Git-Url: http://winboard.nl/cgi-bin?a=commitdiff_plain;h=5140d4e7975253863b5f938955ae725eea28a6f5;p=fairystockfish.git Merge official-stockfish/master No functional change. --- 5140d4e7975253863b5f938955ae725eea28a6f5 diff --cc src/bitboard.cpp index 0ac73b8,d90201d..155a3bb --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@@ -24,291 -24,33 +24,296 @@@ #include "misc.h" uint8_t PopCnt16[1 << 16]; - int8_t SquareDistance[SQUARE_NB][SQUARE_NB]; + uint8_t SquareDistance[SQUARE_NB][SQUARE_NB]; +Bitboard BoardSizeBB[FILE_NB][RANK_NB]; Bitboard SquareBB[SQUARE_NB]; Bitboard ForwardRanksBB[COLOR_NB][RANK_NB]; Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; Bitboard LineBB[SQUARE_NB][SQUARE_NB]; -Bitboard DistanceRingBB[SQUARE_NB][8]; -Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; -Bitboard PawnAttacks[COLOR_NB][SQUARE_NB]; +Bitboard DistanceRingBB[SQUARE_NB][FILE_NB]; +Bitboard PseudoAttacks[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB]; +Bitboard PseudoMoves[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB]; +Bitboard LeaperAttacks[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB]; +Bitboard LeaperMoves[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB]; + Bitboard KingFlank[FILE_NB] = { + QueenSide ^ FileDBB, QueenSide, QueenSide, + CenterFiles, CenterFiles, + KingSide, KingSide, KingSide ^ FileEBB + }; + Magic RookMagics[SQUARE_NB]; Magic BishopMagics[SQUARE_NB]; namespace { +#ifdef LARGEBOARDS + Bitboard RookTable[0xA80000]; // To store rook attacks + Bitboard BishopTable[0x33C00]; // To store bishop attacks +#else Bitboard RookTable[0x19000]; // To store rook attacks Bitboard BishopTable[0x1480]; // To store bishop attacks - +#endif + +#ifdef PRECOMPUTED_MAGICS +#define B(a, b) (Bitboard(a) << 64) ^ Bitboard(b) + // Use precomputed magics if pext is not avaible, + // since the magics generation is very slow. + Bitboard RookMagicInit[SQUARE_NB] = { + B(0x4068000028000894, 0x20006051028), + B(0x2004000042000004, 0x2810000008004000), + B(0x1020000220004000, 0x8004290180020200), + B(0x4310000101000020, 0x8020100004002000), + B(0x38000080211108, 0x118000104000000), + B(0x4050000080400004, 0x2011040500118010), + B(0x4010000048100200, 0x100000840204000), + B(0x4020000820000100, 0x410106024000804), + B(0x910000008D00021, 0x800004400100010), + B(0x6830000821080004, 0x80C00010100000), + B(0x8040000040500008, 0x200031840804901), + B(0x4018000042201000, 0x8300002D80000841), + B(0x100008000044000, 0x1980020094A89400), + B(0x1000004000082000, 0x4408540710000181), + B(0x1206010001100802, 0x40004100048), + B(0x984010000410001, 0x208080028AE), + B(0x411210000261014, 0x8000414100011208), + B(0x8200100000B0002, 0x1082008404000008), + B(0x5004090000400096, 0x10004020001000E2), + B(0x8899220000020001, 0x8401004904082000), + B(0x801720000080040, 0x101000200082020), + B(0x800060000102411, 0xA8200008808400), + B(0x30C0000081004, 0x1004200082100418), + B(0x1018010000020102, 0x4100000040014082), + B(0x24000008000001, 0x4080041809020000), + B(0x3011200814000104, 0x2110004020000000), + B(0x1814410050000800, 0x4041010220000400), + B(0x20B002010000211, 0x100104188808), + B(0x821020000114, 0x22080A0200304020), + B(0xC0E0020000082, 0x1004108210042000), + B(0x9010010000084, 0x2000011014020406), + B(0x400208018000040, 0x20D000052800018), + B(0x108008000080, 0x240400000104), + B(0x8012001080004400, 0x102010420201000), + B(0x1000000C0001210, 0x821000080441200), + B(0x1C500000200004D0, 0x20042084400410), + B(0x4000284000108000, 0x1809420810080140), + B(0x40804004000, 0x2220005410000000), + B(0x4007080A1020000, 0x8004020D41200020), + B(0x1080000800008000, 0x4080210000002002), + B(0x400000400250000, 0x8000001100410000), + B(0xC8010090010001, 0x2004000068009022), + B(0x8300200008210000, 0x410804100111004), + B(0x42150008210000, 0x81100004A400200), + B(0x2C1410001810001, 0x8200800000411020), + B(0x28420004020000, 0x409002880830900), + B(0x200028000008000, 0x8100000040200004), + B(0x4001030120000, 0x41008A020140404), + B(0x288000004240804, 0x2410020000090), + B(0x104202000004004, 0x2008010000040), + B(0x800A020008022020, 0x4112108040400), + B(0x90044001082420, 0x239806020040A), + B(0x4018000414800030, 0x2001100010000), + B(0x102820010088120, 0x8002004090008), + B(0x280100200000410, 0x840441100000), + B(0x4A020000040020, 0x10820040C0881), + B(0x20000010020, 0x21000800402010), + B(0x161A0400212C80, 0x42000400203002), + B(0xAB00800181208440, 0x3120A01004040), + B(0x261100084025060, 0x81800A2100400), + B(0x1008000000A02000, 0x940000010040910), + B(0x1406400004A010, 0x100011080188C05), + B(0x400002000011000, 0x2080005008080002), + B(0x402C1004012, 0x600004200488003), + B(0x1800080802000409, 0x200012061200104), + B(0x843020018100800, 0xE2000040100E0A04), + B(0xA0010200005048, 0x80000851000012), + B(0x20000900041, 0x200006904002024), + B(0x20010000080002, 0x100000490211000), + B(0x1000018070C, 0x4100008200400010), + B(0x40000004101060, 0x40000109A800112), + B(0x44000908010404, 0x2200000420010409), + B(0x169D042288081204, 0x18000040A000), + B(0x1000041002000, 0x6040040001208000), + B(0x130040088200DA, 0x81600004010300), + B(0x3000062004000220, 0x8404200010200020), + B(0xC000102000020A, 0x108200004001000), + B(0x2000008606120000, 0xC010200008010821), + B(0x80040200000100, 0x80080000800440), + B(0x508028000040100, 0x4280000800124), + B(0x5AA422000B810100, 0xA802200002004404), + B(0x10000A0000012100, 0x8080200000400802), + B(0x240048004008102, 0x200400010800100), + B(0x4140030108004, 0x8C012000024909A0), + B(0x1400018A0A8000, 0x90841080008200), + B(0xA500120088001010, 0x4040020200008042), + B(0x5008024008888001, 0x1A0200A00005000), + B(0x4004D13000026, 0x800008008000A012), + B(0x201501022901000E, 0x8000024100001102), + B(0xE80010140000800C, 0x20004B1080000820), + B(0x8011010100046A00, 0x90010000C021), + B(0x1008020008401440, 0x80900020000E088), + B(0x100088000040000, 0x8124800080002200), + B(0x12C04120401200, 0x410500E80004040B), + B(0x9904A0100020008, 0x800108400020040), + B(0x4000842405D0004, 0x10220200000080), + B(0x4000001080802010, 0x4040880A00200001), + B(0x4000001080802010, 0x4040880A00200001), + B(0x800002021008000, 0xA04000420020000C), + B(0x12A6020000304, 0x8290144200000), + B(0x102803020008, 0x40824014A0200000), + B(0x1400020080210008, 0x8001004000500000), + B(0x120000148212, 0x801C001003A00000), + B(0x2020002908040, 0x2000804140200000), + B(0x820000010080, 0x10A2020420200000), + B(0x508200022440, 0xB004001108800040), + B(0x8202004084010C81, 0xC081A03000400008), + B(0xB04080040204050, 0x1810028080200000), + B(0xAA20014010120001, 0x80308004022200), + B(0xAA20014010120001, 0x80308004022200), + B(0x208018020814020, 0x2004020200410A00), + B(0x6000801000002800, 0xC80121082004080), + B(0x84002080140202, 0x8000004100090100), + B(0x3100114050000, 0x2000818014000100), + B(0x280805000008A400, 0x401042000000300), + B(0x245A20000040401, 0x1000850102080200), + B(0x4010430000D00240, 0xD0800001201100), + B(0x20000080040, 0x9053000880500600), + B(0x1840000610021088, 0x440801002428400), + B(0x448814040010, 0x8410085020500600) + }; + Bitboard BishopMagicInit[SQUARE_NB] = { + B(0x2001040305000010, 0x830200040400082), + B(0x1042400080E01200, 0x2004904010811400), + B(0x400010120200, 0x880080D080018000), + B(0x240190C00100040, 0x100A020140044404), + B(0x1018010404010004, 0x1001010018081E0), + B(0x41200A804C0904, 0x40000322000008), + B(0x4001180A004, 0x8000001106000000), + B(0x6006020020030600, 0x1840002100004841), + B(0x4200200100, 0x4001041808002000), + B(0x4100020050124600, 0x1001802902400CA0), + B(0x448C0081440161, 0x200206010008000), + B(0x400008008008408, 0x1000080210100080), + B(0x200280C01008200, 0x210200813000080), + B(0x1A000204400, 0x222200401023000), + B(0x10081040640A00, 0x8410021881400000), + B(0x1840400318080008, 0x800800840080000), + B(0x4204050C040, 0x6500600200140000), + B(0x1012100040204, 0x402404444400000), + B(0x6000012680008240, 0x410140000004220), + B(0x1000020810040008, 0x2D0011000060000), + B(0x1020020400, 0x400108059001001), + B(0x400020001100808, 0x480204800200000B), + B(0x10000010030084, 0x2042000848900022), + B(0x10000010030084, 0x2042000848900022), + B(0x100D801402400, 0x1512404009000400), + B(0x8000208005112400, 0xA02040401000000), + B(0x1000420002800200, 0x4CA000183020000), + B(0x800811480020, 0x408801010224001), + B(0xC805200810900100, 0x9000084204004020), + B(0x8200160204100004, 0x8040004004002022), + B(0x104514013080080, 0x146410040001000), + B(0x140844000080002, 0x1008102020040001), + B(0x4040400041A2002, 0x8040000A8802510), + B(0x801014041008002, 0x80068008025200), + B(0xA00540A414040, 0x4101040010A0000), + B(0x6484008010810002, 0x1100506884024000), + B(0x2800401008006000, 0x1005420884029020), + B(0x6822091010004421, 0x2000458080480), + B(0x40101000200101, 0x10020100001C4E0), + B(0x100400008C42, 0x4000100009008000), + B(0x851220018800400, 0x1681800040080080), + B(0x64200002010, 0x900020200040002), + B(0x20800080000022, 0x80040810002010), + B(0xA88408000802080, 0x20808001000000), + B(0x200000400C005040, 0x100140020290108), + B(0x224100000800408, 0x4204802004400020), + B(0x80080620010210, 0x91080088804040), + B(0x4008002100010, 0x80AC201001000001), + B(0x10008200902C046, 0x8080D03004000010), + B(0x3002100081000180, 0x2210002121528408), + B(0x8C101800804420, 0x1019880200043008), + B(0x200022000920D0, 0x8000800081300020), + B(0x1D40800880000, 0x400040001400050), + B(0x2020004100040, 0x200008040008008), + B(0x4840800040100001, 0x100100040203040), + B(0x40084001105, 0x8800080088000089), + B(0x4000128008020008, 0x4004200200440020), + B(0x210040008520000, 0x820219001080022), + B(0x1494040018002116, 0x400101047020008), + B(0x510008001910C224, 0x80200148118000), + B(0xC0301002301000, 0x4211A08004801), + B(0x50008E0C01001080, 0x100C004102845100), + B(0x400600020060400, 0x88024100250050), + B(0x8202920002002040, 0x810012000003), + B(0x800004208800200, 0x18AA00201000048), + B(0x402100800100002, 0x411000081000400), + B(0x101000022004044, 0x9000100040000), + B(0x41068001001, 0xC00400010001), + B(0x310210001040, 0x1A1200020010000), + B(0xA082409200004048, 0x490040800124101), + B(0x18844820E0040212, 0x1000404420D10000), + B(0x802908A40003348, 0x20200040104140), + B(0x1800404028205003, 0xC020010401089020), + B(0x802100044D01000, 0x8C41888000800040), + B(0x1D0161011410081, 0x10008000100200), + B(0x401000480040100, 0x286800404002212), + B(0x821030000100009, 0x2000090200A00000), + B(0x200020800200800, 0x2000480900841012), + B(0x80A000048030080, 0x200000120200008), + B(0x40B1400008020020, 0x148000200008004), + B(0xA021700002002010, 0x3040E400040100), + B(0x400242C200200640, 0x20440210200281), + B(0x80AC140040206240, 0x120000102801401), + B(0x2020340040832040, 0x10402100A44000), + B(0x420100400040220, 0x80014C8004000106), + B(0x504300822421120, 0x8004004008400100), + B(0x2001100008040, 0x2020104302000000), + B(0xA500802000A, 0x2008008000114100), + B(0x8A0020000200, 0x9C00101001002408), + B(0x104000001001008, 0x9001000204040060), + B(0x1000820080108200, 0xA401000008100001), + B(0x2008600009000480, 0x9008020001400000), + B(0x4000800200040200, 0xA00030400308082), + B(0x4004300202004709, 0x1000100180010020), + B(0xC014800100440010, 0x402020280002C010), + B(0x220208010884680, 0x1040280000042110), + B(0x40B0018019202801, 0x1008408000100040), + B(0x8269010206080044, 0x8001810000000040), + B(0x4000020880081040, 0x208A44000028000), + B(0x4004004E9004220A, 0x2104004001400024), + B(0x8035006008C0904, 0x402002001080120), + B(0x1800884002, 0x404400820000000), + B(0x8088000004008910, 0x8024100401000000), + B(0x142200086000100, 0x28021040020002E), + B(0x1000409141004018, 0x100410820080040A), + B(0x1800801800140, 0x810801060C0801), + B(0x1000C00100402220, 0x808023420000000), + B(0x8A0A202414305008, 0x100040200000021), + B(0xC0208024050, 0x8003088008020401), + B(0x8044004201440101, 0x400820080C024022), + B(0x406018884120099, 0xB00088018002000), + B(0x2000800010403010, 0xC5A002002010010), + B(0x800020040840, 0x201800202800200), + B(0x201280120020008D, 0x258809001000040), + B(0x9100002020181, 0x80400082204000), + B(0x104010080201001, 0x40080080181080), + B(0x8440248092000430, 0xA200804900100000), + B(0x2031010C01000C20, 0x200310A560082008), + B(0x400202081811400, 0x40081802050000C), + B(0x1011002100821300, 0x2400825040804100) + }; +#undef B +#endif + +#ifdef PRECOMPUTED_MAGICS + void init_magics(Bitboard table[], Magic magics[], Direction directions[], Bitboard magicsInit[]); +#else void init_magics(Bitboard table[], Magic magics[], Direction directions[]); +#endif // popcount16() counts the non-zero bits using SWAR-Popcount algorithm - unsigned popcount16(unsigned u) { u -= (u >> 1) & 0x5555U; u = ((u >> 2) & 0x3333U) + (u & 0x3333U); @@@ -361,270 -85,54 +366,264 @@@ const std::string Bitboards::pretty(Bit void Bitboards::init() { for (unsigned i = 0; i < (1 << 16); ++i) - PopCnt16[i] = (uint8_t) popcount16(i); + PopCnt16[i] = (uint8_t)popcount16(i); - for (Square s = SQ_A1; s <= SQ_H8; ++s) - SquareBB[s] = (1ULL << s); + for (Square s = SQ_A1; s <= SQ_MAX; ++s) + SquareBB[s] = make_bitboard(s); + - for (Rank r = RANK_1; r < RANK_MAX; ++r) - ForwardRanksBB[WHITE][r] = ~(ForwardRanksBB[BLACK][r + 1] = ForwardRanksBB[BLACK][r] | rank_bb(r)); - + for (File f = FILE_A; f <= FILE_MAX; ++f) + for (Rank r = RANK_1; r <= RANK_MAX; ++r) + BoardSizeBB[f][r] = forward_file_bb(BLACK, make_square(f, r)) | SquareBB[make_square(f, r)] | (f > FILE_A ? BoardSizeBB[f - 1][r] : 0); - for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) - for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) + for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1) + for (Square s2 = SQ_A1; s2 <= SQ_MAX; ++s2) - if (s1 != s2) { SquareDistance[s1][s2] = std::max(distance(s1, s2), distance(s1, s2)); DistanceRingBB[s1][SquareDistance[s1][s2]] |= s2; } - int steps[][5] = { {}, { 7, 9 }, { 6, 10, 15, 17 }, {}, {}, {}, { 1, 7, 8, 9 } }; + // Piece moves + Direction RookDirections[5] = { NORTH, EAST, SOUTH, WEST }; + Direction BishopDirections[5] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }; + +#ifdef PRECOMPUTED_MAGICS + init_magics(RookTable, RookMagics, RookDirections, RookMagicInit); + init_magics(BishopTable, BishopMagics, BishopDirections, BishopMagicInit); +#else + init_magics(RookTable, RookMagics, RookDirections); + init_magics(BishopTable, BishopMagics, BishopDirections); +#endif + + int stepsCapture[][13] = { + {}, // NO_PIECE_TYPE + { NORTH_WEST, NORTH_EAST }, // pawn + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // knight + {}, // bishop + {}, // rook + {}, // queen + { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // fers/met + { 2 * SOUTH_WEST, 2 * SOUTH_EAST, 2 * NORTH_WEST, 2 * NORTH_EAST }, // alfil + { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH, NORTH_EAST }, // silver/khon + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH_WEST, SOUTH_EAST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH_WEST, NORTH_EAST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // aiwok + { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // bers/dragon + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // archbishop + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // chancellor + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // amazon + {}, // knibis + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // biskni + { NORTH }, // shogi pawn + {}, // lance + { 2 * NORTH + WEST, 2 * NORTH + EAST }, // shogi knight + { WEST, EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // euroshogi knight + { SOUTH, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST }, // gold + { SOUTH, WEST, EAST, NORTH }, // horse + { SOUTH, WEST, EAST, NORTH }, // clobber + { NORTH_WEST, NORTH_EAST }, // breakthrough + {}, // immobile + { SOUTH, WEST, EAST, NORTH }, // wazir + { SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST }, // commoner + { SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST } // king + }; + int stepsQuiet[][13] = { + {}, // NO_PIECE_TYPE + { NORTH }, // pawn + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // knight + {}, // bishop + {}, // rook + {}, // queen + { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // fers/met + { 2 * SOUTH_WEST, 2 * SOUTH_EAST, 2 * NORTH_WEST, 2 * NORTH_EAST }, // alfil + { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH, NORTH_EAST }, // silver/khon + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH_WEST, SOUTH_EAST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH_WEST, NORTH_EAST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // aiwok + { SOUTH_WEST, SOUTH_EAST, NORTH_WEST, NORTH_EAST }, // bers/dragon + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // archbishop + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // chancellor + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // amazon + { 2 * SOUTH + WEST, 2 * SOUTH + EAST, SOUTH + 2 * WEST, SOUTH + 2 * EAST, + NORTH + 2 * WEST, NORTH + 2 * EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // knibis + {}, // biskni + { NORTH }, // shogi pawn + {}, // lance + { 2 * NORTH + WEST, 2 * NORTH + EAST }, // shogi knight + { WEST, EAST, 2 * NORTH + WEST, 2 * NORTH + EAST }, // euroshogi knight + { SOUTH, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST }, // gold + { SOUTH, WEST, EAST, NORTH }, // horse + {}, // clobber + { NORTH_WEST, NORTH, NORTH_EAST }, // breakthrough + {}, // immobile + { SOUTH, WEST, EAST, NORTH }, // wazir + { SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST }, // commoner + { SOUTH_WEST, SOUTH, SOUTH_EAST, WEST, EAST, NORTH_WEST, NORTH, NORTH_EAST } // king + }; + Direction sliderCapture[][9] = { + {}, // NO_PIECE_TYPE + {}, // pawn + {}, // knight + { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // bishop + { NORTH, EAST, SOUTH, WEST }, // rook + { NORTH, EAST, SOUTH, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // queen + {}, // fers/met + {}, // alfil + {}, // silver/khon + { NORTH, EAST, SOUTH, WEST }, // aiwok + { NORTH, EAST, SOUTH, WEST }, // bers/dragon + { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // archbishop + { NORTH, EAST, SOUTH, WEST }, // chancellor + { NORTH, EAST, SOUTH, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // amazon + { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // knibis + {}, // biskni + {}, // shogi pawn + { NORTH }, // lance + {}, // shogi knight + {}, // euroshogi knight + {}, // gold + { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // horse + {}, // clobber + {}, // breakthrough + {}, // immobile + {}, // wazir + {}, // commoner + {} // king + }; + Direction sliderQuiet[][9] = { + {}, // NO_PIECE_TYPE + {}, // pawn + {}, // knight + { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // bishop + { NORTH, EAST, SOUTH, WEST }, // rook + { NORTH, EAST, SOUTH, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // queen + {}, // fers/met + {}, // alfil + {}, // silver/khon + { NORTH, EAST, SOUTH, WEST }, // aiwok + { NORTH, EAST, SOUTH, WEST }, // bers/dragon + { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // archbishop + { NORTH, EAST, SOUTH, WEST }, // chancellor + { NORTH, EAST, SOUTH, WEST, NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // amazon + {}, // knibis + { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // biskni + {}, // shogi pawn + { NORTH }, // lance + {}, // shogi knight + {}, // euroshogi knight + {}, // gold + { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }, // horse + {}, // clobber + {}, // breakthrough + {}, // immobile + {}, // wazir + {}, // commoner + {} // king + }; + int sliderDistCapture[] = { + 0, // NO_PIECE_TYPE + 0, // pawn + 0, // knight + FILE_MAX, // bishop + FILE_MAX, // rook + FILE_MAX, // queen + 0, // fers/met + 0, // alfil + 0, // silver/khon + FILE_MAX, // aiwok + FILE_MAX, // bers/dragon + FILE_MAX, // archbishop + FILE_MAX, // chancellor + FILE_MAX, // amazon + FILE_MAX, // knibis + 0, // biskni + 0, // shogi pawn + FILE_MAX, // lance + 0, // shogi knight + 0, // euroshogi knight + 0, // gold + FILE_MAX, // horse + 0, // clobber + 0, // breakthrough + 0, // immobile + 0, // wazir + 0, // commoner + 0 // king + }; + int sliderDistQuiet[] = { + 0, // NO_PIECE_TYPE + 0, // pawn + 0, // knight + FILE_MAX, // bishop + FILE_MAX, // rook + FILE_MAX, // queen + 0, // fers/met + 0, // alfil + 0, // silver/khon + FILE_MAX, // aiwok + FILE_MAX, // bers/dragon + FILE_MAX, // archbishop + FILE_MAX, // chancellor + FILE_MAX, // amazon + 0, // knibis + FILE_MAX, // biskni + 0, // shogi pawn + FILE_MAX, // lance + 0, // shogi knight + 0, // euroshogi knight + 0, // gold + FILE_MAX, // horse + 0, // clobber + 0, // breakthrough + 0, // immobile + 0, // wazir + 0, // commoner + 0 // king + }; for (Color c = WHITE; c <= BLACK; ++c) - for (PieceType pt : { PAWN, KNIGHT, KING }) - for (Square s = SQ_A1; s <= SQ_H8; ++s) - for (int i = 0; steps[pt][i]; ++i) + for (PieceType pt = PAWN; pt <= KING; ++pt) + for (Square s = SQ_A1; s <= SQ_MAX; ++s) + { + for (int i = 0; stepsCapture[pt][i]; ++i) { - Square to = s + Direction(c == WHITE ? steps[pt][i] : -steps[pt][i]); + Square to = s + Direction(c == WHITE ? stepsCapture[pt][i] : -stepsCapture[pt][i]); - if (is_ok(to) && distance(s, to) < 3) + if (is_ok(to) && distance(s, to) < 4) { - if (pt == PAWN) - PawnAttacks[c][s] |= to; - else - PseudoAttacks[pt][s] |= to; + PseudoAttacks[c][pt][s] |= to; + LeaperAttacks[c][pt][s] |= to; } } + for (int i = 0; stepsQuiet[pt][i]; ++i) + { + Square to = s + Direction(c == WHITE ? stepsQuiet[pt][i] : -stepsQuiet[pt][i]); - Direction RookDirections[] = { NORTH, EAST, SOUTH, WEST }; - Direction BishopDirections[] = { NORTH_EAST, SOUTH_EAST, SOUTH_WEST, NORTH_WEST }; - - init_magics(RookTable, RookMagics, RookDirections); - init_magics(BishopTable, BishopMagics, BishopDirections); + if (is_ok(to) && distance(s, to) < 4) + { + PseudoMoves[c][pt][s] |= to; + LeaperMoves[c][pt][s] |= to; + } + } + PseudoAttacks[c][pt][s] |= sliding_attack(sliderCapture[pt], s, 0, sliderDistCapture[pt], c); + PseudoMoves[c][pt][s] |= sliding_attack(sliderQuiet[pt], s, 0, sliderDistQuiet[pt], c); + } - for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1) + for (Square s1 = SQ_A1; s1 <= SQ_MAX; ++s1) { - PseudoAttacks[QUEEN][s1] = PseudoAttacks[BISHOP][s1] = attacks_bb(s1, 0); - PseudoAttacks[QUEEN][s1] |= PseudoAttacks[ ROOK][s1] = attacks_bb< ROOK>(s1, 0); - for (PieceType pt : { BISHOP, ROOK }) - for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2) - if (PseudoAttacks[pt][s1] & s2) + for (Square s2 = SQ_A1; s2 <= SQ_MAX; ++s2) - { - if (!(PseudoAttacks[WHITE][pt][s1] & s2)) - continue; - - LineBB[s1][s2] = (attacks_bb(WHITE, pt, s1, 0) & attacks_bb(WHITE, pt, s2, 0)) | s1 | s2; - BetweenBB[s1][s2] = attacks_bb(WHITE, pt, s1, SquareBB[s2]) & attacks_bb(WHITE, pt, s2, SquareBB[s1]); - } ++ if (PseudoAttacks[WHITE][pt][s1] & s2) + { - LineBB[s1][s2] = (attacks_bb(pt, s1, 0) & attacks_bb(pt, s2, 0)) | s1 | s2; - BetweenBB[s1][s2] = attacks_bb(pt, s1, SquareBB[s2]) & attacks_bb(pt, s2, SquareBB[s1]); ++ LineBB[s1][s2] = (attacks_bb(WHITE, pt, s1, 0) & attacks_bb(WHITE, pt, s2, 0)) | s1 | s2; ++ BetweenBB[s1][s2] = attacks_bb(WHITE, pt, s1, SquareBB[s2]) & attacks_bb(WHITE, pt, s2, SquareBB[s1]); + } } } diff --cc src/bitboard.h index 9614d33,af7b592..d8198c1 --- a/src/bitboard.h +++ b/src/bitboard.h @@@ -62,47 -50,32 +62,53 @@@ constexpr Bitboard FileEBB = FileABB < constexpr Bitboard FileFBB = FileABB << 5; constexpr Bitboard FileGBB = FileABB << 6; constexpr Bitboard FileHBB = FileABB << 7; +#ifdef LARGEBOARDS +constexpr Bitboard FileIBB = FileABB << 8; +constexpr Bitboard FileJBB = FileABB << 9; +constexpr Bitboard FileKBB = FileABB << 10; +constexpr Bitboard FileLBB = FileABB << 11; +#endif + +#ifdef LARGEBOARDS +constexpr Bitboard Rank1BB = 0xFFF; +#else constexpr Bitboard Rank1BB = 0xFF; -constexpr Bitboard Rank2BB = Rank1BB << (8 * 1); -constexpr Bitboard Rank3BB = Rank1BB << (8 * 2); -constexpr Bitboard Rank4BB = Rank1BB << (8 * 3); -constexpr Bitboard Rank5BB = Rank1BB << (8 * 4); -constexpr Bitboard Rank6BB = Rank1BB << (8 * 5); -constexpr Bitboard Rank7BB = Rank1BB << (8 * 6); -constexpr Bitboard Rank8BB = Rank1BB << (8 * 7); +#endif +constexpr Bitboard Rank2BB = Rank1BB << (FILE_NB * 1); +constexpr Bitboard Rank3BB = Rank1BB << (FILE_NB * 2); +constexpr Bitboard Rank4BB = Rank1BB << (FILE_NB * 3); +constexpr Bitboard Rank5BB = Rank1BB << (FILE_NB * 4); +constexpr Bitboard Rank6BB = Rank1BB << (FILE_NB * 5); +constexpr Bitboard Rank7BB = Rank1BB << (FILE_NB * 6); +constexpr Bitboard Rank8BB = Rank1BB << (FILE_NB * 7); +#ifdef LARGEBOARDS +constexpr Bitboard Rank9BB = Rank1BB << (FILE_NB * 8); +constexpr Bitboard Rank10BB = Rank1BB << (FILE_NB * 9); +#endif - extern int8_t SquareDistance[SQUARE_NB][SQUARE_NB]; + constexpr Bitboard QueenSide = FileABB | FileBBB | FileCBB | FileDBB; + constexpr Bitboard CenterFiles = FileCBB | FileDBB | FileEBB | FileFBB; + constexpr Bitboard KingSide = FileEBB | FileFBB | FileGBB | FileHBB; + constexpr Bitboard Center = (FileDBB | FileEBB) & (Rank4BB | Rank5BB); + + extern uint8_t PopCnt16[1 << 16]; + extern uint8_t SquareDistance[SQUARE_NB][SQUARE_NB]; +extern Bitboard BoardSizeBB[FILE_NB][RANK_NB]; extern Bitboard SquareBB[SQUARE_NB]; - extern Bitboard ForwardRanksBB[COLOR_NB][RANK_NB]; extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; extern Bitboard LineBB[SQUARE_NB][SQUARE_NB]; -extern Bitboard DistanceRingBB[SQUARE_NB][8]; -extern Bitboard PseudoAttacks[PIECE_TYPE_NB][SQUARE_NB]; -extern Bitboard PawnAttacks[COLOR_NB][SQUARE_NB]; +extern Bitboard DistanceRingBB[SQUARE_NB][FILE_NB]; +extern Bitboard PseudoAttacks[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB]; +extern Bitboard PseudoMoves[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB]; +extern Bitboard LeaperAttacks[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB]; +extern Bitboard LeaperMoves[COLOR_NB][PIECE_TYPE_NB][SQUARE_NB]; + extern Bitboard KingFlank[FILE_NB]; +#ifdef LARGEBOARDS +int popcount(Bitboard b); // required for 128 bit pext +#endif /// Magic holds all magic bitboards relevant data for a single square struct Magic { @@@ -277,21 -214,9 +285,23 @@@ inline Bitboard between_bb(Square s1, S /// in front of the given one, from the point of view of the given color. For instance, /// forward_ranks_bb(BLACK, SQ_D3) will return the 16 squares on ranks 1 and 2. - inline Bitboard forward_ranks_bb(Color c, Rank r) { - return ForwardRanksBB[c][r]; + inline Bitboard forward_ranks_bb(Color c, Square s) { - return c == WHITE ? ~Rank1BB << 8 * (rank_of(s) - RANK_1) - : ~Rank8BB >> 8 * (RANK_8 - rank_of(s)); ++ return c == WHITE ? (AllSquares ^ Rank1BB) << FILE_NB * (rank_of(s) - RANK_1) ++ : (AllSquares ^ rank_bb(RANK_MAX)) >> FILE_NB * (RANK_MAX - rank_of(s)); +} + - inline Bitboard forward_ranks_bb(Color c, Square s) { - return ForwardRanksBB[c][rank_of(s)]; ++inline Bitboard forward_ranks_bb(Color c, Rank r) { ++ return c == WHITE ? (AllSquares ^ Rank1BB) << FILE_NB * (r - RANK_1) ++ : (AllSquares ^ rank_bb(RANK_MAX)) >> FILE_NB * (RANK_MAX - r); +} + + +/// promotion_zone_bb() returns a bitboard representing the squares on all the ranks +/// in front of and on the given relative rank, from the point of view of the given color. +/// For instance, promotion_zone_bb(BLACK, RANK_7) will return the 16 squares on ranks 1 and 2. + +inline Bitboard promotion_zone_bb(Color c, Rank r, Rank maxRank) { - return ForwardRanksBB[c][relative_rank(c, r, maxRank)] | rank_bb(relative_rank(c, r, maxRank)); ++ return forward_ranks_bb(c, relative_rank(c, r, maxRank)) | rank_bb(relative_rank(c, r, maxRank)); } @@@ -366,15 -294,8 +375,14 @@@ inline int popcount(Bitboard b) #ifndef USE_POPCNT - extern uint8_t PopCnt16[1 << 16]; +#ifdef LARGEBOARDS + union { Bitboard bb; uint16_t u[8]; } v = { b }; + return PopCnt16[v.u[0]] + PopCnt16[v.u[1]] + PopCnt16[v.u[2]] + PopCnt16[v.u[3]] + + PopCnt16[v.u[4]] + PopCnt16[v.u[5]] + PopCnt16[v.u[6]] + PopCnt16[v.u[7]]; +#else union { Bitboard bb; uint16_t u[4]; } v = { b }; return PopCnt16[v.u[0]] + PopCnt16[v.u[1]] + PopCnt16[v.u[2]] + PopCnt16[v.u[3]]; +#endif #elif defined(_MSC_VER) || defined(__INTEL_COMPILER) diff --cc src/evaluate.cpp index 90c2e95,27e1dd3..7b65bfc --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@@ -73,18 -73,8 +73,7 @@@ using namespace Trace namespace { - constexpr Bitboard QueenSide = FileABB | FileBBB | FileCBB | FileDBB; - constexpr Bitboard CenterFiles = FileCBB | FileDBB | FileEBB | FileFBB; - constexpr Bitboard KingSide = FileEBB | FileFBB | FileGBB | FileHBB; - constexpr Bitboard Center = (FileDBB | FileEBB) & (Rank4BB | Rank5BB); - - constexpr Bitboard KingFlank[FILE_NB] = { - QueenSide ^ FileDBB, QueenSide, QueenSide, - CenterFiles, CenterFiles, - KingSide, KingSide, KingSide ^ FileEBB - }; - - // Threshold for lazy and space evaluation - constexpr Value LazyThreshold = Value(1500); + // Threshold for space evaluation constexpr Value SpaceThreshold = Value(12222); // KingAttackWeights[PieceType] contains king attack weights by piece type @@@ -464,13 -388,11 +453,14 @@@ Score Evaluation::king() const { constexpr Color Them = (Us == WHITE ? BLACK : WHITE); - constexpr Bitboard Camp = (Us == WHITE ? AllSquares ^ Rank6BB ^ Rank7BB ^ Rank8BB - : AllSquares ^ Rank1BB ^ Rank2BB ^ Rank3BB); + Rank r = relative_rank(Us, std::min(Rank((pos.max_rank() - 1) / 2 + 1), pos.max_rank()), pos.max_rank()); + Bitboard Camp = AllSquares ^ forward_ranks_bb(Us, r); + + if (!pos.count(Us) || !pos.checking_permitted()) + return SCORE_ZERO; - Bitboard weak, b, b1, b2, safe, QueenCheck, unsafeChecks = 0; + Bitboard weak, b1, b2, safe, unsafeChecks = 0; - Bitboard rookChecks, queenChecks, bishopChecks, knightChecks; ++ Bitboard queenChecks, knightChecks, pawnChecks, otherChecks; int kingDanger = 0; const Square ksq = pos.square(Us); @@@ -489,60 -411,44 +479,60 @@@ b1 = attacks_bb(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)); b2 = attacks_bb(ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)); - // Enemy rooks checks - rookChecks = b1 & safe & attackedBy[Them][ROOK]; - - if (rookChecks) - kingDanger += RookSafeCheck; - else - unsafeChecks |= b1 & attackedBy[Them][ROOK]; - - // Enemy queen safe checks: we count them only if they are from squares from - // which we can't give a rook check, because rook checks are more valuable. - queenChecks = (b1 | b2) - & attackedBy[Them][QUEEN] - & safe - & ~attackedBy[Us][QUEEN] - & ~rookChecks; - - if (queenChecks) - kingDanger += QueenSafeCheck; - - // Enemy bishops checks: we count them only if they are from squares from - // which we can't give a queen check, because queen checks are more valuable. - bishopChecks = b2 - & attackedBy[Them][BISHOP] - & safe - & ~queenChecks; - - if (bishopChecks) - kingDanger += BishopSafeCheck; - else - unsafeChecks |= b2 & attackedBy[Them][BISHOP]; - - // Enemy knights checks - knightChecks = pos.attacks_from(ksq) & attackedBy[Them][KNIGHT]; + std::function get_attacks = [this](Color c, PieceType pt) { + return attackedBy[c][pt] | (pos.captures_to_hand() && pos.count_in_hand(c, pt) ? ~pos.pieces() : 0); + }; + for (PieceType pt : pos.piece_types()) + { + switch (pt) + { + case QUEEN: + // Enemy queen safe checks: we count them only if they are from squares from + // which we can't give a rook check, because rook checks are more valuable. - QueenCheck = (b1 | b2) ++ queenChecks = (b1 | b2) + & get_attacks(Them, QUEEN) + & safe + & ~attackedBy[Us][QUEEN] + & ~(b1 & attackedBy[Them][ROOK]); + - if (QueenCheck) ++ if (queenChecks) + kingDanger += QueenSafeCheck; + break; + case ROOK: + case BISHOP: + case KNIGHT: - b = attacks_bb(Us, pt, ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)) & get_attacks(Them, pt) & pos.board_bb(); - if (b & safe) ++ knightChecks = attacks_bb(Us, pt, ksq, pos.pieces() ^ pos.pieces(Us, QUEEN)) & get_attacks(Them, pt) & pos.board_bb(); ++ if (knightChecks & safe) + kingDanger += pt == ROOK ? RookSafeCheck + : pt == BISHOP ? BishopSafeCheck + : KnightSafeCheck; + else - unsafeChecks |= b; ++ unsafeChecks |= knightChecks; + break; + case PAWN: + if (pos.captures_to_hand() && pos.count_in_hand(Them, pt)) + { - b = attacks_bb(Us, pt, ksq, pos.pieces()) & ~pos.pieces() & pos.board_bb(); - if (b & safe) ++ pawnChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & ~pos.pieces() & pos.board_bb(); ++ if (pawnChecks & safe) + kingDanger += OtherSafeCheck; + else - unsafeChecks |= b; ++ unsafeChecks |= pawnChecks; + } + break; + case SHOGI_PAWN: + case KING: + break; + default: - b = attacks_bb(Us, pt, ksq, pos.pieces()) & get_attacks(Them, pt) & pos.board_bb(); - if (b & safe) ++ otherChecks = attacks_bb(Us, pt, ksq, pos.pieces()) & get_attacks(Them, pt) & pos.board_bb(); ++ if (otherChecks & safe) + kingDanger += OtherSafeCheck; + else - unsafeChecks |= b; ++ unsafeChecks |= otherChecks; + } + } - if (knightChecks & safe) - kingDanger += KnightSafeCheck; - else - unsafeChecks |= knightChecks; + if (pos.max_check_count()) + kingDanger *= 2; // Unsafe or occupied checking squares will also be considered, as long as // the square is in the attacker's mobility area. @@@ -600,29 -499,11 +590,29 @@@ constexpr Direction Up = (Us == WHITE ? NORTH : SOUTH); constexpr Bitboard TRank3BB = (Us == WHITE ? Rank3BB : Rank6BB); - Bitboard b, weak, defended, nonPawnEnemies, stronglyProtected, safe, restricted; + Bitboard b, weak, defended, nonPawnEnemies, stronglyProtected, safe; Score score = SCORE_ZERO; + // Bonuses for variants with mandatory captures + if (pos.must_capture()) + { + // Penalties for possible captures + score -= make_score(100, 100) * popcount(attackedBy[Us][ALL_PIECES] & pos.pieces(Them)); + + // Bonus if we threaten to force captures + Bitboard moves = 0, piecebb = pos.pieces(Us); + while (piecebb) + { + Square s = pop_lsb(&piecebb); + if (type_of(pos.piece_on(s)) != KING) + moves |= pos.moves_from(Us, type_of(pos.piece_on(s)), s); + } + score += make_score(200, 200) * popcount(attackedBy[Them][ALL_PIECES] & moves & ~pos.pieces()); + score += make_score(200, 200) * popcount(attackedBy[Them][ALL_PIECES] & moves & ~pos.pieces() & ~attackedBy2[Us]); + } + // Non-pawn enemies - nonPawnEnemies = pos.pieces(Them) & ~pos.pieces(PAWN); + nonPawnEnemies = pos.pieces(Them) & ~pos.pieces(PAWN, SHOGI_PAWN); // Squares strongly protected by the enemy, either because they defend the // square with a pawn, or because they defend the square twice and we don't. @@@ -1151,7 -900,7 +1141,8 @@@ std::string Eval::trace(const Position << " Threats | " << Term(THREAT) << " Passed | " << Term(PASSED) << " Space | " << Term(SPACE) + << " Initiative | " << Term(INITIATIVE) + << " Variant | " << Term(VARIANT) << " ------------+-------------+-------------+------------\n" << " Total | " << Term(TOTAL); diff --cc src/pawns.cpp index 5c9cb2c,6072745..f95eb28 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@@ -96,13 -96,13 +96,13 @@@ namespace // Flag the pawn opposed = theirPawns & forward_file_bb(Us, s); - stoppers = theirPawns & passed_pawn_mask(Us, s); + stoppers = theirPawns & passed_pawn_span(Us, s); - lever = theirPawns & PawnAttacks[Us][s]; - leverPush = theirPawns & PawnAttacks[Us][s + Up]; - doubled = ourPawns & (s - Up); + lever = theirPawns & PseudoAttacks[Us][PAWN][s]; + leverPush = relative_rank(Them, s, pos.max_rank()) > RANK_1 ? theirPawns & PseudoAttacks[Us][PAWN][s + Up] : 0; + doubled = relative_rank(Us, s, pos.max_rank()) > RANK_1 ? ourPawns & (s - Up) : 0; neighbours = ourPawns & adjacent_files_bb(f); phalanx = neighbours & rank_bb(s); - support = neighbours & rank_bb(s - Up); + support = relative_rank(Us, s, pos.max_rank()) > RANK_1 ? neighbours & rank_bb(s - Up) : 0; // A pawn is backward when it is behind all pawns of the same color // on the adjacent files and cannot be safely advanced. diff --cc src/ucioption.cpp index f4b190b,813a089..779626d --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@@ -20,7 -20,8 +20,9 @@@ #include #include + #include + #include +#include #include "misc.h" #include "search.h" @@@ -188,6 -166,17 +190,15 @@@ Option& Option::operator=(const string || (type == "spin" && (stof(v) < min || stof(v) > max))) return *this; + if (type == "combo") + { + OptionsMap comboMap; // To have case insensitive compare - string token; - std::istringstream ss(defaultValue); - while (ss >> token) ++ for (string token : comboValues) + comboMap[token] << Option(); + if (!comboMap.count(v) || v == "var") + return *this; + } + if (type != "button") currentValue = v;