From 506bd4343e940f5e30de2f4240058decf35e234d Mon Sep 17 00:00:00 2001 From: basil00 Date: Sun, 25 Sep 2016 19:30:59 +0800 Subject: [PATCH 1/9] Experimental LazySMP version of Gull --- README.md | 4 +- src/Gull.cpp | 10683 ++++++++++++++++++++--------------------------- src/Linux.cpp | 354 +- src/Linux.h | 14 + src/Makefile | 47 +- src/data.c | 715 ++++ src/data.h | 118 + src/tbconfig.h | 53 +- 8 files changed, 5558 insertions(+), 6430 deletions(-) create mode 100644 src/data.c create mode 100644 src/data.h diff --git a/README.md b/README.md index 1e8ecf2..3769365 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -Gull 3 Chess (SYZYGY) -===================== +Gull 3 Chess (SYZYGY + LAZYSMP) +=============================== This is a portable (Linux/MacOSX/Windows) version the Gull chess engine version 3. diff --git a/src/Gull.cpp b/src/Gull.cpp index 0b6f4e9..699acda 100644 --- a/src/Gull.cpp +++ b/src/Gull.cpp @@ -11,28 +11,9 @@ #define _WIN32_WINNT 0x0501 #endif -// #ifndef W32_BUILD -// #define HNI -// #undef HNI -// #endif - #define CPU_TIMING #undef CPU_TIMING -#define TUNER -#undef TUNER - -#ifdef TUNER -#include "time.h" - -//#define PGN -#define RANDOM_SPHERICAL -//#define WIN_PR -//#define TIMING -//#define RECORD_GAMES - -#endif - #define EXPLAIN_EVAL #undef EXPLAIN_EVAL @@ -45,15 +26,6 @@ #define TIME_TO_DEPTH //#undef TIME_TO_DEPTH -typedef unsigned char uint8; -typedef char sint8; -typedef unsigned short uint16; -typedef short sint16; -typedef unsigned int uint32; -typedef int sint32; -typedef unsigned long long uint64; -typedef long long sint64; - #ifdef LINUX #include "Linux.h" #endif @@ -62,6 +34,8 @@ typedef long long sint64; #include "Windows.h" #endif +#include "data.h" + #define Convert(x,type) ((type)(x)) #define Abs(x) ((x) > 0 ? (x) : (-(x))) @@ -78,8 +52,8 @@ typedef long long sint64; #define Compose16(x,y) Compose((x)/16,(y)/16) #define Compose64(x,y) Compose((x)/64,(y)/64) #define Compose256(x,y) Compose((x)/256,(y)/256) -#define Opening(x) Convert((x) & 0xFFFF,sint16) -#define Endgame(x) ((((x) >> 15) & 1) + Convert((x) >> 16,sint16)) +#define Opening(x) Convert((x) & 0xFFFF,int16_t) +#define Endgame(x) ((((x) >> 15) & 1) + Convert((x) >> 16,int16_t)) #define File(x) ((x) & 7) #define Rank(x) ((x) >> 3) @@ -90,7 +64,7 @@ typedef long long sint64; #define VarC(var,me) ((me) ? (var##_b) : (var##_w)) #define PVarC(prefix,var,me) ((me) ? (prefix.var##_b) : (prefix.var##_w)) -#define Bit(x) (Convert(1,uint64) << (x)) +#define Bit(x) (Convert(1,uint64_t) << (x)) #ifndef HNI #define Cut(x) (x &= (x) - 1) #else @@ -111,19 +85,19 @@ typedef long long sint64; #define PieceAtOrigin(move) Square(From(move)) #define Target(move) Square(To(move)) -#define Empty Convert(0,uint64) +#define Empty Convert(0,uint64_t) #define Filled (~Empty) -#define Interior Convert(0x007E7E7E7E7E7E00,uint64) +#define Interior Convert(0x007E7E7E7E7E7E00,uint64_t) #define Boundary (~Interior) -#define WhiteArea Convert(0x00000000FFFFFFFF,uint64) +#define WhiteArea Convert(0x00000000FFFFFFFF,uint64_t) #define BlackArea (~WhiteArea) -#define LightArea Convert(0x55AA55AA55AA55AA,uint64) +#define LightArea Convert(0x55AA55AA55AA55AA,uint64_t) #define DarkArea (~LightArea) -#define FileA Convert(0x0101010101010101,uint64) -#define Line0 Convert(0x00000000000000FF,uint64) +#define FileA Convert(0x0101010101010101,uint64_t) +#define Line0 Convert(0x00000000000000FF,uint64_t) #define High32(x) ((x) >> 32) -#define Low32(x) Convert(x,uint32) +#define Low32(x) Convert(x,uint32_t) #define White 0 #define Black 1 @@ -162,128 +136,141 @@ typedef long long sint64; #define IsEP(move) (((move) & 0xF000) == 0x2000) #define Promotion(move,side) ((side) + (((move) & 0xF000) >> 12)) -const uint8 UpdateCastling[64] = { - 0xFF^CanCastle_OOO,0xFF,0xFF,0xFF,0xFF^(CanCastle_OO|CanCastle_OOO),0xFF,0xFF,0xFF^CanCastle_OO, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF^CanCastle_ooo,0xFF,0xFF,0xFF,0xFF^(CanCastle_oo|CanCastle_ooo),0xFF,0xFF,0xFF^CanCastle_oo +const uint8_t UpdateCastling[64] = +{ + 0xFF^CanCastle_OOO,0xFF,0xFF,0xFF,0xFF^(CanCastle_OO|CanCastle_OOO), + 0xFF,0xFF,0xFF^CanCastle_OO, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF^CanCastle_ooo,0xFF,0xFF,0xFF,0xFF^(CanCastle_oo|CanCastle_ooo), + 0xFF,0xFF,0xFF^CanCastle_oo }; -extern const uint64 BMagic[64] = { - 0x0048610528020080, 0x00c4100212410004, 0x0004180181002010, 0x0004040188108502, - 0x0012021008003040, 0x0002900420228000, 0x0080808410c00100, 0x000600410c500622, - 0x00c0056084140184, 0x0080608816830050, 0x00a010050200b0c0, 0x0000510400800181, - 0x0000431040064009, 0x0000008820890a06, 0x0050028488184008, 0x00214a0104068200, - 0x004090100c080081, 0x000a002014012604, 0x0020402409002200, 0x008400c240128100, - 0x0001000820084200, 0x0024c02201101144, 0x002401008088a800, 0x0003001045009000, - 0x0084200040981549, 0x0001188120080100, 0x0048050048044300, 0x0008080000820012, - 0x0001001181004003, 0x0090038000445000, 0x0010820800a21000, 0x0044010108210110, - 0x0090241008204e30, 0x000c04204004c305, 0x0080804303300400, 0x00a0020080080080, - 0x0000408020220200, 0x0000c08200010100, 0x0010008102022104, 0x0008148118008140, - 0x0008080414809028, 0x0005031010004318, 0x0000603048001008, 0x0008012018000100, - 0x0000202028802901, 0x004011004b049180, 0x0022240b42081400, 0x00c4840c00400020, - 0x0084009219204000, 0x000080c802104000, 0x0002602201100282, 0x0002040821880020, - 0x0002014008320080, 0x0002082078208004, 0x0009094800840082, 0x0020080200b1a010, - 0x0003440407051000, 0x000000220e100440, 0x00480220a4041204, 0x00c1800011084800, - 0x000008021020a200, 0x0000414128092100, 0x0000042002024200, 0x0002081204004200 +#ifdef GULL_MAGIC_BITBOARDS + +static const uint64_t BMagic[64] = +{ + 0x0048610528020080, 0x00c4100212410004, 0x0004180181002010, + 0x0004040188108502, 0x0012021008003040, 0x0002900420228000, + 0x0080808410c00100, 0x000600410c500622, 0x00c0056084140184, + 0x0080608816830050, 0x00a010050200b0c0, 0x0000510400800181, + 0x0000431040064009, 0x0000008820890a06, 0x0050028488184008, + 0x00214a0104068200, 0x004090100c080081, 0x000a002014012604, + 0x0020402409002200, 0x008400c240128100, 0x0001000820084200, + 0x0024c02201101144, 0x002401008088a800, 0x0003001045009000, + 0x0084200040981549, 0x0001188120080100, 0x0048050048044300, + 0x0008080000820012, 0x0001001181004003, 0x0090038000445000, + 0x0010820800a21000, 0x0044010108210110, 0x0090241008204e30, + 0x000c04204004c305, 0x0080804303300400, 0x00a0020080080080, + 0x0000408020220200, 0x0000c08200010100, 0x0010008102022104, + 0x0008148118008140, 0x0008080414809028, 0x0005031010004318, + 0x0000603048001008, 0x0008012018000100, 0x0000202028802901, + 0x004011004b049180, 0x0022240b42081400, 0x00c4840c00400020, + 0x0084009219204000, 0x000080c802104000, 0x0002602201100282, + 0x0002040821880020, 0x0002014008320080, 0x0002082078208004, + 0x0009094800840082, 0x0020080200b1a010, 0x0003440407051000, + 0x000000220e100440, 0x00480220a4041204, 0x00c1800011084800, + 0x000008021020a200, 0x0000414128092100, 0x0000042002024200, + 0x0002081204004200 }; -extern const uint64 RMagic[64] = { - 0x00800011400080a6, 0x004000100120004e, 0x0080100008600082, 0x0080080016500080, - 0x0080040008000280, 0x0080020005040080, 0x0080108046000100, 0x0080010000204080, - 0x0010800424400082, 0x00004002c8201000, 0x000c802000100080, 0x00810010002100b8, - 0x00ca808014000800, 0x0002002884900200, 0x0042002148041200, 0x00010000c200a100, - 0x00008580004002a0, 0x0020004001403008, 0x0000820020411600, 0x0002120021401a00, - 0x0024808044010800, 0x0022008100040080, 0x00004400094a8810, 0x0000020002814c21, - 0x0011400280082080, 0x004a050e002080c0, 0x00101103002002c0, 0x0025020900201000, - 0x0001001100042800, 0x0002008080022400, 0x000830440021081a, 0x0080004200010084, - 0x00008000c9002104, 0x0090400081002900, 0x0080220082004010, 0x0001100101000820, - 0x0000080011001500, 0x0010020080800400, 0x0034010224009048, 0x0002208412000841, - 0x000040008020800c, 0x001000c460094000, 0x0020006101330040, 0x0000a30010010028, - 0x0004080004008080, 0x0024000201004040, 0x0000300802440041, 0x00120400c08a0011, - 0x0080006085004100, 0x0028600040100040, 0x00a0082110018080, 0x0010184200221200, - 0x0040080005001100, 0x0004200440104801, 0x0080800900220080, 0x000a01140081c200, - 0x0080044180110021, 0x0008804001001225, 0x00a00c4020010011, 0x00001000a0050009, - 0x0011001800021025, 0x00c9000400620811, 0x0032009001080224, 0x001400810044086a +static const uint64_t RMagic[64] = +{ + 0x00800011400080a6, 0x004000100120004e, 0x0080100008600082, + 0x0080080016500080, 0x0080040008000280, 0x0080020005040080, + 0x0080108046000100, 0x0080010000204080, 0x0010800424400082, + 0x00004002c8201000, 0x000c802000100080, 0x00810010002100b8, + 0x00ca808014000800, 0x0002002884900200, 0x0042002148041200, + 0x00010000c200a100, 0x00008580004002a0, 0x0020004001403008, + 0x0000820020411600, 0x0002120021401a00, 0x0024808044010800, + 0x0022008100040080, 0x00004400094a8810, 0x0000020002814c21, + 0x0011400280082080, 0x004a050e002080c0, 0x00101103002002c0, + 0x0025020900201000, 0x0001001100042800, 0x0002008080022400, + 0x000830440021081a, 0x0080004200010084, 0x00008000c9002104, + 0x0090400081002900, 0x0080220082004010, 0x0001100101000820, + 0x0000080011001500, 0x0010020080800400, 0x0034010224009048, + 0x0002208412000841, 0x000040008020800c, 0x001000c460094000, + 0x0020006101330040, 0x0000a30010010028, 0x0004080004008080, + 0x0024000201004040, 0x0000300802440041, 0x00120400c08a0011, + 0x0080006085004100, 0x0028600040100040, 0x00a0082110018080, + 0x0010184200221200, 0x0040080005001100, 0x0004200440104801, + 0x0080800900220080, 0x000a01140081c200, 0x0080044180110021, + 0x0008804001001225, 0x00a00c4020010011, 0x00001000a0050009, + 0x0011001800021025, 0x00c9000400620811, 0x0032009001080224, + 0x001400810044086a }; -extern const int BShift[64] = { - 58, 59, 59, 59, 59, 59, 59, 58, - 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 57, 57, 57, 57, 59, 59, - 59, 59, 57, 55, 55, 57, 59, 59, - 59, 59, 57, 55, 55, 57, 59, 59, - 59, 59, 57, 57, 57, 57, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, - 58, 59, 59, 59, 59, 59, 59, 58 +const int32_t BShift[64] = +{ + 58, 59, 59, 59, 59, 59, 59, 58, + 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 57, 57, 57, 57, 59, 59, + 59, 59, 57, 55, 55, 57, 59, 59, + 59, 59, 57, 55, 55, 57, 59, 59, + 59, 59, 57, 57, 57, 57, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, + 58, 59, 59, 59, 59, 59, 59, 58 }; -const int BOffset[64] = { - 0, 64, 96, 128, 160, 192, 224, 256, - 320, 352, 384, 416, 448, 480, 512, 544, - 576, 608, 640, 768, 896, 1024, 1152, 1184, - 1216, 1248, 1280, 1408, 1920, 2432, 2560, 2592, - 2624, 2656, 2688, 2816, 3328, 3840, 3968, 4000, - 4032, 4064, 4096, 4224, 4352, 4480, 4608, 4640, - 4672, 4704, 4736, 4768, 4800, 4832, 4864, 4896, - 4928, 4992, 5024, 5056, 5088, 5120, 5152, 5184 +const int32_t BOffset[64] = +{ + 0, 64, 96, 128, 160, 192, 224, 256, + 320, 352, 384, 416, 448, 480, 512, 544, + 576, 608, 640, 768, 896, 1024, 1152, 1184, + 1216, 1248, 1280, 1408, 1920, 2432, 2560, 2592, + 2624, 2656, 2688, 2816, 3328, 3840, 3968, 4000, + 4032, 4064, 4096, 4224, 4352, 4480, 4608, 4640, + 4672, 4704, 4736, 4768, 4800, 4832, 4864, 4896, + 4928, 4992, 5024, 5056, 5088, 5120, 5152, 5184 }; -extern const int RShift[64] = { - 52, 53, 53, 53, 53, 53, 53, 52, - 53, 54, 54, 54, 54, 54, 54, 53, - 53, 54, 54, 54, 54, 54, 54, 53, - 53, 54, 54, 54, 54, 54, 54, 53, - 53, 54, 54, 54, 54, 54, 54, 53, - 53, 54, 54, 54, 54, 54, 54, 53, - 53, 54, 54, 54, 54, 54, 54, 53, - 52, 53, 53, 53, 53, 53, 53, 52 +const int32_t RShift[64] = +{ + 52, 53, 53, 53, 53, 53, 53, 52, + 53, 54, 54, 54, 54, 54, 54, 53, + 53, 54, 54, 54, 54, 54, 54, 53, + 53, 54, 54, 54, 54, 54, 54, 53, + 53, 54, 54, 54, 54, 54, 54, 53, + 53, 54, 54, 54, 54, 54, 54, 53, + 53, 54, 54, 54, 54, 54, 54, 53, + 52, 53, 53, 53, 53, 53, 53, 52 }; -const int ROffset[64] = { - 5248, 9344, 11392, 13440, 15488, 17536, 19584, 21632, - 25728, 27776, 28800, 29824, 30848, 31872, 32896, 33920, - 35968, 38016, 39040, 40064, 41088, 42112, 43136, 44160, - 46208, 48256, 49280, 50304, 51328, 52352, 53376, 54400, - 56448, 58496, 59520, 60544, 61568, 62592, 63616, 64640, - 66688, 68736, 69760, 70784, 71808, 72832, 73856, 74880, - 76928, 78976, 80000, 81024, 82048, 83072, 84096, 85120, +const int32_t ROffset[64] = +{ + 5248, 9344, 11392, 13440, 15488, 17536, 19584, 21632, + 25728, 27776, 28800, 29824, 30848, 31872, 32896, 33920, + 35968, 38016, 39040, 40064, 41088, 42112, 43136, 44160, + 46208, 48256, 49280, 50304, 51328, 52352, 53376, 54400, + 56448, 58496, 59520, 60544, 61568, 62592, 63616, 64640, + 66688, 68736, 69760, 70784, 71808, 72832, 73856, 74880, + 76928, 78976, 80000, 81024, 82048, 83072, 84096, 85120, 87168, 91264, 93312, 95360, 97408, 99456, 101504, 103552 }; -uint64 * BOffsetPointer[64]; -uint64 * ROffsetPointer[64]; +#endif #ifndef HNI -#define BishopAttacks(sq,occ) (*(BOffsetPointer[sq] + (((BMagicMask[sq] & (occ)) * BMagic[sq]) >> BShift[sq]))) -#define RookAttacks(sq,occ) (*(ROffsetPointer[sq] + (((RMagicMask[sq] & (occ)) * RMagic[sq]) >> RShift[sq]))) +#define BishopAttacks(sq, occ) \ + (*(DATA->BOffsetPointer[sq] + \ + (((DATA->BMagicMask[sq] & (occ)) * \ + DATA->BMagic[sq]) >> DATA->BShift[sq]))) +#define RookAttacks(sq, occ) \ + (*(DATA->ROffsetPointer[sq] + \ + (((DATA->RMagicMask[sq] & (occ)) * \ + DATA->RMagic[sq]) >> DATA->RShift[sq]))) #else #define BishopAttacks(sq,occ) (*(BOffsetPointer[sq] + _pext_u64(occ,BMagicMask[sq]))) #define RookAttacks(sq,occ) (*(ROffsetPointer[sq] + _pext_u64(occ,RMagicMask[sq]))) #endif -#define QueenAttacks(sq,occ) (BishopAttacks(sq,occ) | RookAttacks(sq,occ)) - -#define MatWQ 1 -#define MatBQ 3 -#define MatWR (3 * 3) -#define MatBR (3 * 3 * 3) -#define MatWL (3 * 3 * 3 * 3) -#define MatBL (3 * 3 * 3 * 3 * 2) -#define MatWD (3 * 3 * 3 * 3 * 2 * 2) -#define MatBD (3 * 3 * 3 * 3 * 2 * 2 * 2) -#define MatWN (3 * 3 * 3 * 3 * 2 * 2 * 2 * 2) -#define MatBN (3 * 3 * 3 * 3 * 2 * 2 * 2 * 2 * 3) -#define MatWP (3 * 3 * 3 * 3 * 2 * 2 * 2 * 2 * 3 * 3) -#define MatBP (3 * 3 * 3 * 3 * 2 * 2 * 2 * 2 * 3 * 3 * 9) -#define TotalMat ((2*(MatWQ+MatBQ)+MatWL+MatBL+MatWD+MatBD+2*(MatWR+MatBR+MatWN+MatBN)+8*(MatWP+MatBP)) + 1) +#define QueenAttacks(sq, occ) (BishopAttacks(sq, occ) | RookAttacks(sq, occ)) + #define FlagUnusualMaterial (1 << 30) const int MatCode[16] = {0,0,MatWP,MatBP,MatWN,MatBN,MatWL,MatBL,MatWD,MatBD,MatWR,MatBR,MatWQ,MatBQ,0,0}; -const uint64 File[8] = {FileA,FileA<<1,FileA<<2,FileA<<3,FileA<<4,FileA<<5,FileA<<6,FileA<<7}; -const uint64 Line[8] = {Line0,(Line0<<8),(Line0<<16),(Line0<<24),(Line0<<32),(Line0<<40),(Line0<<48),(Line0<<56)}; #define opp (1 ^ (me)) @@ -316,10 +303,10 @@ const uint64 Line[8] = {Line0,(Line0<<8),(Line0<<16),(Line0<<24),(Line0<<32),(Li #define NonPawnKingAll (NonPawnKing(White) | NonPawnKing(Black)) #define KingPos(me) (lsb(King(me))) -#define ShiftNW(target) (((target) & (~(File[0] | Line[7]))) << 7) -#define ShiftNE(target) (((target) & (~(File[7] | Line[7]))) << 9) -#define ShiftSE(target) (((target) & (~(File[7] | Line[0]))) >> 7) -#define ShiftSW(target) (((target) & (~(File[0] | Line[0]))) >> 9) +#define ShiftNW(target) (((target) & (~(DATA->File[0] | DATA->Line[7]))) << 7) +#define ShiftNE(target) (((target) & (~(DATA->File[7] | DATA->Line[7]))) << 9) +#define ShiftSE(target) (((target) & (~(DATA->File[7] | DATA->Line[0]))) >> 7) +#define ShiftSW(target) (((target) & (~(DATA->File[0] | DATA->Line[0]))) >> 9) #define ShiftW(me,target) ((me) ? ShiftSW(target) : ShiftNW(target)) #define ShiftE(me,target) ((me) ? ShiftSE(target) : ShiftNE(target)) #define ShiftN(target) ((target) << 8) @@ -331,43 +318,35 @@ const uint64 Line[8] = {Line0,(Line0<<8),(Line0<<16),(Line0<<24),(Line0<<32),(Li #define Dir(me) ((me) ? (-1) : (1)) #define IsGreater(me,x,y) ((me) ? ((x) < (y)) : ((x) > (y))) -#define Line(me,n) ((me) ? Line[7 - n] : Line[n]) +#define Line(me,n) ((me) ? DATA->Line[7 - n] : DATA->Line[n]) #define Square(sq) Board->square[sq] #define AddMove(from,to,flags,score) { *list = ((from) << 6) | (to) | (flags) | (score); list++; } -#define AddCapture(from,to,flags) AddMove(from,to,flags,MvvLva[Square(from)][Square(to)]) -#define AddCaptureP(piece,from,to,flags) AddMove(from,to,flags,MvvLva[piece][Square(to)]) +#define AddCapture(from,to,flags) AddMove(from,to,flags,DATA->MvvLva[Square(from)][Square(to)]) +#define AddCaptureP(piece,from,to,flags) AddMove(from,to,flags,DATA->MvvLva[piece][Square(to)]) #define AddHistoryP(piece,from,to,flags) AddMove(from,to,flags,HistoryP(piece,from,to)) #define AddHistory(from,to) AddMove(from,to,0,History(from,to)) -#define AddDeltaP(piece,from,to,flags) AddMove(from,to,flags,Convert(DeltaScore(piece,from,to)+(sint16)0x4000,int) << 16) -#define AddDelta(from,to) AddMove(from,to,0,Convert(Delta(from,to)+(sint16)0x4000,int) << 16) -#define AddCDeltaP(piece,from,to,flags) {if (DeltaScore(piece,from,to) >= Current->margin) AddMove(from,to,flags,Convert(DeltaScore(piece,from,to)+(sint16)0x4000,int) << 16)} -#define AddCDelta(from,to) {if (Delta(from,to) >= Current->margin) AddMove(from,to,0,Convert(Delta(from,to)+(sint16)0x4000,int) << 16)} +#define AddDeltaP(piece,from,to,flags) AddMove(from,to,flags,Convert(DeltaScore(piece,from,to)+(int16_t)0x4000,int) << 16) +#define AddDelta(from,to) AddMove(from,to,0,Convert(Delta(from,to)+(int16_t)0x4000,int) << 16) +#define AddCDeltaP(piece,from,to,flags) {if (DeltaScore(piece,from,to) >= Current->margin) AddMove(from,to,flags,Convert(DeltaScore(piece,from,to)+(int16_t)0x4000,int) << 16)} +#define AddCDelta(from,to) {if (Delta(from,to) >= Current->margin) AddMove(from,to,0,Convert(Delta(from,to)+(int16_t)0x4000,int) << 16)} #define Check(me) T(Current->att[(me) ^ 1] & King(me)) -#define IsIllegal(me,move) ((T(Current->xray[opp] & Bit(From(move))) && F(Bit(To(move)) & FullLine[lsb(King(me))][From(move)])) \ - || (IsEP(move) && T(Line[Rank(From(move))] & King(me)) && T(Line[Rank(From(move))] & Major(opp)) && \ - T(RookAttacks(lsb(King(me)),PieceAll ^ Bit(From(move)) ^ Bit(Current->ep_square - Push(me))) & Major(opp)))) +#define IsIllegal(me,move) ((T(Current->xray[opp] & Bit(From(move))) && F(Bit(To(move)) & DATA->FullLine[lsb(King(me))][From(move)])) \ + || (IsEP(move) && T(DATA->Line[Rank(From(move))] & King(me)) && T(DATA->Line[Rank(From(move))] & Major(opp)) && \ + T(RookAttacks(lsb(King(me)),PieceAll ^ Bit(From(move)) ^ Bit(Current->ep_square - Push(me))) & Major(opp)))) #define IsRepetition(margin,move) ((margin) > 0 && Current->ply >= 2 && (Current-1)->move == ((To(move) << 6) | From(move)) && F(Square(To(move))) && F((move) & 0xF000)) -#ifdef EXPLAIN_EVAL -FILE * fexplain; -int explain = 0, cpp_length; -char GullCppFile[16384][256]; -#define IncV(var,x) (explain ? (me ? ((var -= (x)) && fprintf(fexplain,"(%d, %d): %s [Black]: %s",Opening(-(x)),Endgame(-(x)),__FUNCTION__,GullCppFile[Min(__LINE__-1,cpp_length)])) : ((var += (x)) && fprintf(fexplain,"(%d, %d): %s [White]: %s",Opening(x),Endgame(x),__FUNCTION__,GullCppFile[Min(__LINE__-1,cpp_length)]))) : (me ? (var -= (x)) : (var += (x)))) -#else #define IncV(var,x) (me ? (var -= (x)) : (var += (x))) -#endif #define DecV(var,x) IncV(var,-(x)) #define KpkValue 300 #define EvalValue 30000 #define MateValue 32760 -#ifdef TB #define TBMateValue 30000 #define TBCursedMateValue 3 -const int TbValues[5] = {-TBMateValue, -TBCursedMateValue, 0, TBCursedMateValue, TBMateValue}; +const int TbValues[5] = + {-TBMateValue, -TBCursedMateValue, 0, TBCursedMateValue, TBMateValue}; #define TbDepth (depth+6>=127?127:depth+6) -#endif /* general move: @@ -379,11 +358,14 @@ general move: delta move: 0 - 11: from & to 12 - 15: flags -16 - 31: sint16 delta + (sint16)0x4000 +16 - 31: int16_t delta + (int16_t)0x4000 */ + const int MvvLvaVictim[16] = {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 3}; -const int MvvLvaAttacker[16] = {0, 0, 5, 5, 4, 4, 3, 3, 3, 3, 2, 2, 1, 1, 6, 6}; -const int MvvLvaAttackerKB[16] = {0, 0, 9, 9, 7, 7, 5, 5, 5, 5, 3, 3, 1, 1, 11, 11}; +const int MvvLvaAttacker[16] = + {0, 0, 5, 5, 4, 4, 3, 3, 3, 3, 2, 2, 1, 1, 6, 6}; +const int MvvLvaAttackerKB[16] = + {0, 0, 9, 9, 7, 7, 5, 5, 5, 5, 3, 3, 1, 1, 11, 11}; #define PawnCaptureMvvLva(attacker) (MvvLvaAttacker[attacker]) #define MaxPawnCaptureMvvLva (MvvLvaAttacker[15]) // 6 #define KnightCaptureMvvLva(attacker) (MaxPawnCaptureMvvLva + MvvLvaAttackerKB[attacker]) @@ -394,12 +376,12 @@ const int MvvLvaAttackerKB[16] = {0, 0, 9, 9, 7, 7, 5, 5, 5, 5, 3, 3, 1, 1, 11, #define MaxRookCaptureMvvLva (MaxBishopCaptureMvvLva + MvvLvaAttacker[15]) // 24 #define QueenCaptureMvvLva(attacker) (MaxRookCaptureMvvLva + MvvLvaAttacker[attacker]) -#define MvvLvaPromotion (MvvLva[WhiteQueen][BlackQueen]) -#define MvvLvaPromotionKnight (MvvLva[WhiteKnight][BlackKnight]) -#define MvvLvaPromotionCap(capture) (MvvLva[((capture) < WhiteRook) ? WhiteRook : ((capture) >= WhiteQueen ? WhiteKing : WhiteKnight)][BlackQueen]) -#define MvvLvaPromotionKnightCap(capture) (MvvLva[WhiteKing][capture]) -#define MvvLvaXray (MvvLva[WhiteQueen][WhitePawn]) -#define MvvLvaXrayCap(capture) (MvvLva[WhiteKing][capture]) +#define MvvLvaPromotion (DATA->MvvLva[WhiteQueen][BlackQueen]) +#define MvvLvaPromotionKnight (DATA->MvvLva[WhiteKnight][BlackKnight]) +#define MvvLvaPromotionCap(capture) (DATA->MvvLva[((capture) < WhiteRook) ? WhiteRook : ((capture) >= WhiteQueen ? WhiteKing : WhiteKnight)][BlackQueen]) +#define MvvLvaPromotionKnightCap(capture) (DATA->MvvLva[WhiteKing][capture]) +#define MvvLvaXray (DATA->MvvLva[WhiteQueen][WhitePawn]) +#define MvvLvaXrayCap(capture) (DATA->MvvLva[WhiteKing][capture]) #define RefOneScore ((0xFF << 16) | (3 << 24)) #define RefTwoScore ((0xFF << 16) | (2 << 24)) #define KillerOneScore ((0xFF << 16) | (1 << 24)) @@ -407,7 +389,7 @@ const int MvvLvaAttackerKB[16] = {0, 0, 9, 9, 7, 7, 5, 5, 5, 5, 3, 3, 1, 1, 11, #define halt_check if ((Current - Data) >= 126) {evaluate(); return Current->score;} \ if (Current->ply >= 100) return 0; \ - for (i = 4; i <= Current->ply; i+= 2) if (Stack[sp-i] == Current->key) return 0 + for (i = 4; i <= Current->ply; i+= 2) if (Stack[sp-i] == Current->key) return 0 #define ExtFlag(ext) ((ext) << 16) #define Ext(flags) (((flags) >> 16) & 0xF) #define FlagHashCheck (1 << 20) // first 20 bits are reserved for the hash killer and extension @@ -424,32 +406,30 @@ const int MvvLvaAttackerKB[16] = {0, 0, 9, 9, 7, 7, 5, 5, 5, 5, 3, 3, 1, 1, 11, #define NBZ(me, x) ((me) ? MSBZ(x) : LSBZ(x)) typedef struct { - uint64 bb[16]; - uint8 square[64]; + uint64_t bb[16]; + uint8_t square[64]; } GBoard; __align(64) GBoard Board[1]; -uint64 Stack[2048]; +uint64_t Stack[2048]; int sp, save_sp; -uint64 nodes, check_node, check_node_smp; GBoard SaveBoard[1]; -uint64 tb_hits; typedef struct { - uint64 key, pawn_key; - uint16 move; - uint8 turn, castle_flags, ply, ep_square, piece, capture; - uint8 square[64]; - int pst, material; + uint64_t key, pawn_key; + uint16_t move; + uint8_t turn, castle_flags, ply, ep_square, piece, capture; + uint8_t square[64]; + int pst, material; } GPosData; typedef struct { - uint64 key, pawn_key, eval_key, att[2], patt[2], passer, xray[2], pin[2], threat, mask; - uint8 turn, castle_flags, ply, ep_square, capture, gen_flags, piece, stage, mul, dummy; - sint16 score; - uint16 move, killer[3], ref[2]; - int best; - int material, pst; - int margin, *start, *current; - int moves[230]; + uint64_t key, pawn_key, eval_key, att[2], patt[2], passer, xray[2], pin[2], threat, mask; + uint8_t turn, castle_flags, ply, ep_square, capture, gen_flags, piece, stage, mul, dummy; + int16_t score; + uint16_t move, killer[3], ref[2]; + int best; + int material, pst; + int margin, *start, *current; + int moves[230]; } GData; __align(64) GData Data[128]; GData *Current = Data; @@ -458,204 +438,107 @@ GData *Current = Data; GData SaveData[1]; enum { - stage_search, s_hash_move, s_good_cap, s_special, s_quiet, s_bad_cap, s_none, - stage_evasion, e_hash_move, e_ev, e_none, - stage_razoring, r_hash_move, r_cap, r_checks, r_none + stage_search, s_hash_move, s_good_cap, s_special, s_quiet, s_bad_cap, s_none, + stage_evasion, e_hash_move, e_ev, e_none, + stage_razoring, r_hash_move, r_cap, r_checks, r_none }; #define StageNone ((1 << s_none) | (1 << e_none) | (1 << r_none)) typedef struct { - uint32 key; - uint16 date; - uint16 move; - sint16 low; - sint16 high; - uint16 flags; - uint8 low_depth; - uint8 high_depth; + uint32_t key; + uint16_t date; + uint16_t move; + int16_t low; + int16_t high; + uint16_t flags; + uint8_t low_depth; + uint8_t high_depth; } GEntry; -#ifndef TUNER #define initial_hash_size (1024 * 1024) -#else -#define initial_hash_size (64 * 1024) -GEntry HashOne[initial_hash_size]; -GEntry HashTwo[initial_hash_size]; -#endif -sint64 hash_size = initial_hash_size; -uint64 hash_mask = (initial_hash_size - 4); -GEntry * Hash; +int64_t hash_size = initial_hash_size; +uint64_t hash_mask = (initial_hash_size - 4); typedef struct { - uint64 key; - sint16 shelter[2]; - uint8 passer[2], draw[2]; - int score; + uint64_t key; + int16_t shelter[2]; + uint8_t passer[2], draw[2]; + int score; } GPawnEntry; -#ifndef TUNER #define pawn_hash_size (1024 * 1024) -__align(64) GPawnEntry PawnHash[pawn_hash_size]; -#else -#define pawn_hash_size (32 * 1024) -__align(64) GPawnEntry PawnHashOne[pawn_hash_size]; -__align(64) GPawnEntry PawnHashTwo[pawn_hash_size]; -GPawnEntry * PawnHash = PawnHashOne; -#endif +#define pawnHashSize (pawn_hash_size * sizeof(GPawnEntry)) #define pawn_hash_mask (pawn_hash_size - 1) typedef struct { - uint32 key; - uint16 date; - uint16 move; - sint16 value; - sint16 exclusion; - uint8 depth; - uint8 ex_depth; - int knodes; - int ply; + uint32_t key; + uint16_t date; + uint16_t move; + int16_t value; + int16_t exclusion; + uint8_t depth; + uint8_t ex_depth; + int knodes; + int ply; } GPVEntry; -#ifndef TUNER #define pv_hash_size (1024 * 1024) -#else -#define pv_hash_size (16 * 1024) -GPVEntry PVHashOne[pv_hash_size]; -GPVEntry PVHashTwo[pv_hash_size]; -#endif #define pv_cluster_size 4 #define pv_hash_mask (pv_hash_size - pv_cluster_size) -GPVEntry * PVHash = NULL; +#define pvHashSize (pv_hash_size * sizeof(GPVEntry)) int RootList[256]; #define prefetch(a,mode) _mm_prefetch(a,mode) -uint64 Forward[2][8]; -uint64 West[8]; -uint64 East[8]; -uint64 PIsolated[8]; -uint64 HLine[64]; -uint64 VLine[64]; -uint64 NDiag[64]; -uint64 SDiag[64]; -uint64 RMask[64]; -uint64 BMask[64]; -uint64 QMask[64]; -uint64 BMagicMask[64]; -uint64 RMagicMask[64]; -uint64 NAtt[64]; -uint64 SArea[64]; -uint64 DArea[64]; -uint64 NArea[64]; -uint64 BishopForward[2][64]; -uint64 PAtt[2][64]; -uint64 PMove[2][64]; -uint64 PWay[2][64]; -uint64 PSupport[2][64]; -uint64 Between[64][64]; -uint64 FullLine[64][64]; - -#define magic_size 107648 -uint64 * MagicAttacks; -typedef struct { - sint16 score; - uint8 phase, flags; - uint8 mul[2], pieces[2]; -#ifdef TUNER - uint32 generation; -#endif -} GMaterial; -GMaterial * Material; #define FlagSingleBishop_w (1 << 0) #define FlagSingleBishop_b (1 << 1) #define FlagCallEvalEndgame_w (1 << 2) #define FlagCallEvalEndgame_b (1 << 3) -#ifndef TUNER -int Pst[16 * 64]; -#else -int PstOne[16 * 64]; -int PstTwo[16 * 64]; -int * Pst = PstOne; -#endif -#define Pst(piece,sq) Pst[((piece) << 6) | (sq)] -int MvvLva[16][16]; // [piece][capture] -uint64 TurnKey; -uint64 PieceKey[16][64]; -uint64 CastleKey[16]; -uint64 EPKey[8]; -uint16 date; - -uint64 Kpk[2][64][64]; - -#ifndef TUNER -sint16 History[16 * 64]; -#else -sint16 HistoryOne[16 * 64]; -sint16 HistoryTwo[16 * 64]; -sint16 * History = HistoryOne; -#endif +#define Pst(piece,sq) DATA->Pst[((piece) << 6) | (sq)] + +int16_t History[16 * 64]; #define HistoryScore(piece,from,to) History[((piece) << 6) | (to)] #define HistoryP(piece,from,to) ((Convert(HistoryScore(piece,from,to) & 0xFF00,int)/Convert(HistoryScore(piece,from,to) & 0x00FF,int)) << 16) #define History(from,to) HistoryP(Square(from),from,to) #define HistoryM(move) HistoryScore(Square(From(move)),From(move),To(move)) #define HistoryInc(depth) Min(((depth) >> 1) * ((depth) >> 1), 64) #define HistoryGood(move) if ((HistoryM(move) & 0x00FF) >= 256 - HistoryInc(depth)) \ - HistoryM(move) = ((HistoryM(move) & 0xFEFE) >> 1) + ((HistoryInc(depth) << 8) | HistoryInc(depth)); \ - else HistoryM(move) += ((HistoryInc(depth) << 8) | HistoryInc(depth)) + HistoryM(move) = ((HistoryM(move) & 0xFEFE) >> 1) + ((HistoryInc(depth) << 8) | HistoryInc(depth)); \ + else HistoryM(move) += ((HistoryInc(depth) << 8) | HistoryInc(depth)) #define HistoryBad(move) if ((HistoryM(move) & 0x00FF) >= 256 - HistoryInc(depth)) \ - HistoryM(move) = ((HistoryM(move) & 0xFEFE) >> 1) + HistoryInc(depth); else HistoryM(move) += HistoryInc(depth) + HistoryM(move) = ((HistoryM(move) & 0xFEFE) >> 1) + HistoryInc(depth); else HistoryM(move) += HistoryInc(depth) -#ifndef TUNER -sint16 Delta[16 * 4096]; -#else -sint16 DeltaOne[16 * 4096]; -sint16 DeltaTwo[16 * 4096]; -sint16 * Delta = DeltaOne; -#endif +int16_t Delta[16 * 4096]; #define DeltaScore(piece,from,to) Delta[((piece) << 12) | ((from) << 6) | (to)] #define Delta(from,to) DeltaScore(Square(from),from,to) #define DeltaM(move) Delta(From(move),To(move)) #define UpdateDelta if (F(Current->capture) && T(Current->move) && F(Current->move & 0xE000) && Current > Data) { \ - if (DeltaScore(Current->piece,From(Current->move),To(Current->move)) <= -Current->score - ((Current - 1)->score)) \ - DeltaScore(Current->piece,From(Current->move),To(Current->move)) = -Current->score - ((Current - 1)->score); \ - else DeltaScore(Current->piece,From(Current->move),To(Current->move))--; } + if (DeltaScore(Current->piece,From(Current->move),To(Current->move)) <= -Current->score - ((Current - 1)->score)) \ + DeltaScore(Current->piece,From(Current->move),To(Current->move)) = -Current->score - ((Current - 1)->score); \ + else DeltaScore(Current->piece,From(Current->move),To(Current->move))--; } #define DeltaMarginP(piece,from,to) (DeltaScore(piece,from,to) >= Current->margin) #define DeltaMargin(from,to) (Delta(from,to) >= Current->margin) typedef struct { - uint16 ref[2]; - uint16 check_ref[2]; + uint16_t ref[2]; + uint16_t check_ref[2]; } GRef; -#ifndef TUNER GRef Ref[16 * 64]; -#else -GRef RefOne[16 * 64]; -GRef RefTwo[16 * 64]; -GRef * Ref = RefOne; -#endif #define RefPointer(piece,from,to) Ref[((piece) << 6) | (to)] #define RefM(move) RefPointer(Square(To(move)),From(move),To(move)) #define UpdateRef(ref_move) if (T(Current->move) && RefM(Current->move).ref[0] != (ref_move)) { \ - RefM(Current->move).ref[1] = RefM(Current->move).ref[0]; RefM(Current->move).ref[0] = (ref_move); } + RefM(Current->move).ref[1] = RefM(Current->move).ref[0]; RefM(Current->move).ref[0] = (ref_move); } #define UpdateCheckRef(ref_move) if (T(Current->move) && RefM(Current->move).check_ref[0] != (ref_move)) { \ - RefM(Current->move).check_ref[1] = RefM(Current->move).check_ref[0]; RefM(Current->move).check_ref[0] = (ref_move); } - -uint64 seed = 1; -uint8 PieceFromChar[256]; -uint16 PV[128]; -char info_string[1024]; -char pv_string[1024]; -char score_string[16]; -char mstring[65536]; -int MultiPV[256]; -int pvp; -int pv_length; -int best_move, best_score; -int TimeLimit1, TimeLimit2, Console, HardwarePopCnt; -int DepthLimit, LastDepth, LastTime, LastValue, LastExactValue, PrevMove, InstCnt; -sint64 LastSpeed; -int PVN, Stop, Print, Input = 1, PVHashing = 1, Infinite, MoveTime, SearchMoves, SMPointer, Ponder, Searching, Previous; + RefM(Current->move).check_ref[1] = RefM(Current->move).check_ref[0]; RefM(Current->move).check_ref[0] = (ref_move); } + +uint64_t seed = 1; +// int MultiPV[256]; +// int pvp; +// int pv_length; +int LastDepth, LastTime, LastValue, LastExactValue, PrevMove, InstCnt; +int64_t LastSpeed; +int PVN, PVHashing = 1, SearchMoves, SMPointer, Previous; typedef struct { - int Bad, Change, Singular, Early, FailLow, FailHigh; + int Bad, Change, Singular, Early, FailLow, FailHigh; } GSearchInfo; GSearchInfo CurrentSI[1], BaseSI[1]; #ifdef CPU_TIMING @@ -663,7 +546,7 @@ int CpuTiming = 0, UciMaxDepth = 0, UciMaxKNodes = 0, UciBaseTime = 1000, UciInc int GlobalTime[2] = { 0, 0 }; int GlobalInc[2] = { 0, 0 }; int GlobalTurn = 0; -#define CyclesPerMSec Convert(3400000, sint64) +#define CyclesPerMSec Convert(3400000, int64_t) #endif int Aspiration = 1, LargePages = 1; #define TimeSingTwoMargin 20 @@ -675,8 +558,8 @@ int Aspiration = 1, LargePages = 1; #define MovesTg 30 #define InfoLag 5000 #define InfoDelay 1000 -sint64 StartTime, InfoTime, CurrTime; -uint16 SMoves[256]; +int64_t InfoTime; +uint16_t SMoves[256]; jmp_buf Jump, ResetJump; GHandle StreamHandle; @@ -688,258 +571,223 @@ GHandle StreamHandle; // EVAL -const sint8 DistC[8] = {3, 2, 1, 0, 0, 1, 2, 3}; -const sint8 RankR[8] = {-3, -2, -1, 0, 1, 2, 3, 4}; +const int8_t DistC[8] = {3, 2, 1, 0, 0, 1, 2, 3}; +const int8_t RankR[8] = {-3, -2, -1, 0, 1, 2, 3, 4}; -const int SeeValue[16] = {0, 0, 90, 90, 325, 325, 325, 325, 325, 325, 510, 510, 975, 975, 30000, 30000}; +const int SeeValue[16] = + {0, 0, 90, 90, 325, 325, 325, 325, 325, 325, 510, 510, 975, 975, + 30000, 30000}; const int PieceType[16] = {0, 0, 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 5}; -#ifndef TUNER #define V(x) (x) -#else -#define MaxVariables 1024 -int var_number, active_vars; -typedef struct { - char line[256]; -} GString; -GString SourceFile[1000], VarName[1000]; -int VarIndex[1000]; -int src_str_num = 0, var_name_num = 0; -int Variables[MaxVariables]; -uint8 Active[MaxVariables]; -double Var[MaxVariables], Base[MaxVariables], FE[MaxVariables], SE[MaxVariables], Grad[MaxVariables]; -#define V(x) Variables[x] -double EvalOne[MaxVariables], EvalTwo[MaxVariables]; -int RecordGames = 0; -char RecordString[65536], PosStr[256], *Buffer; -FILE * frec; -#endif -#define GullCpp "C:/Users/Administrator/Documents/Visual Studio 2010/Projects/Gull/Gull/Gull.cpp" #define ArrayIndex(width,row,column) (((row) * (width)) + (column)) -#ifndef TUNER #define Av(x,width,row,column) (*((x) + ArrayIndex(width,row,column))) -#else -#define Av(x,width,row,column) V((I##x) + ArrayIndex(width,row,column)) -#endif #define TrAv(x,w,r,c) Av(x,0,0,(((r)*(2*(w)-(r)+1))/2)+(c)) #define Sa(x,y) Av(x,0,0,y) #define Ca(x,y) Compose(Av(x,0,0,((y) * 2)),Av(x,0,0,((y) * 2)+1)) +#include +#include +static inline int popcount(uint64_t x) +{ + return _mm_popcnt_u64(x); +} + +#include "tbprobe.h" + // EVAL WEIGHTS // tuner: start enum { // tuner: enum - IMatLinear, - IMatQuadMe = IMatLinear + 5, - IMatQuadOpp = IMatQuadMe + 14, - IBishopPairQuad = IMatQuadOpp + 10, - IMatSpecial = IBishopPairQuad + 9, - IPstQuadWeights = IMatSpecial + 20, - IPstLinearWeights = IPstQuadWeights + 48, - IPstQuadMixedWeights = IPstLinearWeights + 48, - IMobilityLinear = IPstQuadMixedWeights + 24, - IMobilityLog = IMobilityLinear + 8, - IShelterValue = IMobilityLog + 8, - IStormQuad = IShelterValue + 15, - IStormLinear = IStormQuad + 5, - IStormHof = IStormLinear + 5, - IPasserQuad = IStormHof + 2, - IPasserLinear = IPasserQuad + 18, - IPasserAttDefQuad = IPasserLinear + 18, - IPasserAttDefLinear = IPasserAttDefQuad + 4, - IPasserSpecial = IPasserAttDefLinear + 4, - IIsolated = IPasserSpecial + 4, - IUnprotected = IIsolated + 10, - IBackward = IUnprotected + 6, - IDoubled = IBackward + 4, - IRookSpecial = IDoubled + 4, - ITactical = IRookSpecial + 20, - IKingDefence = ITactical + 12, - IPawnSpecial = IKingDefence + 8, - IBishopSpecial = IPawnSpecial + 8, - IKnightSpecial = IBishopSpecial + 4, - IPin = IKnightSpecial + 10, - IKingRay = IPin + 10, - IKingAttackWeight = IKingRay + 6 + IMatLinear, + IMatQuadMe = IMatLinear + 5, + IMatQuadOpp = IMatQuadMe + 14, + IBishopPairQuad = IMatQuadOpp + 10, + IMatSpecial = IBishopPairQuad + 9, + IPstQuadWeights = IMatSpecial + 20, + IPstLinearWeights = IPstQuadWeights + 48, + IPstQuadMixedWeights = IPstLinearWeights + 48, + IMobilityLinear = IPstQuadMixedWeights + 24, + IMobilityLog = IMobilityLinear + 8, + IShelterValue = IMobilityLog + 8, + IStormQuad = IShelterValue + 15, + IStormLinear = IStormQuad + 5, + IStormHof = IStormLinear + 5, + IPasserQuad = IStormHof + 2, + IPasserLinear = IPasserQuad + 18, + IPasserAttDefQuad = IPasserLinear + 18, + IPasserAttDefLinear = IPasserAttDefQuad + 4, + IPasserSpecial = IPasserAttDefLinear + 4, + IIsolated = IPasserSpecial + 4, + IUnprotected = IIsolated + 10, + IBackward = IUnprotected + 6, + IDoubled = IBackward + 4, + IRookSpecial = IDoubled + 4, + ITactical = IRookSpecial + 20, + IKingDefence = ITactical + 12, + IPawnSpecial = IKingDefence + 8, + IBishopSpecial = IPawnSpecial + 8, + IKnightSpecial = IBishopSpecial + 4, + IPin = IKnightSpecial + 10, + IKingRay = IPin + 10, + IKingAttackWeight = IKingRay + 6 }; const int Phase[5] = { - 0, 325, 325, 510, 975 + 0, 325, 325, 510, 975 }; #define MaxPhase (16 * Phase[0] + 4 * Phase[1] + 4 * Phase[2] + 4 * Phase[3] + 2 * Phase[4]) #define PhaseMin (2 * Phase[3] + Phase[1] + Phase[2]) #define PhaseMax (MaxPhase - Phase[1] - Phase[2]) const int MatLinear[5] = { // tuner: type=array, var=50, active=0 - 3, 0, 3, 19, 0 + 3, 0, 3, 19, 0 }; // pawn, knight, bishop, rook, queen const int MatQuadMe[14] = { // tuner: type=array, var=1000, active=0 - -33, 17, -23, -155, -247, - 15, 296, -105, -83, - -162, 327, 315, - -861, -1013 + -33, 17, -23, -155, -247, + 15, 296, -105, -83, + -162, 327, 315, + -861, -1013 }; const int MatQuadOpp[10] = { // tuner: type=array, var=1000, active=0 - -14, 47, -20, -278, - 35, 39, 49, - 9, -2, - 75 + -14, 47, -20, -278, + 35, 39, 49, + 9, -2, + 75 }; const int BishopPairQuad[9] = { // tuner: type=array, var=1000, active=0 - -38, 164, 99, 246, -84, -57, -184, 88, -186 + -38, 164, 99, 246, -84, -57, -184, 88, -186 }; enum { MatRB, MatRN, MatQRR, MatQRB, MatQRN, MatQ3, MatBBR, MatBNR, MatNNR, MatM }; const int MatSpecial[20] = { // tuner: type=array, var=30, active=0 - 13, -13, 10, -9, 8, 12, 4, 6, 5, 9, -3, -8, -4, 7, 2, 0, 0, -6, 1, 3 + 13, -13, 10, -9, 8, 12, 4, 6, 5, 9, -3, -8, -4, 7, 2, 0, 0, -6, 1, 3 }; // piece type (6) * direction (4: h center dist, v center dist, diag dist, rank) * phase (2) const int PstQuadWeights[48] = { // tuner: type=array, var=100, active=0 - -15, -19, -70, -13, 33, -20, 0, 197, -36, -122, 0, -60, -8, -3, -17, -28, - -27, -63, -17, -7, 14, 0, -24, -5, -64, -2, 0, -38, -8, 0, 77, 11, - -67, 3, -4, -92, -2, 12, -13, -42, -62, -84, -175, -42, -2, -17, 40, -19 + -15, -19, -70, -13, 33, -20, 0, 197, -36, -122, 0, -60, -8, -3, -17, -28, + -27, -63, -17, -7, 14, 0, -24, -5, -64, -2, 0, -38, -8, 0, 77, 11, + -67, 3, -4, -92, -2, 12, -13, -42, -62, -84, -175, -42, -2, -17, 40, -19 }; const int PstLinearWeights[48] = { // tuner: type=array, var=500, active=0 - -107, 67, -115, 83, -55, 67, 92, 443, -177, 5, -82, -61, -106, -104, 273, 130, - 0, -145, -105, -58, -99, -37, -133, 14, -185, -43, -67, -53, 53, -65, 174, 134, - -129, 7, 98, -231, 107, -40, -27, 311, 256, -117, 813, -181, 2, -215, -44, 344 + -107, 67, -115, 83, -55, 67, 92, 443, -177, 5, -82, -61, -106, -104, 273, 130, + 0, -145, -105, -58, -99, -37, -133, 14, -185, -43, -67, -53, 53, -65, 174, 134, + -129, 7, 98, -231, 107, -40, -27, 311, 256, -117, 813, -181, 2, -215, -44, 344 }; // piece type (6) * type (2: h * v, h * rank) * phase (2) const int PstQuadMixedWeights[24] = { // tuner: type=array, var=100, active=0 - 14, -6, 1, -4, -8, -2, 4, -4, - 1, -7, -12, 0, -2, -1, -5, 4, - 5, -10, 0, 4, -2, 5, 4, -2 + 14, -6, 1, -4, -8, -2, 4, -4, + 1, -7, -12, 0, -2, -1, -5, 4, + 5, -10, 0, 4, -2, 5, 4, -2 }; // piece type (4) * phase (2) const int MobilityLinear[8] = { // tuner: type=array, var=300, active=0 - 328, 171, 311, 102, 284, 164, 155, 288 + 328, 171, 311, 102, 284, 164, 155, 288 }; const int MobilityLog[8] = { // tuner: type=array, var=500, active=0 - 485, -21, 388, 389, -168, 313, 438, -276 + 485, -21, 388, 389, -168, 313, 438, -276 }; -int Mobility[4][32]; // file type (3) * distance from 2d rank/open (5) const int ShelterValue[15] = { // tuner: type=array, var=10, active=0 - 2, 9, 11, 0, 0, 12, 18, 11, 0, 2, 24, 7, 8, 0, 0 + 2, 9, 11, 0, 0, 12, 18, 11, 0, 2, 24, 7, 8, 0, 0 }; -sint16 Shelter[3][8]; enum { StormBlockedMul, StormShelterAttMul, StormConnectedMul, StormOpenMul, StormFreeMul }; const int StormQuad[5] = { // tuner: type=array, var=250, active=0 - 126, 328, 463, 215, 89 + 126, 328, 463, 215, 89 }; const int StormLinear[5] = { // tuner: type=array, var=500, active=0 - 83, 156, 438, 321, 12 + 83, 156, 438, 321, 12 }; enum { StormHofValue, StormOfValue }; const int StormHof[2] = { // tuner: type=array, var=20, active=1 - 0, 22 + 0, 22 }; -sint16 StormBlocked[4]; -sint16 StormShelterAtt[4]; -sint16 StormConnected[4]; -sint16 StormOpen[4]; -sint16 StormFree[4]; // type (7: general, blocked, free, supported, protected, connected, outside, candidate, clear) * phase (2) const int PasserQuad[18] = { // tuner: type=array, var=50, active=0 - 19, 13, 21, 3, -24, 126, 0, 65, 32, 56, 27, -5, 32, -16, 13, 4, 1, 1 + 19, 13, 21, 3, -24, 126, 0, 65, 32, 56, 27, -5, 32, -16, 13, 4, 1, 1 }; const int PasserLinear[18] = { // tuner: type=array, var=200, active=0 - 41, 2, 111, 86, 178, 113, 202, 15, -61, 21, 93, 166, 86, 92, 27, 34, -18, -7 + 41, 2, 111, 86, 178, 113, 202, 15, -61, 21, 93, 166, 86, 92, 27, 34, -18, -7 }; // type (2: att, def) * scaling (2: linear, log) const int PasserAttDefQuad[4] = { // tuner: type=array, var=500, active=0 - 191, 51, 83, 19 + 191, 51, 83, 19 }; const int PasserAttDefLinear[4] = { // tuner: type=array, var=500, active=0 - 634, 4, 233, 66 + 634, 4, 233, 66 }; enum { PasserOnePiece, PasserOpKingControl, PasserOpMinorControl, PasserOpRookBlock }; const int PasserSpecial[4] = { // tuner: type=array, var=100, active=0 - 0, 0, 0, 13 + 0, 0, 0, 13 }; -uint8 LogDist[16]; -int PasserGeneral[8]; -int PasserBlocked[8]; -int PasserFree[8]; -int PasserSupported[8]; -int PasserProtected[8]; -int PasserConnected[8]; -int PasserOutside[8]; -int PasserCandidate[8]; -int PasserClear[8]; -sint16 PasserAtt[8]; -sint16 PasserDef[8]; -sint16 PasserAttLog[8]; -sint16 PasserDefLog[8]; - enum { IsolatedOpen, IsolatedClosed, IsolatedBlocked, IsolatedDoubledOpen, IsolatedDoubledClosed }; const int Isolated[10] = { // tuner: type=array, var=10, active=0 - 6, 6, 8, 2, -8, 0, -1, 10, 7, 9 + 6, 6, 8, 2, -8, 0, -1, 10, 7, 9 }; enum { UpBlocked, PasserTarget, ChainRoot }; const int Unprotected[6] = { // tuner: type=array, var=10, active=0 - 4, 5, -5, -1, 9, -1 + 4, 5, -5, -1, 9, -1 }; enum { BackwardOpen, BackwardClosed }; const int Backward[4] = { // tuner: type=array, var=10, active=0 - 17, 10, 4, 1 + 17, 10, 4, 1 }; enum { DoubledOpen, DoubledClosed }; const int Doubled[4] = { // tuner: type=array, var=10, active=0 - 3, 0, 1, 0 + 3, 0, 1, 0 }; enum { RookHof, RookHofWeakPAtt, RookOf, RookOfOpen, RookOfMinorFixed, RookOfMinorHaging, RookOfKingAtt, Rook7th, Rook7thK8th, Rook7thDoubled }; const int RookSpecial[20] = { // tuner: type=array, var=10, active=0 - 8, 0, 2, 0, 11, 8, -1, 2, -1, -1, 14, -1, 5, -5, -5, 0, -6, 8, -7, 31 + 8, 0, 2, 0, 11, 8, -1, 2, -1, -1, 14, -1, 5, -5, -5, 0, -6, 8, -7, 31 }; enum { TacticalMajorPawn, TacticalMinorPawn, TacticalMajorMinor, TacticalMinorMinor, TacticalThreat, TacticalDoubleThreat }; const int Tactical[12] = { // tuner: type=array, var=20, active=0 - -1, 5, 0, 5, 11, 29, 23, 32, 19, 11, 41, 12 + -1, 5, 0, 5, 11, 29, 23, 32, 19, 11, 41, 12 }; enum { KingDefKnight, KingDefBishop, KingDefRook, KingDefQueen }; const int KingDefence[8] = { // tuner: type=array, var=5, active=0 - 2, 0, 0, 1, 0, 0, 4, 0 + 2, 0, 0, 1, 0, 0, 4, 0 }; enum { PawnChainLinear, PawnChain, PawnBlocked, PawnFileSpan }; const int PawnSpecial[8] = { // tuner: type=array, var=10, active=0 - 11, 9, 9, 4, 0, 9, 1, 1 + 11, 9, 9, 4, 0, 9, 1, 1 }; enum { BishopNonForwardPawn, BishopPawnBlock }; const int BishopSpecial[4] = { // tuner: type=array, var=5, active=0 - 0, 0, 0, 3 + 0, 0, 0, 3 }; -const uint64 Outpost[2] = { Convert(0x00007E7E3C000000, uint64), Convert(0x0000003C7E7E0000, uint64) }; +const uint64_t Outpost[2] = { Convert(0x00007E7E3C000000, uint64_t), Convert(0x0000003C7E7E0000, uint64_t) }; enum { KnightOutpost, KnightOutpostProtected, KnightOutpostPawnAtt, KnightOutpostBishopAtt, KnightOutpostKingAtt }; const int KnightSpecial[10] = { // tuner: type=array, var=10, active=0 - 11, 7, 23, 0, 13, 6, 1, 5, 26, 6 + 11, 7, 23, 0, 13, 6, 1, 5, 26, 6 }; enum { WeakPin, StrongPin, ThreatPin, SelfPawnPin, SelfPiecePin }; const int Pin[10] = { // tuner: type=array, var=20, active=0 - 21, 39, 6, 80, 45, 29, 8, 9, 48, 27 + 21, 39, 6, 80, 45, 29, 8, 9, 48, 27 }; enum { QKingRay, RKingRay, BKingRay }; const int KingRay[6] = { // tuner: type=array, var=20, active=0 - 4, 8, -4, 11, 11, -3 + 4, 8, -4, 11, 11, -3 }; const int KingAttackWeight[7] = { // tuner: type=array, var=20, active=0 - 17, 14, 22, 45, 48, 64, 64 + 17, 14, 22, 45, 48, 64, 64 }; #define KingNAttack Compose(1, Av(KingAttackWeight, 0, 0, 0)) #define KingBAttack Compose(1, Av(KingAttackWeight, 0, 0, 1)) @@ -955,114 +803,99 @@ const int KingAttackScale[16] = { 0, 1, 4, 9, 16, 25, 36, 49, 64, 64, 64, 64, 64 // END EVAL WEIGHTS -// SMP - -#define MaxPrN 1 -#ifndef DEBUG -#ifndef TUNER -#undef MaxPrN -#ifndef W32_BUILD -#define MaxPrN 64 // mustn't exceed 64 -#else -#define MaxPrN 32 // mustn't exceed 32 -#endif -#endif -#endif - -int PrN = 1, CPUs = 1, HT = 0, parent = 1, child = 0, WinParId, Id = 0, ResetHash = 1, NewPrN = 0; -GProcess ChildPr[MaxPrN]; -#define SplitDepth 10 -#define SplitDepthPV 4 -#define MaxSplitPoints 64 // mustn't exceed 64 - typedef struct { - GPosData Position[1]; - uint64 stack[100]; - uint16 killer[16][2]; - int sp, date; + GPosData Position[1]; + uint64_t stack[100]; + uint16_t killer[16][2]; + int sp, date; } GPos; #define FlagClaimed (1 << 1) #define FlagFinished (1 << 2) -typedef struct { - volatile uint16 move; - volatile uint8 reduced_depth, research_depth, stage, ext, id, flags; -} GMove; - -typedef struct { - volatile long int lock; - volatile int claimed, active, finished, pv, move_number, current, depth, alpha, beta, singular, split, best_move, height; - GMove move[128]; - jmp_buf jump; - GPos Pos[1]; -} GSP; - -typedef struct { - volatile long long nodes, active_sp, searching; -#ifndef W32_BUILD - volatile long long stop, fail_high; -#else - volatile long stop, fail_high; -#endif - volatile long long tb_hits; - volatile sint64 hash_size; - volatile int PrN; - GSP Sp[MaxSplitPoints]; -#if TB - char tb_path[1024]; -#endif -} GSMPI; - -#define SharedMaterialOffset (sizeof(GSMPI)) -#define SharedMagicOffset (SharedMaterialOffset + TotalMat * sizeof(GMaterial)) -#define SharedPVHashOffset (SharedMagicOffset + magic_size * sizeof(uint64)) - -GSMPI * Smpi; +#define STOPPED 0 + +typedef struct +{ + volatile bool stop; + bool newGame; + size_t nodes; + size_t tbHits; + int pid; + int id; + int depth; + int selDepth; + int bestMove; + int bestScore; + int PV[]; +} GThreadInfo; +#define MAX_PV_LEN ((PAGE_SIZE - sizeof(GThreadInfo)) / sizeof(int)) + +typedef struct +{ + unsigned numThreads; + unsigned syzygyProbeDepth; + size_t hashSize; +} GSettings; + +typedef struct +{ + int state; + int init; + uint16_t date; + GMutex mutex; + GCondVar goCondVar; + GCondVar initCondVar; + unsigned rootDepth; + unsigned depthLimit; + uint64_t startTime; + uint64_t softTimeLimit; + uint64_t hardTimeLimit; + volatile bool ponder; + GBoard rootBoard; + GData rootData; + unsigned rootSp; + uint64_t rootStack[1024]; +} GSharedInfo; + +static const uint32_t Schedule[] = +{ + 0x00FFFFFF, + 0x00555555, + 0x00AAAAAA, + 0x00333333, + 0x00666666, + 0x00CCCCCC, + 0x001C71C7, + 0x0038E38E, + 0x0071C71C, + 0x00E38E38, + 0x00C71C71, + 0x008E38E3, + 0x000F0F0F, + 0x001E1E1E, + 0x003C3C3C, + 0x00787878, + 0x00F0F0F0, + 0x00E1E1E1, + 0x00C3C3C3, + 0x00878787 +}; jmp_buf CheckJump; -GHandle SHARED = NULL, HASH = NULL; - -#ifndef W32_BUILD -#define SET_BIT(var,bit) (builtin_sync_fetch_and_or(&(var),1 << (bit))) -#define SET_BIT_64(var,bit) (builtin_sync_fetch_and_or(&(var),Bit(bit))); -#define ZERO_BIT_64(var,bit) (builtin_sync_fetch_and_and(&(var),~Bit(bit))); -#define TEST_RESET_BIT(var,bit) (builtin_sync_bit_test_and_reset(&(var),bit)) -#define TEST_RESET(var) (builtin_sync_lock_test_and_set(&(var),0)) -#else -#define SET_BIT(var,bit) (builtin_sync_fetch_and_or(&(var),1 << (bit))) -#define SET_BIT_64(var,bit) {if ((bit) < 32) builtin_sync_fetch_and_or((LONG*)&(var),1 << (bit)); else builtin_sync_fetch_and_or(((LONG*)(&(var))) + 1,1 << ((bit) - 32));} -#define ZERO_BIT_64(var,bit) {if ((bit) < 32) builtin_sync_fetch_and_and((LONG*)&(var),~(1 << (bit))); else builtin_sync_fetch_and_and(((LONG*)(&(var))) + 1,~(1 << ((bit) - 32)));} -#define TEST_RESET_BIT(var,bit) (builtin_sync_bit_test_and_reset(&(var),bit)) -#define TEST_RESET(var) (builtin_sync_lock_test_and_set(&(var),0)) -#endif -#define SET(var,value) (builtin_sync_lock_test_and_set(&(var),value)) - -#define LOCK(lock) {while (builtin_sync_val_compare_and_swap(&(lock),1,0)) _mm_pause();} -#define UNLOCK(lock) {SET(lock,0);} - -// END SMP - -__forceinline int lsb(uint64 x); -__forceinline int msb(uint64 x); -__forceinline int popcnt(uint64 x); -__forceinline int MinF(int x, int y); -__forceinline int MaxF(int x, int y); -__forceinline double MinF(double x, double y); -__forceinline double MaxF(double x, double y); -template __forceinline int popcount(uint64 x); -uint64 BMagicAttacks(int i, uint64 occ); -uint64 RMagicAttacks(int i, uint64 occ); -uint16 rand16(); -uint64 rand64(); -void init_pst(); -void init_eval(); -void init(); +inline int lsb(uint64_t x); +inline int msb(uint64_t x); +inline int popcount(uint64_t x); +inline int MinF(int x, int y); +inline int MaxF(int x, int y); +inline double MinF(double x, double y); +inline double MaxF(double x, double y); +uint16_t rand16(void); +uint64_t rand64(void); void init_search(int clear_hash); void setup_board(); -void get_board(const char fen[]); -void init_hash(); +const char *get_board(const char fen[]); void move_to_string(int move, char string[]); int move_from_string(char string[]); void pick_pv(); @@ -1070,13 +903,13 @@ template void do_move(int move); template void undo_move(int move); void do_null(); void undo_null(); -__forceinline void evaluate(); +inline void evaluate(); template int is_legal(int move); template int is_check(int move); void hash_high(int value, int depth); void hash_low(int move, int value, int depth); void hash_exact(int move, int value, int depth, int exclusion, int ex_depth, int knodes); -__forceinline int pick_move(); +inline int pick_move(); template int get_move(); template int see(int move, int margin); template void gen_root_moves(); @@ -1094,21 +927,26 @@ template int pv_search(int alpha, int beta, int depth, int template void root(); template int multipv(int depth); void send_pv(int depth, int alpha, int beta, int score); +static void send_pv(const int *PV, size_t nodes, size_t tbHits, int depth, + int selDepth, int bestScore, int bestMove, uint64_t startTime); void send_multipv(int depth, int curr_number); -void send_best_move(); -void get_position(char string[]); -void get_time_limit(char string[]); -sint64 get_time(); +static void send_curr_move(int move, int cnt); +static void send_best_move(); +static void send_best_move(const int *PV, size_t nodes, size_t tbHits, + int bestScore, int bestMove, uint64_t startTime); +int64_t get_time(); int time_to_stop(GSearchInfo * SI, int time, int searching); -void check_time(int searching); -void check_time(int time, int searching); -void check_state(); -int input(); +static void emergency_stop(void); void uci(); +void send_position(GPos * Pos); +void retrieve_position(GPos * Pos, int copy_stack); +static void nuke_children(void); +static void create_children(size_t numThreads, size_t syzygyProbeDepth, + size_t hashSize, const char *tbPath); +static void reset(size_t numThreads, size_t syzygyProbeDepth, size_t hashSize, + const char *tbPath); -#ifdef TB #include "tbprobe.h" -#endif #ifdef LINUX #include "Linux.cpp" @@ -1118,1704 +956,389 @@ void uci(); #include "Windows.cpp" #endif -#ifdef TUNER -#ifndef RECORD_GAMES -int ResignThreshold = 150; -#else -int ResignThreshold = 1500; -#endif - -typedef struct { - int wins, draws, losses; -} GMatchInfo; -GMatchInfo MatchInfo[1] = {(0, 0, 0)}; - -char Fen[65536][128]; -int opening_positions = 0; - -int Client = 0, Server = 0, Local = 1, cmd_number = 0; -int generation = 0; - -#ifdef PGN -typedef struct { - uint64 bb[6]; // white, black, pawns, minor, major, queens and knights - uint8 ep_square, turn, ply, castle_flags; -} GPos; -GPos Pos[65536]; -int pgn_positions = 0; - -void position_to_pos(GPos * pos) { - pos->bb[0] = Piece(White); - pos->bb[1] = Piece(Black); - pos->bb[2] = PawnAll; - pos->bb[3] = Minor(White) | Minor(Black); - pos->bb[4] = Major(White) | Major(Black); - pos->bb[5] = Queen(White) | Queen(Black) | Knight(White) | Knight(Black); - pos->ep_square = Current->ep_square; - pos->turn = Current->turn; - pos->castle_flags = Current->castle_flags; -} - -void position_from_pos(GPos * pos) { - Current = Data; - memset(Board, 0, sizeof(GBoard)); - memset(Current, 0, sizeof(GData)); - BB(White) = pos->bb[0]; - BB(Black) = pos->bb[1]; - for (int me = 0; me < 2; me++) { - BB(me) = pos->bb[me]; - BB(IPawn(me)) = pos->bb[2] & BB(me); - BB(IKnight(me)) = pos->bb[3] & pos->bb[5] & BB(me); - BB(ILight(me)) = pos->bb[3] & (~pos->bb[5]) & LightArea & BB(me); - BB(IDark(me)) = pos->bb[3] & (~pos->bb[5]) & DarkArea & BB(me); - BB(IRook(me)) = pos->bb[4] & (~pos->bb[5]) & BB(me); - BB(IQueen(me)) = pos->bb[4] & pos->bb[5] & BB(me); - BB(IKing(me)) = BB(me) & (~(pos->bb[2] | pos->bb[3] | pos->bb[4])); - } - for (int i = 2; i < 16; i++) for (uint64 u = BB(i); u; Cut(u)) Square(lsb(u)) = i; - Current->ep_square = pos->ep_square; - Current->ply = pos->ply; - Current->castle_flags = pos->castle_flags; - Current->turn = pos->turn; - setup_board(); -} - -int pos_shelter_tune() { - if (!Queen(White) || !Queen(Black)) return 0; - if (popcnt(NonPawnKingAll) < 10) return 0; - if (Current->castle_flags) return 0; - if (File(lsb(King(White))) <= 2 && File(lsb(King(Black))) >= 5) return 1; - if (File(lsb(King(White))) >= 5 && File(lsb(King(Black))) <= 2) return 1; - return 0; -} -int pos_passer_tune() { - if (Current->passer) return 1; - return 0; -} -#endif - -void init_openings() { - FILE * ffen = NULL; - ffen = fopen("8moves.epd","r"); - if (ffen != NULL) { - for (int i = 0; i < 65536; i++) { - fgets(Fen[i],128,ffen); - if (feof(ffen)) { - opening_positions = Max(opening_positions - 1, 0); - break; - } else opening_positions++; - } - } else { - fprintf(stdout,"File '8moves.epd' not found\n"); - exit(0); - goto no_fen; - } - fclose(ffen); -no_fen: - if (opening_positions == 0) { - sprintf(Fen[0],"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1\n"); - opening_positions = 1; - } -#ifdef PGN - FILE * fpgn = fopen("uci_games.pgn", "r"); - if (fpgn == NULL) { - fprintf(stdout, "File 'uci_games.pgn' not found\n"); - exit(0); - } - while (pgn_positions < 65536) { - fgets(mstring, 65536, fpgn); - if (feof(fpgn)) { - pgn_positions = Max(pgn_positions - 1, 0); - break; - } - if (strstr(mstring, "FEN")) get_board(mstring + 6); - if (strchr(mstring, '[')) continue; - if (strlen(mstring) < 100) continue; - char * ptr = mstring; - while (*ptr != 0) { - evaluate(); - if (pos_passer_tune()) { - position_to_pos(&Pos[pgn_positions++]); - break; - } - pv_string[0] = *ptr++; - pv_string[1] = *ptr++; - pv_string[2] = *ptr++; - pv_string[3] = *ptr++; - if (*ptr == 0 || *ptr == ' ') pv_string[4] = 0; - else { - pv_string[4] = *ptr++; - pv_string[5] = 0; - } - if (pv_string[0] == '1' || pv_string[0] == '0') break; - int move = move_from_string(pv_string); - if (Current->turn) { - if (!is_legal<1>(move)) break; - do_move<1>(move); - } else { - if (!is_legal<0>(move)) break; - do_move<0>(move); - } - memcpy(Data, Current, sizeof(GData)); - Current = Data; - while (*ptr == ' ') ptr++; - } - } - fclose(fpgn); - fprintf(stdout, "%d PGN positions\n", pgn_positions); -#endif -} -void init_variables() { - int i, j, k, start = 0; - FILE * f; - - if (Local) f = fopen(GullCpp, "r"); - else if (Server) f = fopen("./Server/Gull.cpp", "r"); - else f = fopen("./Client/Gull.cpp", "r"); - while (!feof(f)) { - (void)fgets(mstring, 256, f); - if (!start && memcmp(mstring, "// tuner: start", 15)) continue; - start = 1; - if (!memcmp(mstring, "// tuner: stop", 14)) break; - memcpy(SourceFile[src_str_num].line, mstring, 256); - src_str_num++; - } - fclose(f); - - var_number = 0; - active_vars = 0; - - int curr_ind = -1, active, indexed[MaxVariables]; - double var; - char *p, *q; - memset(VarName, 0, 1000 * sizeof(GString)); memset(indexed, 0, MaxVariables * sizeof(int)); - for (i = 0; i < src_str_num; i++) { - if (!strstr(SourceFile[i].line, "tuner: enum")) continue; - for (i++; !strstr(SourceFile[i].line, "};"); i++) { - p = strchr(SourceFile[i].line, 'I') + 1; - strcpy(VarName[var_name_num].line, p); - for (j = 0; VarName[var_name_num].line[j] >= '0' && VarName[var_name_num].line[j] <= 'z'; j++); - VarName[var_name_num].line[j] = '\n'; - for (k = j + 1; k < 1000; k++) VarName[var_name_num].line[k] = 0; - q = strchr(p, '+'); - if (q != NULL) curr_ind += atoi(q + 1); - else curr_ind++; - VarIndex[var_name_num] = curr_ind; - var_name_num++; - } - break; - } - for (i = 0; i < src_str_num; i++) { - if (!(p = strstr(SourceFile[i].line, "tuner:"))) continue; - q = strstr(p, "type="); if (q == NULL) continue; q += 5; - p = strstr(q, "active="); - if (p == NULL) active = 1; - else active = atoi(p + 7); - uint8 active_mask[1024]; - memset(active_mask, 1, 1024); - if (p = strstr(q, "mask=")) { - p += 5; - j = 0; - while (p[0] != ' ') { - int value = 0; if (p[0] == 's') value = 1; - if (p[1] == '&') { - if (value == 1) break; - for (k = j; k < 1024; k++) active_mask[k] = 0; - break; - } - for (k = 0; k < p[1] - '0'; k++) active_mask[j + k] = value; - j += p[1] - '0'; - p += 2; - } - } - p = strstr(q, "var="); - if (p == NULL) var = 1000.0; - else var = (double)atoi(p + 4); - if (!memcmp(q, "array", 5)) { - p = strstr(SourceFile[i].line, "int "); p += 4; - q = strchr(p, '['); - for (j = 0; j < var_name_num; j++) if (!memcmp(p, VarName[j].line, (int)(q - p))) break; - curr_ind = VarIndex[j]; - fprintf(stdout, "Array (%d) active=%d var=%.2lf: %s", curr_ind, active, var, VarName[j].line); - } - i++; - memset(mstring, 0, strlen(mstring)); - while (!strstr(SourceFile[i].line, "};")) { - strcat(mstring, SourceFile[i].line); - i++; - } - i--; - p = mstring - 1; - int cnt = 0; - do { - p++; - Variables[curr_ind] = atoi(p); var_number++; - if (indexed[curr_ind]) { fprintf(stdout, "index mismatch: %d (%s)\n", curr_ind, VarName[j].line); exit(0); } - indexed[curr_ind]++; - int activate = 0; - if (active && active_mask[cnt]) activate = 1; - if (activate) Var[active_vars] = var; - Active[curr_ind++] = activate; active_vars += activate; cnt++; - } while (p = strchr(p, ',')); - } - for (i = 0; i < curr_ind; i++) if (!indexed[i]) { fprintf(stdout, "index skipped %d\n", i); exit(0); } - fprintf(stdout, "%d variables, %d active\n", var_number, active_vars); -} -void eval_to_cpp(const char * filename, double * list) { - FILE * f = fopen(filename, "w"); - for (int i = 0; i < var_name_num; i++) VarName[i].line[strlen(VarName[i].line) - 1] = 0; - for (int i = 0; i < src_str_num; i++) { - fprintf(f, "%s", SourceFile[i].line); - if (!strstr(SourceFile[i].line, "type=array") || strstr(SourceFile[i].line, "active=0")) continue; - for (int j = 0; j < var_name_num; j++) if (strstr(SourceFile[i].line, VarName[j].line)) { - int n = 0; -start: - i++; - fprintf(f, " "); - int cnt = 0, index = 0; for (int k = 0; k < VarIndex[j]; k++) if (Active[k]) index++; - char * p = SourceFile[i].line, *end; - while ((p = strchr(p+1, ',')) != NULL) cnt++; if (end = strstr(SourceFile[i + 1].line, "};")) cnt++; - for (int k = 0; k < cnt; k++) { - fprintf(f, "%d", (int)list[index + (n++)]); - if (k + 1 < cnt) fprintf(f, ", "); - else if (end == NULL) fprintf(f, ",\n"); - else fprintf(f, "\n"); - } - if (end == NULL) goto start; - } - } - fclose(f); -} -void print_eval() { - int i, j; - FILE * f = fopen("eval.txt", "w"); - fprintf(f, "Pst\n"); - for (j = 2; j < 16; j += 2) { - if (j == 8) continue; - fprintf(f, "%d:\n", j); - for (i = 0; i < 64; i++) { - fprintf(f, "(%d,%d), ", Opening(Pst(j, i)), Endgame(Pst(j, i))); - if ((i + 1) % 8 == 0) fprintf(f, "\n"); - } - } - fprintf(f, "Mobility\n"); - for (j = 0; j < 4; j++) { - fprintf(f, "%d:\n", j); - for (i = 0; i < 32; i++) fprintf(f, "(%d,%d), ", Opening(Mobility[j][i]), Endgame(Mobility[j][i])); - fprintf(f, "\n"); - } - fprintf(f, "PasserGeneral\n"); - for (i = 0; i < 8; i++) fprintf(f, "(%d,%d), ", Opening(PasserGeneral[i]), Endgame(PasserGeneral[i])); - fprintf(f, "\n"); - - fprintf(f, "PasserBlocked\n"); - for (i = 0; i < 8; i++) fprintf(f, "(%d,%d), ", Opening(PasserBlocked[i]), Endgame(PasserBlocked[i])); - fprintf(f, "\n"); - - fprintf(f, "PasserFree\n"); - for (i = 0; i < 8; i++) fprintf(f, "(%d,%d), ", Opening(PasserFree[i]), Endgame(PasserFree[i])); - fprintf(f, "\n"); - - fprintf(f, "PasserSupported\n"); - for (i = 0; i < 8; i++) fprintf(f, "(%d,%d), ", Opening(PasserSupported[i]), Endgame(PasserSupported[i])); - fprintf(f, "\n"); - - fprintf(f, "PasserProtected\n"); - for (i = 0; i < 8; i++) fprintf(f, "(%d,%d), ", Opening(PasserProtected[i]), Endgame(PasserProtected[i])); - fprintf(f, "\n"); - - fprintf(f, "PasserConnected\n"); - for (i = 0; i < 8; i++) fprintf(f, "(%d,%d), ", Opening(PasserConnected[i]), Endgame(PasserConnected[i])); - fprintf(f, "\n"); - - fprintf(f, "PasserOutside\n"); - for (i = 0; i < 8; i++) fprintf(f, "(%d,%d), ", Opening(PasserOutside[i]), Endgame(PasserOutside[i])); - fprintf(f, "\n"); - - fprintf(f, "PasserCandidate\n"); - for (i = 0; i < 8; i++) fprintf(f, "(%d,%d), ", Opening(PasserCandidate[i]), Endgame(PasserCandidate[i])); - fprintf(f, "\n"); - - fprintf(f, "PasserClear\n"); - for (i = 0; i < 8; i++) fprintf(f, "(%d,%d), ", Opening(PasserClear[i]), Endgame(PasserClear[i])); - fprintf(f, "\n"); - - fprintf(f, "PasserAtt\n"); - for (i = 0; i < 8; i++) fprintf(f, "%d, ", PasserAtt[i]); - fprintf(f, "\n"); - - fprintf(f, "PasserDef\n"); - for (i = 0; i < 8; i++) fprintf(f, "%d, ", PasserDef[i]); - fprintf(f, "\n"); - - fprintf(f, "PasserAttLog\n"); - for (i = 0; i < 8; i++) fprintf(f, "%d, ", PasserAttLog[i]); - fprintf(f, "\n"); - - fprintf(f, "PasserDefLog\n"); - for (i = 0; i < 8; i++) fprintf(f, "%d, ", PasserDefLog[i]); - fprintf(f, "\n"); - - fprintf(f, "StormBlocked\n"); - for (i = 0; i < 4; i++) fprintf(f, "%d, ", StormBlocked[i]); - fprintf(f, "\n"); - - fprintf(f, "StormShelterAtt\n"); - for (i = 0; i < 4; i++) fprintf(f, "%d, ", StormShelterAtt[i]); - fprintf(f, "\n"); - - fprintf(f, "StormConnected\n"); - for (i = 0; i < 4; i++) fprintf(f, "%d, ", StormConnected[i]); - fprintf(f, "\n"); - - fprintf(f, "StormOpen\n"); - for (i = 0; i < 4; i++) fprintf(f, "%d, ", StormOpen[i]); - fprintf(f, "\n"); - - fprintf(f, "StormFree\n"); - for (i = 0; i < 4; i++) fprintf(f, "%d, ", StormFree[i]); - fprintf(f, "\n"); - - fclose(f); -} - -double ratio_from_elo(double elo) { return 1.0 / (1.0 + exp(((-elo) / 400.0)*log(10.0))); } -double elo_from_ratio(double ratio) { return -(log((1.0 / MinF(0.99999, Max(ratio, 0.00001))) - 1.0) / log(10.0)) * 400.0; } -double rand_u() { return MinF(1.0, Max(0.0, ((double)((rand() << 15) | rand())) / (32768.0 * 32768.0))); } -double gaussian(double mean, double sigma) { return sqrt(Max(0.0000001, -2.0 * log(Max(0.0000001, rand_u())))) * sin(2.0 * 3.14159265358979323846 * rand_u()) * sigma + mean; } -void int_to_double(double * dst, int * src, int n) {for (int i = 0; i < n; i++) dst[i] = (double)src[i];} -void double_to_int(int * dst, double * src, int n) {for (int i = 0; i < n; i++) dst[i] = (int)src[i];} -void double_to_double(double * dst, double * src, int n) {for (int i = 0; i < n; i++) dst[i] = src[i];} -void int_to_int(int * dst, int * src, int n) {for (int i = 0; i < n; i++) dst[i] = src[i];} -double scalar(double * one, double * two, int n) { - double result = 0.0; - for (int i = 0; i < n; i++) result += one[i] * two[i]; - return result; -} -void load_list(double * list) { - int i, j = 0; - for (i = 0; i < var_number; i++) if (Active[i]) Variables[i] = (int)list[j++]; -} -void save_list(double * list) { - int i, j = 0; - for (i = 0; i < var_number; i++) if (Active[i]) list[j++] = (double)Variables[i]; -} -void log_list(FILE * f, double * list, int n) { - fprintf(f,"("); - for (int i = 0; i < n; i++) { - fprintf(f,"%.2lf",list[i]); - if (i < n - 1) fprintf(f,","); - } - fprintf(f,")\n"); -} -void log_list(const char * file_name, double * list, int n) { - FILE * f = fopen(file_name,"a"); - log_list(f,list,n); - fclose(f); -} -void log_list(char * s, double * list, int n, bool precision) { - sprintf(s+strlen(s),"("); - for (int i = 0; i < n; i++) { - if (!precision) sprintf(s+strlen(s),"%.2lf",list[i]); - else sprintf(s+strlen(s),"%lf",list[i]); - if (i < n - 1) sprintf(s+strlen(s),","); - } - sprintf(s+strlen(s),") "); -} -void read_list(char * string, double * list, int n) { - int i = 0; - char * p = strchr(string,'('); - do { - p++; - list[i++] = atof(p); - if (i >= n) break; - } while (p = strchr(p,',')); -} -void init_eval_data(double * one, double * two) { - if (one != EvalOne) double_to_double(EvalOne,one,var_number); - if (two != EvalTwo) double_to_double(EvalTwo,two,var_number); - load_list(one); Pst = PstOne; init_pst(); - load_list(two); Pst = PstTwo; init_pst(); -} -void load_eval(int first) { - int i; - generation++; - for (i = 1; i < 128; i++) Data[i].eval_key = 0; - if (first) { - load_list(EvalOne); - Hash = HashOne; - PawnHash = PawnHashOne; - PVHash = PVHashOne; - Pst = PstOne; - History = HistoryOne; - Delta = DeltaOne; - Ref = RefOne; - } else { - load_list(EvalTwo); - Hash = HashTwo; - PawnHash = PawnHashTwo; - PVHash = PVHashTwo; - Pst = PstTwo; - History = HistoryTwo; - Delta = DeltaTwo; - Ref = RefTwo; - } - Current->pst = 0; - for (i = 0; i < 64; i++) if (Square(i)) Current->pst += Pst(Square(i),i); - init_eval(); -} -void compute_list(double * dst, double * base, double * dir, double * var, double a) {for (int i = 0; i < active_vars; i++) dst[i] = base[i] + dir[i] * var[i] * a;} -void scale_list(double * list, double r) { - int i; - double x = 0.0; - for (i = 0; i < active_vars; i++) x += Sqr(list[i]); - x = r/sqrt(x); - for (i = 0; i < active_vars; i++) list[i] *= x; -} -int play(int depth) { - LastDepth = TimeLimit1 = TimeLimit2 = 0; -#ifdef TIMING - Infinite = 0; - int nmoves = MovesTg - 1; - if (Current->ply > 40) nmoves += Min(Current->ply - 40, (100 - Current->ply) / 2); - TimeLimit1 = Min(GlobalTime[GlobalTurn], (GlobalTime[GlobalTurn] + nmoves * GlobalInc[GlobalTurn]) / nmoves); - TimeLimit2 = Min(GlobalTime[GlobalTurn], (GlobalTime[GlobalTurn] + nmoves * GlobalInc[GlobalTurn]) / 3); - TimeLimit1 = Min(GlobalTime[GlobalTurn], (TimeLimit1 * TimeRatio) / 100); - DepthLimit = 128; Searching = 1; nodes = Stop = 0; - StartTime = get_time(); -#else - DepthLimit = 2 * depth + 2; - Infinite = 1; -#endif - best_score = best_move = 0; - Print = 0; - if (Current->turn == White) root<0>(); else root<1>(); - return best_score; -} -double play_game(double * one, double * two, int depth, char * fen) { - int i, cnt, sdepth, value, previous = 0, im = 0; - load_eval(0); init_search(1); load_eval(1); init_search(1); -#ifndef PGN - get_board(fen); - if (RecordGames) { - RecordString[0] = 0; - for (cnt = 0; fen[cnt] != '\n'; cnt++) PosStr[cnt] = fen[cnt]; - PosStr[cnt] = 0; - } -#else - position_from_pos((GPos*)fen); -#endif - init_eval_data(one,two); - -#ifdef TIMING - GlobalTime[0] = GlobalTime[1] = Convert((1.0 + rand_u()) * (double)(1000 << (int)(depth)),int); - GlobalInc[0] = GlobalInc[1] = GlobalTime[0] / 200; -#endif - - for (cnt = 0; cnt < 200 + (RecordGames ? 200 : 0); cnt++) { - GlobalTurn = Even(cnt); - load_eval(GlobalTurn); - memcpy(Data, Current, sizeof(GData)); - Current = Data; - if (Even(cnt)) sdepth = depth + Odd(rand16()); - value = play(sdepth); - if (!best_move) goto loss; - if (value < -ResignThreshold && previous > ResignThreshold) goto loss; - if (!RecordGames) { - if (value == 0 && previous == 0 && cnt >= 60) goto draw; - if (Abs(value) <= 3 && Abs(previous) <= 3 && cnt >= 120) goto draw; - } - if (Current->ply >= 100) goto draw; - for (i = 4; i <= Current->ply; i += 2) if (Stack[sp - i] == Current->key) goto draw; - int me = 0; - if (!PawnAll) { - int my_score = 3 * popcnt(Minor(me)) + 5 * popcnt(Rook(me)) + 9 * popcnt(Queen(me)); - int opp_score = 3 * popcnt(Minor(opp)) + 5 * popcnt(Rook(opp)) + 9 * popcnt(Queen(opp)); - if (Abs(my_score - opp_score) <= 3 && Max(popcnt(NonPawnKing(me)),popcnt(NonPawnKing(opp))) <= 2) { - im++; - if (im >= 10 && Abs(value) < 50 && Abs(previous) < 50) goto draw; - } - } -#ifdef WIN_PR - if (cnt >= 6 && ( - (!Queen(White) && !Queen(Black)) || - (popcnt(NonPawnKing(White)) <= 2 && popcnt(NonPawnKing(Black)) <= 2) || - (!Current->castle_flags && ((File[File(lsb(King(White)))] | PIsolated[File(lsb(King(White)))]) & King(Black))) - )) return ratio_from_elo(3.0 * (double)value) + ratio_from_elo(-3.0 * (double)previous); -#endif - previous = value; - if (!Current->turn) do_move<0>(best_move); - else do_move<1>(best_move); - if (RecordGames) { - move_to_string(best_move, pv_string); - sprintf(RecordString + strlen(RecordString), "%s { %.2lf / %d } ", pv_string, (double)(Current->turn ? value : (-value)) / 100.0, LastDepth/2); - } - } -draw: - if (RecordGames) sprintf(Buffer + strlen(Buffer), "[FEN \"%s\"]\n[Result \"1/2-1/2\"]\n%s\n", PosStr, RecordString); - return 1.0; -loss: - if (Even(cnt)) { - if (RecordGames) { - if (Current->turn) sprintf(Buffer + strlen(Buffer), "[FEN \"%s\"]\n[Result \"1-0\"]\n%s\n", PosStr, RecordString); - else sprintf(Buffer + strlen(Buffer), "[FEN \"%s\"]\n[Result \"0-1\"]\n%s\n", PosStr, RecordString); - } - return 0.0; - } else { - if (RecordGames) { - if (Current->turn) sprintf(Buffer + strlen(Buffer), "[FEN \"%s\"]\n[Result \"1-0\"]\n%s\n", PosStr, RecordString); - else sprintf(Buffer + strlen(Buffer), "[FEN \"%s\"]\n[Result \"0-1\"]\n%s\n", PosStr, RecordString); - } - return 2.0; - } -} -double play_position(double * one, double * two, int depth, char * fen, GMatchInfo * MI) { - double result, score = 0.0; - result = play_game(one, two, depth, fen); if (result >= 1.98) MI->wins++; else if (result <= 0.02) MI->losses++; else MI->draws++; - score += result; - result = play_game(two, one, depth, fen); if (result >= 1.98) MI->losses++; else if (result <= 0.02) MI->wins++; else MI->draws++; - score += 2.0 - result; - return score; -} -double match(double * one, double * two, int positions, int depth, GMatchInfo * MI) { - double score = 0.0; - memset(MI,0,sizeof(GMatchInfo)); - for (int i = 0; i < positions; i++) { -#ifndef PGN - score += play_position(one, two, depth, Fen[random() % (uint64)opening_positions], MI); -#else - score += play_position(one, two, depth, (char*)&Pos[random() % (uint64)pgn_positions], MI); -#endif - } - return (25.0 * (double)score)/(double)(positions); -} -int match_los(double * one, double * two, int positions, int chunk_size, int depth, double high, double low, double uh, double ul, GMatchInfo * MI, bool print) { - int pos = 0; - double score, ratio, stdev, wins, draws, losses, total, tot_score = 0.0; - cmd_number++; - - memset(mstring,0,strlen(mstring)); - sprintf(mstring,"$ Number=%d Command=match Depth=%d Positions=%d",cmd_number,depth,chunk_size); - sprintf(mstring+strlen(mstring)," First="); log_list(mstring,one,active_vars,false); - sprintf(mstring+strlen(mstring)," Second="); log_list(mstring,two,active_vars,false); - fseek(stdin,0,SEEK_END); - fprintf(stdout,"%s\n",mstring); - - memset(MI,0,sizeof(GMatchInfo)); - while (pos < positions) { - pos += chunk_size; -start: - fgets(mstring,65536,stdin); - char * p = strstr(mstring,"Number="); - if (p == NULL) goto start; - if (atoi(p+7) != cmd_number) goto start; - p = strstr(mstring, "Wins="); MI->wins += atoi(p + 5); - p = strstr(mstring, "Draws="); MI->draws += atoi(p + 6); - p = strstr(mstring, "Losses="); MI->losses += atoi(p + 7); - p = strstr(mstring, "Result="); tot_score += atof(p + 7); - - wins = (double)MI->wins; draws = (double)MI->draws; losses = (double)MI->losses; total = Max(wins + losses,1.0); -#ifndef WIN_PR - score = (100.0 * wins + 50.0 * draws)/(total + draws); -#else - score = tot_score / (double)(pos / chunk_size); -#endif - if (print) fprintf(stdout,"%.2lf (%d positions played): %d-%d-%d\n",score,pos,MI->wins,MI->draws,MI->losses); - if (total <= 0.99) continue; - ratio = wins/total; - stdev = 0.5/sqrt(total); - if (high > 0.01) { - if (ratio >= 0.5 + stdev * high) return 1; -#ifdef WIN_PR - if (score / 100.0 >= 0.5 + stdev * high) return 1; -#endif - } - if (low > 0.01) { - if (ratio <= 0.5 - stdev * low) return -1; -#ifdef WIN_PR - if (score / 100.0 <= 0.5 - stdev * low) return -1; -#endif - } - if (pos >= positions) break; - double remaining = ((2.0 * (double)positions - total - draws) * (wins + losses)) / (total + draws); - double target_high = 0.5 * (1.0 + (high / sqrt(total + remaining))); - double target_low = 0.5 * (1.0 - (low / sqrt(total + remaining))); - double ratio_high = target_high + 0.5 * (uh / sqrt(remaining)); - double ratio_low = target_low - 0.5 * (ul / sqrt(remaining)); - if (uh > 0.01) if ((wins + ratio_high * remaining) / (total + remaining) < target_high) return -1; - if (ul > 0.01) if ((wins + ratio_low * remaining) / (total + remaining) > target_low) return 1; - } - return 0; -} -void gradient(double * base, double * var, int iter, int pos_per_iter, int depth, double radius, double * grad) { - int i, j; - double dir[MaxVariables], A[MaxVariables], B[MaxVariables], r; - memset(grad,0,active_vars * sizeof(double)); - for (i = 0; i < iter; i++) { -#ifndef RANDOM_SPHERICAL - for (j = 0; j < active_vars; j++) dir[j] = (Odd(rand()) ? 1.0 : (-1.0))/sqrt(active_vars); -#else - for (j = 0, r = 0.0; j < active_vars; j++) { - dir[j] = gaussian(0.0, 1.0); - r += dir[j] * dir[j]; - } - r = 1.0/sqrt(Max(r, 0.0000001)); - for (j = 0; j < active_vars; j++) dir[j] *= r; -#endif - compute_list(A,base,dir,Var,-radius); - compute_list(B,base,dir,Var,radius); - r = 50.0 - match(A,B,pos_per_iter,depth,MatchInfo); - for (j = 0; j < active_vars; j++) grad[j] += r * dir[j]; - } - for (i = 0; i < active_vars; i++) grad[i] /= (double)iter; -} -void NormalizeVar(double * base, double * base_var, int depth, int positions, double radius, double target, double * var) { - int i, j; - double A[MaxVariables], r, value, curr_var; - - fprintf(stdout,"NormalizeVar(): depth=%d, positions=%d, radius=%.2lf, target=%.2lf\n",depth,positions,radius,target); - for (i = 0; i < active_vars; i++) { - double_to_double(A,base,active_vars); - curr_var = base_var[i]; - fprintf(stdout,"Variable %d (%.2lf):\n",i,curr_var); - for (j = 0; j < 10; j++) { - A[i] = base[i] + (radius * curr_var); - match_los(base,A,positions,16,depth,0.0,0.0,0.0,0.0,MatchInfo,false); - r = Convert(100 * MatchInfo->wins + 50 * (double)MatchInfo->draws,double)/(double)(MatchInfo->wins + MatchInfo->draws + MatchInfo->losses); - value = elo_from_ratio(r * 0.01); - if (value < target) break; - curr_var = curr_var * MinF(sqrt(target/Max(value, 1.0)),1.5); - fprintf(stdout,"(%.2lf,%.2lf)\n",value,curr_var); - if (curr_var > base_var[i]) { - curr_var = base_var[i]; - break; - } - } - var[i] = curr_var; - fprintf(stdout, "(%.2lf,%.2lf)\n", value, curr_var); - } - log_list("var.txt",var,active_vars); -} - -void Gradient(double * base, double * var, int depth, int iter, int pos_per_iter, int max_positions, double radius, double angle_target, double * grad) { - typedef struct { - double grad[MaxVariables]; - } GGradient; - GGradient A[4], N[4]; - double list[MaxVariables], av, angle; - int i, j, cnt = 0; - cmd_number++; - - fprintf(stdout,"Gradient(): depth=%d, iter=%d, pos_per_iter=%d, max_positions=%d, radius=%.2lf\n",depth,iter,pos_per_iter,max_positions,radius); - memset(A,0,4 * sizeof(GGradient)); - memset(grad,0,active_vars * sizeof(double)); - - memset(mstring,0,strlen(mstring)); - sprintf(mstring,"$ Number=%d Command=gradient Depth=%d Iter=%d Positions=%d Radius=%lf Var=",cmd_number,depth,iter,pos_per_iter,radius); log_list(mstring,Var,active_vars,false); - sprintf(mstring+strlen(mstring)," Base="); log_list(mstring,Base,active_vars,false); - fseek(stdin,0,SEEK_END); - fprintf(stdout,"%s\n",mstring); - - while (cnt < max_positions) { - for (j = 0; j < 4; j++) { -start: - fgets(mstring,65536,stdin); - char * p = strstr(mstring,"Number="); - if (p == NULL) goto start; - if (atoi(p+7) != cmd_number) goto start; - p = strstr(mstring,"Grad="); read_list(p,list,active_vars); - - for (i = 0; i < active_vars; i++) { - A[j].grad[i] += list[i]; - N[j].grad[i] = A[j].grad[i]; - } - scale_list(N[j].grad,1.0); - } - for (i = 0; i < active_vars; i++) grad[i] = A[0].grad[i] + A[1].grad[i] + A[2].grad[i] + A[3].grad[i]; - scale_list(grad,1.0); - av = 0.0; - for (i = 0; i < 4; i++) for (j = i + 1; j < 4; j++) av += scalar(N[i].grad,N[j].grad,active_vars); - av /= 6.0; - av = Min(0.99999,Max(-0.99999,av)); - angle = (acos(av) * 180.0)/3.1415926535; - cnt += 4 * pos_per_iter * iter; - fprintf(stdout,"%d positions: angle = %.2lf, gradient = ",cnt,angle); - log_list(stdout,grad,active_vars); - if (angle < angle_target) break; - FILE * fgrad = fopen("gradient.txt","w"); - log_list(fgrad,grad,active_vars); - fprintf(fgrad,"%d\n",cnt); - fclose(fgrad); - } -} -void GD(double * base, double * var, int depth, double radius, double min_radius, double angle_target, int max_grad_positions, int max_line_positions, double high, double low, double uh, double ul) { - double Grad[MaxVariables], a, br, A[MaxVariables], B[MaxVariables]; - FILE * fbest = fopen("gd.txt","w"); fclose(fbest); +#include "data.c" - fprintf(stdout,"GD()\n"); - while (true) { -start: - fbest = fopen("gd.txt","a"); fprintf(fbest,"radius = %.2lf:\n",radius); log_list(fbest,base,active_vars); fclose(fbest); - log_list(stdout,base,active_vars); - //radius = 2.0; read_list("(0.05,-0.04,-0.00,0.04,0.09,-0.10,-0.00,0.06,-0.14,-0.08,-0.06,0.05,-0.21,-0.10,-0.03,0.04,0.06,-0.01,-0.04,0.06,0.01,-0.05,-0.02,-0.06,-0.05,0.14,0.18,-0.01,-0.01,0.02,-0.11,0.05,-0.00,0.18,-0.15,-0.02,0.03,0.01,-0.06,-0.07,-0.03,0.11,0.13,-0.07,0.06,0.02,-0.01,0.06,-0.07,-0.09,0.01,-0.09,0.13,-0.03,0.04,0.03,-0.04,0.16,0.03,-0.21,-0.01,0.04,-0.03,-0.11,0.00,-0.03,-0.03,-0.11,-0.00,-0.06,0.04,-0.05,0.00,-0.03,-0.12,0.00,-0.07,-0.13,-0.08,0.10,0.11,0.03,0.08,0.12,-0.05,-0.07,-0.01,-0.02,0.08,-0.12,-0.05,0.02,0.03,0.13,-0.08,0.05,0.04,0.02,-0.00,0.06,-0.06,-0.07,-0.00,0.05,-0.09,-0.16,-0.02,-0.07,0.16,-0.24,0.09,0.04,-0.09,0.03,-0.06,0.01,-0.05,0.00,-0.10,-0.02,-0.12,-0.05,-0.05,0.07,0.14,0.16,-0.07,0.03,-0.06,-0.16,-0.03,0.04,-0.04,0.02,-0.12,-0.18,0.01,-0.04,-0.04,-0.18,0.08,0.09,-0.06,-0.00,0.02,-0.03,0.10,0.04,-0.02)", Grad, active_vars); - Gradient(base,var,depth,32,1,max_grad_positions,radius,angle_target,Grad); - min_radius = Min(radius * 0.45, min_radius); - a = radius; - while (a >= min_radius) { - fprintf(stdout,"Verification %.2lf:\n",a); - compute_list(A,base,Grad,var,a); - //eval_to_cpp("gd.cpp", A); - if (match_los(A,base,max_line_positions,32,depth,high,low,uh,ul,MatchInfo,true) == 1) { - br = a; - a *= 0.6; - compute_list(B,base,Grad,var,a); - double_to_double(base,A,active_vars); - log_list("gd.txt",base,active_vars); - eval_to_cpp("gd.cpp", base); - fprintf(stdout,"New best: "); log_list(stdout,base,active_vars); - fprintf(stdout,"Try %.2lf:\n",a); - if (match_los(B,A,max_line_positions,32,depth,2.0,2.0,2.0,0.0,MatchInfo,true) == 1) { - br = a; - double_to_double(base,B,active_vars); - log_list("gd.txt",base,active_vars); - eval_to_cpp("gd.cpp", base); - fprintf(stdout,"New best: "); log_list(stdout,base,active_vars); - } - if (br < radius * 0.29) radius *= 0.7; - goto start; - } - a *= 0.7; - } - radius *= 0.7; - } -} -void get_command() { - enum {mode_grad, mode_match}; - int mode, depth, positions, number; - char * p; - - if (RecordGames) Buffer[0] = 0; - fgets(mstring,65536,stdin); - fseek(stdin,0,SEEK_END); - p = strstr(mstring,"Command="); - if (p == NULL) return; - if (!memcmp(p+8,"gradient",8)) mode = mode_grad; - else if (!memcmp(p+8,"match",5)) mode = mode_match; - else return; - p = strstr(mstring,"Number="); number = atoi(p+7); - p = strstr(mstring,"Depth="); depth = atoi(p+6); - p = strstr(mstring,"Positions="); positions = atoi(p+10); - if (mode == mode_grad) { - p = strstr(mstring,"Iter="); int iter = atoi(p+5); - p = strstr(mstring,"Radius="); int radius = atof(p+7); - p = strstr(mstring,"Var="); read_list(p,Var,active_vars); - p = strstr(mstring,"Base="); read_list(p,Base,active_vars); - gradient(Base,Var,iter,positions,depth,radius,Grad); - memset(mstring,0,strlen(mstring)); - sprintf(mstring,"$ Number=%d Grad=",number); log_list(mstring,Grad,active_vars,true); - fprintf(stdout,"%s\n",mstring); - } else if (mode == mode_match) { - p = strstr(mstring,"First="); read_list(p,FE,active_vars); - p = strstr(mstring,"Second="); read_list(p,SE,active_vars); - double r = match(FE,SE,positions,depth,MatchInfo); - if (RecordGames) { - frec = fopen("games.pgn", "a"); - fprintf(frec, "%s\n", Buffer); - fclose(frec); - } - memset(mstring,0,strlen(mstring)); - sprintf(mstring,"$ Number=%d Result=%lf Wins=%d Draws=%d Losses=%d",number,r,MatchInfo->wins,MatchInfo->draws,MatchInfo->losses); - fprintf(stdout,"%s\n",mstring); - } else nodes /= 0; -} -int get_mat_index(int wq, int bq, int wr, int br, int wl, int bl, int wd, int bd, int wn, int bn, int wp, int bp) { - if (wq > 2 || bq > 2 || wr > 2 || br > 2 || wl > 1 || bl > 1 || wd > 1 || bd > 1 || wn > 2 || bn > 2 || wp > 8 || bp > 8) return -1; - return wp*MatWP + bp*MatBP + wn*MatWN + bn*MatBN + wl*MatWL + bl*MatBL + wd*MatWD + bd*MatBD + wr*MatWR + br*MatBR + wq*MatWQ + bq*MatBQ; -} -int conj_mat_index(int index, int * conj_symm, int * conj_ld, int * conj_ld_symm) { - int wq = index % 3; index /= 3; - int bq = index % 3; index /= 3; - int wr = index % 3; index /= 3; - int br = index % 3; index /= 3; - int wl = index % 2; index /= 2; - int bl = index % 2; index /= 2; - int wd = index % 2; index /= 2; - int bd = index % 2; index /= 2; - int wn = index % 3; index /= 3; - int bn = index % 3; index /= 3; - int wp = index % 9; index /= 9; - int bp = index; - *conj_symm = -1; - *conj_ld = -1; - *conj_ld_symm = -1; - if (wq != bq || wr != br || wl != bd || wd != bl || wn != bn || wp != bp) { - *conj_symm = get_mat_index(bq, wq, br, wr, bd, wd, bl, wl, bn, wn, bp, wp); - if (wl != wd || bl != bd) { - *conj_ld = get_mat_index(wq, bq, wr, br, wd, bd, wl, bl, wn, bn, wp, bp); - *conj_ld_symm = get_mat_index(bq, wq, br, wr, bl, wl, bd, wd, bn, wn, bp, wp); - } - } - return *conj_symm; -} -void pgn_stat() { -#define elo_eval_ratio 1.0 -#define PosInRow 6 -#define ratio_from_eval(x) ratio_from_elo(elo_eval_ratio * (x)) -#define ind_from_eval(x) (ratio_from_eval((double)(x)) >= 0.5 ? Max(0, (int)((ratio_from_eval((double)(x)) - 0.5) * 100.0)) : Max(0, (int)((0.5 - ratio_from_eval((double)(x))) * 100.0))) -#define est_from_ind(x) (Eval[x].score/Max(1.0,(double)Eval[x].cnt)) -#define est_from_eval(x) ((x) >= 0 ? est_from_ind(ind_from_eval(x)) : (1.0 - est_from_ind(ind_from_eval(x)))) - typedef struct { - double score; - double est; - int cnt; - } GStat; - GStat Eval[64]; for (int i = 0; i < 64; i++) { Eval[i].cnt = 0; Eval[i].score = 1.0; } - GStat * Mat = (GStat*)malloc(TotalMat * sizeof(GStat)); memset(Mat, 0, TotalMat * sizeof(GStat)); - FILE * fpgn; - int iter = 0; -loop: - fpgn = fopen("D:/Development/G3T/games.pgn", "r"); - if (fpgn == NULL) { - fprintf(stdout, "File 'games.pgn' not found\n"); getchar(); - exit(0); - } - double stat = 0.0, est = 0.0; - int cnt = 0; - while (true) { - fgets(mstring, 65536, fpgn); - if (feof(fpgn)) break; - if (strstr(mstring, "FEN")) get_board(mstring + 6); - double result; - if (strstr(mstring, "Result")) { - if (strstr(mstring, "1-0")) result = 1.0; - else if (strstr(mstring, "0-1")) result = 0.0; - else result = 0.5; - } - if (strchr(mstring, '[')) continue; - if (strlen(mstring) < 100) continue; - char * ptr = mstring; - int eval[20], nc = 0; memset(eval, 0, 20 * sizeof(int)); - while (*ptr != 0) { - if (!Current->capture && !(Current->move & 0xE000)) nc++; - else nc = 0; - evaluate(); - if (nc == PosInRow) { - double ratio = ratio_from_eval((double)eval[PosInRow - 2]); - int r_index; - if (ratio >= 0.5) r_index = Max(0, (int)((ratio - 0.5) * 100.0)); - else r_index = Max(0, (int)((0.5 - ratio) * 100.0)); - if (Even(iter)) { - Eval[r_index].cnt++; - Eval[r_index].score += (ratio >= 0.5 ? result : (1.0 - result)); - } - - if (!(Current->material & FlagUnusualMaterial) && Odd(iter)) { - int index = Current->material, conj_symm, conj_ld, conj_ld_symm; - conj_mat_index(index, &conj_symm, &conj_ld, &conj_ld_symm); - Mat[index].cnt++; Mat[index].score += result; Mat[index].est += est_from_eval(eval[PosInRow - 1]); - if (conj_symm >= 0) Mat[conj_symm].cnt++; Mat[conj_symm].score += 1.0 - result; Mat[conj_symm].est += 1.0 - est_from_eval(eval[PosInRow - 1]); - if (conj_ld >= 0) Mat[conj_ld].cnt++; Mat[conj_ld].score += result; Mat[conj_ld].est += est_from_eval(eval[PosInRow - 1]); - if (conj_ld_symm >= 0) Mat[conj_ld_symm].cnt++; Mat[conj_ld_symm].score += 1.0 - result; Mat[conj_ld_symm].est += 1.0 - est_from_eval(eval[PosInRow - 1]); - } - } - pv_string[0] = *ptr++; - pv_string[1] = *ptr++; - pv_string[2] = *ptr++; - pv_string[3] = *ptr++; - if (*ptr == 0 || *ptr == ' ') pv_string[4] = 0; - else { - pv_string[4] = *ptr++; - pv_string[5] = 0; - } - int move = move_from_string(pv_string); - if (Current->turn) { - if (!is_legal<1>(move)) break; - do_move<1>(move); - } else { - if (!is_legal<0>(move)) break; - do_move<0>(move); - } - memcpy(Data, Current, sizeof(GData)); - Current = Data; - while (*ptr == ' ') ptr++; - for (int i = 19; i >= 1; i--) eval[i] = eval[i - 1]; - eval[0] = (int)(atof(ptr + 2) * 100.0); - ptr = strchr(ptr, '}') + 2; - } - } - fclose(fpgn); - if (!iter) { - for (int i = 0; i < 64; i++) fprintf(stdout, "ratio(eval x %.2lf) in (%.2lf, %.2lf), score = %.2lf\n", elo_eval_ratio, 50.0 + (double)i, 50.0 + (double)(i + 1), (Eval[i].score * 100.0) / Max(1.0, (double)Eval[i].cnt)); - iter++; - goto loop; - } - FILE * fmat = fopen("material.txt", "w"); - fprintf(fmat, "const int MaterialShift[MaterialShiftSize] = {\n"); - int mat_cnt = 0; - for (int index = 0; index < TotalMat; index++) { - int cnt = Mat[index].cnt; - if (cnt < 64) continue; - double ratio = Mat[index].score / (double)cnt; - double est = Mat[index].est / (double)cnt; - bool flag = (ratio < est); - double error = (sqrt(2.0) * 0.5) / sqrt((double)cnt); - if (Abs(ratio - est) <= error + 0.01) continue; - ratio = ((ratio >= est) ? (ratio - error) : (ratio + error)); - if (est <= 0.5 && ratio > 0.5) ratio = 0.5000001; - if (est >= 0.5 && ratio < 0.5) ratio = 0.4999999; - double abs_ratio = ((ratio >= 0.5) ? ratio : (1.0 - ratio)); - double abs_est = ((est >= 0.5) ? est : (1.0 - est)); - int curr_ind = 0, new_ind = 0; - for (int i = 0; i < 64; i++) { - if (Eval[i].score / Max(1.0, (double)Eval[i].cnt) < abs_ratio) new_ind = i; - if (Eval[i].score / Max(1.0, (double)Eval[i].cnt) < abs_est) curr_ind = i; - } - if (Abs(curr_ind - new_ind) <= 1) continue; - if (new_ind > curr_ind) new_ind--; - else new_ind++; - double curr_eval = elo_from_ratio(Eval[curr_ind].score / Max(1.0, (double)Eval[curr_ind].cnt)) / elo_eval_ratio; - double new_eval = elo_from_ratio(Eval[new_ind].score / Max(1.0, (double)Eval[new_ind].cnt)) / elo_eval_ratio; - int score = (int)Abs(curr_eval - new_eval); - if (flag) score = -score; - if (Sgn(score) != Sgn(Material[index].score)) score = Sgn(score) * Min(Abs(Material[index].score), Abs(score)); - if (Abs(score) < 5) continue; - mat_cnt++; - fprintf(fmat, "%d, %d, ", index, score); - if ((mat_cnt % 8) == 0) fprintf(fmat, "\n"); - } - fprintf(fmat, "}; %d\n", mat_cnt * 2); - fclose(fmat); - fprintf(stdout, "Press any key...\n"); -} -#endif +#define HASH_SIZE(n) ((n) == 0? (1 << 20): Bit(msb((size_t)(n) * (1 << 20)))) #ifndef W32_BUILD -__forceinline int lsb(uint64 x) { - register unsigned long long y; +inline int lsb(uint64_t x) { + register unsigned long long y; __asm__("bsfq %1, %0": "=r"(y): "rm"(x)); - return y; + return y; } -__forceinline int msb(uint64 x) { - register unsigned long long y; +inline int msb(uint64_t x) { + register unsigned long long y; __asm__("bsrq %1, %0": "=r"(y): "rm"(x)); - return y; -} - -__forceinline int popcnt(uint64 x) { - x = x - ((x >> 1) & 0x5555555555555555); - x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333); - x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f; - return (x * 0x0101010101010101) >> 56; + return y; } -template __forceinline int popcount(uint64 x) { - return HPopCnt ? builtin_popcnt_u64(x) : popcnt(x); -} +//inline int popcount(uint64_t x) { +// x = x - ((x >> 1) & 0x5555555555555555); +// x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333); +// x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f; +// return (x * 0x0101010101010101) >> 56; +//} #else -__forceinline int lsb(uint64 x) { - _asm { - mov eax, dword ptr x[0] - test eax, eax - jz l_high - bsf eax, eax - jmp l_ret - l_high : bsf eax, dword ptr x[4] - add eax, 20h - l_ret : - } -} - -__forceinline int msb(uint64 x) { - _asm { - mov eax, dword ptr x[4] - test eax, eax - jz l_low - bsr eax, eax - add eax, 20h - jmp l_ret - l_low : bsr eax, dword ptr x[0] - l_ret : - } -} - -__forceinline int popcnt(uint64 x) { - unsigned int x1, x2; - x1 = (unsigned int)(x & 0xFFFFFFFF); - x1 -= (x1 >> 1) & 0x55555555; - x1 = (x1 & 0x33333333) + ((x1 >> 2) & 0x33333333); - x1 = (x1 + (x1 >> 4)) & 0x0F0F0F0F; - x2 = (unsigned int)(x >> 32); - x2 -= (x2 >> 1) & 0x55555555; - x2 = (x2 & 0x33333333) + ((x2 >> 2) & 0x33333333); - x2 = (x2 + (x2 >> 4)) & 0x0F0F0F0F; - return ((x1 * 0x01010101) >> 24) + ((x2 * 0x01010101) >> 24); -} - -template __forceinline int popcount(uint64 x) { - return HPopCnt ? (__popcnt((int)x) + __popcnt(x >> 32)) : popcnt(x); -} -#endif - -__forceinline int MinF(int x, int y) { return Min(x, y); } -__forceinline int MaxF(int x, int y) { return Max(x, y); } -__forceinline double MinF(double x, double y) { return Min(x, y); } -__forceinline double MaxF(double x, double y) { return Max(x, y); } - -uint64 BMagicAttacks(int i, uint64 occ) { - uint64 att = 0; - for (uint64 u = BMask[i]; T(u); Cut(u)) if (F(Between[i][lsb(u)] & occ)) att |= Between[i][lsb(u)] | Bit(lsb(u)); - return att; -} - -uint64 RMagicAttacks(int i, uint64 occ) { - uint64 att = 0; - for (uint64 u = RMask[i]; T(u); Cut(u)) if (F(Between[i][lsb(u)] & occ)) att |= Between[i][lsb(u)] | Bit(lsb(u)); - return att; +inline int lsb(uint64_t x) { + _asm { + mov eax, dword ptr x[0] + test eax, eax + jz l_high + bsf eax, eax + jmp l_ret + l_high : bsf eax, dword ptr x[4] + add eax, 20h + l_ret : + } } -uint16 rand16() { - seed = (seed * Convert(6364136223846793005,uint64)) + Convert(1442695040888963407,uint64); - return Convert((seed >> 32) & 0xFFFF,uint16); +inline int msb(uint64_t x) { + _asm { + mov eax, dword ptr x[4] + test eax, eax + jz l_low + bsr eax, eax + add eax, 20h + jmp l_ret + l_low : bsr eax, dword ptr x[0] + l_ret : + } } -uint64 rand64() { - uint64 key = Convert(rand16(),uint64); key <<= 16; - key |= Convert(rand16(),uint64); key <<= 16; - key |= Convert(rand16(),uint64); key <<= 16; - return key | Convert(rand16(),uint64); -} +//inline int popcount(uint64_t x) { +// unsigned int x1, x2; +// x1 = (unsigned int)(x & 0xFFFFFFFF); +// x1 -= (x1 >> 1) & 0x55555555; +// x1 = (x1 & 0x33333333) + ((x1 >> 2) & 0x33333333); +// x1 = (x1 + (x1 >> 4)) & 0x0F0F0F0F; +// x2 = (unsigned int)(x >> 32); +// x2 -= (x2 >> 1) & 0x55555555; +// x2 = (x2 & 0x33333333) + ((x2 >> 2) & 0x33333333); +// x2 = (x2 + (x2 >> 4)) & 0x0F0F0F0F; +// return ((x1 * 0x01010101) >> 24) + ((x2 * 0x01010101) >> 24); +//} -void init_misc() { - int i, j, k, l, n; - uint64 u; - - for (i = 0; i < 64; i++) { - HLine[i] = VLine[i] = NDiag[i] = SDiag[i] = RMask[i] = BMask[i] = QMask[i] = 0; - BMagicMask[i] = RMagicMask[i] = NAtt[i] = SArea[i] = DArea[i] = NArea[i] = 0; - PAtt[0][i] = PAtt[1][i] = PMove[0][i] = PMove[1][i] = PWay[0][i] = PWay[1][i] = PSupport[0][i] = PSupport[1][i] = BishopForward[0][i] = BishopForward[1][i] = 0; - for (j = 0; j < 64; j++) Between[i][j] = FullLine[i][j] = 0; - } - - for (i = 0; i < 64; i++) for (j = 0; j < 64; j++) if (i != j) { - u = Bit(j); - if (File(i) == File(j)) VLine[i] |= u; - if (Rank(i) == Rank(j)) HLine[i] |= u; - if (NDiag(i) == NDiag(j)) NDiag[i] |= u; - if (SDiag(i) == SDiag(j)) SDiag[i] |= u; - if (Dist(i,j) <= 2) { - DArea[i] |= u; - if (Dist(i,j) <= 1) SArea[i] |= u; - if (Abs(Rank(i)-Rank(j)) + Abs(File(i)-File(j)) == 3) NAtt[i] |= u; - } - if (j == i + 8) PMove[0][i] |= u; - if (j == i - 8) PMove[1][i] |= u; - if (Abs(File(i) - File(j)) == 1) { - if (Rank(j) >= Rank(i)) { - PSupport[1][i] |= u; - if (Rank(j) - Rank(i) == 1) PAtt[0][i] |= u; - } - if (Rank(j) <= Rank(i)) { - PSupport[0][i] |= u; - if (Rank(i) - Rank(j) == 1) PAtt[1][i] |= u; - } - } else if (File(i) == File(j)) { - if (Rank(j) > Rank(i)) PWay[0][i] |= u; - else PWay[1][i] |= u; - } - } - for (i = 0; i < 64; i++) { - RMask[i] = HLine[i] | VLine[i]; - BMask[i] = NDiag[i] | SDiag[i]; - QMask[i] = RMask[i] | BMask[i]; - BMagicMask[i] = BMask[i] & Interior; - RMagicMask[i] = RMask[i]; - if (File(i) > 0) RMagicMask[i] &= ~File[0]; - if (Rank(i) > 0) RMagicMask[i] &= ~Line[0]; - if (File(i) < 7) RMagicMask[i] &= ~File[7]; - if (Rank(i) < 7) RMagicMask[i] &= ~Line[7]; - for (j = 0; j < 64; j++) if (NAtt[i] & NAtt[j]) Add(NArea[i],j); - } - for (i = 0; i < 8; i++) { - West[i] = 0; - East[i] = 0; - Forward[0][i] = Forward[1][i] = 0; - PIsolated[i] = 0; - for (j = 0; j < 8; j++) { - if (i < j) Forward[0][i] |= Line[j]; - else if (i > j) Forward[1][i] |= Line[j]; - if (i < j) East[i] |= File[j]; - else if (i > j) West[i] |= File[j]; - } - if (i > 0) PIsolated[i] |= File[i - 1]; - if (i < 7) PIsolated[i] |= File[i + 1]; - } - for (i = 0; i < 64; i++) { - for (u = QMask[i]; T(u); Cut(u)) { - j = lsb(u); - k = Sgn(Rank(j)-Rank(i)); - l = Sgn(File(j)-File(i)); - for (n = i + 8 * k + l; n != j; n += (8 * k + l)) Add(Between[i][j],n); - } - for (u = BMask[i]; T(u); Cut(u)) { - j = lsb(u); - FullLine[i][j] = BMask[i] & BMask[j]; - } - for (u = RMask[i]; T(u); Cut(u)) { - j = lsb(u); - FullLine[i][j] = RMask[i] & RMask[j]; - } - BishopForward[0][i] |= PWay[0][i]; - BishopForward[1][i] |= PWay[1][i]; - for (j = 0; j < 64; j++) { - if ((PWay[1][j] | Bit(j)) & BMask[i] & Forward[0][Rank(i)]) BishopForward[0][i] |= Bit(j); - if ((PWay[0][j] | Bit(j)) & BMask[i] & Forward[1][Rank(i)]) BishopForward[1][i] |= Bit(j); - } - } - - for (i = 0; i < 16; i++) for (j = 0; j < 16; j++) { - if (j < WhitePawn) MvvLva[i][j] = 0; - else if (j < WhiteKnight) MvvLva[i][j] = PawnCaptureMvvLva(i) << 26; - else if (j < WhiteLight) MvvLva[i][j] = KnightCaptureMvvLva(i) << 26; - else if (j < WhiteRook) MvvLva[i][j] = BishopCaptureMvvLva(i) << 26; - else if (j < WhiteQueen) MvvLva[i][j] = RookCaptureMvvLva(i) << 26; - else MvvLva[i][j] = QueenCaptureMvvLva(i) << 26; - } - - for (i = 0; i < 256; i++) PieceFromChar[i] = 0; - PieceFromChar[66] = 6; PieceFromChar[75] = 14; PieceFromChar[78] = 4; PieceFromChar[80] = 2; PieceFromChar[81] = 12; PieceFromChar[82] = 10; - PieceFromChar[98] = 7; PieceFromChar[107] = 15; PieceFromChar[110] = 5; PieceFromChar[112] = 3; PieceFromChar[113] = 13; PieceFromChar[114] = 11; - - TurnKey = rand64(); - for (i = 0; i < 8; i++) EPKey[i] = rand64(); - for (i = 0; i < 16; i++) CastleKey[i] = rand64(); - for (i = 0; i < 16; i++) for (j = 0; j < 64; j++) { - if (i == 0) PieceKey[i][j] = 0; - else PieceKey[i][j] = rand64(); - } - for (i = 0; i < 16; i++) LogDist[i] = (int)(10.0 * log(1.01 + (double)i)); +inline int popcount(uint64_t x) { + return __popcount((int)x) + __popcount(x >> 32); } - -void init_magic() { - int i, j, k, index, bits, bit_list[16]; - uint64 u; -#ifdef TUNER - MagicAttacks = (uint64*)malloc(magic_size * sizeof(uint64)); -#endif - for (i = 0; i < 64; i++) { - bits = 64 - BShift[i]; - for (u = BMagicMask[i], j = 0; T(u); Cut(u), j++) bit_list[j] = lsb(u); - for (j = 0; j < Bit(bits); j++) { - u = 0; - for (k = 0; k < bits; k++) - if (Odd(j >> k)) Add(u,bit_list[k]); -#ifndef HNI - index = Convert(BOffset[i] + ((BMagic[i] * u) >> BShift[i]),int); -#else - index = Convert(BOffset[i] + _pext_u64(u,BMagicMask[i]),int); #endif - MagicAttacks[index] = BMagicAttacks(i,u); - } - bits = 64 - RShift[i]; - for (u = RMagicMask[i], j = 0; T(u); Cut(u), j++) bit_list[j] = lsb(u); - for (j = 0; j < Bit(bits); j++) { - u = 0; - for (k = 0; k < bits; k++) - if (Odd(j >> k)) Add(u,bit_list[k]); -#ifndef HNI - index = Convert(ROffset[i] + ((RMagic[i] * u) >> RShift[i]),int); -#else - index = Convert(ROffset[i] + _pext_u64(u,RMagicMask[i]),int); -#endif - MagicAttacks[index] = RMagicAttacks(i,u); - } - } -} -void gen_kpk() { - int turn, wp, wk, bk, to, cnt, old_cnt, un; - uint64 bwp, bwk, bbk, u; - uint8 Kpk_gen[2][64][64][64]; - - memset(Kpk_gen, 0, 2 * 64 * 64 * 64); - - cnt = 0; - old_cnt = 1; -start: - if (cnt == old_cnt) goto end; - old_cnt = cnt; - cnt = 0; - for (turn = 0; turn < 2; turn++) { - for (wp = 0; wp < 64; wp++) { - for (wk = 0; wk < 64; wk++) { - for (bk = 0; bk < 64; bk++) { - if (Kpk_gen[turn][wp][wk][bk]) continue; - cnt++; - if (wp < 8 || wp >= 56) goto set_draw; - if (wp == wk || wk == bk || bk == wp) goto set_draw; - bwp = Bit(wp); - bwk = Bit(wk); - bbk = Bit(bk); - if (PAtt[White][wp] & bbk) { - if (turn == White) goto set_draw; - else if (F(SArea[wk] & bwp)) goto set_draw; - } - un = 0; - if (turn == Black) { - u = SArea[bk] & (~(SArea[wk] | PAtt[White][wp])); - if (F(u)) goto set_draw; - for (; T(u); Cut(u)) { - to = lsb(u); - if (Kpk_gen[turn ^ 1][wp][wk][to] == 1) goto set_draw; - else if (Kpk_gen[turn ^ 1][wp][wk][to] == 0) un++; - } - if (F(un)) goto set_win; - } - else { - for (u = SArea[wk] & (~(SArea[bk] | bwp)); T(u); Cut(u)) { - to = lsb(u); - if (Kpk_gen[turn ^ 1][wp][to][bk] == 2) goto set_win; - else if (Kpk_gen[turn ^ 1][wp][to][bk] == 0) un++; - } - to = wp + 8; - if (to != wk && to != bk) { - if (to >= 56) { - if (F(SArea[to] & bbk)) goto set_win; - if (SArea[to] & bwk) goto set_win; - } - else { - if (Kpk_gen[turn ^ 1][to][wk][bk] == 2) goto set_win; - else if (Kpk_gen[turn ^ 1][to][wk][bk] == 0) un++; - if (to < 24) { - to += 8; - if (to != wk && to != bk) { - if (Kpk_gen[turn ^ 1][to][wk][bk] == 2) goto set_win; - else if (Kpk_gen[turn ^ 1][to][wk][bk] == 0) un++; - } - } - } - } - if (F(un)) goto set_draw; - } - continue; - set_draw: - Kpk_gen[turn][wp][wk][bk] = 1; - continue; - set_win: - Kpk_gen[turn][wp][wk][bk] = 2; - continue; - } - } - } - } - if (cnt) goto start; -end: - for (turn = 0; turn < 2; turn++) { - for (wp = 0; wp < 64; wp++) { - for (wk = 0; wk < 64; wk++) { - Kpk[turn][wp][wk] = 0; - for (bk = 0; bk < 64; bk++) { - if (Kpk_gen[turn][wp][wk][bk] == 2) Kpk[turn][wp][wk] |= Bit(bk); - } - } - } - } -} - -void init_pst() { - int i, j, k, op, eg, index, r, f, d, e, distQ[4], distL[4], distM[2]; - memset(Pst,0,16 * 64 * sizeof(int)); - - for (i = 0; i < 64; i++) { - r = Rank(i); - f = File(i); - d = Abs(f - r); - e = Abs(f + r - 7); - distQ[0] = DistC[f] * DistC[f]; distL[0] = DistC[f]; - distQ[1] = DistC[r] * DistC[r]; distL[1] = DistC[r]; - distQ[2] = RankR[d] * RankR[d] + RankR[e] * RankR[e]; distL[2] = RankR[d] + RankR[e]; - distQ[3] = RankR[r] * RankR[r]; distL[3] = RankR[r]; - distM[0] = DistC[f] * DistC[r]; distM[1] = DistC[f] * RankR[r]; - for (j = 2; j < 16; j += 2) { - index = PieceType[j]; - op = eg = 0; - for (k = 0; k < 2; k++) { - op += Av(PstQuadMixedWeights, 4, index, (k * 2)) * distM[k]; - eg += Av(PstQuadMixedWeights, 4, index, (k * 2) + 1) * distM[k]; - } - for (k = 0; k < 4; k++) { - op += Av(PstQuadWeights,8,index,(k * 2)) * distQ[k]; - eg += Av(PstQuadWeights,8,index,(k * 2) + 1) * distQ[k]; - op += Av(PstLinearWeights,8,index,(k * 2)) * distL[k]; - eg += Av(PstLinearWeights,8,index,(k * 2) + 1) * distL[k]; - } - Pst(j,i) = Compose(op/64, eg/64); - } - } - - Pst(WhiteKnight,56) -= Compose(100, 0); - Pst(WhiteKnight,63) -= Compose(100, 0); - for (i = 0; i < 64; i++) { - for (j = 3; j < 16; j+=2) { - op = Opening(Pst(j-1,63-i)); - eg = Endgame(Pst(j-1,63-i)); - Pst(j,i) = Compose(-op,-eg); - } - } - Current->pst = 0; - for (i = 0; i < 64; i++) - if (Square(i)) Current->pst += Pst(Square(i),i); -} - -void init_eval() { - int i, j, k, index; - memset(Mobility,0,4 * 32 * sizeof(int)); - for (i = 0; i < 4; i++) for (j = 0; j < 32; j++) { - index = i * 2; - double op = (double)(Av(MobilityLinear,8,0,index) * j) + log(1.01 + (double)j) * (double)(Av(MobilityLog,8,0,index)); - index = i * 2 + 1; - double eg = (double)(Av(MobilityLinear,8,0,index) * j) + log(1.01 + (double)j) * (double)(Av(MobilityLog,8,0,index)); - Mobility[i][j] = Compose((int)(op/64.0),(int)(eg/64.0)); - } - - for (i = 0; i < 3; i++) for (j = 7; j >= 0; j--) { - Shelter[i][j] = 0; - if (j > 1) for (k = 1; k < Min(j, 5); k++) Shelter[i][j] += Av(ShelterValue, 0, 0, (i * 5) + k - 1); - if (!j) Shelter[i][j] = Shelter[i][7] + Av(ShelterValue, 0, 0, (i * 5) + 4); - } - - for (i = 0; i < 4; i++) { - StormBlocked[i] = ((Sa(StormQuad, StormBlockedMul) * i * i) + (Sa(StormLinear, StormBlockedMul) * (i + 1))) / 100; - StormShelterAtt[i] = ((Sa(StormQuad, StormShelterAttMul) * i * i) + (Sa(StormLinear, StormShelterAttMul) * (i + 1))) / 100; - StormConnected[i] = ((Sa(StormQuad, StormConnectedMul) * i * i) + (Sa(StormLinear, StormConnectedMul) * (i + 1))) / 100; - StormOpen[i] = ((Sa(StormQuad, StormOpenMul) * i * i) + (Sa(StormLinear, StormOpenMul) * (i + 1))) / 100; - StormFree[i] = ((Sa(StormQuad, StormFreeMul) * i * i) + (Sa(StormLinear, StormFreeMul) * (i + 1))) / 100; - } - - for (i = 0; i < 8; i++) { - int l = Max(i - 2, 0); - int q = l * l; - PasserGeneral[i] = Compose16(Av(PasserQuad, 2, 0, 0) * q + Av(PasserLinear, 2, 0, 0) * l, Av(PasserQuad, 2, 0, 1) * q + Av(PasserLinear, 2, 0, 1) * l); - PasserBlocked[i] = Compose16(Av(PasserQuad, 2, 1, 0) * q + Av(PasserLinear, 2, 1, 0) * l, Av(PasserQuad, 2, 1, 1) * q + Av(PasserLinear, 2, 1, 1) * l); - PasserFree[i] = Compose16(Av(PasserQuad, 2, 2, 0) * q + Av(PasserLinear, 2, 2, 0) * l, Av(PasserQuad, 2, 2, 1) * q + Av(PasserLinear, 2, 2, 1) * l); - PasserSupported[i] = Compose16(Av(PasserQuad, 2, 3, 0) * q + Av(PasserLinear, 2, 3, 0) * l, Av(PasserQuad, 2, 3, 1) * q + Av(PasserLinear, 2, 3, 1) * l); - PasserProtected[i] = Compose16(Av(PasserQuad, 2, 4, 0) * q + Av(PasserLinear, 2, 4, 0) * l, Av(PasserQuad, 2, 4, 1) * q + Av(PasserLinear, 2, 4, 1) * l); - PasserConnected[i] = Compose16(Av(PasserQuad, 2, 5, 0) * q + Av(PasserLinear, 2, 5, 0) * l, Av(PasserQuad, 2, 5, 1) * q + Av(PasserLinear, 2, 5, 1) * l); - PasserOutside[i] = Compose16(Av(PasserQuad, 2, 6, 0) * q + Av(PasserLinear, 2, 6, 0) * l, Av(PasserQuad, 2, 6, 1) * q + Av(PasserLinear, 2, 6, 1) * l); - PasserCandidate[i] = Compose16(Av(PasserQuad, 2, 7, 0) * q + Av(PasserLinear, 2, 7, 0) * l, Av(PasserQuad, 2, 7, 1) * q + Av(PasserLinear, 2, 7, 1) * l); - PasserClear[i] = Compose16(Av(PasserQuad, 2, 8, 0) * q + Av(PasserLinear, 2, 8, 0) * l, Av(PasserQuad, 2, 8, 1) * q + Av(PasserLinear, 2, 8, 1) * l); - - PasserAtt[i] = Av(PasserAttDefQuad, 2, 0, 0) * q + Av(PasserAttDefLinear, 2, 0, 0) * l; - PasserDef[i] = Av(PasserAttDefQuad, 2, 1, 0) * q + Av(PasserAttDefLinear, 2, 1, 0) * l; - PasserAttLog[i] = Av(PasserAttDefQuad, 2, 0, 1) * q + Av(PasserAttDefLinear, 2, 0, 1) * l; - PasserDefLog[i] = Av(PasserAttDefQuad, 2, 1, 1) * q + Av(PasserAttDefLinear, 2, 1, 1) * l; - } -} +inline int MinF(int x, int y) { return Min(x, y); } +inline int MaxF(int x, int y) { return Max(x, y); } +inline double MinF(double x, double y) { return Min(x, y); } +inline double MaxF(double x, double y) { return Max(x, y); } + +uint16_t rand16(void) +{ + seed = (seed * Convert(6364136223846793005,uint64_t)) + Convert(1442695040888963407,uint64_t); + return Convert((seed >> 32) & 0xFFFF,uint16_t); +} + +uint64_t rand64(void) +{ + uint64_t key = Convert(rand16(),uint64_t); key <<= 16; + key |= Convert(rand16(),uint64_t); key <<= 16; + key |= Convert(rand16(),uint64_t); key <<= 16; + return key | Convert(rand16(),uint64_t); +} + +static char SyzygyPath[BUFSIZ] = {'\0'}; +#define MAX_THREADS (PAGE_SIZE / sizeof(GThreadInfo *)) +static GThreadInfo *THREADS[MAX_THREADS] = {NULL}; + +static void stop(void) +{ + for (unsigned i = 0; i < SETTINGS->numThreads; i++) + THREADS[i]->stop = true; +} + +static void go(void) +{ + if (popcount(PieceAll) <= TB_LARGEST) + { + unsigned res = tb_probe_root(Piece(White), Piece(Black), + King(White) | King(Black), + Queen(White) | Queen(Black), + Rook(White) | Rook(Black), + Bishop(White) | Bishop(Black), + Knight(White) | Knight(Black), + Pawn(White) | Pawn(Black), + Current->ply, + Current->castle_flags, + Current->ep_square, + (Current->turn == White), NULL); + if (res != TB_RESULT_FAILED) + { + int bestScore = TbValues[TB_GET_WDL(res)]; + int flags = 0; + unsigned to = TB_GET_TO(res); + switch (TB_GET_PROMOTES(res)) + { + case TB_PROMOTES_QUEEN: + flags |= FlagPQueen; break; + case TB_PROMOTES_ROOK: + flags |= FlagPRook; break; + case TB_PROMOTES_BISHOP: + flags |= (Bit(to) & LightArea? FlagPLight: FlagPDark); + case TB_PROMOTES_KNIGHT: + flags |= FlagPKnight; break; + default: + break; + } + int bestMove = (TB_GET_FROM(res) << 6) | to | flags; + char movStr[16]; + move_to_string(bestMove, movStr); + char line[BUFSIZ]; + int len = snprintf(line, sizeof(line)-1, "info depth 1 seldepth 1 " + "score cp %d nodes 1 tbhits 1 pv %s\n", bestScore, movStr); + if (len > 0 && len < sizeof(line)-1) + put_line(line, len); + len = snprintf(line, sizeof(line)-1, "bestmove %s\n", movStr); + if (len > 0 && len < sizeof(line)-1) + put_line(line, len); + return; + } + } -void calc_material(int index) { - int pawns[2], knights[2], light[2], dark[2], rooks[2], queens[2], bishops[2], major[2], minor[2], tot[2], mat[2], mul[2], quad[2], score, phase, me, i = index; -#ifdef TUNER - Material[index].generation = generation; -#endif - queens[White] = i % 3; i /= 3; - queens[Black] = i % 3; i /= 3; - rooks[White] = i % 3; i /= 3; - rooks[Black] = i % 3; i /= 3; - light[White] = i % 2; i /= 2; - light[Black] = i % 2; i /= 2; - dark[White] = i % 2; i /= 2; - dark[Black] = i % 2; i /= 2; - knights[White] = i % 3; i /= 3; - knights[Black] = i % 3; i /= 3; - pawns[White] = i % 9; i /= 9; - pawns[Black] = i % 9; - for (me = 0; me < 2; me++) { - bishops[me] = light[me] + dark[me]; - major[me] = rooks[me] + queens[me]; - minor[me] = bishops[me] + knights[me]; - tot[me] = 3 * minor[me] + 5 * rooks[me] + 9 * queens[me]; - mat[me] = mul[me] = 32; - quad[me] = 0; - } - score = (SeeValue[WhitePawn] + Av(MatLinear, 0, 0, 0)) * (pawns[White] - pawns[Black]) + (SeeValue[WhiteKnight] + Av(MatLinear, 0, 0, 1)) * (knights[White] - knights[Black]) - + (SeeValue[WhiteLight] + Av(MatLinear, 0, 0, 2)) * (bishops[White] - bishops[Black]) + (SeeValue[WhiteRook] + Av(MatLinear, 0, 0, 3)) * (rooks[White] - rooks[Black]) - + (SeeValue[WhiteQueen] + Av(MatLinear, 0, 0, 4)) * (queens[White] - queens[Black]) + 50 * ((bishops[White] / 2) - (bishops[Black] / 2)); - phase = Phase[PieceType[WhitePawn]] * (pawns[White] + pawns[Black]) + Phase[PieceType[WhiteKnight]] * (knights[White] + knights[Black]) - + Phase[PieceType[WhiteLight]] * (bishops[White] + bishops[Black]) + Phase[PieceType[WhiteRook]] * (rooks[White] + rooks[Black]) - + Phase[PieceType[WhiteQueen]] * (queens[White] + queens[Black]); - Material[index].phase = Min((Max(phase - PhaseMin, 0) * 128) / (PhaseMax - PhaseMin), 128); - - int special = 0; - for (me = 0; me < 2; me++) { - if (queens[me] == queens[opp]) { - if (rooks[me] - rooks[opp] == 1) { - if (knights[me] == knights[opp] && bishops[opp] - bishops[me] == 1) IncV(special, Ca(MatSpecial, MatRB)); - else if (bishops[me] == bishops[opp] && knights[opp] - knights[me] == 1) IncV(special, Ca(MatSpecial, MatRN)); - else if (knights[me] == knights[opp] && bishops[opp] - bishops[me] == 2) DecV(special, Ca(MatSpecial, MatBBR)); - else if (bishops[me] == bishops[opp] && knights[opp] - knights[me] == 2) DecV(special, Ca(MatSpecial, MatNNR)); - else if (bishops[opp] - bishops[me] == 1 && knights[opp] - knights[me] == 1) DecV(special, Ca(MatSpecial, MatBNR)); - } else if (rooks[me] == rooks[opp] && minor[me] - minor[opp] == 1) IncV(special, Ca(MatSpecial, MatM)); - } else if (queens[me] - queens[opp] == 1) { - if (rooks[opp] - rooks[me] == 2 && minor[opp] - minor[me] == 0) IncV(special, Ca(MatSpecial, MatQRR)); - else if (rooks[opp] - rooks[me] == 1 && knights[opp] == knights[me] && bishops[opp] - bishops[me] == 1) IncV(special, Ca(MatSpecial, MatQRB)); - else if (rooks[opp] - rooks[me] == 1 && knights[opp] - knights[me] == 1 && bishops[opp] == bishops[me]) IncV(special, Ca(MatSpecial, MatQRN)); - else if ((major[opp] + minor[opp]) - (major[me] + minor[me]) >= 2) IncV(special, Ca(MatSpecial, MatQ3)); - } - } - score += (Opening(special) * Material[index].phase + Endgame(special) * (128 - (int)Material[index].phase)) / 128; - - for (me = 0; me < 2; me++) { - quad[me] += pawns[me] * (pawns[me] * TrAv(MatQuadMe, 5, 0, 0) + knights[me] * TrAv(MatQuadMe, 5, 0, 1) - + bishops[me] * TrAv(MatQuadMe, 5, 0, 2) + rooks[me] * TrAv(MatQuadMe, 5, 0, 3) + queens[me] * TrAv(MatQuadMe, 5, 0, 4)); - quad[me] += knights[me] * (knights[me] * TrAv(MatQuadMe, 5, 1, 0) - + bishops[me] * TrAv(MatQuadMe, 5, 1, 1) + rooks[me] * TrAv(MatQuadMe, 5, 1, 2) + queens[me] * TrAv(MatQuadMe, 5, 1, 3)); - quad[me] += bishops[me] * (bishops[me] * TrAv(MatQuadMe, 5, 2, 0) + rooks[me] * TrAv(MatQuadMe, 5, 2, 1) + queens[me] * TrAv(MatQuadMe, 5, 2, 2)); - - quad[me] += rooks[me] * (rooks[me] * TrAv(MatQuadMe, 5, 3, 0) + queens[me] * TrAv(MatQuadMe, 5, 3, 1)); - quad[me] += pawns[me] * (knights[opp] * TrAv(MatQuadOpp, 4, 0, 0) - + bishops[opp] * TrAv(MatQuadOpp, 4, 0, 1) + rooks[opp] * TrAv(MatQuadOpp, 4, 0, 2) + queens[opp] * TrAv(MatQuadOpp, 4, 0, 3)); - quad[me] += knights[me] * (bishops[opp] * TrAv(MatQuadOpp, 4, 1, 0) + rooks[opp] * TrAv(MatQuadOpp, 4, 1, 1) + queens[opp] * TrAv(MatQuadOpp, 4, 1, 2)); - quad[me] += bishops[me] * (rooks[opp] * TrAv(MatQuadOpp, 4, 2, 0) + queens[opp] * TrAv(MatQuadOpp, 4, 2, 1)); - quad[me] += rooks[me] * queens[opp] * TrAv(MatQuadOpp, 4, 3, 0); - - if (bishops[me] >= 2) quad[me] += pawns[me] * Av(BishopPairQuad, 0, 0, 0) + knights[me] * Av(BishopPairQuad, 0, 0, 1) + rooks[me] * Av(BishopPairQuad, 0, 0, 2) - + queens[me] * Av(BishopPairQuad, 0, 0, 3) + pawns[opp] * Av(BishopPairQuad, 0, 0, 4) + knights[opp] * Av(BishopPairQuad, 0, 0, 5) - + bishops[opp] * Av(BishopPairQuad, 0, 0, 6) + rooks[opp] * Av(BishopPairQuad, 0, 0, 7) + queens[opp] * Av(BishopPairQuad, 0, 0, 8); - } - score += (quad[White] - quad[Black]) / 100; - - for (me = 0; me < 2; me++) { - if (tot[me] - tot[opp] <= 3) { - if (!pawns[me]) { - if (tot[me] <= 3) mul[me] = 0; - if (tot[me] == tot[opp] && major[me] == major[opp] && minor[me] == minor[opp]) mul[me] = major[me] + minor[me] <= 2 ? 0 : (major[me] + minor[me] <= 3 ? 16 : 32); - else if (minor[me] + major[me] <= 2) { - if (bishops[me] < 2) mat[me] = (bishops[me] && rooks[me]) ? 8 : 1; - else if (bishops[opp] + rooks[opp] >= 1) mat[me] = 1; - else mat[me] = 32; - } else if (tot[me] - tot[opp] < 3 && minor[me] + major[me] - minor[opp] - major[opp] <= 1) mat[me] = 4; - else if (minor[me] + major[me] <= 3) mat[me] = 8 * (1 + bishops[me]); - else mat[me] = 8 * (2 + bishops[me]); - } - if (pawns[me] <= 1) { - mul[me] = Min(28, mul[me]); - if (rooks[me] == 1 && queens[me] + minor[me] == 0 && rooks[opp] == 1) mat[me] = Min(23, mat[me]); - } - } - if (!major[me]) { - if (!minor[me]) { - if (!tot[me] && pawns[me] < pawns[opp]) DecV(score, (pawns[opp] - pawns[me]) * SeeValue[WhitePawn]); - } else if (minor[me] == 1) { - if (pawns[me] <= 1 && minor[opp] >= 1) mat[me] = 1; - if (bishops[me] == 1) { - if (minor[opp] == 1 && bishops[opp] == 1 && light[me] != light[opp]) { - mul[me] = Min(mul[me], 15); - if (pawns[me] - pawns[opp] <= 1) mul[me] = Min(mul[me], 11); - } - } - } else if (!pawns[me] && knights[me] == 2 && !bishops[me]) { - if (!tot[opp] && pawns[opp]) mat[me] = 6; - else mul[me] = 0; - } - } - if (!mul[me]) mat[me] = 0; - if (mat[me] <= 1 && tot[me] != tot[opp]) mul[me] = Min(mul[me], 8); - } - if (bishops[White] == 1 && bishops[Black] == 1 && light[White] != light[Black]) { - mul[White] = Min(mul[White], 24 + 2 * (knights[Black] + major[Black])); - mul[Black] = Min(mul[Black], 24 + 2 * (knights[White] + major[White])); - } else if (!minor[White] && !minor[Black] && major[White] == 1 && major[Black] == 1 && rooks[White] == rooks[Black]) { - mul[White] = Min(mul[White], 25); - mul[Black] = Min(mul[Black], 25); - } - for (me = 0; me < 2; me++) { - Material[index].mul[me] = mul[me]; - Material[index].pieces[me] = major[me] + minor[me]; - } - if (score > 0) score = (score * mat[White]) / 32; - else score = (score * mat[Black]) / 32; - Material[index].score = score; - for (me = 0; me < 2; me++) { - if (major[me] == 0 && minor[me] == bishops[me] && minor[me] <= 1) Material[index].flags |= VarC(FlagSingleBishop, me); - if (((major[me] == 0 || minor[me] == 0) && major[me] + minor[me] <= 1) || major[opp] + minor[opp] == 0 - || (!pawns[me] && major[me] == rooks[me] && major[me] == 1 && minor[me] == bishops[me] && minor[me] == 1 && rooks[opp] == 1 && !minor[opp] && !queens[opp])) Material[index].flags |= VarC(FlagCallEvalEndgame, me); - } + SHARED->date++; + assert(PVN == 1); // Multi-PV NYI. + memcpy(&SHARED->rootBoard, Board, sizeof(GBoard)); + memcpy(&SHARED->rootData, Current, sizeof(GData)); + memcpy(&SHARED->rootStack, Stack, sp * sizeof(uint64_t)); + SHARED->rootSp = sp; + for (int i = 0; i < SETTINGS->numThreads; i++) + { + THREADS[i]->stop = false; + THREADS[i]->nodes = 0; + THREADS[i]->tbHits = 0; + THREADS[i]->depth = 0; + THREADS[i]->selDepth = 0; + THREADS[i]->bestMove = 0; + THREADS[i]->bestScore = 0; + THREADS[i]->PV[0] = 0; + } + SHARED->state = SETTINGS->numThreads; + cond_broadcast(&SHARED->goCondVar); +} + +static void wait_for_go(void) +{ + cond_wait(&SHARED->goCondVar, &SHARED->mutex); +} + +static void wait_for_stop(void) +{ + const uint64_t maxStopTime = 300; // Max 300ms to stop all threads; + mutex_unlock(&SHARED->mutex); + uint64_t stopTime = get_time(), currTime = stopTime; + while (true) + { + msleep(1); + currTime = get_time(); + if (mutex_lock(&SHARED->mutex, + (currTime - stopTime > maxStopTime? 5: + maxStopTime - (currTime - stopTime)))) + { + emergency_stop(); + return; + } + if (SHARED->state == STOPPED) + break; + if (currTime - stopTime > maxStopTime) + { + emergency_stop(); + return; + } + mutex_unlock(&SHARED->mutex); + } } -void init_material() { -#ifdef TUNER - Material = (GMaterial*)malloc(TotalMat * sizeof(GMaterial)); -#endif - memset(Material,0,TotalMat * sizeof(GMaterial)); - for (int index = 0; index < TotalMat; index++) calc_material(index); +static void emergency_stop(void) +{ + // Something is wrong -- threads are not stopping, or have crashed. + // It is unspecified if the global mutex is locked. We no longer care + // about races. + // Reset everthing. We may lose on time, but so be it. + bool go = (SHARED->state != STOPPED); + int bestMove = 0; + for (unsigned i = 0; go && bestMove == 0 && i < SETTINGS->numThreads; i++) + bestMove = THREADS[i]->bestMove; + // Log this incident: + log("warning: threads crashed or deadlocked; initiating emergency reset\n"); + reset(SETTINGS->numThreads, SETTINGS->syzygyProbeDepth, SETTINGS->hashSize, + SyzygyPath); + if (!go) + return; + char line[32], moveStr[16]; + move_to_string(bestMove, moveStr); + int len = snprintf(line, sizeof(line)-1, "bestmove %s\n", moveStr); + if (len > 0 && len < sizeof(line)-1) + put_line(line, len); + else + { + // Giveup: + char reply[] = "bestmove 0\n"; + put_line(reply, sizeof(reply)); + } } -void init() { - init_shared(); - init_misc(); - if (parent) init_magic(); - for (int i = 0; i < 64; i++) { - BOffsetPointer[i] = MagicAttacks + BOffset[i]; - ROffsetPointer[i] = MagicAttacks + ROffset[i]; - } - gen_kpk(); - init_pst(); - init_eval(); - if (parent) init_material(); -#ifdef EXPLAIN_EVAL - memset(GullCppFile, 0, 16384 * 256); - FILE * fcpp; fcpp = fopen(GullCpp, "r"); - for (cpp_length = 0; cpp_length < 16384; cpp_length++) { - if (feof(fcpp)) break; - fgets(mstring, 65536, fcpp); - memcpy(GullCppFile[cpp_length], mstring, 256); - if (!strchr(GullCppFile[cpp_length], '\n')) GullCppFile[cpp_length][255] = '\n'; - char * p; for (p = GullCppFile[cpp_length]; (*p) == '\t'; p++); - strcpy(mstring, p); strcpy(GullCppFile[cpp_length], mstring); - } - cpp_length--; - fclose(fcpp); -#endif +static inline void check_for_stop(void) +{ + if (!INFO->stop) + return; + longjmp(CheckJump, 1); } void init_search(int clear_hash) { - memset(History,1,16 * 64 * sizeof(sint16)); - memset(Delta,0,16 * 4096 * sizeof(sint16)); - memset(Ref,0,16 * 64 * sizeof(GRef)); - memset(Data + 1, 0, 127 * sizeof(GData)); - if (clear_hash) { - date = 0; - date = 1; - memset(Hash,0,hash_size * sizeof(GEntry)); - memset(PVHash,0,pv_hash_size * sizeof(GPVEntry)); - } - get_board("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); - tb_hits = nodes = 0; - best_move = best_score = 0; - LastTime = LastValue = LastExactValue = InstCnt = 0; - LastSpeed = 0; - PVN = 1; - Infinite = 1; - SearchMoves = 0; - TimeLimit1 = TimeLimit2 = 0; - Stop = Searching = 0; - if (MaxPrN > 1) ZERO_BIT_64(Smpi->searching, 0); - DepthLimit = 128; - LastDepth = 128; - Print = 1; - memset(CurrentSI,0,sizeof(GSearchInfo)); - memset(BaseSI,0,sizeof(GSearchInfo)); + memset(History,1,16 * 64 * sizeof(int16_t)); + memset(Delta,0,16 * 4096 * sizeof(int16_t)); + memset(Ref,0,16 * 64 * sizeof(GRef)); + memset(Data + 1, 0, 127 * sizeof(GData)); + if (clear_hash) { + SHARED->date = 1; + memset(HASH,0,SETTINGS->hashSize); + memset(PVHASH,0,pvHashSize); + } + hash_size = SETTINGS->hashSize / sizeof(GEntry); + assert((hash_size & (hash_size - 1)) == 0); + hash_mask = hash_size - 4; + + get_board("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); +// best_move = best_score = 0; + LastTime = LastValue = LastExactValue = InstCnt = 0; + LastSpeed = 0; + PVN = 1; + SearchMoves = 0; + LastDepth = 128; + memset(CurrentSI,0,sizeof(GSearchInfo)); + memset(BaseSI,0,sizeof(GSearchInfo)); #ifdef CPU_TIMING - GlobalTime[GlobalTurn] = UciBaseTime; - GlobalInc[GlobalTurn] = UciIncTime; + GlobalTime[GlobalTurn] = UciBaseTime; + GlobalInc[GlobalTurn] = UciIncTime; #endif } void setup_board() { - int i; - uint64 occ; - GEntry * Entry; - GPVEntry * PVEntry; - - occ = 0; - sp = 0; - date++; - if (date > 0x8000) { // musn't ever happen - date = 2; - // now GUI must wait for readyok... we have plenty of time :) - for (Entry = Hash, i = 0; i < hash_size; i++, Entry++) Entry->date = 1; - for (PVEntry = PVHash, i = 0; i < pv_hash_size; i++, PVEntry++) PVEntry->date = 1; - } - Current->material = 0; - Current->pst = 0; - Current->key = PieceKey[0][0]; - if (Current->turn) Current->key ^= TurnKey; - Current->key ^= CastleKey[Current->castle_flags]; - if (Current->ep_square) Current->key ^= EPKey[File(Current->ep_square)]; - Current->pawn_key = 0; - Current->pawn_key ^= CastleKey[Current->castle_flags]; - for (i = 0; i < 16; i++) BB(i) = 0; - for (i = 0; i < 64; i++) { - if (Square(i)) { - Add(BB(Square(i)),i); - Add(BB(Square(i) & 1),i); - Add(occ,i); - Current->key ^= PieceKey[Square(i)][i]; - if (Square(i) < WhiteKnight) Current->pawn_key ^= PieceKey[Square(i)][i]; - if (Square(i) < WhiteKing) Current->material += MatCode[Square(i)]; - else Current->pawn_key ^= PieceKey[Square(i)][i]; - Current->pst += Pst(Square(i),i); - } - } - if (popcnt(BB(WhiteKnight)) > 2 || popcnt(BB(WhiteLight)) > 1 || popcnt(BB(WhiteDark)) > 1 - || popcnt(BB(WhiteRook)) > 2 || popcnt(BB(WhiteQueen)) > 2) Current->material |= FlagUnusualMaterial; - if (popcnt(BB(BlackKnight)) > 2 || popcnt(BB(BlackLight)) > 1 || popcnt(BB(BlackDark)) > 1 - || popcnt(BB(BlackRook)) > 2 || popcnt(BB(BlackQueen)) > 2) Current->material |= FlagUnusualMaterial; - Current->capture = 0; - Current->killer[1] = Current->killer[2] = 0; - Current->ply = 0; - Stack[sp] = Current->key; -} - -void get_board(const char fen[]) { - int pos, i, j; - unsigned char c; - - Current = Data; - memset(Board,0,sizeof(GBoard)); - memset(Current,0,sizeof(GData)); - pos = 0; - c = fen[pos]; - while (c == ' ') c = fen[++pos]; - for (i = 56; i >= 0; i -= 8) { - for (j = 0; j <= 7; ) { + int i; + uint64_t occ; + GEntry * Entry; + GPVEntry * PVEntry; + + occ = 0; + sp = 0; + SHARED->date++; + if (SHARED->date > 0x8000) { // musn't ever happen + SHARED->date = 2; + // now GUI must wait for readyok... we have plenty of time :) + for (Entry = HASH, i = 0; i < hash_size; i++, Entry++) Entry->date = 1; + for (PVEntry = PVHASH, i = 0; i < pv_hash_size; i++, PVEntry++) PVEntry->date = 1; + } + Current->material = 0; + Current->pst = 0; + Current->key = DATA->PieceKey[0][0]; + if (Current->turn) Current->key ^= DATA->TurnKey; + Current->key ^= DATA->CastleKey[Current->castle_flags]; + if (Current->ep_square) Current->key ^= DATA->EPKey[File(Current->ep_square)]; + Current->pawn_key = 0; + Current->pawn_key ^= DATA->CastleKey[Current->castle_flags]; + for (i = 0; i < 16; i++) BB(i) = 0; + for (i = 0; i < 64; i++) { + if (Square(i)) { + Add(BB(Square(i)),i); + Add(BB(Square(i) & 1),i); + Add(occ,i); + Current->key ^= DATA->PieceKey[Square(i)][i]; + if (Square(i) < WhiteKnight) Current->pawn_key ^= DATA->PieceKey[Square(i)][i]; + if (Square(i) < WhiteKing) Current->material += MatCode[Square(i)]; + else Current->pawn_key ^= DATA->PieceKey[Square(i)][i]; + Current->pst += Pst(Square(i),i); + } + } + if (popcount(BB(WhiteKnight)) > 2 || popcount(BB(WhiteLight)) > 1 || popcount(BB(WhiteDark)) > 1 + || popcount(BB(WhiteRook)) > 2 || popcount(BB(WhiteQueen)) > 2) Current->material |= FlagUnusualMaterial; + if (popcount(BB(BlackKnight)) > 2 || popcount(BB(BlackLight)) > 1 || popcount(BB(BlackDark)) > 1 + || popcount(BB(BlackRook)) > 2 || popcount(BB(BlackQueen)) > 2) Current->material |= FlagUnusualMaterial; + Current->capture = 0; + Current->killer[1] = Current->killer[2] = 0; + Current->ply = 0; + Stack[sp] = Current->key; +} + +const char *get_board(const char fen[]) { + int pos, i, j; + unsigned char c; + + Current = Data; + memset(Board,0,sizeof(GBoard)); + memset(Current,0,sizeof(GData)); + pos = 0; + c = fen[pos]; + while (c == ' ') c = fen[++pos]; + for (i = 56; i >= 0; i -= 8) { + for (j = 0; j <= 7; ) { if (c <= '8') j += c - '0'; - else { - Square(i+j) = PieceFromChar[c]; - if (Even(SDiag(i+j)) && (Square(i+j)/2) == 3) Square(i+j) += 2; - j++; - } - c = fen[++pos]; - } - c = fen[++pos]; - } - if (c == 'b') Current->turn = 1; - c = fen[++pos]; c = fen[++pos]; + else { + Square(i+j) = DATA->PieceFromChar[c]; + if (Even(SDiag(i+j)) && (Square(i+j)/2) == 3) Square(i+j) += 2; + j++; + } + c = fen[++pos]; + } + c = fen[++pos]; + } + if (c == 'b') Current->turn = 1; + c = fen[++pos]; c = fen[++pos]; if (c == '-') c = fen[++pos]; - if (c == 'K') { Current->castle_flags |= CanCastle_OO; c = fen[++pos]; } - if (c == 'Q') { Current->castle_flags |= CanCastle_OOO; c = fen[++pos]; } - if (c == 'k') { Current->castle_flags |= CanCastle_oo; c = fen[++pos]; } - if (c == 'q') { Current->castle_flags |= CanCastle_ooo; c = fen[++pos]; } - c = fen[++pos]; - if (c != '-') { + if (c == 'K') { Current->castle_flags |= CanCastle_OO; c = fen[++pos]; } + if (c == 'Q') { Current->castle_flags |= CanCastle_OOO; c = fen[++pos]; } + if (c == 'k') { Current->castle_flags |= CanCastle_oo; c = fen[++pos]; } + if (c == 'q') { Current->castle_flags |= CanCastle_ooo; c = fen[++pos]; } + c = fen[++pos]; + if (c == '-') c = fen[++pos]; + else + { i = c + fen[++pos] * 8 - 489; - j = i ^ 8; - if (Square(i) != 0) i = 0; - else if (Square(j) != (3 - Current->turn)) i = 0; - else if (Square(j-1) != (Current->turn+2) && Square(j+1) != (Current->turn+2)) i = 0; - Current->ep_square = i; - } - setup_board(); -} - -__forceinline GEntry * probe_hash() { - for (GEntry * Entry = Hash + (High32(Current->key) & hash_mask); Entry < (Hash + (High32(Current->key) & hash_mask)) + 4; Entry++) if (Low32(Current->key) == Entry->key) { - Entry->date = date; - return Entry; - } - return NULL; + j = i ^ 8; + if (Square(i) != 0) i = 0; + else if (Square(j) != (3 - Current->turn)) i = 0; + else if (Square(j-1) != (Current->turn+2) && Square(j+1) != (Current->turn+2)) i = 0; + Current->ep_square = i; + } + c = fen[++pos]; + char numStr[4] = {'\0'}; + numStr[0] = c; + for (i = 1; i < 3 && isdigit(c = fen[++pos]); i++) + numStr[i] = c; + Current->ply = atoi(numStr); + memset(numStr, 0, sizeof(numStr)); + c = fen[++pos]; + numStr[0] = c; + for (i = 1; i < 3 && isdigit(c = fen[++pos]); i++) + numStr[i] = c; + SHARED->rootDepth = atoi(numStr); + setup_board(); + return fen + pos; +} + +inline GEntry * probe_hash() { + for (GEntry * Entry = HASH + (High32(Current->key) & hash_mask); Entry < (HASH + (High32(Current->key) & hash_mask)) + 4; Entry++) if (Low32(Current->key) == Entry->key) { + Entry->date = SHARED->date; + return Entry; + } + return NULL; } -__forceinline GPVEntry * probe_pv_hash() { - for (GPVEntry * PVEntry = PVHash + (High32(Current->key) & pv_hash_mask); PVEntry < PVHash + (High32(Current->key) & pv_hash_mask) + pv_cluster_size; PVEntry++) if (Low32(Current->key) == PVEntry->key) { - PVEntry->date = date; - return PVEntry; - } - return NULL; +inline GPVEntry * probe_pv_hash() { + for (GPVEntry * PVEntry = PVHASH + (High32(Current->key) & pv_hash_mask); PVEntry < PVHASH + (High32(Current->key) & pv_hash_mask) + pv_cluster_size; PVEntry++) if (Low32(Current->key) == PVEntry->key) { + PVEntry->date = SHARED->date; + return PVEntry; + } + return NULL; } void move_to_string(int move, char string[]) { - int pos = 0; + int pos = 0; string[pos++] = ((move >> 6) & 7) + 'a'; string[pos++] = ((move >> 9) & 7) + '1'; string[pos++] = (move & 7) + 'a'; @@ -2830,7 +1353,7 @@ void move_to_string(int move, char string[]) { } int move_from_string(char string[]) { - int from, to, move; + int from, to, move; from = ((string[1] - '1') * 8) + (string[0] - 'a'); to = ((string[3] - '1') * 8) + (string[2] - 'a'); move = (from << 6) | to; @@ -2840,4316 +1363,3954 @@ int move_from_string(char string[]) { if (string[4] == 'q') move |= FlagPQueen; else if (string[4] == 'r') move |= FlagPRook; else if (string[4] == 'b') { - if (Odd(to ^ Rank(to))) move |= FlagPLight; - else move |= FlagPDark; - } else if (string[4] == 'n') move |= FlagPKnight; + if (Odd(to ^ Rank(to))) move |= FlagPLight; + else move |= FlagPDark; + } else if (string[4] == 'n') move |= FlagPKnight; } return move; } -void pick_pv() { - GEntry * Entry; - GPVEntry * PVEntry; - int i, depth, move; - if (pvp >= Min(pv_length,64)) { - PV[pvp] = 0; - return; - } - move = 0; - depth = -256; - if (Entry = probe_hash()) if (T(Entry->move) && Entry->low_depth > depth) { - depth = Entry->low_depth; - move = Entry->move; - } - if (PVEntry = probe_pv_hash()) if (T(PVEntry->move) && PVEntry->depth > depth) { - depth = PVEntry->depth; - move = PVEntry->move; - } - evaluate(); - if (Current->att[Current->turn] & King(Current->turn ^ 1)) PV[pvp] = 0; - else if (move && (Current->turn ? is_legal<1>(move) : is_legal<0>(move))) { - PV[pvp] = move; - pvp++; - if (Current->turn) do_move<1>(move); - else do_move<0>(move); - if (Current->ply >= 100) goto finish; - for (i = 4; i <= Current->ply; i+= 2) if (Stack[sp-i] == Current->key) { - PV[pvp] = 0; - goto finish; - } - pick_pv(); +void pick_pv(unsigned pvPtr, unsigned pvLen) +{ + GEntry *Entry; + GPVEntry *PVEntry; + int i, depth, move; + if (pvPtr >= Min(pvLen, MAX_PV_LEN)) + { + INFO->PV[pvPtr] = 0; + return; + } + move = 0; + depth = -256; + if ((Entry = probe_hash()) && T(Entry->move) && Entry->low_depth > depth) + { + depth = Entry->low_depth; + move = Entry->move; + } + if ((PVEntry = probe_pv_hash()) && T(PVEntry->move) && PVEntry->depth > depth) + { + depth = PVEntry->depth; + move = PVEntry->move; + } + evaluate(); + if (Current->att[Current->turn] & King(Current->turn ^ 1)) + INFO->PV[pvPtr] = 0; + else if (move && (Current->turn ? is_legal<1>(move) : is_legal<0>(move))) + { + INFO->PV[pvPtr] = move; + pvPtr++; + if (Current->turn) do_move<1>(move); else do_move<0>(move); + if (Current->ply >= 100) goto finish; + for (i = 4; i <= Current->ply; i+= 2) + { + if (Stack[sp-i] == Current->key) + { + INFO->PV[pvPtr] = 0; + goto finish; + } + } + pick_pv(pvPtr, pvLen); finish: - if (Current->turn ^ 1) undo_move<1>(move); - else undo_move<0>(move); - } else PV[pvp] = 0; + if (Current->turn ^ 1) undo_move<1>(move); else undo_move<0>(move); + } + else + INFO->PV[pvPtr] = 0; } template int draw_in_pv() { - if ((Current - Data) >= 126) return 1; - if (Current->ply >= 100) return 1; - for (int i = 4; i <= Current->ply; i += 2) if (Stack[sp - i] == Current->key) return 1; - if (GPVEntry * PVEntry = probe_pv_hash()) { - if (!PVEntry->value) return 1; - if (int move = PVEntry->move) { - do_move(move); - int value = draw_in_pv(); - undo_move(move); - return value; - } - } - return 0; + if ((Current - Data) >= 126) return 1; + if (Current->ply >= 100) return 1; + for (int i = 4; i <= Current->ply; i += 2) if (Stack[sp - i] == Current->key) return 1; + if (GPVEntry * PVEntry = probe_pv_hash()) { + if (!PVEntry->value) return 1; + if (int move = PVEntry->move) { + do_move(move); + int value = draw_in_pv(); + undo_move(move); + return value; + } + } + return 0; } template void do_move(int move) { - GEntry * Entry; - GPawnEntry * PawnEntry; - int from, to, piece, capture; - GData * Next; - uint64 u, mask_from, mask_to; - - to = To(move); - Next = Current + 1; - Next->ep_square = 0; - capture = Square(to); + GEntry * Entry; + GPawnEntry * PawnEntry; + int from, to, piece, capture; + GData * Next; + uint64_t u, mask_from, mask_to; + + to = To(move); + Next = Current + 1; + Next->ep_square = 0; + capture = Square(to); if (F(capture)) { - Next->capture = 0; - goto non_capture; - } - from = From(move); - piece = Square(from); - Next->turn = opp; - Next->capture = capture; - Square(from) = 0; - Square(to) = piece; - Next->piece = piece; - mask_from = Bit(from); - mask_to = Bit(to); - BB(piece) ^= mask_from; - Piece(me) ^= mask_from; - BB(capture) ^= mask_to; - Piece(opp) ^= mask_to; - BB(piece) |= mask_to; - Piece(me) |= mask_to; - Next->castle_flags = Current->castle_flags & UpdateCastling[to] & UpdateCastling[from]; - Next->pst = Current->pst + Pst(piece,to) - Pst(piece,from) - Pst(capture,to); - Next->key = Current->key ^ PieceKey[piece][from] ^ PieceKey[piece][to] ^ PieceKey[capture][to] ^ CastleKey[Current->castle_flags] ^ CastleKey[Next->castle_flags]; - if (capture != IPawn(opp)) Next->pawn_key = Current->pawn_key ^ CastleKey[Current->castle_flags] ^ CastleKey[Next->castle_flags]; // of course we can put a lot of operations inside this "if {}" but the speedup won't be worth the effort - else Next->pawn_key = Current->pawn_key ^ PieceKey[IPawn(opp)][to] ^ CastleKey[Current->castle_flags] ^ CastleKey[Next->castle_flags]; - Next->material = Current->material - MatCode[capture]; - if (T(Current->material & FlagUnusualMaterial) && capture >= WhiteKnight) { - if (popcnt(BB(WhiteQueen)) <= 2 && popcnt(BB(BlackQueen)) <= 2) { - if (popcnt(BB(WhiteLight)) <= 1 && popcnt(BB(BlackLight)) <= 1 && popcnt(BB(WhiteKnight)) <= 2 - && popcnt(BB(BlackKnight)) <= 2 && popcnt(BB(WhiteRook)) <= 2 && popcnt(BB(BlackRook)) <= 2) - Next->material ^= FlagUnusualMaterial; - } - } - if (piece == IPawn(me)) { - Next->pawn_key ^= PieceKey[IPawn(me)][from] ^ PieceKey[piece][to]; - if (IsPromotion(move)) { - piece = Promotion(move,me); - Square(to) = piece; - Next->material += MatCode[piece] - MatCode[IPawn(me)]; - if (piece < WhiteRook) { - if (piece >= WhiteLight && T(BB(piece))) Next->material |= FlagUnusualMaterial; - if (Multiple(BB(piece))) Next->material |= FlagUnusualMaterial; - } else if (Multiple(BB(piece))) Next->material |= FlagUnusualMaterial; - Pawn(me) ^= mask_to; - BB(piece) |= mask_to; - Next->pst += Pst(piece,to) - Pst(IPawn(me),to); - Next->key ^= PieceKey[piece][to] ^ PieceKey[IPawn(me)][to]; - Next->pawn_key ^= PieceKey[IPawn(me)][to]; - } - PawnEntry = PawnHash + (Next->pawn_key & pawn_hash_mask); - prefetch((char *)PawnEntry,_MM_HINT_NTA); - } else if (piece >= WhiteKing) { - Next->pawn_key ^= PieceKey[piece][from] ^ PieceKey[piece][to]; - PawnEntry = PawnHash + (Next->pawn_key & pawn_hash_mask); - prefetch((char *)PawnEntry,_MM_HINT_NTA); - } else if (capture < WhiteKnight) { - PawnEntry = PawnHash + (Next->pawn_key & pawn_hash_mask); - prefetch((char *)PawnEntry,_MM_HINT_NTA); - } - if (F(Next->material & FlagUnusualMaterial)) prefetch((char *)(Material + Next->material), _MM_HINT_NTA); - if (Current->ep_square) Next->key ^= EPKey[File(Current->ep_square)]; - Next->turn = Current->turn ^ 1; - Next->key ^= TurnKey; - Entry = Hash + (High32(Next->key) & hash_mask); - prefetch((char *)Entry,_MM_HINT_NTA); - Next->ply = 0; - goto finish; + Next->capture = 0; + goto non_capture; + } + from = From(move); + piece = Square(from); + Next->turn = opp; + Next->capture = capture; + Square(from) = 0; + Square(to) = piece; + Next->piece = piece; + mask_from = Bit(from); + mask_to = Bit(to); + BB(piece) ^= mask_from; + Piece(me) ^= mask_from; + BB(capture) ^= mask_to; + Piece(opp) ^= mask_to; + BB(piece) |= mask_to; + Piece(me) |= mask_to; + Next->castle_flags = Current->castle_flags & DATA->UpdateCastling[to] & DATA->UpdateCastling[from]; + Next->pst = Current->pst + Pst(piece,to) - Pst(piece,from) - Pst(capture,to); + Next->key = Current->key ^ DATA->PieceKey[piece][from] ^ DATA->PieceKey[piece][to] ^ DATA->PieceKey[capture][to] ^ DATA->CastleKey[Current->castle_flags] ^ DATA->CastleKey[Next->castle_flags]; + if (capture != IPawn(opp)) Next->pawn_key = Current->pawn_key ^ DATA->CastleKey[Current->castle_flags] ^ DATA->CastleKey[Next->castle_flags]; // of course we can put a lot of operations inside this "if {}" but the speedup won't be worth the effort + else Next->pawn_key = Current->pawn_key ^ DATA->PieceKey[IPawn(opp)][to] ^ DATA->CastleKey[Current->castle_flags] ^ DATA->CastleKey[Next->castle_flags]; + Next->material = Current->material - MatCode[capture]; + if (T(Current->material & FlagUnusualMaterial) && capture >= WhiteKnight) { + if (popcount(BB(WhiteQueen)) <= 2 && popcount(BB(BlackQueen)) <= 2) { + if (popcount(BB(WhiteLight)) <= 1 && popcount(BB(BlackLight)) <= 1 && popcount(BB(WhiteKnight)) <= 2 + && popcount(BB(BlackKnight)) <= 2 && popcount(BB(WhiteRook)) <= 2 && popcount(BB(BlackRook)) <= 2) + Next->material ^= FlagUnusualMaterial; + } + } + if (piece == IPawn(me)) { + Next->pawn_key ^= DATA->PieceKey[IPawn(me)][from] ^ DATA->PieceKey[piece][to]; + if (IsPromotion(move)) { + piece = Promotion(move,me); + Square(to) = piece; + Next->material += MatCode[piece] - MatCode[IPawn(me)]; + if (piece < WhiteRook) { + if (piece >= WhiteLight && T(BB(piece))) Next->material |= FlagUnusualMaterial; + if (Multiple(BB(piece))) Next->material |= FlagUnusualMaterial; + } else if (Multiple(BB(piece))) Next->material |= FlagUnusualMaterial; + Pawn(me) ^= mask_to; + BB(piece) |= mask_to; + Next->pst += Pst(piece,to) - Pst(IPawn(me),to); + Next->key ^= DATA->PieceKey[piece][to] ^ DATA->PieceKey[IPawn(me)][to]; + Next->pawn_key ^= DATA->PieceKey[IPawn(me)][to]; + } + PawnEntry = PAWNHASH + (Next->pawn_key & pawn_hash_mask); + prefetch((char *)PawnEntry,_MM_HINT_NTA); + } else if (piece >= WhiteKing) { + Next->pawn_key ^= DATA->PieceKey[piece][from] ^ DATA->PieceKey[piece][to]; + PawnEntry = PAWNHASH + (Next->pawn_key & pawn_hash_mask); + prefetch((char *)PawnEntry,_MM_HINT_NTA); + } else if (capture < WhiteKnight) { + PawnEntry = PAWNHASH + (Next->pawn_key & pawn_hash_mask); + prefetch((char *)PawnEntry,_MM_HINT_NTA); + } + if (F(Next->material & FlagUnusualMaterial)) prefetch((char *)(DATA->Material + Next->material), _MM_HINT_NTA); + if (Current->ep_square) Next->key ^= DATA->EPKey[File(Current->ep_square)]; + Next->turn = Current->turn ^ 1; + Next->key ^= DATA->TurnKey; + Entry = HASH + (High32(Next->key) & hash_mask); + prefetch((char *)Entry,_MM_HINT_NTA); + Next->ply = 0; + goto finish; non_capture: - from = From(move); - Next->ply = Current->ply + 1; - piece = Square(from); - Square(from) = 0; - Square(to) = piece; - Next->piece = piece; - mask_from = Bit(from); - mask_to = Bit(to); - BB(piece) ^= mask_from; - Piece(me) ^= mask_from; - BB(piece) |= mask_to; - Piece(me) |= mask_to; - Next->castle_flags = Current->castle_flags & UpdateCastling[to] & UpdateCastling[from]; - Next->pst = Current->pst + Pst(piece,to) - Pst(piece,from); - Next->key = Current->key ^ PieceKey[piece][to] ^ PieceKey[piece][from] ^ CastleKey[Current->castle_flags] ^ CastleKey[Next->castle_flags]; - Next->material = Current->material; - if (piece == IPawn(me)) { - Next->ply = 0; - Next->pawn_key = Current->pawn_key ^ PieceKey[IPawn(me)][to] ^ PieceKey[IPawn(me)][from] ^ CastleKey[Current->castle_flags] ^ CastleKey[Next->castle_flags]; - if (IsEP(move)) { - Square(to ^ 8) = 0; - u = Bit(to ^ 8); - Next->key ^= PieceKey[IPawn(opp)][to ^ 8]; - Next->pawn_key ^= PieceKey[IPawn(opp)][to ^ 8]; - Next->pst -= Pst(IPawn(opp),to ^ 8); - Pawn(opp) &= ~u; - Piece(opp) &= ~u; - Next->material -= MatCode[IPawn(opp)]; - } else if (IsPromotion(move)) { - piece = Promotion(move,me); - Square(to) = piece; - Next->material += MatCode[piece] - MatCode[IPawn(me)]; - if (piece < WhiteRook) { - if (piece >= WhiteLight && T(BB(piece))) Next->material |= FlagUnusualMaterial; - if (Multiple(BB(piece))) Next->material |= FlagUnusualMaterial; - } else if (Multiple(BB(piece))) Next->material |= FlagUnusualMaterial; - Pawn(me) ^= mask_to; - BB(piece) |= mask_to; - Next->pst += Pst(piece,to) - Pst(IPawn(me),to); - Next->key ^= PieceKey[piece][to] ^ PieceKey[IPawn(me)][to]; - Next->pawn_key ^= PieceKey[IPawn(me)][to]; - } else if ((to ^ from) == 16) { - if (PAtt[me][(to + from) >> 1] & Pawn(opp)) { - Next->ep_square = (to + from) >> 1; - Next->key ^= EPKey[File(Next->ep_square)]; - } - } - PawnEntry = PawnHash + (Next->pawn_key & pawn_hash_mask); - prefetch((char *)PawnEntry,_MM_HINT_NTA); - } else { - if (piece < WhiteKing) Next->pawn_key = Current->pawn_key ^ CastleKey[Current->castle_flags] ^ CastleKey[Next->castle_flags]; - else { - Next->pawn_key = Current->pawn_key ^ PieceKey[piece][to] ^ PieceKey[piece][from] ^ CastleKey[Current->castle_flags] ^ CastleKey[Next->castle_flags]; - PawnEntry = PawnHash + (Next->pawn_key & pawn_hash_mask); - prefetch((char *)PawnEntry,_MM_HINT_NTA); - } - if (IsCastling(move)) { - int rold, rnew; - Next->ply = 0; - if (to == 6) { - rold = 7; - rnew = 5; - } else if (to == 2) { + from = From(move); + Next->ply = Current->ply + 1; + piece = Square(from); + Square(from) = 0; + Square(to) = piece; + Next->piece = piece; + mask_from = Bit(from); + mask_to = Bit(to); + BB(piece) ^= mask_from; + Piece(me) ^= mask_from; + BB(piece) |= mask_to; + Piece(me) |= mask_to; + Next->castle_flags = Current->castle_flags & DATA->UpdateCastling[to] & DATA->UpdateCastling[from]; + Next->pst = Current->pst + Pst(piece,to) - Pst(piece,from); + Next->key = Current->key ^ DATA->PieceKey[piece][to] ^ DATA->PieceKey[piece][from] ^ DATA->CastleKey[Current->castle_flags] ^ DATA->CastleKey[Next->castle_flags]; + Next->material = Current->material; + if (piece == IPawn(me)) { + Next->ply = 0; + Next->pawn_key = Current->pawn_key ^ DATA->PieceKey[IPawn(me)][to] ^ DATA->PieceKey[IPawn(me)][from] ^ DATA->CastleKey[Current->castle_flags] ^ DATA->CastleKey[Next->castle_flags]; + if (IsEP(move)) { + Square(to ^ 8) = 0; + u = Bit(to ^ 8); + Next->key ^= DATA->PieceKey[IPawn(opp)][to ^ 8]; + Next->pawn_key ^= DATA->PieceKey[IPawn(opp)][to ^ 8]; + Next->pst -= Pst(IPawn(opp),to ^ 8); + Pawn(opp) &= ~u; + Piece(opp) &= ~u; + Next->material -= MatCode[IPawn(opp)]; + } else if (IsPromotion(move)) { + piece = Promotion(move,me); + Square(to) = piece; + Next->material += MatCode[piece] - MatCode[IPawn(me)]; + if (piece < WhiteRook) { + if (piece >= WhiteLight && T(BB(piece))) Next->material |= FlagUnusualMaterial; + if (Multiple(BB(piece))) Next->material |= FlagUnusualMaterial; + } else if (Multiple(BB(piece))) Next->material |= FlagUnusualMaterial; + Pawn(me) ^= mask_to; + BB(piece) |= mask_to; + Next->pst += Pst(piece,to) - Pst(IPawn(me),to); + Next->key ^= DATA->PieceKey[piece][to] ^ DATA->PieceKey[IPawn(me)][to]; + Next->pawn_key ^= DATA->PieceKey[IPawn(me)][to]; + } else if ((to ^ from) == 16) { + if (DATA->PAtt[me][(to + from) >> 1] & Pawn(opp)) { + Next->ep_square = (to + from) >> 1; + Next->key ^= DATA->EPKey[File(Next->ep_square)]; + } + } + PawnEntry = PAWNHASH + (Next->pawn_key & pawn_hash_mask); + prefetch((char *)PawnEntry,_MM_HINT_NTA); + } else { + if (piece < WhiteKing) Next->pawn_key = Current->pawn_key ^ DATA->CastleKey[Current->castle_flags] ^ DATA->CastleKey[Next->castle_flags]; + else { + Next->pawn_key = Current->pawn_key ^ DATA->PieceKey[piece][to] ^ DATA->PieceKey[piece][from] ^ DATA->CastleKey[Current->castle_flags] ^ DATA->CastleKey[Next->castle_flags]; + PawnEntry = PAWNHASH + (Next->pawn_key & pawn_hash_mask); + prefetch((char *)PawnEntry,_MM_HINT_NTA); + } + if (IsCastling(move)) { + int rold, rnew; + Next->ply = 0; + if (to == 6) { + rold = 7; + rnew = 5; + } else if (to == 2) { rold = 0; - rnew = 3; - } else if (to == 62) { + rnew = 3; + } else if (to == 62) { rold = 63; - rnew = 61; - } else if (to == 58) { + rnew = 61; + } else if (to == 58) { rold = 56; - rnew = 59; - } - Add(mask_to,rnew); - Square(rold) = 0; - Square(rnew) = IRook(me); - BB(IRook(me)) ^= Bit(rold); - Piece(me) ^= Bit(rold); - BB(IRook(me)) |= Bit(rnew); - Piece(me) |= Bit(rnew); - Next->pst += Pst(IRook(me),rnew) - Pst(IRook(me),rold); - Next->key ^= PieceKey[IRook(me)][rnew] ^ PieceKey[IRook(me)][rold]; - } - } - - if (Current->ep_square) Next->key ^= EPKey[File(Current->ep_square)]; - Next->turn = opp; - Next->key ^= TurnKey; - Entry = Hash + (High32(Next->key) & hash_mask); - prefetch((char *)Entry,_MM_HINT_NTA); + rnew = 59; + } + Add(mask_to,rnew); + Square(rold) = 0; + Square(rnew) = IRook(me); + BB(IRook(me)) ^= Bit(rold); + Piece(me) ^= Bit(rold); + BB(IRook(me)) |= Bit(rnew); + Piece(me) |= Bit(rnew); + Next->pst += Pst(IRook(me),rnew) - Pst(IRook(me),rold); + Next->key ^= DATA->PieceKey[IRook(me)][rnew] ^ DATA->PieceKey[IRook(me)][rold]; + } + } + + if (Current->ep_square) Next->key ^= DATA->EPKey[File(Current->ep_square)]; + Next->turn = opp; + Next->key ^= DATA->TurnKey; + Entry = HASH + (High32(Next->key) & hash_mask); + prefetch((char *)Entry,_MM_HINT_NTA); finish: - sp++; - Stack[sp] = Next->key; - Next->move = move; - Next->gen_flags = 0; - Current++; - nodes++; + sp++; + Stack[sp] = Next->key; + Next->move = move; + Next->gen_flags = 0; + Current++; + INFO->nodes++; } template void undo_move(int move) { - int to, from, piece; - from = From(move); - to = To(move); - if (IsPromotion(move)) { - BB(Square(to)) ^= Bit(to); - piece = IPawn(me); - } else piece = Square(to); - Square(from) = piece; - BB(piece) |= Bit(from); - Piece(me) |= Bit(from); - BB(piece) &= ~Bit(to); - Piece(me) ^= Bit(to); - Square(to) = Current->capture; - if (Current->capture) { - BB(Current->capture) |= Bit(to); - Piece(opp) |= Bit(to); - } else { - if (IsCastling(move)) { - int rold, rnew; - if (to == 6) { - rold = 7; - rnew = 5; - } else if (to == 2) { + int to, from, piece; + from = From(move); + to = To(move); + if (IsPromotion(move)) { + BB(Square(to)) ^= Bit(to); + piece = IPawn(me); + } else piece = Square(to); + Square(from) = piece; + BB(piece) |= Bit(from); + Piece(me) |= Bit(from); + BB(piece) &= ~Bit(to); + Piece(me) ^= Bit(to); + Square(to) = Current->capture; + if (Current->capture) { + BB(Current->capture) |= Bit(to); + Piece(opp) |= Bit(to); + } else { + if (IsCastling(move)) { + int rold, rnew; + if (to == 6) { + rold = 7; + rnew = 5; + } else if (to == 2) { rold = 0; - rnew = 3; - } else if (to == 62) { + rnew = 3; + } else if (to == 62) { rold = 63; - rnew = 61; - } else if (to == 58) { + rnew = 61; + } else if (to == 58) { rold = 56; - rnew = 59; - } - Square(rnew) = 0; - Square(rold) = IRook(me); - Rook(me) ^= Bit(rnew); - Piece(me) ^= Bit(rnew); - Rook(me) |= Bit(rold); - Piece(me) |= Bit(rold); - } else if (IsEP(move)) { - to = to ^ 8; - piece = IPawn(opp); - Square(to) = piece; - Piece(opp) |= Bit(to); - Pawn(opp) |= Bit(to); - } - } - Current--; - sp--; + rnew = 59; + } + Square(rnew) = 0; + Square(rold) = IRook(me); + Rook(me) ^= Bit(rnew); + Piece(me) ^= Bit(rnew); + Rook(me) |= Bit(rold); + Piece(me) |= Bit(rold); + } else if (IsEP(move)) { + to = to ^ 8; + piece = IPawn(opp); + Square(to) = piece; + Piece(opp) |= Bit(to); + Pawn(opp) |= Bit(to); + } + } + Current--; + sp--; } void do_null() { - GData * Next; - GEntry * Entry; - - Next = Current + 1; - Next->key = Current->key ^ TurnKey; - Entry = Hash + (High32(Next->key) & hash_mask); - prefetch((char *)Entry,_MM_HINT_NTA); - Next->pawn_key = Current->pawn_key; - Next->eval_key = 0; - Next->turn = Current->turn ^ 1; - Next->material = Current->material; - Next->pst = Current->pst; - Next->ply = 0; - Next->castle_flags = Current->castle_flags; - Next->ep_square = 0; - Next->capture = 0; - if (Current->ep_square) Next->key ^= EPKey[File(Current->ep_square)]; - sp++; - Next->att[White] = Current->att[White]; - Next->att[Black] = Current->att[Black]; - Next->patt[White] = Current->patt[White]; - Next->patt[Black] = Current->patt[Black]; - Next->xray[White] = Current->xray[White]; - Next->xray[Black] = Current->xray[Black]; - Next->pin[White] = Current->pin[White]; - Next->pin[Black] = Current->pin[Black]; - Stack[sp] = Next->key; - Next->threat = Current->threat; - Next->passer = Current->passer; - Next->score = -Current->score; - Next->move = 0; - Next->gen_flags = 0; - Current++; - nodes++; + GData * Next; + GEntry * Entry; + + Next = Current + 1; + Next->key = Current->key ^ DATA->TurnKey; + Entry = HASH + (High32(Next->key) & hash_mask); + prefetch((char *)Entry,_MM_HINT_NTA); + Next->pawn_key = Current->pawn_key; + Next->eval_key = 0; + Next->turn = Current->turn ^ 1; + Next->material = Current->material; + Next->pst = Current->pst; + Next->ply = 0; + Next->castle_flags = Current->castle_flags; + Next->ep_square = 0; + Next->capture = 0; + if (Current->ep_square) Next->key ^= DATA->EPKey[File(Current->ep_square)]; + sp++; + Next->att[White] = Current->att[White]; + Next->att[Black] = Current->att[Black]; + Next->patt[White] = Current->patt[White]; + Next->patt[Black] = Current->patt[Black]; + Next->xray[White] = Current->xray[White]; + Next->xray[Black] = Current->xray[Black]; + Next->pin[White] = Current->pin[White]; + Next->pin[Black] = Current->pin[Black]; + Stack[sp] = Next->key; + Next->threat = Current->threat; + Next->passer = Current->passer; + Next->score = -Current->score; + Next->move = 0; + Next->gen_flags = 0; + Current++; + INFO->nodes++; } void undo_null() { - Current--; - sp--; + Current--; + sp--; } template int krbkrx() { - if (King(opp) & Interior) return 1; - return 16; + if (King(opp) & Interior) return 1; + return 16; } template int kpkx() { - uint64 u; - if (me == White) u = Kpk[Current->turn][lsb(Pawn(White))][lsb(King(White))] & Bit(lsb(King(Black))); - else u = Kpk[Current->turn ^ 1][63 - lsb(Pawn(Black))][63 - lsb(King(Black))] & Bit(63 - lsb(King(White))); - if (u) return 32; - else if (Piece(opp) ^ King(opp)) return 1; - else return 0; + uint64_t u; + if (me == White) u = DATA->Kpk[Current->turn][lsb(Pawn(White))][lsb(King(White))] & Bit(lsb(King(Black))); + else u = DATA->Kpk[Current->turn ^ 1][63 - lsb(Pawn(Black))][63 - lsb(King(Black))] & Bit(63 - lsb(King(White))); + if (u) return 32; + else if (Piece(opp) ^ King(opp)) return 1; + else return 0; } template int knpkx() { - if (Pawn(me) & Line(me, 6) & (File[0] | File[7])) { - int sq = lsb(Pawn(me)); - if (SArea[sq] & King(opp) & (Line(me, 6) | Line(me, 7))) return 0; - if (Square(sq + Push(me)) == IKing(me) && (SArea[lsb(King(me))] && SArea[lsb(King(opp))] & Line(me, 7))) return 0; - } else if (Pawn(me) & Line(me, 5) & (File[0] | File[7])) { - int sq = lsb(Pawn(me)); - if (Square(sq + Push(me)) == IPawn(opp)) { - if (SArea[sq + Push(me)] & King(opp) & Line(me, 7)) return 0; - if ((SArea[sq + Push(me)] & SArea[lsb(King(opp))] & Line(me, 7)) && (!(NAtt[sq + Push(me)] & Knight(me)) || Current->turn == opp)) return 0; - } - } - return 32; + if (Pawn(me) & Line(me, 6) & (DATA->File[0] | DATA->File[7])) { + int sq = lsb(Pawn(me)); + if (DATA->SArea[sq] & King(opp) & (Line(me, 6) | Line(me, 7))) return 0; + if (Square(sq + Push(me)) == IKing(me) && (DATA->SArea[lsb(King(me))] && DATA->SArea[lsb(King(opp))] & Line(me, 7))) return 0; + } else if (Pawn(me) & Line(me, 5) & (DATA->File[0] | DATA->File[7])) { + int sq = lsb(Pawn(me)); + if (Square(sq + Push(me)) == IPawn(opp)) { + if (DATA->SArea[sq + Push(me)] & King(opp) & Line(me, 7)) return 0; + if ((DATA->SArea[sq + Push(me)] & DATA->SArea[lsb(King(opp))] & Line(me, 7)) && (!(DATA->NAtt[sq + Push(me)] & Knight(me)) || Current->turn == opp)) return 0; + } + } + return 32; } template int krpkrx() { - int mul = 32; - int sq = lsb(Pawn(me)); - int rrank = CRank(me, sq); - int o_king = lsb(King(opp)); - int o_rook = lsb(Rook(opp)); - int m_king = lsb(King(me)); - int add_mat = T(Piece(opp) ^ King(opp) ^ Rook(opp)); - int clear = F(add_mat) || F((PWay[opp][sq] | PIsolated[File(sq)]) & Forward[opp][Rank(sq + Push(me))] & (Piece(opp) ^ King(opp) ^ Rook(opp))); - - if (!clear) return 32; - if (!add_mat && !(Pawn(me) & (File[0] | File[7]))) { - int m_rook = lsb(Rook(me)); - if (CRank(me, o_king) < CRank(me, m_rook) && CRank(me, m_rook) < rrank && CRank(me, m_king) >= rrank - 1 && CRank(me, m_king) > CRank(me, m_rook) - && ((SArea[m_king] & Pawn(me)) || (Current->turn == me && Abs(File(sq) - File(m_king)) <= 1 && Abs(rrank - CRank(me, m_king)) <= 2))) return 128; - if (SArea[m_king] & Pawn(me)) { - if (rrank >= 4) { - if ((File(sq) < File(m_rook) && File(m_rook) < File(o_king)) || (File(sq) > File(m_rook) && File(m_rook) > File(o_king))) return 128; - } else if (rrank >= 2) { - if (!(Pawn(me) & (File[1] | File[6])) && rrank + Abs(File(sq) - File(m_rook)) > 4 - && ((File(sq) < File(m_rook) && File(m_rook) < File(o_king)) || (File(sq) > File(m_rook) && File(m_rook) > File(o_king)))) return 128; - } - } - } - - if (PWay[me][sq] & King(opp)) { - if (Pawn(me) & (File[0] | File[7])) mul = Min(mul, add_mat << 3); - if (rrank <= 3) mul = Min(mul, add_mat << 3); - if (rrank == 4 && CRank(me, m_king) <= 4 && CRank(me, o_rook) == 5 && T(King(opp) & (Line(me, 6) | Line(me, 7))) - && (Current->turn != me || F(PAtt[me][sq] & RookAttacks(lsb(Rook(me)), PieceAll) & (~SArea[o_king])))) mul = Min(mul, add_mat << 3); - if (rrank >= 5 && CRank(me, o_rook) <= 1 && (Current->turn != me || Check(me) || Dist(m_king, sq) >= 2)) mul = Min(mul, add_mat << 3); - if (T(King(opp) & (File[1] | File[2] | File[6] | File[7])) && T(Rook(opp) & Line(me, 7)) && T(Between[o_king][o_rook] & (File[3] | File[4])) && F(Rook(me) & Line(me, 7))) mul = Min(mul, add_mat << 3); - return mul; - } else if (rrank == 6 && (Pawn(me) & (File[0] | File[7])) && ((PSupport[me][sq] | PWay[opp][sq]) & Rook(opp)) && CRank(me, o_king) >= 6) { - int dist = Abs(File(sq) - File(o_king)); - if (dist <= 3) mul = Min(mul, add_mat << 3); - if (dist == 4 && ((PSupport[me][o_king] & Rook(me)) || Current->turn == opp)) mul = Min(mul, add_mat << 3); - } - - if (SArea[o_king] & PWay[me][sq] & Line(me, 7)) { - if (rrank <= 4 && CRank(me, m_king) <= 4 && CRank(me, o_rook) == 5) mul = Min(mul, add_mat << 3); - if (rrank == 5 && CRank(me, o_rook) <= 1 && Current->turn != me || (F(SArea[m_king] & PAtt[me][sq] & (~SArea[o_king])) && (Check(me) || Dist(m_king, sq) >= 2))) - mul = Min(mul, add_mat << 3); - } - - if (T(PWay[me][sq] & Rook(me)) && T(PWay[opp][sq] & Rook(opp))) { - if (King(opp) & (File[0] | File[1] | File[6] | File[7]) & Line(me, 6)) mul = Min(mul, add_mat << 3); - else if ((Pawn(me) & (File[0] | File[7])) && (King(opp) & (Line(me, 5) | Line(me, 6))) && Abs(File(sq) - File(o_king)) <= 2 && File(sq) != File(o_king)) mul = Min(mul, add_mat << 3); - } - - if (Abs(File(sq) - File(o_king)) <= 1 && Abs(File(sq) - File(o_rook)) <= 1 && CRank(me, o_rook) > rrank && CRank(me, o_king) > rrank) mul = Min(mul, (Pawn(me) & (File[3] | File[4])) ? 12 : 16); - - return mul; + int mul = 32; + int sq = lsb(Pawn(me)); + int rrank = CRank(me, sq); + int o_king = lsb(King(opp)); + int o_rook = lsb(Rook(opp)); + int m_king = lsb(King(me)); + int add_mat = T(Piece(opp) ^ King(opp) ^ Rook(opp)); + int clear = F(add_mat) || F((DATA->PWay[opp][sq] | DATA->PIsolated[File(sq)]) & DATA->Forward[opp][Rank(sq + Push(me))] & (Piece(opp) ^ King(opp) ^ Rook(opp))); + + if (!clear) return 32; + if (!add_mat && !(Pawn(me) & (DATA->File[0] | DATA->File[7]))) { + int m_rook = lsb(Rook(me)); + if (CRank(me, o_king) < CRank(me, m_rook) && CRank(me, m_rook) < rrank && CRank(me, m_king) >= rrank - 1 && CRank(me, m_king) > CRank(me, m_rook) + && ((DATA->SArea[m_king] & Pawn(me)) || (Current->turn == me && Abs(File(sq) - File(m_king)) <= 1 && Abs(rrank - CRank(me, m_king)) <= 2))) return 128; + if (DATA->SArea[m_king] & Pawn(me)) { + if (rrank >= 4) { + if ((File(sq) < File(m_rook) && File(m_rook) < File(o_king)) || (File(sq) > File(m_rook) && File(m_rook) > File(o_king))) return 128; + } else if (rrank >= 2) { + if (!(Pawn(me) & (DATA->File[1] | DATA->File[6])) && rrank + Abs(File(sq) - File(m_rook)) > 4 + && ((File(sq) < File(m_rook) && File(m_rook) < File(o_king)) || (File(sq) > File(m_rook) && File(m_rook) > File(o_king)))) return 128; + } + } + } + + if (DATA->PWay[me][sq] & King(opp)) { + if (Pawn(me) & (DATA->File[0] | DATA->File[7])) mul = Min(mul, add_mat << 3); + if (rrank <= 3) mul = Min(mul, add_mat << 3); + if (rrank == 4 && CRank(me, m_king) <= 4 && CRank(me, o_rook) == 5 && T(King(opp) & (Line(me, 6) | Line(me, 7))) + && (Current->turn != me || F(DATA->PAtt[me][sq] & RookAttacks(lsb(Rook(me)), PieceAll) & (~DATA->SArea[o_king])))) mul = Min(mul, add_mat << 3); + if (rrank >= 5 && CRank(me, o_rook) <= 1 && (Current->turn != me || Check(me) || Dist(m_king, sq) >= 2)) mul = Min(mul, add_mat << 3); + if (T(King(opp) & (DATA->File[1] | DATA->File[2] | DATA->File[6] | DATA->File[7])) && T(Rook(opp) & Line(me, 7)) && T(DATA->Between[o_king][o_rook] & (DATA->File[3] | DATA->File[4])) && F(Rook(me) & Line(me, 7))) mul = Min(mul, add_mat << 3); + return mul; + } else if (rrank == 6 && (Pawn(me) & (DATA->File[0] | DATA->File[7])) && ((DATA->PSupport[me][sq] | DATA->PWay[opp][sq]) & Rook(opp)) && CRank(me, o_king) >= 6) { + int dist = Abs(File(sq) - File(o_king)); + if (dist <= 3) mul = Min(mul, add_mat << 3); + if (dist == 4 && ((DATA->PSupport[me][o_king] & Rook(me)) || Current->turn == opp)) mul = Min(mul, add_mat << 3); + } + + if (DATA->SArea[o_king] & DATA->PWay[me][sq] & Line(me, 7)) { + if (rrank <= 4 && CRank(me, m_king) <= 4 && CRank(me, o_rook) == 5) mul = Min(mul, add_mat << 3); + if (rrank == 5 && CRank(me, o_rook) <= 1 && Current->turn != me || (F(DATA->SArea[m_king] & DATA->PAtt[me][sq] & (~DATA->SArea[o_king])) && (Check(me) || Dist(m_king, sq) >= 2))) + mul = Min(mul, add_mat << 3); + } + + if (T(DATA->PWay[me][sq] & Rook(me)) && T(DATA->PWay[opp][sq] & Rook(opp))) { + if (King(opp) & (DATA->File[0] | DATA->File[1] | DATA->File[6] | DATA->File[7]) & Line(me, 6)) mul = Min(mul, add_mat << 3); + else if ((Pawn(me) & (DATA->File[0] | DATA->File[7])) && (King(opp) & (Line(me, 5) | Line(me, 6))) && Abs(File(sq) - File(o_king)) <= 2 && File(sq) != File(o_king)) mul = Min(mul, add_mat << 3); + } + + if (Abs(File(sq) - File(o_king)) <= 1 && Abs(File(sq) - File(o_rook)) <= 1 && CRank(me, o_rook) > rrank && CRank(me, o_king) > rrank) mul = Min(mul, (Pawn(me) & (DATA->File[3] | DATA->File[4])) ? 12 : 16); + + return mul; } template int krpkbx() { - if (!(Pawn(me) & Line(me, 5))) return 32; - int sq = lsb(Pawn(me)); - if (!(PWay[me][sq] & King(opp))) return 32; - int diag_sq = NB(me, BMask[sq + Push(me)]); - if (CRank(me, diag_sq) > 1) return 32; - uint64 mdiag = FullLine[sq + Push(me)][diag_sq] | Bit(sq + Push(me)) | Bit(diag_sq); - int check_sq = NB(me, BMask[sq - Push(me)]); - uint64 cdiag = FullLine[sq - Push(me)][check_sq] | Bit(sq - Push(me)) | Bit(check_sq); - if ((mdiag | cdiag) & (Piece(opp) ^ King(opp) ^ Bishop(opp))) return 32; - if (cdiag & Bishop(opp)) return 0; - if ((mdiag & Bishop(opp)) && (Current->turn == opp || !(King(me) & PAtt[opp][sq + Push(me)]))) return 0; - return 32; + if (!(Pawn(me) & Line(me, 5))) return 32; + int sq = lsb(Pawn(me)); + if (!(DATA->PWay[me][sq] & King(opp))) return 32; + int diag_sq = NB(me, DATA->BMask[sq + Push(me)]); + if (CRank(me, diag_sq) > 1) return 32; + uint64_t mdiag = DATA->FullLine[sq + Push(me)][diag_sq] | Bit(sq + Push(me)) | Bit(diag_sq); + int check_sq = NB(me, DATA->BMask[sq - Push(me)]); + uint64_t cdiag = DATA->FullLine[sq - Push(me)][check_sq] | Bit(sq - Push(me)) | Bit(check_sq); + if ((mdiag | cdiag) & (Piece(opp) ^ King(opp) ^ Bishop(opp))) return 32; + if (cdiag & Bishop(opp)) return 0; + if ((mdiag & Bishop(opp)) && (Current->turn == opp || !(King(me) & DATA->PAtt[opp][sq + Push(me)]))) return 0; + return 32; } template int kqkp() { - if (F(SArea[lsb(King(opp))] & Pawn(opp) & Line(me, 1) & (File[0] | File[2] | File[5] | File[7]))) return 32; - if (PWay[opp][lsb(Pawn(opp))] & (King(me) | Queen(me))) return 32; - if (Pawn(opp) & (File[0] | File[7])) return 1; - else return 4; + if (F(DATA->SArea[lsb(King(opp))] & Pawn(opp) & Line(me, 1) & (DATA->File[0] | DATA->File[2] | DATA->File[5] | DATA->File[7]))) return 32; + if (DATA->PWay[opp][lsb(Pawn(opp))] & (King(me) | Queen(me))) return 32; + if (Pawn(opp) & (DATA->File[0] | DATA->File[7])) return 1; + else return 4; } template int kqkrpx() { - int rsq = lsb(Rook(opp)); - uint64 pawns = SArea[lsb(King(opp))] & PAtt[me][rsq] & Pawn(opp) & Interior & Line(me, 6); - if (pawns && CRank(me, lsb(King(me))) <= 4) return 0; - return 32; + int rsq = lsb(Rook(opp)); + uint64_t pawns = DATA->SArea[lsb(King(opp))] & DATA->PAtt[me][rsq] & Pawn(opp) & Interior & Line(me, 6); + if (pawns && CRank(me, lsb(King(me))) <= 4) return 0; + return 32; } template int krkpx() { - if (T(SArea[lsb(King(opp))] & Pawn(opp) & Line(me, 1)) & F(PWay[opp][NB(me, Pawn(opp))] & King(me))) return 0; - return 32; + if (T(DATA->SArea[lsb(King(opp))] & Pawn(opp) & Line(me, 1)) & F(DATA->PWay[opp][NB(me, Pawn(opp))] & King(me))) return 0; + return 32; } template int krppkrpx() { - if (Current->passer & Pawn(me)) { - if (Single(Current->passer & Pawn(me))) { - int sq = lsb(Current->passer & Pawn(me)); - if (PWay[me][sq] & King(opp) & (File[0] | File[1] | File[6] | File[7])) { - int opp_king = lsb(King(opp)); - if (SArea[opp_king] & Pawn(opp)) { - int king_file = File(opp_king); - if (!((~(File[king_file] | PIsolated[king_file])) & Pawn(me))) return 1; - } - } - } - return 32; - } - if (F((~(PWay[opp][lsb(King(opp))] | PSupport[me][lsb(King(opp))])) & Pawn(me))) return 0; - return 32; + if (Current->passer & Pawn(me)) { + if (Single(Current->passer & Pawn(me))) { + int sq = lsb(Current->passer & Pawn(me)); + if (DATA->PWay[me][sq] & King(opp) & (DATA->File[0] | DATA->File[1] | DATA->File[6] | DATA->File[7])) { + int opp_king = lsb(King(opp)); + if (DATA->SArea[opp_king] & Pawn(opp)) { + int king_file = File(opp_king); + if (!((~(DATA->File[king_file] | DATA->PIsolated[king_file])) & Pawn(me))) return 1; + } + } + } + return 32; + } + if (F((~(DATA->PWay[opp][lsb(King(opp))] | DATA->PSupport[me][lsb(King(opp))])) & Pawn(me))) return 0; + return 32; } template int krpppkrppx() { - if (T(Current->passer & Pawn(me)) || F((SArea[lsb(Pawn(opp))] | SArea[msb(Pawn(opp))]) & Pawn(opp))) return 32; - if (F((~(PWay[opp][lsb(King(opp))] | PSupport[me][lsb(King(opp))])) & Pawn(me))) return 0; - return 32; + if (T(Current->passer & Pawn(me)) || F((DATA->SArea[lsb(Pawn(opp))] | DATA->SArea[msb(Pawn(opp))]) & Pawn(opp))) return 32; + if (F((~(DATA->PWay[opp][lsb(King(opp))] | DATA->PSupport[me][lsb(King(opp))])) & Pawn(me))) return 0; + return 32; } template int kbpkbx() { - int sq = lsb(Pawn(me)); - uint64 u; - if ((T(Board->bb[ILight(me)]) && T(Board->bb[IDark(opp)])) || (T(Board->bb[IDark(me)]) && T(Board->bb[ILight(opp)]))) { - if (CRank(me, sq) <= 4) return 0; - if (T(PWay[me][sq] & King(opp)) && CRank(me, sq) <= 5) return 0; - for (u = Bishop(opp); T(u); Cut(u)) { - if (CRank(me, lsb(u)) <= 4 && T(BishopAttacks(lsb(u), PieceAll) & PWay[me][sq])) return 0; - if (Current->turn == opp && T(BishopAttacks(lsb(u), PieceAll) & Pawn(me))) return 0; - } - } else if (T(PWay[me][sq] & King(opp)) && T(King(opp) & LightArea) != T(Bishop(me) & LightArea)) return 0; - return 32; + int sq = lsb(Pawn(me)); + uint64_t u; + if ((T(Board->bb[ILight(me)]) && T(Board->bb[IDark(opp)])) || (T(Board->bb[IDark(me)]) && T(Board->bb[ILight(opp)]))) { + if (CRank(me, sq) <= 4) return 0; + if (T(DATA->PWay[me][sq] & King(opp)) && CRank(me, sq) <= 5) return 0; + for (u = Bishop(opp); T(u); Cut(u)) { + if (CRank(me, lsb(u)) <= 4 && T(BishopAttacks(lsb(u), PieceAll) & DATA->PWay[me][sq])) return 0; + if (Current->turn == opp && T(BishopAttacks(lsb(u), PieceAll) & Pawn(me))) return 0; + } + } else if (T(DATA->PWay[me][sq] & King(opp)) && T(King(opp) & LightArea) != T(Bishop(me) & LightArea)) return 0; + return 32; } template int kbpknx() { - uint64 u; - if (T(PWay[me][lsb(Pawn(me))] & King(opp)) && T(King(opp) & LightArea) != T(Bishop(me) & LightArea)) return 0; - if (Current->turn == opp) - for (u = Knight(opp); T(u); Cut(u)) - if (NAtt[lsb(u)] & Pawn(me)) return 0; - return 32; + uint64_t u; + if (T(DATA->PWay[me][lsb(Pawn(me))] & King(opp)) && T(King(opp) & LightArea) != T(Bishop(me) & LightArea)) return 0; + if (Current->turn == opp) + for (u = Knight(opp); T(u); Cut(u)) + if (DATA->NAtt[lsb(u)] & Pawn(me)) return 0; + return 32; } template int kbppkbx() { - int sq1 = NB(me, Pawn(me)); - int sq2 = NB(opp, Pawn(me)); - int o_king = lsb(King(opp)); - int o_bishop = lsb(Bishop(opp)); - - if (File(sq1) == File(sq2)) { - if (CRank(me, sq2) <= 3) return 0; - if (T(PWay[me][sq2] & King(opp)) && CRank(me, sq2) <= 5) return 0; - } else if (PIsolated[File(sq1)] & Pawn(me)) { - if (T(King(opp) & LightArea) != T(Bishop(me) & LightArea)) { - if (T((SArea[o_king] | King(opp)) & Bit(sq2 + Push(me))) && T(BishopAttacks(o_bishop, PieceAll) & Bit(sq2 + Push(me)))) - if (T((SArea[o_king] | King(opp)) & Bit((sq2 & 0xFFFFFFF8) | File(sq1))) && T(BishopAttacks(o_bishop, PieceAll) & Bit((sq2 & 0xFFFFFFF8) | File(sq1)))) return 0; - } - } - return 32; + int sq1 = NB(me, Pawn(me)); + int sq2 = NB(opp, Pawn(me)); + int o_king = lsb(King(opp)); + int o_bishop = lsb(Bishop(opp)); + + if (File(sq1) == File(sq2)) { + if (CRank(me, sq2) <= 3) return 0; + if (T(DATA->PWay[me][sq2] & King(opp)) && CRank(me, sq2) <= 5) return 0; + } else if (DATA->PIsolated[File(sq1)] & Pawn(me)) { + if (T(King(opp) & LightArea) != T(Bishop(me) & LightArea)) { + if (T((DATA->SArea[o_king] | King(opp)) & Bit(sq2 + Push(me))) && T(BishopAttacks(o_bishop, PieceAll) & Bit(sq2 + Push(me)))) + if (T((DATA->SArea[o_king] | King(opp)) & Bit((sq2 & 0xFFFFFFF8) | File(sq1))) && T(BishopAttacks(o_bishop, PieceAll) & Bit((sq2 & 0xFFFFFFF8) | File(sq1)))) return 0; + } + } + return 32; } template int krppkrx() { - int sq1 = NB(me, Pawn(me)); - int sq2 = NB(opp, Pawn(me)); - - if ((Piece(opp) ^ King(opp) ^ Rook(opp)) & Forward[me][Rank(sq1 - Push(me))]) return 32; - if (File(sq1) == File(sq2)) { - if (T(PWay[me][sq2] & King(opp))) return 16; - return 32; - } - if (T(PIsolated[File(sq2)] & Pawn(me)) && T((File[0] | File[7]) & Pawn(me)) && T(King(opp) & Shift(me, Pawn(me)))) { - if (CRank(me, sq2) == 5 && CRank(me, sq1) == 4 && T(Rook(opp) & (Line(me, 5) | Line(me, 6)))) return 10; - else if (CRank(me, sq2) < 5) return 16; - } - return 32; + int sq1 = NB(me, Pawn(me)); + int sq2 = NB(opp, Pawn(me)); + + if ((Piece(opp) ^ King(opp) ^ Rook(opp)) & DATA->Forward[me][Rank(sq1 - Push(me))]) return 32; + if (File(sq1) == File(sq2)) { + if (T(DATA->PWay[me][sq2] & King(opp))) return 16; + return 32; + } + if (T(DATA->PIsolated[File(sq2)] & Pawn(me)) && T((DATA->File[0] | DATA->File[7]) & Pawn(me)) && T(King(opp) & Shift(me, Pawn(me)))) { + if (CRank(me, sq2) == 5 && CRank(me, sq1) == 4 && T(Rook(opp) & (Line(me, 5) | Line(me, 6)))) return 10; + else if (CRank(me, sq2) < 5) return 16; + } + return 32; } typedef struct { - int king_w, king_b, score; - uint64 patt_w, patt_b, double_att_w, double_att_b; + int king_w, king_b, score; + uint64_t patt_w, patt_b, double_att_w, double_att_b; } GPawnEvalInfo; -template __forceinline void eval_pawns(GPawnEntry * PawnEntry, GPawnEvalInfo &PEI) { - int kf = File(PVarC(PEI, king, me)); - int kr = Rank(PVarC(PEI, king, me)); - int start, inc; - if (kf <= 3) { - start = Max(kf - 1, 0); - inc = 1; - } else { - start = Min(kf + 1, 7); - inc = -1; - } - int shelter = 0; - uint64 mpawns = Pawn(me) & Forward[me][me ? Min(kr + 1, 7) : Max(kr - 1, 0)]; - for (int file = start, i = 0; i < 3; file += inc, i++) { - shelter += Shelter[i][CRank(me, NBZ(me, mpawns & File[file]))]; - int rank; - if (Pawn(opp) & File[file]) { - int sq = NB(me, Pawn(opp) & File[file]); - if ((rank = CRank(opp, sq)) < 6) { - if (rank >= 3) shelter += StormBlocked[rank - 3]; - if (uint64 u = (PIsolated[File(sq)] & Forward[opp][Rank(sq)] & Pawn(me))) { - int square = NB(opp, u); - uint64 att_sq = PAtt[me][square] & PWay[opp][sq]; // may be zero - if ((File[File(square)] | PIsolated[File(square)]) & King(me)) if (!(PVarC(PEI, double_att, me) & att_sq) || (Current->patt[opp] & att_sq)) { - if (PWay[opp][square] & Pawn(me)) continue; - if (!(PawnAll & PWay[opp][sq] & Forward[me][Rank(square)])) { - if (rank >= 3) { - shelter += StormShelterAtt[rank - 3]; - if (PVarC(PEI, patt, opp) & Bit(sq + Push(opp))) shelter += StormConnected[rank - 3]; - if (!(PWay[opp][sq] & PawnAll)) shelter += StormOpen[rank - 3]; - } - if (!((File[File(sq)] | PIsolated[File(sq)]) & King(opp)) && rank <= 4) shelter += StormFree[rank - 1]; - } - } - } - } - } else { - shelter += Sa(StormHof, StormHofValue); - if (!(Pawn(me) & File[file])) shelter += Sa(StormHof, StormOfValue); - } - } - PawnEntry->shelter[me] = shelter; - - uint64 b; - int min_file = 7, max_file = 0; - for (uint64 u = Pawn(me); T(u); u ^= b) { - int sq = lsb(u); - b = Bit(sq); - int rank = Rank(sq); - int rrank = CRank(me, sq); - int file = File(sq); - uint64 way = PWay[me][sq]; - int next = Square(sq + Push(me)); - if (file < min_file) min_file = file; - if (file > max_file) max_file = file; - - int isolated = !(Pawn(me) & PIsolated[file]); - int doubled = T(Pawn(me) & (File[file] ^ b)); - int open = !(PawnAll & way); - int up = !(PVarC(PEI, patt, me) & b); - - if (isolated) { - if (open) DecV(PEI.score, Ca(Isolated, IsolatedOpen)); - else { - DecV(PEI.score, Ca(Isolated, IsolatedClosed)); - if (next == IPawn(opp)) DecV(PEI.score, Ca(Isolated, IsolatedBlocked)); - } - if (doubled) { - if (open) DecV(PEI.score, Ca(Isolated, IsolatedDoubledOpen)); - else DecV(PEI.score, Ca(Isolated, IsolatedDoubledClosed)); - } - } else { - if (doubled) { - if (open) DecV(PEI.score, Ca(Doubled, DoubledOpen)); - else DecV(PEI.score, Ca(Doubled, DoubledClosed)); - } - if (rrank >= 3 && (b & (File[2] | File[3] | File[4] | File[5])) && next != IPawn(opp) && (PIsolated[file] & Line[rank] & Pawn(me))) - IncV(PEI.score, Ca(PawnSpecial, PawnChainLinear) * (rrank - 3) + Ca(PawnSpecial, PawnChain)); - } - int backward = 0; - if (!(PSupport[me][sq] & Pawn(me))) { - if (isolated) backward = 1; - else if (uint64 v = (PawnAll | PVarC(PEI, patt, opp)) & way) if (IsGreater(me, NB(me, PVarC(PEI, patt, me) & way), NB(me, v))) backward = 1; - } - if (backward) { - if (open) DecV(PEI.score, Ca(Backward, BackwardOpen)); - else DecV(PEI.score, Ca(Backward, BackwardClosed)); - } else if (open) if (!(Pawn(opp) & PIsolated[file]) || popcount(Pawn(me) & PIsolated[file]) >= popcount(Pawn(opp) & PIsolated[file])) IncV(PEI.score,PasserCandidate[rrank]); // IDEA: more precise pawn counting for the case of, say, white e5 candidate with black pawn on f5 or f4... - if (up && next == IPawn(opp)) { - DecV(PEI.score, Ca(Unprotected, UpBlocked)); - if (backward) { - if (rrank <= 2) { // IDEA (based on weird passer target tuning result): may be score unprotected/backward depending on rank/file? - DecV(PEI.score, Ca(Unprotected, PasserTarget)); - if (rrank <= 1) DecV(PEI.score, Ca(Unprotected, PasserTarget)); - } - for (uint64 v = PAtt[me][sq] & Pawn(me); v; Cut(v)) if ((PSupport[me][lsb(v)] & Pawn(me)) == b) { - DecV(PEI.score, Ca(Unprotected, ChainRoot)); - break; - } - } - } - if (open && !(PIsolated[file] & Forward[me][rank] & Pawn(opp))) { - PawnEntry->passer[me] |= (uint8)(1 << file); - if (rrank <= 2) continue; - IncV(PEI.score, PasserGeneral[rrank]); - int dist_att = Dist(PVarC(PEI, king, opp), sq + Push(me)); // IDEA: average the distance with the distance to the promotion square? or just use the latter? - int dist_def = Dist(PVarC(PEI, king, me), sq + Push(me)); - IncV(PEI.score, Compose256(0, dist_att * (int)PasserAtt[rrank] + LogDist[dist_att] * (int)PasserAttLog[rrank] - dist_def * (int)PasserDef[rrank] - (int)LogDist[dist_def] * (int)PasserDefLog[rrank])); - if (PVarC(PEI, patt, me) & b) IncV(PEI.score, PasserProtected[rrank]); - if (!(Pawn(opp) & West[file]) || !(Pawn(opp) & East[file])) IncV(PEI.score, PasserOutside[rrank]); - } - } - uint64 files = 0; - for (int i = 1; i < 7; i++) files |= (Pawn(me) >> (i << 3)) & 0xFF; - int file_span = (files ? (msb(files) - lsb(files)) : 0); - IncV(PEI.score, Ca(PawnSpecial, PawnFileSpan) * file_span); - PawnEntry->draw[me] = (7 - file_span) * Max(5 - popcount(files), 0); +template inline void eval_pawns(GPawnEntry * PawnEntry, GPawnEvalInfo &PEI) { + int kf = File(PVarC(PEI, king, me)); + int kr = Rank(PVarC(PEI, king, me)); + int start, inc; + if (kf <= 3) { + start = Max(kf - 1, 0); + inc = 1; + } else { + start = Min(kf + 1, 7); + inc = -1; + } + int shelter = 0; + uint64_t mpawns = Pawn(me) & DATA->Forward[me][me ? Min(kr + 1, 7) : Max(kr - 1, 0)]; + for (int file = start, i = 0; i < 3; file += inc, i++) { + shelter += DATA->Shelter[i][CRank(me, NBZ(me, mpawns & DATA->File[file]))]; + int rank; + if (Pawn(opp) & DATA->File[file]) { + int sq = NB(me, Pawn(opp) & DATA->File[file]); + if ((rank = CRank(opp, sq)) < 6) { + if (rank >= 3) shelter += DATA->StormBlocked[rank - 3]; + if (uint64_t u = (DATA->PIsolated[File(sq)] & DATA->Forward[opp][Rank(sq)] & Pawn(me))) { + int square = NB(opp, u); + uint64_t att_sq = DATA->PAtt[me][square] & DATA->PWay[opp][sq]; // may be zero + if ((DATA->File[File(square)] | DATA->PIsolated[File(square)]) & King(me)) if (!(PVarC(PEI, double_att, me) & att_sq) || (Current->patt[opp] & att_sq)) { + if (DATA->PWay[opp][square] & Pawn(me)) continue; + if (!(PawnAll & DATA->PWay[opp][sq] & DATA->Forward[me][Rank(square)])) { + if (rank >= 3) { + shelter += DATA->StormShelterAtt[rank - 3]; + if (PVarC(PEI, patt, opp) & Bit(sq + Push(opp))) shelter += DATA->StormConnected[rank - 3]; + if (!(DATA->PWay[opp][sq] & PawnAll)) shelter += DATA->StormOpen[rank - 3]; + } + if (!((DATA->File[File(sq)] | DATA->PIsolated[File(sq)]) & King(opp)) && rank <= 4) shelter += DATA->StormFree[rank - 1]; + } + } + } + } + } else { + shelter += Sa(StormHof, StormHofValue); + if (!(Pawn(me) & DATA->File[file])) shelter += Sa(StormHof, StormOfValue); + } + } + PawnEntry->shelter[me] = shelter; + + uint64_t b; + int min_file = 7, max_file = 0; + for (uint64_t u = Pawn(me); T(u); u ^= b) { + int sq = lsb(u); + b = Bit(sq); + int rank = Rank(sq); + int rrank = CRank(me, sq); + int file = File(sq); + uint64_t way = DATA->PWay[me][sq]; + int next = Square(sq + Push(me)); + if (file < min_file) min_file = file; + if (file > max_file) max_file = file; + + int isolated = !(Pawn(me) & DATA->PIsolated[file]); + int doubled = T(Pawn(me) & (DATA->File[file] ^ b)); + int open = !(PawnAll & way); + int up = !(PVarC(PEI, patt, me) & b); + + if (isolated) { + if (open) DecV(PEI.score, Ca(Isolated, IsolatedOpen)); + else { + DecV(PEI.score, Ca(Isolated, IsolatedClosed)); + if (next == IPawn(opp)) DecV(PEI.score, Ca(Isolated, IsolatedBlocked)); + } + if (doubled) { + if (open) DecV(PEI.score, Ca(Isolated, IsolatedDoubledOpen)); + else DecV(PEI.score, Ca(Isolated, IsolatedDoubledClosed)); + } + } else { + if (doubled) { + if (open) DecV(PEI.score, Ca(Doubled, DoubledOpen)); + else DecV(PEI.score, Ca(Doubled, DoubledClosed)); + } + if (rrank >= 3 && (b & (DATA->File[2] | DATA->File[3] | DATA->File[4] | DATA->File[5])) && next != IPawn(opp) && (DATA->PIsolated[file] & DATA->Line[rank] & Pawn(me))) + IncV(PEI.score, Ca(PawnSpecial, PawnChainLinear) * (rrank - 3) + Ca(PawnSpecial, PawnChain)); + } + int backward = 0; + if (!(DATA->PSupport[me][sq] & Pawn(me))) { + if (isolated) backward = 1; + else if (uint64_t v = (PawnAll | PVarC(PEI, patt, opp)) & way) if (IsGreater(me, NB(me, PVarC(PEI, patt, me) & way), NB(me, v))) backward = 1; + } + if (backward) { + if (open) DecV(PEI.score, Ca(Backward, BackwardOpen)); + else DecV(PEI.score, Ca(Backward, BackwardClosed)); + } else if (open) if (!(Pawn(opp) & DATA->PIsolated[file]) || popcount(Pawn(me) & DATA->PIsolated[file]) >= popcount(Pawn(opp) & DATA->PIsolated[file])) IncV(PEI.score,DATA->PasserCandidate[rrank]); // IDEA: more precise pawn counting for the case of, say, white e5 candidate with black pawn on f5 or f4... + if (up && next == IPawn(opp)) { + DecV(PEI.score, Ca(Unprotected, UpBlocked)); + if (backward) { + if (rrank <= 2) { // IDEA (based on weird passer target tuning result): may be score unprotected/backward depending on rank/file? + DecV(PEI.score, Ca(Unprotected, PasserTarget)); + if (rrank <= 1) DecV(PEI.score, Ca(Unprotected, PasserTarget)); + } + for (uint64_t v = DATA->PAtt[me][sq] & Pawn(me); v; Cut(v)) if ((DATA->PSupport[me][lsb(v)] & Pawn(me)) == b) { + DecV(PEI.score, Ca(Unprotected, ChainRoot)); + break; + } + } + } + if (open && !(DATA->PIsolated[file] & DATA->Forward[me][rank] & Pawn(opp))) { + PawnEntry->passer[me] |= (uint8_t)(1 << file); + if (rrank <= 2) continue; + IncV(PEI.score, DATA->PasserGeneral[rrank]); + int dist_att = Dist(PVarC(PEI, king, opp), sq + Push(me)); // IDEA: average the distance with the distance to the promotion square? or just use the latter? + int dist_def = Dist(PVarC(PEI, king, me), sq + Push(me)); + IncV(PEI.score, Compose256(0, dist_att * (int)DATA->PasserAtt[rrank] + DATA->LogDist[dist_att] * (int)DATA->PasserAttLog[rrank] - dist_def * (int)DATA->PasserDef[rrank] - (int)DATA->LogDist[dist_def] * (int)DATA->PasserDefLog[rrank])); + if (PVarC(PEI, patt, me) & b) IncV(PEI.score, DATA->PasserProtected[rrank]); + if (!(Pawn(opp) & DATA->West[file]) || !(Pawn(opp) & DATA->East[file])) IncV(PEI.score, DATA->PasserOutside[rrank]); + } + } + uint64_t files = 0; + for (int i = 1; i < 7; i++) files |= (Pawn(me) >> (i << 3)) & 0xFF; + int file_span = (files ? (msb(files) - lsb(files)) : 0); + IncV(PEI.score, Ca(PawnSpecial, PawnFileSpan) * file_span); + PawnEntry->draw[me] = (7 - file_span) * Max(5 - popcount(files), 0); } -template void eval_pawn_structure(GPawnEntry * PawnEntry) { - GPawnEvalInfo PEI; - for (int i = 0; i < sizeof(GPawnEntry) / sizeof(int); i++) *(((int*)PawnEntry) + i) = 0; - PawnEntry->key = Current->pawn_key; +void eval_pawn_structure(GPawnEntry * PawnEntry) { + GPawnEvalInfo PEI; + for (int i = 0; i < sizeof(GPawnEntry) / sizeof(int); i++) *(((int*)PawnEntry) + i) = 0; + PawnEntry->key = Current->pawn_key; - PEI.patt_w = ShiftW(White, Pawn(White)) | ShiftE(White, Pawn(White)); - PEI.patt_b = ShiftW(Black, Pawn(Black)) | ShiftE(Black, Pawn(Black)); - PEI.double_att_w = ShiftW(White, Pawn(White)) & ShiftE(White, Pawn(White)); - PEI.double_att_b = ShiftW(Black, Pawn(Black)) & ShiftE(Black, Pawn(Black)); - PEI.king_w = lsb(King(White)); - PEI.king_b = lsb(King(Black)); - PEI.score = 0; + PEI.patt_w = ShiftW(White, Pawn(White)) | ShiftE(White, Pawn(White)); + PEI.patt_b = ShiftW(Black, Pawn(Black)) | ShiftE(Black, Pawn(Black)); + PEI.double_att_w = ShiftW(White, Pawn(White)) & ShiftE(White, Pawn(White)); + PEI.double_att_b = ShiftW(Black, Pawn(Black)) & ShiftE(Black, Pawn(Black)); + PEI.king_w = lsb(King(White)); + PEI.king_b = lsb(King(Black)); + PEI.score = 0; - eval_pawns(PawnEntry, PEI); - eval_pawns(PawnEntry, PEI); + eval_pawns(PawnEntry, PEI); + eval_pawns(PawnEntry, PEI); - PawnEntry->score = PEI.score; + PawnEntry->score = PEI.score; } typedef struct { - int score, king_w, king_b, mul; - uint64 occ, area_w, area_b, free_w, free_b; - uint32 king_att_w, king_att_b; - GPawnEntry * PawnEntry; - GMaterial * material; + int score, king_w, king_b, mul; + uint64_t occ, area_w, area_b, free_w, free_b; + uint32_t king_att_w, king_att_b; + GPawnEntry * PawnEntry; + const GMaterial * material; } GEvalInfo; -template __forceinline void eval_queens(GEvalInfo &EI) { - uint64 u, b; - for (u = Queen(me); T(u); u ^= b) { - int sq = lsb(u); - b = Bit(sq); - uint64 att = QueenAttacks(sq,EI.occ); - Current->att[me] |= att; - if (QMask[sq] & King(opp)) if (uint64 v = Between[PVarC(EI,king,opp)][sq] & EI.occ) if (Single(v)) { - Current->xray[me] |= v; - uint64 square = lsb(v); int piece = Square(square); int katt = 0; - if (piece == IPawn(me)) { - if (!Square(square + Push(me))) IncV(EI.score, Ca(Pin, SelfPawnPin)); - } else if ((piece & 1) == me) { - IncV(EI.score, Ca(Pin, SelfPiecePin)); - katt = 1; - } else if (piece != IPawn(opp) && !(((BMask[sq] & Bishop(opp)) | (RMask[sq] & Rook(opp)) | Queen(opp)) & v)) { - IncV(EI.score, Ca(Pin, WeakPin)); - if (!(Current->patt[opp] & v)) katt = 1; - } - if (katt && !(att & PVarC(EI, area, opp))) PVarC(EI, king_att, me) += KingAttack; - } else if (v == (v & Minor(opp))) IncV(EI.score, Ca(KingRay, QKingRay)); - if (att & PVarC(EI, area, opp)) { - PVarC(EI, king_att, me) += KingQAttack; - for (uint64 v = att & PVarC(EI, area, opp); T(v); Cut(v)) - if (FullLine[sq][lsb(v)] & att & ((Rook(me) & RMask[sq]) | (Bishop(me) & BMask[sq]))) PVarC(EI, king_att, me)++; - } - IncV(EI.score,Mobility[PieceType[WhiteQueen] - 1][popcount(att & PVarC(EI,free,me))]); - if (att & PVarC(EI, free, me) & Pawn(opp)) IncV(EI.score, Ca(Tactical, TacticalMajorPawn)); - if (att & PVarC(EI, free, me) & Minor(opp)) IncV(EI.score, Ca(Tactical, TacticalMajorMinor)); - if (att & PVarC(EI, area, me)) IncV(EI.score, Ca(KingDefence, KingDefQueen)); - } -} -template __forceinline void eval_rooks(GEvalInfo &EI) { - uint64 u, b; - for (u = Rook(me); T(u); u ^= b) { - int sq = lsb(u); - b = Bit(sq); - uint64 att = RookAttacks(sq,EI.occ); - Current->att[me] |= att; - if (RMask[sq] & King(opp)) if (uint64 v = Between[PVarC(EI, king, opp)][sq] & EI.occ) if (Single(v)) { - Current->xray[me] |= v; - uint64 square = lsb(v); int piece = Square(square); int katt = 0; - if (piece == IPawn(me)) { - if (!Square(square + Push(me))) IncV(EI.score, Ca(Pin, SelfPawnPin)); - } else if ((piece & 1) == me) { - IncV(EI.score, Ca(Pin, SelfPiecePin)); - katt = 1; - } else if (piece != IPawn(opp)) { - if (piece < IRook(opp)) { - IncV(EI.score, Ca(Pin, WeakPin)); - if (!(Current->patt[opp] & v)) katt = 1; - } else if (piece == IQueen(opp)) IncV(EI.score, Ca(Pin, ThreatPin)); - } - if (katt && !(att & PVarC(EI, area, opp))) PVarC(EI, king_att, me) += KingAttack; - } else if (v == (v & (Minor(opp) | Queen(opp)))) IncV(EI.score, Ca(KingRay, RKingRay)); - if (att & PVarC(EI, area, opp)) { - PVarC(EI, king_att, me) += KingRAttack; - for (uint64 v = att & PVarC(EI, area, opp); T(v); Cut(v)) - if (FullLine[sq][lsb(v)] & att & Major(me)) PVarC(EI, king_att, me)++; - } - IncV(EI.score,Mobility[PieceType[WhiteRook] - 1][popcount(att & PVarC(EI,free,me))]); - if (att & PVarC(EI, free, me) & Pawn(opp)) IncV(EI.score, Ca(Tactical, TacticalMajorPawn)); - if (att & PVarC(EI, free, me) & Minor(opp)) IncV(EI.score, Ca(Tactical, TacticalMajorMinor)); - if (att & PVarC(EI, area, me)) IncV(EI.score, Ca(KingDefence, KingDefRook)); - Current->threat |= att & Queen(opp); - if (!(PWay[me][sq] & Pawn(me))) { - IncV(EI.score, Ca(RookSpecial, RookHof)); - int hof_score = 0; - if (!(PWay[me][sq] & Pawn(opp))) { - IncV(EI.score, Ca(RookSpecial, RookOf)); - if (att & Line(me, 7)) hof_score += Ca(RookSpecial, RookOfOpen); - else if (uint64 target = att & PWay[me][sq] & Minor(opp)) { - if (!(Current->patt[opp] & target)) { - hof_score += Ca(RookSpecial, RookOfMinorHaging); - if (PWay[me][sq] & King(opp)) hof_score += Ca(RookSpecial, RookOfKingAtt); - } else hof_score += Ca(RookSpecial, RookOfMinorFixed); - } - } else if (att & PWay[me][sq] & Pawn(opp)) { - uint64 square = lsb(att & PWay[me][sq] & Pawn(opp)); - if (!(PSupport[opp][square] & Pawn(opp))) hof_score += Ca(RookSpecial, RookHofWeakPAtt); - } - IncV(EI.score, hof_score); - if (PWay[opp][sq] & att & Major(me)) IncV(EI.score, hof_score); - } - if ((b & Line(me, 6)) && ((King(opp) | Pawn(opp)) & (Line(me, 6) | Line(me, 7)))) { - IncV(EI.score, Ca(RookSpecial, Rook7th)); - if (King(opp) & Line(me, 7)) IncV(EI.score, Ca(RookSpecial, Rook7thK8th)); - if (Major(me) & att & Line(me, 6)) IncV(EI.score, Ca(RookSpecial, Rook7thDoubled)); - } - } +template inline void eval_queens(GEvalInfo &EI) { + uint64_t u, b; + for (u = Queen(me); T(u); u ^= b) { + int sq = lsb(u); + b = Bit(sq); + uint64_t att = QueenAttacks(sq,EI.occ); + Current->att[me] |= att; + if (DATA->QMask[sq] & King(opp)) if (uint64_t v = DATA->Between[PVarC(EI,king,opp)][sq] & EI.occ) if (Single(v)) { + Current->xray[me] |= v; + uint64_t square = lsb(v); int piece = Square(square); int katt = 0; + if (piece == IPawn(me)) { + if (!Square(square + Push(me))) IncV(EI.score, Ca(Pin, SelfPawnPin)); + } else if ((piece & 1) == me) { + IncV(EI.score, Ca(Pin, SelfPiecePin)); + katt = 1; + } else if (piece != IPawn(opp) && !(((DATA->BMask[sq] & Bishop(opp)) | (DATA->RMask[sq] & Rook(opp)) | Queen(opp)) & v)) { + IncV(EI.score, Ca(Pin, WeakPin)); + if (!(Current->patt[opp] & v)) katt = 1; + } + if (katt && !(att & PVarC(EI, area, opp))) PVarC(EI, king_att, me) += KingAttack; + } else if (v == (v & Minor(opp))) IncV(EI.score, Ca(KingRay, QKingRay)); + if (att & PVarC(EI, area, opp)) { + PVarC(EI, king_att, me) += KingQAttack; + for (uint64_t v = att & PVarC(EI, area, opp); T(v); Cut(v)) + if (DATA->FullLine[sq][lsb(v)] & att & ((Rook(me) & DATA->RMask[sq]) | (Bishop(me) & DATA->BMask[sq]))) PVarC(EI, king_att, me)++; + } + IncV(EI.score,DATA->Mobility[PieceType[WhiteQueen] - 1][popcount(att & PVarC(EI,free,me))]); + if (att & PVarC(EI, free, me) & Pawn(opp)) IncV(EI.score, Ca(Tactical, TacticalMajorPawn)); + if (att & PVarC(EI, free, me) & Minor(opp)) IncV(EI.score, Ca(Tactical, TacticalMajorMinor)); + if (att & PVarC(EI, area, me)) IncV(EI.score, Ca(KingDefence, KingDefQueen)); + } } -template __forceinline void eval_bishops(GEvalInfo &EI) { - uint64 u, b; - for (u = Bishop(me); T(u); u ^= b) { - int sq = lsb(u); - b = Bit(sq); - uint64 att = BishopAttacks(sq, EI.occ); - Current->att[me] |= att; - if (BMask[sq] & King(opp)) if (uint64 v = Between[PVarC(EI, king, opp)][sq] & EI.occ) if (Single(v)) { - Current->xray[me] |= v; - uint64 square = lsb(v); int piece = Square(square); int katt = 0; - if (piece == IPawn(me)) { - if (!Square(square + Push(me))) IncV(EI.score, Ca(Pin, SelfPawnPin)); - } else if ((piece & 1) == me) { - IncV(EI.score, Ca(Pin, SelfPiecePin)); - katt = 1; - } else if (piece != IPawn(opp)) { - if (piece < ILight(opp)) { - IncV(EI.score, Ca(Pin, StrongPin)); - if (!(Current->patt[opp] & v)) katt = 1; - } else if (piece >= IRook(opp)) IncV(EI.score, Ca(Pin, ThreatPin)); - } - if (katt && !(att & PVarC(EI, area, opp))) PVarC(EI, king_att, me) += KingAttack; - } else if (v == (v & (Knight(opp) | Major(opp)))) IncV(EI.score, Ca(KingRay, BKingRay)); - if (att & PVarC(EI, area, opp)) PVarC(EI, king_att, me) += KingBAttack; - IncV(EI.score, Mobility[PieceType[WhiteLight] - 1][popcount(att & PVarC(EI, free, me))]); - if (att & PVarC(EI, free, me) & Pawn(opp)) IncV(EI.score, Ca(Tactical, TacticalMinorPawn)); - if (att & PVarC(EI, free, me) & Knight(opp)) IncV(EI.score, Ca(Tactical, TacticalMinorMinor)); - if (att & PVarC(EI, area, me)) IncV(EI.score, Ca(KingDefence, KingDefBishop)); - Current->threat |= att & Major(opp); - if (b & LightArea) { - for (uint64 v = ((~BishopForward[me][sq]) | (att & Forward[me][Rank(sq)])) & Pawn(opp) & (~Current->patt[opp]) & LightArea; v; Cut(v)) { - uint64 square = lsb(v); - if (!((PSupport[opp][square] | PWay[opp][square]) & Pawn(opp))) IncV(EI.score, Ca(BishopSpecial, BishopNonForwardPawn)); - } - uint64 v = BishopForward[me][sq] & Pawn(me) & LightArea; - v |= (v & (File[2] | File[3] | File[4] | File[5] | BMask[sq])) >> 8; - DecV(EI.score, Ca(BishopSpecial, BishopPawnBlock) * popcount(v)); - } else { - for (uint64 v = ((~BishopForward[me][sq]) | (att & Forward[me][Rank(sq)])) & Pawn(opp) & (~Current->patt[opp]) & DarkArea; v; Cut(v)) { - uint64 square = lsb(v); - if (!((PSupport[opp][square] | PWay[opp][square]) & Pawn(opp))) IncV(EI.score, Ca(BishopSpecial, BishopNonForwardPawn)); - } - uint64 v = BishopForward[me][sq] & Pawn(me) & DarkArea; - v |= (v & (File[2] | File[3] | File[4] | File[5] | BMask[sq])) >> 8; - DecV(EI.score, Ca(BishopSpecial, BishopPawnBlock) * popcount(v)); - } - } +template inline void eval_rooks(GEvalInfo &EI) { + uint64_t u, b; + for (u = Rook(me); T(u); u ^= b) { + int sq = lsb(u); + b = Bit(sq); + uint64_t att = RookAttacks(sq,EI.occ); + Current->att[me] |= att; + if (DATA->RMask[sq] & King(opp)) if (uint64_t v = DATA->Between[PVarC(EI, king, opp)][sq] & EI.occ) if (Single(v)) { + Current->xray[me] |= v; + uint64_t square = lsb(v); int piece = Square(square); int katt = 0; + if (piece == IPawn(me)) { + if (!Square(square + Push(me))) IncV(EI.score, Ca(Pin, SelfPawnPin)); + } else if ((piece & 1) == me) { + IncV(EI.score, Ca(Pin, SelfPiecePin)); + katt = 1; + } else if (piece != IPawn(opp)) { + if (piece < IRook(opp)) { + IncV(EI.score, Ca(Pin, WeakPin)); + if (!(Current->patt[opp] & v)) katt = 1; + } else if (piece == IQueen(opp)) IncV(EI.score, Ca(Pin, ThreatPin)); + } + if (katt && !(att & PVarC(EI, area, opp))) PVarC(EI, king_att, me) += KingAttack; + } else if (v == (v & (Minor(opp) | Queen(opp)))) IncV(EI.score, Ca(KingRay, RKingRay)); + if (att & PVarC(EI, area, opp)) { + PVarC(EI, king_att, me) += KingRAttack; + for (uint64_t v = att & PVarC(EI, area, opp); T(v); Cut(v)) + if (DATA->FullLine[sq][lsb(v)] & att & Major(me)) PVarC(EI, king_att, me)++; + } + IncV(EI.score,DATA->Mobility[PieceType[WhiteRook] - 1][popcount(att & PVarC(EI,free,me))]); + if (att & PVarC(EI, free, me) & Pawn(opp)) IncV(EI.score, Ca(Tactical, TacticalMajorPawn)); + if (att & PVarC(EI, free, me) & Minor(opp)) IncV(EI.score, Ca(Tactical, TacticalMajorMinor)); + if (att & PVarC(EI, area, me)) IncV(EI.score, Ca(KingDefence, KingDefRook)); + Current->threat |= att & Queen(opp); + if (!(DATA->PWay[me][sq] & Pawn(me))) { + IncV(EI.score, Ca(RookSpecial, RookHof)); + int hof_score = 0; + if (!(DATA->PWay[me][sq] & Pawn(opp))) { + IncV(EI.score, Ca(RookSpecial, RookOf)); + if (att & Line(me, 7)) hof_score += Ca(RookSpecial, RookOfOpen); + else if (uint64_t target = att & DATA->PWay[me][sq] & Minor(opp)) { + if (!(Current->patt[opp] & target)) { + hof_score += Ca(RookSpecial, RookOfMinorHaging); + if (DATA->PWay[me][sq] & King(opp)) hof_score += Ca(RookSpecial, RookOfKingAtt); + } else hof_score += Ca(RookSpecial, RookOfMinorFixed); + } + } else if (att & DATA->PWay[me][sq] & Pawn(opp)) { + uint64_t square = lsb(att & DATA->PWay[me][sq] & Pawn(opp)); + if (!(DATA->PSupport[opp][square] & Pawn(opp))) hof_score += Ca(RookSpecial, RookHofWeakPAtt); + } + IncV(EI.score, hof_score); + if (DATA->PWay[opp][sq] & att & Major(me)) IncV(EI.score, hof_score); + } + if ((b & Line(me, 6)) && ((King(opp) | Pawn(opp)) & (Line(me, 6) | Line(me, 7)))) { + IncV(EI.score, Ca(RookSpecial, Rook7th)); + if (King(opp) & Line(me, 7)) IncV(EI.score, Ca(RookSpecial, Rook7thK8th)); + if (Major(me) & att & Line(me, 6)) IncV(EI.score, Ca(RookSpecial, Rook7thDoubled)); + } + } } -template __forceinline void eval_knights(GEvalInfo &EI) { - uint64 u, b; - for (u = Knight(me); T(u); u ^= b) { - int sq = lsb(u); - b = Bit(sq); - uint64 att = NAtt[sq]; - Current->att[me] |= att; - if (att & PVarC(EI, area, opp)) PVarC(EI, king_att, me) += KingNAttack; - IncV(EI.score, Mobility[PieceType[WhiteKnight] - 1][popcount(att & PVarC(EI, free, me))]); - if (att & PVarC(EI, free, me) & Pawn(opp)) IncV(EI.score, Ca(Tactical, TacticalMinorPawn)); - if (att & PVarC(EI, free, me) & Bishop(opp)) IncV(EI.score, Ca(Tactical, TacticalMinorMinor)); - if (att & PVarC(EI, area, me)) IncV(EI.score, Ca(KingDefence, KingDefKnight)); - Current->threat |= att & Major(opp); - if ((b & Outpost[me]) && !(Pawn(opp) & PIsolated[File(sq)] & Forward[me][Rank(sq)])) { - IncV(EI.score, Ca(KnightSpecial, KnightOutpost)); - if (Current->patt[me] & b) { - IncV(EI.score, Ca(KnightSpecial, KnightOutpostProtected)); - if (att & PVarC(EI, free, me) & Pawn(opp)) IncV(EI.score, Ca(KnightSpecial, KnightOutpostPawnAtt)); - if (att & PVarC(EI, free, me) & Bishop(opp)) IncV(EI.score, Ca(KnightSpecial, KnightOutpostBishopAtt)); - } - } - } +template inline void eval_bishops(GEvalInfo &EI) { + uint64_t u, b; + for (u = Bishop(me); T(u); u ^= b) { + int sq = lsb(u); + b = Bit(sq); + uint64_t att = BishopAttacks(sq, EI.occ); + Current->att[me] |= att; + if (DATA->BMask[sq] & King(opp)) if (uint64_t v = DATA->Between[PVarC(EI, king, opp)][sq] & EI.occ) if (Single(v)) { + Current->xray[me] |= v; + uint64_t square = lsb(v); int piece = Square(square); int katt = 0; + if (piece == IPawn(me)) { + if (!Square(square + Push(me))) IncV(EI.score, Ca(Pin, SelfPawnPin)); + } else if ((piece & 1) == me) { + IncV(EI.score, Ca(Pin, SelfPiecePin)); + katt = 1; + } else if (piece != IPawn(opp)) { + if (piece < ILight(opp)) { + IncV(EI.score, Ca(Pin, StrongPin)); + if (!(Current->patt[opp] & v)) katt = 1; + } else if (piece >= IRook(opp)) IncV(EI.score, Ca(Pin, ThreatPin)); + } + if (katt && !(att & PVarC(EI, area, opp))) PVarC(EI, king_att, me) += KingAttack; + } else if (v == (v & (Knight(opp) | Major(opp)))) IncV(EI.score, Ca(KingRay, BKingRay)); + if (att & PVarC(EI, area, opp)) PVarC(EI, king_att, me) += KingBAttack; + IncV(EI.score, DATA->Mobility[PieceType[WhiteLight] - 1][popcount(att & PVarC(EI, free, me))]); + if (att & PVarC(EI, free, me) & Pawn(opp)) IncV(EI.score, Ca(Tactical, TacticalMinorPawn)); + if (att & PVarC(EI, free, me) & Knight(opp)) IncV(EI.score, Ca(Tactical, TacticalMinorMinor)); + if (att & PVarC(EI, area, me)) IncV(EI.score, Ca(KingDefence, KingDefBishop)); + Current->threat |= att & Major(opp); + if (b & LightArea) { + for (uint64_t v = ((~DATA->BishopForward[me][sq]) | (att & DATA->Forward[me][Rank(sq)])) & Pawn(opp) & (~Current->patt[opp]) & LightArea; v; Cut(v)) { + uint64_t square = lsb(v); + if (!((DATA->PSupport[opp][square] | DATA->PWay[opp][square]) & Pawn(opp))) IncV(EI.score, Ca(BishopSpecial, BishopNonForwardPawn)); + } + uint64_t v = DATA->BishopForward[me][sq] & Pawn(me) & LightArea; + v |= (v & (DATA->File[2] | DATA->File[3] | DATA->File[4] | DATA->File[5] | DATA->BMask[sq])) >> 8; + DecV(EI.score, Ca(BishopSpecial, BishopPawnBlock) * popcount(v)); + } else { + for (uint64_t v = ((~DATA->BishopForward[me][sq]) | (att & DATA->Forward[me][Rank(sq)])) & Pawn(opp) & (~Current->patt[opp]) & DarkArea; v; Cut(v)) { + uint64_t square = lsb(v); + if (!((DATA->PSupport[opp][square] | DATA->PWay[opp][square]) & Pawn(opp))) IncV(EI.score, Ca(BishopSpecial, BishopNonForwardPawn)); + } + uint64_t v = DATA->BishopForward[me][sq] & Pawn(me) & DarkArea; + v |= (v & (DATA->File[2] | DATA->File[3] | DATA->File[4] | DATA->File[5] | DATA->BMask[sq])) >> 8; + DecV(EI.score, Ca(BishopSpecial, BishopPawnBlock) * popcount(v)); + } + } } -template __forceinline void eval_king(GEvalInfo &EI) { - int cnt = Opening(PVarC(EI, king_att, me)); - int score = Endgame(PVarC(EI, king_att, me)); - if (cnt >= 2 && T(Queen(me))) { - score += (EI.PawnEntry->shelter[opp] * KingShelterQuad)/64; - if (uint64 u = Current->att[me] & PVarC(EI, area, opp) & (~Current->att[opp])) score += popcount(u) * KingAttackSquare; - if (!(SArea[PVarC(EI, king, opp)] & (~(Piece(opp) | Current->att[me])))) score += KingNoMoves; - } - int adjusted = ((score * KingAttackScale[cnt]) >> 3) + EI.PawnEntry->shelter[opp]; - if (!Queen(me)) adjusted /= 2; - IncV(EI.score, adjusted); +template inline void eval_knights(GEvalInfo &EI) { + uint64_t u, b; + for (u = Knight(me); T(u); u ^= b) { + int sq = lsb(u); + b = Bit(sq); + uint64_t att = DATA->NAtt[sq]; + Current->att[me] |= att; + if (att & PVarC(EI, area, opp)) PVarC(EI, king_att, me) += KingNAttack; + IncV(EI.score, DATA->Mobility[PieceType[WhiteKnight] - 1][popcount(att & PVarC(EI, free, me))]); + if (att & PVarC(EI, free, me) & Pawn(opp)) IncV(EI.score, Ca(Tactical, TacticalMinorPawn)); + if (att & PVarC(EI, free, me) & Bishop(opp)) IncV(EI.score, Ca(Tactical, TacticalMinorMinor)); + if (att & PVarC(EI, area, me)) IncV(EI.score, Ca(KingDefence, KingDefKnight)); + Current->threat |= att & Major(opp); + if ((b & Outpost[me]) && !(Pawn(opp) & DATA->PIsolated[File(sq)] & DATA->Forward[me][Rank(sq)])) { + IncV(EI.score, Ca(KnightSpecial, KnightOutpost)); + if (Current->patt[me] & b) { + IncV(EI.score, Ca(KnightSpecial, KnightOutpostProtected)); + if (att & PVarC(EI, free, me) & Pawn(opp)) IncV(EI.score, Ca(KnightSpecial, KnightOutpostPawnAtt)); + if (att & PVarC(EI, free, me) & Bishop(opp)) IncV(EI.score, Ca(KnightSpecial, KnightOutpostBishopAtt)); + } + } + } } -template __forceinline void eval_passer(GEvalInfo &EI) { - for (uint64 u = EI.PawnEntry->passer[me]; T(u); Cut(u)) { - int file = lsb(u); - int sq = NB(opp, File[file] & Pawn(me)); - int rank = CRank(me, sq); - Current->passer |= Bit(sq); - if (rank <= 2) continue; - if (!Square(sq + Push(me))) IncV(EI.score, PasserBlocked[rank]); - uint64 way = PWay[me][sq]; - int connected = 0, supported = 0, hooked = 0, unsupported = 0, free = 0; - if (!(way & Piece(opp))) { - IncV(EI.score, PasserClear[rank]); - if (PWay[opp][sq] & Major(me)) { - int square = NB(opp, PWay[opp][sq] & Major(me)); - if (F(Between[sq][square] & EI.occ)) supported = 1; - } - if (PWay[opp][sq] & Major(opp)) { - int square = NB(opp, PWay[opp][sq] & Major(opp)); - if (F(Between[sq][square] & EI.occ)) hooked = 1; - } - for (uint64 v = PAtt[me][sq - Push(me)] & Pawn(me); T(v); Cut(v)) { - int square = lsb(v); - if (F(Pawn(opp) & (File[File(square)] | PIsolated[File(square)]) & Forward[me][Rank(square)])) connected++; - } - if (connected) IncV(EI.score, PasserConnected[rank]); - if (!hooked && !(Current->att[opp] & way)) { - IncV(EI.score, PasserFree[rank]); - free = 1; - } else { - uint64 attacked = Current->att[opp] | (hooked ? way : 0); - if (supported || (!hooked && connected) || (!(Major(me) & way) && !(attacked & (~Current->att[me])))) IncV(EI.score, PasserSupported[rank]); - else unsupported = 1; - } - } - if (rank == 6) { - if ((way & Rook(me)) && !Minor(me) && !Queen(me) && Single(Rook(me))) DecV(EI.score, Compose(0, Sa(PasserSpecial, PasserOpRookBlock))); - if (!Major(opp) && (!NonPawnKing(opp) || Single(NonPawnKing(opp)))) { - IncV(EI.score, Compose(0, Sa(PasserSpecial, PasserOnePiece))); - if (!free) { - if (!(SArea[sq + Push(me)] & King(opp))) IncV(EI.score, Compose(0, Sa(PasserSpecial, PasserOpMinorControl))); - else IncV(EI.score, Compose(0, Sa(PasserSpecial, PasserOpKingControl))); - } - } - } - } -} -template __forceinline void eval_pieces(GEvalInfo &EI) { - Current->threat |= Current->att[opp] & (~Current->att[me]) & Piece(me); - if (uint64 u = Current->threat & Piece(me)) { - DecV(EI.score, Ca(Tactical, TacticalThreat)); - Cut(u); - if (u) { - DecV(EI.score, Ca(Tactical, TacticalThreat) + Ca(Tactical, TacticalDoubleThreat)); - for (Cut(u); u; Cut(u)) DecV(EI.score, Ca(Tactical, TacticalThreat)); - } - } -} -template void eval_endgame(GEvalInfo &EI) { - if ((EI.material->flags & VarC(FlagSingleBishop, me)) && Pawn(me)) { - int sq = (Board->bb[ILight(me)] ? (me ? 0 : 63) : (Board->bb[IDark(me)] ? (me ? 7 : 56) : (File(lsb(King(opp))) <= 3 ? (me ? 0 : 56) : (me ? 7 : 63)))); - if (!(Pawn(me) & (~PWay[opp][sq]))) { - if ((SArea[sq] | Bit(sq)) & King(opp)) EI.mul = 0; - else if ((SArea[sq] & SArea[lsb(King(opp))] & Line(me, 7)) && Square(sq - Push(me)) == IPawn(opp) && Square(sq - 2 * Push(me)) == IPawn(me)) EI.mul = 0; - } else if ((King(opp) & Line(me, 6) | Line(me, 7)) && Abs(File(sq) - File(lsb(King(opp)))) <= 3 && !(Pawn(me) & (~PSupport[me][sq])) && (Pawn(me) & Line(me, 5) & Shift(opp, Pawn(opp)))) EI.mul = 0; - if (Single(Pawn(me))) { - if (!Bishop(me)) { - EI.mul = MinF(EI.mul, kpkx()); - if (Piece(opp) == King(opp) && EI.mul == 32) IncV(Current->score, KpkValue); - } else { - sq = lsb(Pawn(me)); - if ((Pawn(me) & (File[1] | File[6]) & Line(me, 5)) && Square(sq + Push(me)) == IPawn(opp) && ((PAtt[me][sq + Push(me)] | PWay[me][sq + Push(me)]) & King(opp))) EI.mul = 0; - } - } - if (Bishop(opp) && Single(Bishop(opp)) && T(BB(ILight(me))) != T(BB(ILight(opp)))) { - int pcnt = 0; - if (T(King(opp) & LightArea) == T(Bishop(opp) & LightArea)) { - for (uint64 u = Pawn(me); u; Cut(u)) { - if (pcnt >= 2) goto check_for_partial_block; - pcnt++; - int sq = lsb(u); - if (!(PWay[me][sq] & (PAtt[me][PVarC(EI, king, opp)] | PAtt[opp][PVarC(EI, king, opp)]))) { - if (!(PWay[me][sq] & Pawn(opp))) goto check_for_partial_block; - int bsq = lsb(Bishop(opp)); - uint64 att = BishopAttacks(bsq, EI.occ); - if (!(att & PWay[me][sq] & Pawn(opp))) goto check_for_partial_block; - if (!(BishopForward[me][bsq] & att & PWay[me][sq] & Pawn(opp)) && popcount(FullLine[lsb(att & PWay[me][sq] & Pawn(opp))][bsq] & att) <= 2) goto check_for_partial_block; - } - } - EI.mul = 0; - return; - } - check_for_partial_block: - if (pcnt <= 2 && Multiple(Pawn(me)) && !Pawn(opp) && !(Pawn(me) & Boundary) && EI.mul) { - int sq1 = lsb(Pawn(me)); - int sq2 = msb(Pawn(me)); - int fd = Abs(File(sq2) - File(sq1)); - if (fd >= 5) EI.mul = 32; - else if (fd >= 4) EI.mul = 26; - else if (fd >= 3) EI.mul = 20; - } - if ((SArea[PVarC(EI, king, opp)] | Current->patt[opp]) & Bishop(opp)) { - uint64 push = Shift(me, Pawn(me)); - if (!(push & (~(Piece(opp) | Current->att[opp]))) && (King(opp) & (Board->bb[ILight(opp)] ? LightArea : DarkArea))) { - EI.mul = Min(EI.mul, 8); - int bsq = lsb(Bishop(opp)); - uint64 att = BishopAttacks(bsq, EI.occ); - uint64 prp = (att | SArea[PVarC(EI, king, opp)]) & Pawn(opp) & (Board->bb[ILight(opp)] ? LightArea : DarkArea); - uint64 patt = ShiftW(opp, prp) | ShiftE(opp, prp); - if ((SArea[PVarC(EI, king, opp)] | patt) & Bishop(opp)) { - uint64 double_att = (SArea[PVarC(EI, king, opp)] & patt) | (patt & att) | (SArea[PVarC(EI, king, opp)] & att); - if (!(push & (~(King(opp) | Bishop(opp) | prp | double_att)))) { - EI.mul = 0; - return; - } - } - } - } - } - } - if (F(Major(me))) { - if (T(Bishop(me)) && F(Knight(me)) && Single(Bishop(me)) && T(Pawn(me))) { - int number = popcount(Pawn(me)); - if (number == 1) { - if (Bishop(opp)) EI.mul = MinF(EI.mul, kbpkbx()); - else if (Knight(opp)) EI.mul = MinF(EI.mul, kbpknx()); - } else if (number == 2 && T(Bishop(opp))) EI.mul = MinF(EI.mul, kbppkbx()); - } else if (!Bishop(me) && Knight(me) && Single(Knight(me)) && Pawn(me) && Single(Pawn(me))) EI.mul = MinF(EI.mul, knpkx()); - } else if (F(Minor(me))) { - if (F(Pawn(me)) && F(Rook(me)) && T(Queen(me)) && T(Pawn(opp))) { - if (F(NonPawnKing(opp)) && Single(Pawn(opp))) EI.mul = MinF(EI.mul, kqkp()); - else if (Rook(opp)) EI.mul = MinF(EI.mul, kqkrpx()); - } else if (F(Queen(me)) && T(Rook(me)) && Single(Rook(me))) { - int number = popcount(Pawn(me)); - if (number <= 3) { - if (number == 0) { - if (Pawn(opp)) EI.mul = MinF(EI.mul, krkpx()); - } else if (Rook(opp)) { - if (number == 1) { - int new_mul = krpkrx(); - EI.mul = (new_mul <= 32 ? Min(EI.mul, new_mul) : new_mul); - } else { - if (number == 2) EI.mul = MinF(EI.mul, krppkrx()); - if (Pawn(opp)) { - if (number == 2) EI.mul = MinF(EI.mul, krppkrpx()); - else if (Multiple(Pawn(opp))) EI.mul = MinF(EI.mul, krpppkrppx()); - } - } - } else if (number == 1 && Bishop(opp)) EI.mul = MinF(EI.mul, krpkbx()); - } - } - } else if (!Pawn(me) && Single(Rook(me)) && !Queen(me) && Single(Bishop(me)) && !Knight(me) && Rook(opp)) EI.mul = MinF(EI.mul, krbkrx()); - if (F(NonPawnKing(opp)) && Current->turn == opp && F(Current->att[me] & King(opp)) && !(SArea[PVarC(EI, king, opp)] & (~(Current->att[me] | Piece(opp)))) - && F(Current->patt[opp] & Piece(me)) && F(Shift(opp, Pawn(opp)) & (~EI.occ))) - EI.mul = 0; +template inline void eval_king(GEvalInfo &EI) { + int cnt = Opening(PVarC(EI, king_att, me)); + int score = Endgame(PVarC(EI, king_att, me)); + if (cnt >= 2 && T(Queen(me))) { + score += (EI.PawnEntry->shelter[opp] * KingShelterQuad)/64; + if (uint64_t u = Current->att[me] & PVarC(EI, area, opp) & (~Current->att[opp])) score += popcount(u) * KingAttackSquare; + if (!(DATA->SArea[PVarC(EI, king, opp)] & (~(Piece(opp) | Current->att[me])))) score += KingNoMoves; + } + int adjusted = ((score * KingAttackScale[cnt]) >> 3) + EI.PawnEntry->shelter[opp]; + if (!Queen(me)) adjusted /= 2; + IncV(EI.score, adjusted); +} +template inline void eval_passer(GEvalInfo &EI) { + for (uint64_t u = EI.PawnEntry->passer[me]; T(u); Cut(u)) { + int file = lsb(u); + int sq = NB(opp, DATA->File[file] & Pawn(me)); + int rank = CRank(me, sq); + Current->passer |= Bit(sq); + if (rank <= 2) continue; + if (!Square(sq + Push(me))) IncV(EI.score, DATA->PasserBlocked[rank]); + uint64_t way = DATA->PWay[me][sq]; + int connected = 0, supported = 0, hooked = 0, unsupported = 0, free = 0; + if (!(way & Piece(opp))) { + IncV(EI.score, DATA->PasserClear[rank]); + if (DATA->PWay[opp][sq] & Major(me)) { + int square = NB(opp, DATA->PWay[opp][sq] & Major(me)); + if (F(DATA->Between[sq][square] & EI.occ)) supported = 1; + } + if (DATA->PWay[opp][sq] & Major(opp)) { + int square = NB(opp, DATA->PWay[opp][sq] & Major(opp)); + if (F(DATA->Between[sq][square] & EI.occ)) hooked = 1; + } + for (uint64_t v = DATA->PAtt[me][sq - Push(me)] & Pawn(me); T(v); Cut(v)) { + int square = lsb(v); + if (F(Pawn(opp) & (DATA->File[File(square)] | DATA->PIsolated[File(square)]) & DATA->Forward[me][Rank(square)])) connected++; + } + if (connected) IncV(EI.score, DATA->PasserConnected[rank]); + if (!hooked && !(Current->att[opp] & way)) { + IncV(EI.score, DATA->PasserFree[rank]); + free = 1; + } else { + uint64_t attacked = Current->att[opp] | (hooked ? way : 0); + if (supported || (!hooked && connected) || (!(Major(me) & way) && !(attacked & (~Current->att[me])))) IncV(EI.score, DATA->PasserSupported[rank]); + else unsupported = 1; + } + } + if (rank == 6) { + if ((way & Rook(me)) && !Minor(me) && !Queen(me) && Single(Rook(me))) DecV(EI.score, Compose(0, Sa(PasserSpecial, PasserOpRookBlock))); + if (!Major(opp) && (!NonPawnKing(opp) || Single(NonPawnKing(opp)))) { + IncV(EI.score, Compose(0, Sa(PasserSpecial, PasserOnePiece))); + if (!free) { + if (!(DATA->SArea[sq + Push(me)] & King(opp))) IncV(EI.score, Compose(0, Sa(PasserSpecial, PasserOpMinorControl))); + else IncV(EI.score, Compose(0, Sa(PasserSpecial, PasserOpKingControl))); + } + } + } + } } -template void eval_unusual_material(GEvalInfo &EI) { - int wp, bp, wlight, blight, wr, br, wq, bq; - wp = popcount(Pawn(White)); - bp = popcount(Pawn(Black)); - wlight = popcount(Minor(White)); - blight = popcount(Minor(Black)); - wr = popcount(Rook(White)); - br = popcount(Rook(Black)); - wq = popcount(Queen(White)); - bq = popcount(Queen(Black)); - int phase = Min(24, (wlight + blight) + 2 * (wr + br) + 4 * (wq + bq)); - int mat_score = SeeValue[WhitePawn] * (wp - bp) + SeeValue[WhiteKnight] * (wlight - blight) + SeeValue[WhiteRook] * (wr - br) + SeeValue[WhiteQueen] * (wq - bq); - mat_score = Compose(mat_score,mat_score); - Current->score = (((Opening(mat_score + EI.score) * phase) + (Endgame(mat_score + EI.score) * (24 - phase)))/24); - if (Current->turn) Current->score = -Current->score; - UpdateDelta +template inline void eval_pieces(GEvalInfo &EI) { + Current->threat |= Current->att[opp] & (~Current->att[me]) & Piece(me); + if (uint64_t u = Current->threat & Piece(me)) { + DecV(EI.score, Ca(Tactical, TacticalThreat)); + Cut(u); + if (u) { + DecV(EI.score, Ca(Tactical, TacticalThreat) + Ca(Tactical, TacticalDoubleThreat)); + for (Cut(u); u; Cut(u)) DecV(EI.score, Ca(Tactical, TacticalThreat)); + } + } } - -template void evaluation() { - GEvalInfo EI; - - if (Current->eval_key == Current->key) return; - Current->eval_key = Current->key; - - EI.king_w = lsb(King(White)); - EI.king_b = lsb(King(Black)); - EI.occ = PieceAll; - Current->patt[White] = ShiftW(White,Pawn(White)) | ShiftE(White,Pawn(White)); - Current->patt[Black] = ShiftW(Black,Pawn(Black)) | ShiftE(Black,Pawn(Black)); - EI.area_w = (SArea[EI.king_w] | King(White)) & ((~Current->patt[White]) | Current->patt[Black]); - EI.area_b = (SArea[EI.king_b] | King(Black)) & ((~Current->patt[Black]) | Current->patt[White]); - Current->att[White] = Current->patt[White]; - Current->att[Black] = Current->patt[Black]; - Current->passer = 0; - Current->threat = (Current->patt[White] & NonPawn(Black)) | (Current->patt[Black] & NonPawn(White)); - EI.score = Current->pst; +template void eval_endgame(GEvalInfo &EI) { + if ((EI.material->flags & VarC(FlagSingleBishop, me)) && Pawn(me)) { + int sq = (Board->bb[ILight(me)] ? (me ? 0 : 63) : (Board->bb[IDark(me)] ? (me ? 7 : 56) : (File(lsb(King(opp))) <= 3 ? (me ? 0 : 56) : (me ? 7 : 63)))); + if (!(Pawn(me) & (~DATA->PWay[opp][sq]))) { + if ((DATA->SArea[sq] | Bit(sq)) & King(opp)) EI.mul = 0; + else if ((DATA->SArea[sq] & DATA->SArea[lsb(King(opp))] & Line(me, 7)) && Square(sq - Push(me)) == IPawn(opp) && Square(sq - 2 * Push(me)) == IPawn(me)) EI.mul = 0; + } else if ((King(opp) & Line(me, 6) | Line(me, 7)) && Abs(File(sq) - File(lsb(King(opp)))) <= 3 && !(Pawn(me) & (~DATA->PSupport[me][sq])) && (Pawn(me) & Line(me, 5) & Shift(opp, Pawn(opp)))) EI.mul = 0; + if (Single(Pawn(me))) { + if (!Bishop(me)) { + EI.mul = MinF(EI.mul, kpkx()); + if (Piece(opp) == King(opp) && EI.mul == 32) IncV(Current->score, KpkValue); + } else { + sq = lsb(Pawn(me)); + if ((Pawn(me) & (DATA->File[1] | DATA->File[6]) & Line(me, 5)) && Square(sq + Push(me)) == IPawn(opp) && ((DATA->PAtt[me][sq + Push(me)] | DATA->PWay[me][sq + Push(me)]) & King(opp))) EI.mul = 0; + } + } + if (Bishop(opp) && Single(Bishop(opp)) && T(BB(ILight(me))) != T(BB(ILight(opp)))) { + int pcnt = 0; + if (T(King(opp) & LightArea) == T(Bishop(opp) & LightArea)) { + for (uint64_t u = Pawn(me); u; Cut(u)) { + if (pcnt >= 2) goto check_for_partial_block; + pcnt++; + int sq = lsb(u); + if (!(DATA->PWay[me][sq] & (DATA->PAtt[me][PVarC(EI, king, opp)] | DATA->PAtt[opp][PVarC(EI, king, opp)]))) { + if (!(DATA->PWay[me][sq] & Pawn(opp))) goto check_for_partial_block; + int bsq = lsb(Bishop(opp)); + uint64_t att = BishopAttacks(bsq, EI.occ); + if (!(att & DATA->PWay[me][sq] & Pawn(opp))) goto check_for_partial_block; + if (!(DATA->BishopForward[me][bsq] & att & DATA->PWay[me][sq] & Pawn(opp)) && popcount(DATA->FullLine[lsb(att & DATA->PWay[me][sq] & Pawn(opp))][bsq] & att) <= 2) goto check_for_partial_block; + } + } + EI.mul = 0; + return; + } + check_for_partial_block: + if (pcnt <= 2 && Multiple(Pawn(me)) && !Pawn(opp) && !(Pawn(me) & Boundary) && EI.mul) { + int sq1 = lsb(Pawn(me)); + int sq2 = msb(Pawn(me)); + int fd = Abs(File(sq2) - File(sq1)); + if (fd >= 5) EI.mul = 32; + else if (fd >= 4) EI.mul = 26; + else if (fd >= 3) EI.mul = 20; + } + if ((DATA->SArea[PVarC(EI, king, opp)] | Current->patt[opp]) & Bishop(opp)) { + uint64_t push = Shift(me, Pawn(me)); + if (!(push & (~(Piece(opp) | Current->att[opp]))) && (King(opp) & (Board->bb[ILight(opp)] ? LightArea : DarkArea))) { + EI.mul = Min(EI.mul, 8); + int bsq = lsb(Bishop(opp)); + uint64_t att = BishopAttacks(bsq, EI.occ); + uint64_t prp = (att | DATA->SArea[PVarC(EI, king, opp)]) & Pawn(opp) & (Board->bb[ILight(opp)] ? LightArea : DarkArea); + uint64_t patt = ShiftW(opp, prp) | ShiftE(opp, prp); + if ((DATA->SArea[PVarC(EI, king, opp)] | patt) & Bishop(opp)) { + uint64_t double_att = (DATA->SArea[PVarC(EI, king, opp)] & patt) | (patt & att) | (DATA->SArea[PVarC(EI, king, opp)] & att); + if (!(push & (~(King(opp) | Bishop(opp) | prp | double_att)))) { + EI.mul = 0; + return; + } + } + } + } + } + } + if (F(Major(me))) { + if (T(Bishop(me)) && F(Knight(me)) && Single(Bishop(me)) && T(Pawn(me))) { + int number = popcount(Pawn(me)); + if (number == 1) { + if (Bishop(opp)) EI.mul = MinF(EI.mul, kbpkbx()); + else if (Knight(opp)) EI.mul = MinF(EI.mul, kbpknx()); + } else if (number == 2 && T(Bishop(opp))) EI.mul = MinF(EI.mul, kbppkbx()); + } else if (!Bishop(me) && Knight(me) && Single(Knight(me)) && Pawn(me) && Single(Pawn(me))) EI.mul = MinF(EI.mul, knpkx()); + } else if (F(Minor(me))) { + if (F(Pawn(me)) && F(Rook(me)) && T(Queen(me)) && T(Pawn(opp))) { + if (F(NonPawnKing(opp)) && Single(Pawn(opp))) EI.mul = MinF(EI.mul, kqkp()); + else if (Rook(opp)) EI.mul = MinF(EI.mul, kqkrpx()); + } else if (F(Queen(me)) && T(Rook(me)) && Single(Rook(me))) { + int number = popcount(Pawn(me)); + if (number <= 3) { + if (number == 0) { + if (Pawn(opp)) EI.mul = MinF(EI.mul, krkpx()); + } else if (Rook(opp)) { + if (number == 1) { + int new_mul = krpkrx(); + EI.mul = (new_mul <= 32 ? Min(EI.mul, new_mul) : new_mul); + } else { + if (number == 2) EI.mul = MinF(EI.mul, krppkrx()); + if (Pawn(opp)) { + if (number == 2) EI.mul = MinF(EI.mul, krppkrpx()); + else if (Multiple(Pawn(opp))) EI.mul = MinF(EI.mul, krpppkrppx()); + } + } + } else if (number == 1 && Bishop(opp)) EI.mul = MinF(EI.mul, krpkbx()); + } + } + } else if (!Pawn(me) && Single(Rook(me)) && !Queen(me) && Single(Bishop(me)) && !Knight(me) && Rook(opp)) EI.mul = MinF(EI.mul, krbkrx()); + if (F(NonPawnKing(opp)) && Current->turn == opp && F(Current->att[me] & King(opp)) && !(DATA->SArea[PVarC(EI, king, opp)] & (~(Current->att[me] | Piece(opp)))) + && F(Current->patt[opp] & Piece(me)) && F(Shift(opp, Pawn(opp)) & (~EI.occ))) + EI.mul = 0; +} +void eval_unusual_material(GEvalInfo &EI) { + int wp, bp, wlight, blight, wr, br, wq, bq; + wp = popcount(Pawn(White)); + bp = popcount(Pawn(Black)); + wlight = popcount(Minor(White)); + blight = popcount(Minor(Black)); + wr = popcount(Rook(White)); + br = popcount(Rook(Black)); + wq = popcount(Queen(White)); + bq = popcount(Queen(Black)); + int phase = Min(24, (wlight + blight) + 2 * (wr + br) + 4 * (wq + bq)); + int mat_score = SeeValue[WhitePawn] * (wp - bp) + SeeValue[WhiteKnight] * (wlight - blight) + SeeValue[WhiteRook] * (wr - br) + SeeValue[WhiteQueen] * (wq - bq); + mat_score = Compose(mat_score,mat_score); + Current->score = (((Opening(mat_score + EI.score) * phase) + (Endgame(mat_score + EI.score) * (24 - phase)))/24); + if (Current->turn) Current->score = -Current->score; + UpdateDelta +} + +void evaluation() { + GEvalInfo EI; + + if (Current->eval_key == Current->key) return; + Current->eval_key = Current->key; + + EI.king_w = lsb(King(White)); + EI.king_b = lsb(King(Black)); + EI.occ = PieceAll; + Current->patt[White] = ShiftW(White,Pawn(White)) | ShiftE(White,Pawn(White)); + Current->patt[Black] = ShiftW(Black,Pawn(Black)) | ShiftE(Black,Pawn(Black)); + EI.area_w = (DATA->SArea[EI.king_w] | King(White)) & ((~Current->patt[White]) | Current->patt[Black]); + EI.area_b = (DATA->SArea[EI.king_b] | King(Black)) & ((~Current->patt[Black]) | Current->patt[White]); + Current->att[White] = Current->patt[White]; + Current->att[Black] = Current->patt[Black]; + Current->passer = 0; + Current->threat = (Current->patt[White] & NonPawn(Black)) | (Current->patt[Black] & NonPawn(White)); + EI.score = Current->pst; #define me White - Current->xray[me] = 0; - PVarC(EI, free, me) = Queen(opp) | King(opp) | (~(Current->patt[opp] | Pawn(me) | King(me))); - DecV(EI.score, popcount(Shift(opp, EI.occ) & Pawn(me)) * Ca(PawnSpecial, PawnBlocked)); - if (Current->patt[me] & PVarC(EI, area, opp)) PVarC(EI, king_att, me) = KingAttack; - else PVarC(EI, king_att, me) = 0; - eval_queens(EI); - PVarC(EI, free, me) |= Rook(opp); - eval_rooks(EI); - PVarC(EI, free, me) |= Minor(opp); - eval_bishops(EI); - eval_knights(EI); + Current->xray[me] = 0; + PVarC(EI, free, me) = Queen(opp) | King(opp) | (~(Current->patt[opp] | Pawn(me) | King(me))); + DecV(EI.score, popcount(Shift(opp, EI.occ) & Pawn(me)) * Ca(PawnSpecial, PawnBlocked)); + if (Current->patt[me] & PVarC(EI, area, opp)) PVarC(EI, king_att, me) = KingAttack; + else PVarC(EI, king_att, me) = 0; + eval_queens(EI); + PVarC(EI, free, me) |= Rook(opp); + eval_rooks(EI); + PVarC(EI, free, me) |= Minor(opp); + eval_bishops(EI); + eval_knights(EI); #undef me #define me Black - Current->xray[me] = 0; - PVarC(EI, free, me) = Queen(opp) | King(opp) | (~(Current->patt[opp] | Pawn(me) | King(me))); - DecV(EI.score, popcount(Shift(opp, EI.occ) & Pawn(me)) * Ca(PawnSpecial, PawnBlocked)); - if (Current->patt[me] & PVarC(EI, area, opp)) PVarC(EI, king_att, me) = KingAttack; - else PVarC(EI, king_att, me) = 0; - eval_queens(EI); - PVarC(EI, free, me) |= Rook(opp); - eval_rooks(EI); - PVarC(EI, free, me) |= Minor(opp); - eval_bishops(EI); - eval_knights(EI); + Current->xray[me] = 0; + PVarC(EI, free, me) = Queen(opp) | King(opp) | (~(Current->patt[opp] | Pawn(me) | King(me))); + DecV(EI.score, popcount(Shift(opp, EI.occ) & Pawn(me)) * Ca(PawnSpecial, PawnBlocked)); + if (Current->patt[me] & PVarC(EI, area, opp)) PVarC(EI, king_att, me) = KingAttack; + else PVarC(EI, king_att, me) = 0; + eval_queens(EI); + PVarC(EI, free, me) |= Rook(opp); + eval_rooks(EI); + PVarC(EI, free, me) |= Minor(opp); + eval_bishops(EI); + eval_knights(EI); #undef me - EI.PawnEntry = PawnHash + (Current->pawn_key & pawn_hash_mask); - if (Current->pawn_key != EI.PawnEntry->key) eval_pawn_structure(EI.PawnEntry); - EI.score += EI.PawnEntry->score; - - eval_king(EI); - eval_king(EI); - Current->att[White] |= SArea[EI.king_w]; - Current->att[Black] |= SArea[EI.king_b]; - - eval_passer(EI); - eval_pieces(EI); - eval_passer(EI); - eval_pieces(EI); - - if (Current->material & FlagUnusualMaterial) { - eval_unusual_material(EI); - return; - } - EI.material = &Material[Current->material]; -#ifdef TUNER - if (EI.material->generation != generation) calc_material(Current->material); -#endif - Current->score = EI.material->score + (((Opening(EI.score) * EI.material->phase) + (Endgame(EI.score) * (128 - (int)EI.material->phase)))/128); - - if (Current->ply >= 50) Current->score /= 2; - if (Current->score > 0) { - EI.mul = EI.material->mul[White]; - if (EI.material->flags & FlagCallEvalEndgame_w) eval_endgame(EI); - Current->score -= (Min(Current->score, 100) * (int)EI.PawnEntry->draw[White]) / 64; - } else if (Current->score < 0) { - EI.mul = EI.material->mul[Black]; - if (EI.material->flags & FlagCallEvalEndgame_b) eval_endgame(EI); - Current->score += (Min(-Current->score, 100) * (int)EI.PawnEntry->draw[Black]) / 64; - } else EI.mul = Min(EI.material->mul[White], EI.material->mul[Black]); - Current->score = (Current->score * EI.mul)/32; - - if (Current->turn) Current->score = -Current->score; - UpdateDelta + EI.PawnEntry = PAWNHASH + (Current->pawn_key & pawn_hash_mask); + if (Current->pawn_key != EI.PawnEntry->key) eval_pawn_structure(EI.PawnEntry); + EI.score += EI.PawnEntry->score; + + eval_king(EI); + eval_king(EI); + Current->att[White] |= DATA->SArea[EI.king_w]; + Current->att[Black] |= DATA->SArea[EI.king_b]; + + eval_passer(EI); + eval_pieces(EI); + eval_passer(EI); + eval_pieces(EI); + + if (Current->material & FlagUnusualMaterial) { + eval_unusual_material(EI); + return; + } + EI.material = &DATA->Material[Current->material]; + Current->score = EI.material->score + (((Opening(EI.score) * EI.material->phase) + (Endgame(EI.score) * (128 - (int)EI.material->phase)))/128); + + if (Current->ply >= 50) Current->score /= 2; + if (Current->score > 0) { + EI.mul = EI.material->mul[White]; + if (EI.material->flags & FlagCallEvalEndgame_w) eval_endgame(EI); + Current->score -= (Min(Current->score, 100) * (int)EI.PawnEntry->draw[White]) / 64; + } else if (Current->score < 0) { + EI.mul = EI.material->mul[Black]; + if (EI.material->flags & FlagCallEvalEndgame_b) eval_endgame(EI); + Current->score += (Min(-Current->score, 100) * (int)EI.PawnEntry->draw[Black]) / 64; + } else EI.mul = Min(EI.material->mul[White], EI.material->mul[Black]); + Current->score = (Current->score * EI.mul)/32; + + if (Current->turn) Current->score = -Current->score; + UpdateDelta } -__forceinline void evaluate() { - HardwarePopCnt ? evaluation<1>() : evaluation<0>(); +inline void evaluate() { + evaluation(); } template int is_legal(int move) { - int from, to, piece, capture; - uint64 u, occ; + int from, to, piece, capture; + uint64_t u, occ; from = From(move); - to = To(move); - piece = Board->square[from]; - capture = Board->square[to]; - if (piece == 0) return 0; - if ((piece & 1) != Current->turn) return 0; - if (capture) { - if ((capture & 1) == (piece & 1)) return 0; - if (capture >= WhiteKing) return 0; - } - occ = PieceAll; - u = Bit(to); - if (piece >= WhiteLight && piece < WhiteKing) { - if ((QMask[from] & u) == 0) return 0; - if (Between[from][to] & occ) return 0; - } - if (IsEP(move)) { - if (piece >= WhiteKnight) return 0; - if (Current->ep_square != to) return 0; - return 1; - } - if (IsCastling(move) && Board->square[from] < WhiteKing) return 0; - if (IsPromotion(move) && Board->square[from] >= WhiteKnight) return 0; - if (piece == IPawn(me)) { - if (u & PMove[me][from]) { + to = To(move); + piece = Board->square[from]; + capture = Board->square[to]; + if (piece == 0) return 0; + if ((piece & 1) != Current->turn) return 0; + if (capture) { + if ((capture & 1) == (piece & 1)) return 0; + if (capture >= WhiteKing) return 0; + } + occ = PieceAll; + u = Bit(to); + if (piece >= WhiteLight && piece < WhiteKing) { + if ((DATA->QMask[from] & u) == 0) return 0; + if (DATA->Between[from][to] & occ) return 0; + } + if (IsEP(move)) { + if (piece >= WhiteKnight) return 0; + if (Current->ep_square != to) return 0; + return 1; + } + if (IsCastling(move) && Board->square[from] < WhiteKing) return 0; + if (IsPromotion(move) && Board->square[from] >= WhiteKnight) return 0; + if (piece == IPawn(me)) { + if (u & DATA->PMove[me][from]) { if (capture) return 0; - if (T(u & Line(me,7)) && !IsPromotion(move)) return 0; - return 1; - } else if (to == (from + 2 * Push(me))) { + if (T(u & Line(me,7)) && !IsPromotion(move)) return 0; + return 1; + } else if (to == (from + 2 * Push(me))) { if (capture) return 0; - if (Square(to - Push(me))) return 0; - if (F(u & Line(me,3))) return 0; - return 1; - } else if (u & PAtt[me][from]) { + if (Square(to - Push(me))) return 0; + if (F(u & Line(me,3))) return 0; + return 1; + } else if (u & DATA->PAtt[me][from]) { if (capture == 0) return 0; - if (T(u & Line(me,7)) && !IsPromotion(move)) return 0; - return 1; - } else return 0; - } else if (piece == IKing(me)) { - if (me == White) { - if (IsCastling(move)) { - if (u & 0x40) { + if (T(u & Line(me,7)) && !IsPromotion(move)) return 0; + return 1; + } else return 0; + } else if (piece == IKing(me)) { + if (me == White) { + if (IsCastling(move)) { + if (u & 0x40) { if (((Current->castle_flags) & CanCastle_OO) == 0) return 0; - if (occ & 0x60) return 0; - if (Current->att[Black] & 0x70) return 0; - } else { - if (((Current->castle_flags) & CanCastle_OOO) == 0) return 0; - if (occ & 0xE) return 0; - if (Current->att[Black] & 0x1C) return 0; - } - return 1; - } - } else { + if (occ & 0x60) return 0; + if (Current->att[Black] & 0x70) return 0; + } else { + if (((Current->castle_flags) & CanCastle_OOO) == 0) return 0; + if (occ & 0xE) return 0; + if (Current->att[Black] & 0x1C) return 0; + } + return 1; + } + } else { if (IsCastling(move)) { - if (u & 0x4000000000000000) { + if (u & 0x4000000000000000) { if (((Current->castle_flags) & CanCastle_oo) == 0) return 0; - if (occ & 0x6000000000000000) return 0; - if (Current->att[White] & 0x7000000000000000) return 0; - } else { - if (((Current->castle_flags) & CanCastle_ooo) == 0) return 0; - if (occ & 0x0E00000000000000) return 0; - if (Current->att[White] & 0x1C00000000000000) return 0; - } - return 1; - } - } - if (F(SArea[from] & u)) return 0; - if (Current->att[opp] & u) return 0; - return 1; - } - piece = (piece >> 1) - 2; - if (piece == 0) { - if (u & NAtt[from]) return 1; - else return 0; - } else { - if (piece <= 2) { - if (BMask[from] & u) return 1; - } else if (piece == 3) { - if (RMask[from] & u) return 1; - } else return 1; - return 0; - } + if (occ & 0x6000000000000000) return 0; + if (Current->att[White] & 0x7000000000000000) return 0; + } else { + if (((Current->castle_flags) & CanCastle_ooo) == 0) return 0; + if (occ & 0x0E00000000000000) return 0; + if (Current->att[White] & 0x1C00000000000000) return 0; + } + return 1; + } + } + if (F(DATA->SArea[from] & u)) return 0; + if (Current->att[opp] & u) return 0; + return 1; + } + piece = (piece >> 1) - 2; + if (piece == 0) { + if (u & DATA->NAtt[from]) return 1; + else return 0; + } else { + if (piece <= 2) { + if (DATA->BMask[from] & u) return 1; + } else if (piece == 3) { + if (DATA->RMask[from] & u) return 1; + } else return 1; + return 0; + } } template int is_check(int move) { // doesn't detect castling and ep checks - uint64 king; - int from, to, piece, king_sq; - - from = From(move); - to = To(move); - king = King(opp); - king_sq = lsb(king); - piece = Square(from); - if (T(Bit(from) & Current->xray[me]) && F(FullLine[king_sq][from] & Bit(to))) return 1; - if (piece < WhiteKnight) { - if (PAtt[me][to] & king) return 1; - if (T(Bit(to) & Line(me, 7)) && T(king & Line(me, 7)) && F(Between[to][king_sq] & PieceAll)) return 1; - } else if (piece < WhiteLight) { - if (NAtt[to] & king) return 1; - } else if (piece < WhiteRook) { - if (BMask[to] & king) if (F(Between[king_sq][to] & PieceAll)) return 1; - } else if (piece < WhiteQueen) { - if (RMask[to] & king) if (F(Between[king_sq][to] & PieceAll)) return 1; - } else if (piece < WhiteKing) { - if (QMask[to] & king) if (F(Between[king_sq][to] & PieceAll)) return 1; - } - return 0; + uint64_t king; + int from, to, piece, king_sq; + + from = From(move); + to = To(move); + king = King(opp); + king_sq = lsb(king); + piece = Square(from); + if (T(Bit(from) & Current->xray[me]) && F(DATA->FullLine[king_sq][from] & Bit(to))) return 1; + if (piece < WhiteKnight) { + if (DATA->PAtt[me][to] & king) return 1; + if (T(Bit(to) & Line(me, 7)) && T(king & Line(me, 7)) && F(DATA->Between[to][king_sq] & PieceAll)) return 1; + } else if (piece < WhiteLight) { + if (DATA->NAtt[to] & king) return 1; + } else if (piece < WhiteRook) { + if (DATA->BMask[to] & king) if (F(DATA->Between[king_sq][to] & PieceAll)) return 1; + } else if (piece < WhiteQueen) { + if (DATA->RMask[to] & king) if (F(DATA->Between[king_sq][to] & PieceAll)) return 1; + } else if (piece < WhiteKing) { + if (DATA->QMask[to] & king) if (F(DATA->Between[king_sq][to] & PieceAll)) return 1; + } + return 0; } void hash_high(int value, int depth) { - int i, score, min_score; - GEntry *best, *Entry; - - min_score = 0x70000000; - for (i = 0, best = Entry = Hash + (High32(Current->key) & hash_mask); i < 4; i++, Entry++) { - if (Entry->key == Low32(Current->key)) { - Entry->date = date; - if (depth > Entry->high_depth || (depth == Entry->high_depth && value < Entry->high)) { - if (Entry->low <= value) { - Entry->high_depth = depth; - Entry->high = value; - } else if (Entry->low_depth < depth) { - Entry->high_depth = depth; - Entry->high = value; - Entry->low = value; - } - } - return; - } else score = (Convert(Entry->date,int) << 3) + Convert(Max(Entry->high_depth, Entry->low_depth),int); - if (score < min_score) { - min_score = score; - best = Entry; - } - } - best->date = date; - best->key = Low32(Current->key); - best->high = value; - best->high_depth = depth; - best->low = 0; - best->low_depth = 0; - best->move = 0; - best->flags = 0; - return; + int i, score, min_score; + GEntry *best, *Entry; + + min_score = 0x70000000; + for (i = 0, best = Entry = HASH + (High32(Current->key) & hash_mask); i < 4; i++, Entry++) { + if (Entry->key == Low32(Current->key)) { + Entry->date = SHARED->date; + if (depth > Entry->high_depth || (depth == Entry->high_depth && value < Entry->high)) { + if (Entry->low <= value) { + Entry->high_depth = depth; + Entry->high = value; + } else if (Entry->low_depth < depth) { + Entry->high_depth = depth; + Entry->high = value; + Entry->low = value; + } + } + return; + } else score = (Convert(Entry->date,int) << 3) + Convert(Max(Entry->high_depth, Entry->low_depth),int); + if (score < min_score) { + min_score = score; + best = Entry; + } + } + best->date = SHARED->date; + best->key = Low32(Current->key); + best->high = value; + best->high_depth = depth; + best->low = 0; + best->low_depth = 0; + best->move = 0; + best->flags = 0; + return; } void hash_low(int move, int value, int depth) { - int i, score, min_score; - GEntry *best, *Entry; - - min_score = 0x70000000; - move &= 0xFFFF; - for (i = 0, best = Entry = Hash + (High32(Current->key) & hash_mask); i < 4; i++, Entry++) { - if (Entry->key == Low32(Current->key)) { - Entry->date = date; - if (depth > Entry->low_depth || (depth == Entry->low_depth && value > Entry->low)) { - if (move) Entry->move = move; - if (Entry->high >= value) { - Entry->low_depth = depth; - Entry->low = value; - } else if (Entry->high_depth < depth) { - Entry->low_depth = depth; - Entry->low = value; - Entry->high = value; - } - } else if (F(Entry->move)) Entry->move = move; - return; - } else score = (Convert(Entry->date,int) << 3) + Convert(Max(Entry->high_depth, Entry->low_depth),int); - if (score < min_score) { - min_score = score; - best = Entry; - } - } - best->date = date; - best->key = Low32(Current->key); - best->high = 0; - best->high_depth = 0; - best->low = value; - best->low_depth = depth; - best->move = move; - best->flags = 0; - return; + int i, score, min_score; + GEntry *best, *Entry; + + min_score = 0x70000000; + move &= 0xFFFF; + for (i = 0, best = Entry = HASH + (High32(Current->key) & hash_mask); i < 4; i++, Entry++) { + if (Entry->key == Low32(Current->key)) { + Entry->date = SHARED->date; + if (depth > Entry->low_depth || (depth == Entry->low_depth && value > Entry->low)) { + if (move) Entry->move = move; + if (Entry->high >= value) { + Entry->low_depth = depth; + Entry->low = value; + } else if (Entry->high_depth < depth) { + Entry->low_depth = depth; + Entry->low = value; + Entry->high = value; + } + } else if (F(Entry->move)) Entry->move = move; + return; + } else score = (Convert(Entry->date,int) << 3) + Convert(Max(Entry->high_depth, Entry->low_depth),int); + if (score < min_score) { + min_score = score; + best = Entry; + } + } + best->date = SHARED->date; + best->key = Low32(Current->key); + best->high = 0; + best->high_depth = 0; + best->low = value; + best->low_depth = depth; + best->move = move; + best->flags = 0; + return; } void hash_exact(int move, int value, int depth, int exclusion, int ex_depth, int knodes) { - int i, score, min_score; - GPVEntry *best; - GPVEntry * PVEntry; - - min_score = 0x70000000; - for (i = 0, best = PVEntry = PVHash + (High32(Current->key) & pv_hash_mask); i < pv_cluster_size; i++, PVEntry++) { - if (PVEntry->key == Low32(Current->key)) { - PVEntry->date = date; - PVEntry->knodes += knodes; - if (PVEntry->depth <= depth) { - PVEntry->value = value; - PVEntry->depth = depth; - PVEntry->move = move; - PVEntry->ply = Current->ply; - if (ex_depth) { - PVEntry->exclusion = exclusion; - PVEntry->ex_depth = ex_depth; - } - } - return; - } - score = (Convert(PVEntry->date,int) << 3) + Convert(PVEntry->depth,int); - if (score < min_score) { - min_score = score; - best = PVEntry; - } - } - best->key = Low32(Current->key); - best->date = date; - best->value = value; - best->depth = depth; - best->move = move; - best->exclusion = exclusion; - best->ex_depth = ex_depth; - best->knodes = knodes; - best->ply = Current->ply; -} - -template __forceinline int extension(int move, int depth) { - register int ext = 0; - if (pv) { - if (T(Current->passer & Bit(From(move))) && CRank(Current->turn, From(move)) >= 5 && depth < 16) ext = 2; - } else { - if (T(Current->passer & Bit(From(move))) && CRank(Current->turn, From(move)) >= 5 && depth < 16) ext = 1; - } - return ext; + int i, score, min_score; + GPVEntry *best; + GPVEntry * PVEntry; + + min_score = 0x70000000; + for (i = 0, best = PVEntry = PVHASH + (High32(Current->key) & pv_hash_mask); i < pv_cluster_size; i++, PVEntry++) { + if (PVEntry->key == Low32(Current->key)) { + PVEntry->date = SHARED->date; + PVEntry->knodes += knodes; + if (PVEntry->depth <= depth) { + PVEntry->value = value; + PVEntry->depth = depth; + PVEntry->move = move; + PVEntry->ply = Current->ply; + if (ex_depth) { + PVEntry->exclusion = exclusion; + PVEntry->ex_depth = ex_depth; + } + } + return; + } + score = (Convert(PVEntry->date,int) << 3) + Convert(PVEntry->depth,int); + if (score < min_score) { + min_score = score; + best = PVEntry; + } + } + best->key = Low32(Current->key); + best->date = SHARED->date; + best->value = value; + best->depth = depth; + best->move = move; + best->exclusion = exclusion; + best->ex_depth = ex_depth; + best->knodes = knodes; + best->ply = Current->ply; +} + +template inline int extension(int move, int depth) { + register int ext = 0; + if (pv) { + if (T(Current->passer & Bit(From(move))) && CRank(Current->turn, From(move)) >= 5 && depth < 16) ext = 2; + } else { + if (T(Current->passer & Bit(From(move))) && CRank(Current->turn, From(move)) >= 5 && depth < 16) ext = 1; + } + return ext; } void sort(int * start, int * finish) { - for (int * p = start; p < finish - 1; p++) { - int * best = p; - int value = *p; - int previous = *p; - for (int * q = p + 1; q < finish; q++) if ((*q) > value) { - value = *q; - best = q; - } - *best = previous; - *p = value; - } + for (int * p = start; p < finish - 1; p++) { + int * best = p; + int value = *p; + int previous = *p; + for (int * q = p + 1; q < finish; q++) if ((*q) > value) { + value = *q; + best = q; + } + *best = previous; + *p = value; + } } void sort_moves(int * start, int * finish) { - for (int * p = start + 1; p < finish; p++) for (int * q = p - 1; q >= start; q--) if (((*q) >> 16) < ((*(q+1)) >> 16)) { - int move = *q; - *q = *(q+1); - *(q+1)=move; - } + for (int * p = start + 1; p < finish; p++) for (int * q = p - 1; q >= start; q--) if (((*q) >> 16) < ((*(q+1)) >> 16)) { + int move = *q; + *q = *(q+1); + *(q+1)=move; + } } -__forceinline int pick_move() { - register int move, *p, *best; - move = *(Current->current); - if (F(move)) return 0; - best = Current->current; - for (p = Current->current + 1; T(*p); p++) { - if ((*p) > move) { - best = p; - move = *p; - } - } - *best = *(Current->current); - *(Current->current) = move; - Current->current++; - return move & 0xFFFF; +inline int pick_move() { + register int move, *p, *best; + move = *(Current->current); + if (F(move)) return 0; + best = Current->current; + for (p = Current->current + 1; T(*p); p++) { + if ((*p) > move) { + best = p; + move = *p; + } + } + *best = *(Current->current); + *(Current->current) = move; + Current->current++; + return move & 0xFFFF; } template void gen_next_moves() { - int *p, *q, *r; - Current->gen_flags &= ~FlagSort; - switch (Current->stage) { - case s_hash_move: case r_hash_move: case e_hash_move: - Current->moves[0] = Current->killer[0]; - Current->moves[1] = 0; - return; - case s_good_cap: - Current->mask = Piece(opp); - r = gen_captures(Current->moves); - for (q = r - 1, p = Current->moves; q >= p;) { - int move = (*q) & 0xFFFF; - if (!see(move,0)) { - int next = *p; - *p = *q; - *q = next; - p++; - } else q--; - } - Current->start = p; - Current->current = p; - sort(p, r); - return; - case s_special: - Current->current = Current->start; - p = Current->start; - if (Current->killer[1]) {*p = Current->killer[1]; p++;} - if (Current->killer[2]) {*p = Current->killer[2]; p++;} - if (Current->ref[0] && Current->ref[0] != Current->killer[1] && Current->ref[0] != Current->killer[2]) {*p = Current->ref[0]; p++;} - if (Current->ref[1] && Current->ref[1] != Current->killer[1] && Current->ref[1] != Current->killer[2]) {*p = Current->ref[1]; p++;} - *p = 0; - return; - case s_quiet: - gen_quiet_moves(Current->start); - Current->current = Current->start; - Current->gen_flags |= FlagSort; - return; - case s_bad_cap: - *(Current->start) = 0; - Current->current = Current->moves; - if (!(Current->gen_flags & FlagNoBcSort)) sort(Current->moves, Current->start); - return; - case r_cap: - r = gen_captures(Current->moves); - Current->current = Current->moves; - sort(Current->moves, r); - return; - case r_checks: - r = gen_checks(Current->moves); - Current->current = Current->moves; - sort(Current->moves, r); - return; - case e_ev: - Current->mask = Filled; - r = gen_evasions(Current->moves); - mark_evasions(Current->moves); - sort(Current->moves, r); - Current->current = Current->moves; - return; - } + int *p, *q, *r; + Current->gen_flags &= ~FlagSort; + switch (Current->stage) { + case s_hash_move: case r_hash_move: case e_hash_move: + Current->moves[0] = Current->killer[0]; + Current->moves[1] = 0; + return; + case s_good_cap: + Current->mask = Piece(opp); + r = gen_captures(Current->moves); + for (q = r - 1, p = Current->moves; q >= p;) { + int move = (*q) & 0xFFFF; + if (!see(move,0)) { + int next = *p; + *p = *q; + *q = next; + p++; + } else q--; + } + Current->start = p; + Current->current = p; + sort(p, r); + return; + case s_special: + Current->current = Current->start; + p = Current->start; + if (Current->killer[1]) {*p = Current->killer[1]; p++;} + if (Current->killer[2]) {*p = Current->killer[2]; p++;} + if (Current->ref[0] && Current->ref[0] != Current->killer[1] && Current->ref[0] != Current->killer[2]) {*p = Current->ref[0]; p++;} + if (Current->ref[1] && Current->ref[1] != Current->killer[1] && Current->ref[1] != Current->killer[2]) {*p = Current->ref[1]; p++;} + *p = 0; + return; + case s_quiet: + gen_quiet_moves(Current->start); + Current->current = Current->start; + Current->gen_flags |= FlagSort; + return; + case s_bad_cap: + *(Current->start) = 0; + Current->current = Current->moves; + if (!(Current->gen_flags & FlagNoBcSort)) sort(Current->moves, Current->start); + return; + case r_cap: + r = gen_captures(Current->moves); + Current->current = Current->moves; + sort(Current->moves, r); + return; + case r_checks: + r = gen_checks(Current->moves); + Current->current = Current->moves; + sort(Current->moves, r); + return; + case e_ev: + Current->mask = Filled; + r = gen_evasions(Current->moves); + mark_evasions(Current->moves); + sort(Current->moves, r); + Current->current = Current->moves; + return; + } } template int get_move() { - int move; - - if (root) { - move = (*Current->current) & 0xFFFF; - Current->current++; - return move; - } + int move; + + if (root) { + move = (*Current->current) & 0xFFFF; + Current->current++; + return move; + } start: - if (F(*Current->current)) { - Current->stage++; - if ((1 << Current->stage) & StageNone) return 0; - gen_next_moves(); - goto start; - } - if (Current->gen_flags & FlagSort) move = pick_move(); - else { - move = (*Current->current) & 0xFFFF; - Current->current++; - } - if (Current->stage == s_quiet) { - if (move == Current->killer[1] || move == Current->killer[2] || move == Current->ref[0] || move == Current->ref[1]) goto start; - } else if (Current->stage == s_special && (Square(To(move)) || !is_legal(move))) goto start; - return move; + if (F(*Current->current)) { + Current->stage++; + if ((1 << Current->stage) & StageNone) return 0; + gen_next_moves(); + goto start; + } + if (Current->gen_flags & FlagSort) move = pick_move(); + else { + move = (*Current->current) & 0xFFFF; + Current->current++; + } + if (Current->stage == s_quiet) { + if (move == Current->killer[1] || move == Current->killer[2] || move == Current->ref[0] || move == Current->ref[1]) goto start; + } else if (Current->stage == s_special && (Square(To(move)) || !is_legal(move))) goto start; + return move; } template int see(int move, int margin) { - int from, to, piece, capture, delta, sq, pos; - uint64 clear, def, att, occ, b_area, r_slider_att, b_slider_att, r_slider_def, b_slider_def, r_area, u, new_att, my_bishop, opp_bishop; - from = From(move); - to = To(move); - piece = SeeValue[Square(from)]; - capture = SeeValue[Square(to)]; - delta = piece - capture; - if (delta <= -margin) return 1; - if (piece == SeeValue[WhiteKing]) return 1; - if (Current->xray[me] & Bit(from)) return 1; - if (T(Current->pin[me] & Bit(from)) && piece <= SeeValue[WhiteDark]) return 1; - if (piece > (SeeValue[WhiteKing] >> 1)) return 1; - if (IsEP(move)) return 1; - if (F(Current->att[opp] & Bit(to))) return 1; - att = PAtt[me][to] & Pawn(opp); - if (T(att) && delta + margin > SeeValue[WhitePawn]) return 0; - clear = ~Bit(from); - def = PAtt[opp][to] & Pawn(me) & clear; - if (T(def) && delta + SeeValue[WhitePawn] + margin <= 0) return 1; - att |= NAtt[to] & Knight(opp); - if (T(att) && delta > SeeValue[WhiteDark] - margin) return 0; - occ = PieceAll & clear; + int from, to, piece, capture, delta, sq, pos; + uint64_t clear, def, att, occ, b_area, r_slider_att, b_slider_att, r_slider_def, b_slider_def, r_area, u, new_att, my_bishop, opp_bishop; + from = From(move); + to = To(move); + piece = SeeValue[Square(from)]; + capture = SeeValue[Square(to)]; + delta = piece - capture; + if (delta <= -margin) return 1; + if (piece == SeeValue[WhiteKing]) return 1; + if (Current->xray[me] & Bit(from)) return 1; + if (T(Current->pin[me] & Bit(from)) && piece <= SeeValue[WhiteDark]) return 1; + if (piece > (SeeValue[WhiteKing] >> 1)) return 1; + if (IsEP(move)) return 1; + if (F(Current->att[opp] & Bit(to))) return 1; + att = DATA->PAtt[me][to] & Pawn(opp); + if (T(att) && delta + margin > SeeValue[WhitePawn]) return 0; + clear = ~Bit(from); + def = DATA->PAtt[opp][to] & Pawn(me) & clear; + if (T(def) && delta + SeeValue[WhitePawn] + margin <= 0) return 1; + att |= DATA->NAtt[to] & Knight(opp); + if (T(att) && delta > SeeValue[WhiteDark] - margin) return 0; + occ = PieceAll & clear; b_area = BishopAttacks(to,occ); - opp_bishop = Bishop(opp); - if (delta > SeeValue[IDark(me)] - margin) if (b_area & opp_bishop) return 0; - my_bishop = Bishop(me); - b_slider_att = BMask[to] & (opp_bishop | Queen(opp)); - r_slider_att = RMask[to] & Major(opp); - b_slider_def = BMask[to] & (my_bishop | Queen(me)) & clear; - r_slider_def = RMask[to] & Major(me) & clear; - att |= (b_slider_att & b_area); - def |= NAtt[to] & Knight(me) & clear; - r_area = RookAttacks(to,occ); - att |= (r_slider_att & r_area); - def |= (b_slider_def & b_area); - def |= (r_slider_def & r_area); - att |= SArea[to] & King(opp); - def |= SArea[to] & King(me) & clear; - while (true) { - if (u = (att & Pawn(opp))) { - capture -= piece; - piece = SeeValue[WhitePawn]; - sq = lsb(u); - occ ^= Bit(sq); - att ^= Bit(sq); - for (new_att = FullLine[to][sq] & b_slider_att & occ & (~att); T(new_att); Cut(new_att)) { + opp_bishop = Bishop(opp); + if (delta > SeeValue[IDark(me)] - margin) if (b_area & opp_bishop) return 0; + my_bishop = Bishop(me); + b_slider_att = DATA->BMask[to] & (opp_bishop | Queen(opp)); + r_slider_att = DATA->RMask[to] & Major(opp); + b_slider_def = DATA->BMask[to] & (my_bishop | Queen(me)) & clear; + r_slider_def = DATA->RMask[to] & Major(me) & clear; + att |= (b_slider_att & b_area); + def |= DATA->NAtt[to] & Knight(me) & clear; + r_area = RookAttacks(to,occ); + att |= (r_slider_att & r_area); + def |= (b_slider_def & b_area); + def |= (r_slider_def & r_area); + att |= DATA->SArea[to] & King(opp); + def |= DATA->SArea[to] & King(me) & clear; + while (true) { + if (u = (att & Pawn(opp))) { + capture -= piece; + piece = SeeValue[WhitePawn]; + sq = lsb(u); + occ ^= Bit(sq); + att ^= Bit(sq); + for (new_att = DATA->FullLine[to][sq] & b_slider_att & occ & (~att); T(new_att); Cut(new_att)) { pos = lsb(new_att); - if (F(Between[to][pos] & occ)) { + if (F(DATA->Between[to][pos] & occ)) { Add(att,pos); - break; - } - } - } else if (u = (att & Knight(opp))) { - capture -= piece; - piece = SeeValue[WhiteKnight]; - att ^= (~(u-1)) & u; - } else if (u = (att & opp_bishop)) { + break; + } + } + } else if (u = (att & Knight(opp))) { capture -= piece; - piece = SeeValue[WhiteDark]; - sq = lsb(u); - occ ^= Bit(sq); - att ^= Bit(sq); - for (new_att = FullLine[to][sq] & b_slider_att & occ & (~att); T(new_att); Cut(new_att)) { + piece = SeeValue[WhiteKnight]; + att ^= (~(u-1)) & u; + } else if (u = (att & opp_bishop)) { + capture -= piece; + piece = SeeValue[WhiteDark]; + sq = lsb(u); + occ ^= Bit(sq); + att ^= Bit(sq); + for (new_att = DATA->FullLine[to][sq] & b_slider_att & occ & (~att); T(new_att); Cut(new_att)) { pos = lsb(new_att); - if (F(Between[to][pos] & occ)) { + if (F(DATA->Between[to][pos] & occ)) { Add(att,pos); - break; - } - } - } else if (u = (att & Rook(opp))) { + break; + } + } + } else if (u = (att & Rook(opp))) { capture -= piece; - piece = SeeValue[WhiteRook]; - sq = lsb(u); - occ ^= Bit(sq); - att ^= Bit(sq); - for (new_att = FullLine[to][sq] & r_slider_att & occ & (~att); T(new_att); Cut(new_att)) { + piece = SeeValue[WhiteRook]; + sq = lsb(u); + occ ^= Bit(sq); + att ^= Bit(sq); + for (new_att = DATA->FullLine[to][sq] & r_slider_att & occ & (~att); T(new_att); Cut(new_att)) { pos = lsb(new_att); - if (F(Between[to][pos] & occ)) { + if (F(DATA->Between[to][pos] & occ)) { Add(att,pos); - break; - } - } - } else if (u = (att & Queen(opp))) { + break; + } + } + } else if (u = (att & Queen(opp))) { capture -= piece; - piece = SeeValue[WhiteQueen]; - sq = lsb(u); - occ ^= Bit(sq); - att ^= Bit(sq); - for (new_att = FullLine[to][sq] & (r_slider_att | b_slider_att) & occ & (~att); T(new_att); Cut(new_att)) { + piece = SeeValue[WhiteQueen]; + sq = lsb(u); + occ ^= Bit(sq); + att ^= Bit(sq); + for (new_att = DATA->FullLine[to][sq] & (r_slider_att | b_slider_att) & occ & (~att); T(new_att); Cut(new_att)) { pos = lsb(new_att); - if (F(Between[to][pos] & occ)) { + if (F(DATA->Between[to][pos] & occ)) { Add(att,pos); - break; - } - } - } else if (u = (att & King(opp))) { + break; + } + } + } else if (u = (att & King(opp))) { capture -= piece; - piece = SeeValue[WhiteKing]; - } else return 1; - if (capture < -(SeeValue[WhiteKing] >> 1)) return 0; - if (piece + capture < margin) return 0; - if (u = (def & Pawn(me))) { + piece = SeeValue[WhiteKing]; + } else return 1; + if (capture < -(SeeValue[WhiteKing] >> 1)) return 0; + if (piece + capture < margin) return 0; + if (u = (def & Pawn(me))) { capture += piece; - piece = SeeValue[WhitePawn]; + piece = SeeValue[WhitePawn]; sq = lsb(u); - occ ^= Bit(sq); - def ^= Bit(sq); - for (new_att = FullLine[to][sq] & b_slider_def & occ & (~att); T(new_att); Cut(new_att)) { + occ ^= Bit(sq); + def ^= Bit(sq); + for (new_att = DATA->FullLine[to][sq] & b_slider_def & occ & (~att); T(new_att); Cut(new_att)) { pos = lsb(new_att); - if (F(Between[to][pos] & occ)) { + if (F(DATA->Between[to][pos] & occ)) { Add(def,pos); - break; - } - } - } else if (u = (def & Knight(me))) { + break; + } + } + } else if (u = (def & Knight(me))) { capture += piece; - piece = SeeValue[WhiteKnight]; - def ^= (~(u-1)) & u; - } else if (u = (def & my_bishop)) { + piece = SeeValue[WhiteKnight]; + def ^= (~(u-1)) & u; + } else if (u = (def & my_bishop)) { capture += piece; - piece = SeeValue[WhiteDark]; + piece = SeeValue[WhiteDark]; sq = lsb(u); - occ ^= Bit(sq); - def ^= Bit(sq); - for (new_att = FullLine[to][sq] & b_slider_def & occ & (~att); T(new_att); Cut(new_att)) { + occ ^= Bit(sq); + def ^= Bit(sq); + for (new_att = DATA->FullLine[to][sq] & b_slider_def & occ & (~att); T(new_att); Cut(new_att)) { pos = lsb(new_att); - if (F(Between[to][pos] & occ)) { + if (F(DATA->Between[to][pos] & occ)) { Add(def,pos); - break; - } - } - } else if (u = (def & Rook(me))) { + break; + } + } + } else if (u = (def & Rook(me))) { capture += piece; - piece = SeeValue[WhiteRook]; + piece = SeeValue[WhiteRook]; sq = lsb(u); - occ ^= Bit(sq); - def ^= Bit(sq); - for (new_att = FullLine[to][sq] & r_slider_def & occ & (~att); T(new_att); Cut(new_att)) { + occ ^= Bit(sq); + def ^= Bit(sq); + for (new_att = DATA->FullLine[to][sq] & r_slider_def & occ & (~att); T(new_att); Cut(new_att)) { pos = lsb(new_att); - if (F(Between[to][pos] & occ)) { + if (F(DATA->Between[to][pos] & occ)) { Add(def,pos); - break; - } - } - } else if (u = (def & Queen(me))) { + break; + } + } + } else if (u = (def & Queen(me))) { capture += piece; - piece = SeeValue[WhiteQueen]; - sq = lsb(u); - occ ^= Bit(sq); - def ^= Bit(sq); - for (new_att = FullLine[to][sq] & (r_slider_def | b_slider_def) & occ & (~att); T(new_att); Cut(new_att)) { + piece = SeeValue[WhiteQueen]; + sq = lsb(u); + occ ^= Bit(sq); + def ^= Bit(sq); + for (new_att = DATA->FullLine[to][sq] & (r_slider_def | b_slider_def) & occ & (~att); T(new_att); Cut(new_att)) { pos = lsb(new_att); - if (F(Between[to][pos] & occ)) { + if (F(DATA->Between[to][pos] & occ)) { Add(def,pos); - break; - } - } - } else if (u = (def & King(me))) { + break; + } + } + } else if (u = (def & King(me))) { capture += piece; - piece = SeeValue[WhiteKing]; - } else return 0; - if (capture > (SeeValue[WhiteKing] >> 1)) return 1; - if (capture - piece >= margin) return 1; - } + piece = SeeValue[WhiteKing]; + } else return 0; + if (capture > (SeeValue[WhiteKing] >> 1)) return 1; + if (capture - piece >= margin) return 1; + } } template void gen_root_moves() { - int i, *p, killer, depth = -256, move; - GEntry * Entry; - GPVEntry * PVEntry; - - killer = 0; - if (Entry = probe_hash()) { - if (T(Entry->move) && Entry->low_depth > depth) { - depth = Entry->low_depth; - killer = Entry->move; - } - } - if (PVEntry = probe_pv_hash()) { - if (PVEntry->depth > depth && T(PVEntry->move)) { - depth = PVEntry->depth; - killer = PVEntry->move; - } - } - - Current->killer[0] = killer; - if (Check(me)) Current->stage = stage_evasion; - else { - Current->stage = stage_search; - Current->ref[0] = RefM(Current->move).ref[0]; - Current->ref[1] = RefM(Current->move).ref[1]; - } - Current->gen_flags = 0; - p = RootList; - Current->current = Current->moves; - Current->moves[0] = 0; - while (move = get_move()) { - if (IsIllegal(me,move)) continue; - if (p > RootList && move == killer) continue; - if (SearchMoves) { - for (i = 0; i < SMPointer; i++) - if (SMoves[i] == move) goto keep_move; - continue; - } + int i, *p, killer, depth = -256, move; + GEntry * Entry; + GPVEntry * PVEntry; + + killer = 0; + if (Entry = probe_hash()) { + if (T(Entry->move) && Entry->low_depth > depth) { + depth = Entry->low_depth; + killer = Entry->move; + } + } + if (PVEntry = probe_pv_hash()) { + if (PVEntry->depth > depth && T(PVEntry->move)) { + depth = PVEntry->depth; + killer = PVEntry->move; + } + } + + Current->killer[0] = killer; + if (Check(me)) Current->stage = stage_evasion; + else { + Current->stage = stage_search; + Current->ref[0] = RefM(Current->move).ref[0]; + Current->ref[1] = RefM(Current->move).ref[1]; + } + Current->gen_flags = 0; + p = RootList; + Current->current = Current->moves; + Current->moves[0] = 0; + while (move = get_move()) { + if (IsIllegal(me,move)) continue; + if (p > RootList && move == killer) continue; + if (SearchMoves) { + for (i = 0; i < SMPointer; i++) + if (SMoves[i] == move) goto keep_move; + continue; + } keep_move: - *p = move; - p++; - } - *p = 0; + *p = move; + p++; + } + *p = 0; } template int * gen_captures(int * list) { - uint64 u, v; - - if (Current->ep_square) - for (v = PAtt[opp][Current->ep_square] & Pawn(me); T(v); Cut(v)) AddMove(lsb(v),Current->ep_square,FlagEP,MvvLva[IPawn(me)][IPawn(opp)]) - for (u = Pawn(me) & Line(me,6); T(u); Cut(u)) - if (F(Square(lsb(u) + Push(me)))) { - AddMove(lsb(u),lsb(u) + Push(me),FlagPQueen,MvvLvaPromotion) - if (NAtt[lsb(King(opp))] & Bit(lsb(u) + Push(me))) AddMove(lsb(u),lsb(u) + Push(me),FlagPKnight,MvvLvaPromotionKnight) - } - for (v = ShiftW(opp,Current->mask) & Pawn(me) & Line(me,6); T(v); Cut(v)) { - AddMove(lsb(v),lsb(v)+PushE(me),FlagPQueen,MvvLvaPromotionCap(Square(lsb(v)+PushE(me)))) - if (NAtt[lsb(King(opp))] & Bit(lsb(v) + PushE(me))) AddMove(lsb(v),lsb(v)+PushE(me),FlagPKnight,MvvLvaPromotionKnightCap(Square(lsb(v)+PushE(me)))) - } - for (v = ShiftE(opp,Current->mask) & Pawn(me) & Line(me,6); T(v); Cut(v)) { - AddMove(lsb(v),lsb(v)+PushW(me),FlagPQueen,MvvLvaPromotionCap(Square(lsb(v)+PushW(me)))) - if (NAtt[lsb(King(opp))] & Bit(lsb(v) + PushW(me))) AddMove(lsb(v),lsb(v)+PushW(me),FlagPKnight,MvvLvaPromotionKnightCap(Square(lsb(v)+PushW(me)))) - } - if (F(Current->att[me] & Current->mask)) goto finish; - for (v = ShiftW(opp,Current->mask) & Pawn(me) & (~Line(me,6)); T(v); Cut(v)) AddCaptureP(IPawn(me),lsb(v),lsb(v)+PushE(me),0) - for (v = ShiftE(opp,Current->mask) & Pawn(me) & (~Line(me,6)); T(v); Cut(v)) AddCaptureP(IPawn(me),lsb(v),lsb(v)+PushW(me),0) - for (v = SArea[lsb(King(me))] & Current->mask & (~Current->att[opp]); T(v); Cut(v)) AddCaptureP(IKing(me),lsb(King(me)),lsb(v),0) - for (u = Knight(me); T(u); Cut(u)) - for (v = NAtt[lsb(u)] & Current->mask; T(v); Cut(v)) AddCaptureP(IKnight(me),lsb(u),lsb(v),0) - for (u = Bishop(me); T(u); Cut(u)) - for (v = BishopAttacks(lsb(u),PieceAll) & Current->mask; T(v); Cut(v)) AddCapture(lsb(u),lsb(v),0) - for (u = Rook(me); T(u); Cut(u)) - for (v = RookAttacks(lsb(u),PieceAll) & Current->mask; T(v); Cut(v)) AddCaptureP(IRook(me),lsb(u),lsb(v),0) - for (u = Queen(me); T(u); Cut(u)) - for (v = QueenAttacks(lsb(u),PieceAll) & Current->mask; T(v); Cut(v)) AddCaptureP(IQueen(me),lsb(u),lsb(v),0) + uint64_t u, v; + + if (Current->ep_square) + for (v = DATA->PAtt[opp][Current->ep_square] & Pawn(me); T(v); Cut(v)) AddMove(lsb(v),Current->ep_square,FlagEP,DATA->MvvLva[IPawn(me)][IPawn(opp)]) + for (u = Pawn(me) & Line(me,6); T(u); Cut(u)) + if (F(Square(lsb(u) + Push(me)))) { + AddMove(lsb(u),lsb(u) + Push(me),FlagPQueen,MvvLvaPromotion) + if (DATA->NAtt[lsb(King(opp))] & Bit(lsb(u) + Push(me))) AddMove(lsb(u),lsb(u) + Push(me),FlagPKnight,MvvLvaPromotionKnight) + } + for (v = ShiftW(opp,Current->mask) & Pawn(me) & Line(me,6); T(v); Cut(v)) { + AddMove(lsb(v),lsb(v)+PushE(me),FlagPQueen,MvvLvaPromotionCap(Square(lsb(v)+PushE(me)))) + if (DATA->NAtt[lsb(King(opp))] & Bit(lsb(v) + PushE(me))) AddMove(lsb(v),lsb(v)+PushE(me),FlagPKnight,MvvLvaPromotionKnightCap(Square(lsb(v)+PushE(me)))) + } + for (v = ShiftE(opp,Current->mask) & Pawn(me) & Line(me,6); T(v); Cut(v)) { + AddMove(lsb(v),lsb(v)+PushW(me),FlagPQueen,MvvLvaPromotionCap(Square(lsb(v)+PushW(me)))) + if (DATA->NAtt[lsb(King(opp))] & Bit(lsb(v) + PushW(me))) AddMove(lsb(v),lsb(v)+PushW(me),FlagPKnight,MvvLvaPromotionKnightCap(Square(lsb(v)+PushW(me)))) + } + if (F(Current->att[me] & Current->mask)) goto finish; + for (v = ShiftW(opp,Current->mask) & Pawn(me) & (~Line(me,6)); T(v); Cut(v)) AddCaptureP(IPawn(me),lsb(v),lsb(v)+PushE(me),0) + for (v = ShiftE(opp,Current->mask) & Pawn(me) & (~Line(me,6)); T(v); Cut(v)) AddCaptureP(IPawn(me),lsb(v),lsb(v)+PushW(me),0) + for (v = DATA->SArea[lsb(King(me))] & Current->mask & (~Current->att[opp]); T(v); Cut(v)) AddCaptureP(IKing(me),lsb(King(me)),lsb(v),0) + for (u = Knight(me); T(u); Cut(u)) + for (v = DATA->NAtt[lsb(u)] & Current->mask; T(v); Cut(v)) AddCaptureP(IKnight(me),lsb(u),lsb(v),0) + for (u = Bishop(me); T(u); Cut(u)) + for (v = BishopAttacks(lsb(u),PieceAll) & Current->mask; T(v); Cut(v)) AddCapture(lsb(u),lsb(v),0) + for (u = Rook(me); T(u); Cut(u)) + for (v = RookAttacks(lsb(u),PieceAll) & Current->mask; T(v); Cut(v)) AddCaptureP(IRook(me),lsb(u),lsb(v),0) + for (u = Queen(me); T(u); Cut(u)) + for (v = QueenAttacks(lsb(u),PieceAll) & Current->mask; T(v); Cut(v)) AddCaptureP(IQueen(me),lsb(u),lsb(v),0) finish: - *list = 0; - return list; + *list = 0; + return list; } template int * gen_evasions(int * list) { - int king, att_sq, from; - uint64 att, esc, b, u; - - king = lsb(King(me)); - att = (NAtt[king] & Knight(opp)) | (PAtt[me][king] & Pawn(opp)); - for (u = (BMask[king] & BSlider(opp)) | (RMask[king] & RSlider(opp)); T(u); u ^= b) { - b = Bit(lsb(u)); - if (F(Between[king][lsb(u)] & PieceAll)) att |= b; - } - att_sq = lsb(att); - esc = SArea[king] & (~(Piece(me) | Current->att[opp])) & Current->mask; - if (Square(att_sq) >= WhiteLight) esc &= ~FullLine[king][att_sq]; - Cut(att); - if (att) { - att_sq = lsb(att); - if (Square(att_sq) >= WhiteLight) esc &= ~FullLine[king][att_sq]; - for (; T(esc); Cut(esc)) AddCaptureP(IKing(me),king,lsb(esc),0) - *list = 0; - return list; - } - if (Bit(att_sq) & Current->mask) { - if (T(Current->ep_square) && Current->ep_square == att_sq + Push(me)) - for (u = PAtt[opp][att_sq + Push(me)] & Pawn(me); T(u); Cut(u)) AddMove(lsb(u),att_sq + Push(me),FlagEP,MvvLva[IPawn(me)][IPawn(opp)]) - } - for (u = PAtt[opp][att_sq] & Pawn(me); T(u); Cut(u)) { + int king, att_sq, from; + uint64_t att, esc, b, u; + + king = lsb(King(me)); + att = (DATA->NAtt[king] & Knight(opp)) | (DATA->PAtt[me][king] & Pawn(opp)); + for (u = (DATA->BMask[king] & BSlider(opp)) | (DATA->RMask[king] & RSlider(opp)); T(u); u ^= b) { + b = Bit(lsb(u)); + if (F(DATA->Between[king][lsb(u)] & PieceAll)) att |= b; + } + att_sq = lsb(att); + esc = DATA->SArea[king] & (~(Piece(me) | Current->att[opp])) & Current->mask; + if (Square(att_sq) >= WhiteLight) esc &= ~DATA->FullLine[king][att_sq]; + Cut(att); + if (att) { + att_sq = lsb(att); + if (Square(att_sq) >= WhiteLight) esc &= ~DATA->FullLine[king][att_sq]; + for (; T(esc); Cut(esc)) AddCaptureP(IKing(me),king,lsb(esc),0) + *list = 0; + return list; + } + if (Bit(att_sq) & Current->mask) { + if (T(Current->ep_square) && Current->ep_square == att_sq + Push(me)) + for (u = DATA->PAtt[opp][att_sq + Push(me)] & Pawn(me); T(u); Cut(u)) AddMove(lsb(u),att_sq + Push(me),FlagEP,DATA->MvvLva[IPawn(me)][IPawn(opp)]) + } + for (u = DATA->PAtt[opp][att_sq] & Pawn(me); T(u); Cut(u)) { from = lsb(u); - if (Bit(att_sq) & Line(me,7)) AddMove(from,att_sq,FlagPQueen,MvvLvaPromotionCap(Square(att_sq))) - else if (Bit(att_sq) & Current->mask) AddCaptureP(IPawn(me),from,att_sq,0) - } - for ( ; T(esc); Cut(esc)) AddCaptureP(IKing(me),king,lsb(esc),0) - att = Between[king][att_sq]; - for (u = Shift(opp,att) & Pawn(me); T(u); Cut(u)) { + if (Bit(att_sq) & Line(me,7)) AddMove(from,att_sq,FlagPQueen,MvvLvaPromotionCap(Square(att_sq))) + else if (Bit(att_sq) & Current->mask) AddCaptureP(IPawn(me),from,att_sq,0) + } + for ( ; T(esc); Cut(esc)) AddCaptureP(IKing(me),king,lsb(esc),0) + att = DATA->Between[king][att_sq]; + for (u = Shift(opp,att) & Pawn(me); T(u); Cut(u)) { from = lsb(u); - if (Bit(from) & Line(me,6)) AddMove(from,from + Push(me),FlagPQueen,MvvLvaPromotion) - else if (F(~Current->mask)) AddMove(from,from + Push(me),0,0) - } - if (F(~Current->mask)) { - for (u = Shift(opp,Shift(opp,att)) & Line(me, 1) & Pawn(me); T(u); Cut(u)) + if (Bit(from) & Line(me,6)) AddMove(from,from + Push(me),FlagPQueen,MvvLvaPromotion) + else if (F(~Current->mask)) AddMove(from,from + Push(me),0,0) + } + if (F(~Current->mask)) { + for (u = Shift(opp,Shift(opp,att)) & Line(me, 1) & Pawn(me); T(u); Cut(u)) if (F(Square(lsb(u)+Push(me)))) AddMove(lsb(u),lsb(u) + 2 * Push(me),0,0) } - att |= Bit(att_sq); - for (u = Knight(me); T(u); Cut(u)) - for (esc = NAtt[lsb(u)] & att; T(esc); esc ^= b) { - b = Bit(lsb(esc)); - if (b & Current->mask) AddCaptureP(IKnight(me),lsb(u),lsb(esc),0) - } - for (u = Bishop(me); T(u); Cut(u)) + att |= Bit(att_sq); + for (u = Knight(me); T(u); Cut(u)) + for (esc = DATA->NAtt[lsb(u)] & att; T(esc); esc ^= b) { + b = Bit(lsb(esc)); + if (b & Current->mask) AddCaptureP(IKnight(me),lsb(u),lsb(esc),0) + } + for (u = Bishop(me); T(u); Cut(u)) for (esc = BishopAttacks(lsb(u),PieceAll) & att; T(esc); esc ^= b) { - b = Bit(lsb(esc)); - if (b & Current->mask) AddCapture(lsb(u),lsb(esc),0) - } - for (u = Rook(me); T(u); Cut(u)) + b = Bit(lsb(esc)); + if (b & Current->mask) AddCapture(lsb(u),lsb(esc),0) + } + for (u = Rook(me); T(u); Cut(u)) for (esc = RookAttacks(lsb(u),PieceAll) & att; T(esc); esc ^= b) { - b = Bit(lsb(esc)); - if (b & Current->mask) AddCaptureP(IRook(me),lsb(u),lsb(esc),0) - } - for (u = Queen(me); T(u); Cut(u)) + b = Bit(lsb(esc)); + if (b & Current->mask) AddCaptureP(IRook(me),lsb(u),lsb(esc),0) + } + for (u = Queen(me); T(u); Cut(u)) for (esc = QueenAttacks(lsb(u),PieceAll) & att; T(esc); esc ^= b) { - b = Bit(lsb(esc)); - if (b & Current->mask) AddCaptureP(IQueen(me),lsb(u),lsb(esc),0) - } - *list = 0; - return list; + b = Bit(lsb(esc)); + if (b & Current->mask) AddCaptureP(IQueen(me),lsb(u),lsb(esc),0) + } + *list = 0; + return list; } void mark_evasions(int * list) { - for (; T(*list); list++) { - register int move = (*list) & 0xFFFF; - if (F(Square(To(move))) && F(move & 0xE000)) { - if (move == Current->ref[0]) *list |= RefOneScore; - else if (move == Current->ref[1]) *list |= RefTwoScore; - else if (move == Current->killer[1]) *list |= KillerOneScore; - else if (move == Current->killer[2]) *list |= KillerTwoScore; - else *list |= HistoryP(Square(From(move)),From(move),To(move)); - } - } + for (; T(*list); list++) { + register int move = (*list) & 0xFFFF; + if (F(Square(To(move))) && F(move & 0xE000)) { + if (move == Current->ref[0]) *list |= RefOneScore; + else if (move == Current->ref[1]) *list |= RefTwoScore; + else if (move == Current->killer[1]) *list |= KillerOneScore; + else if (move == Current->killer[2]) *list |= KillerTwoScore; + else *list |= HistoryP(Square(From(move)),From(move),To(move)); + } + } } template int * gen_quiet_moves(int * list) { - int to; - uint64 u, v, free, occ; + int to; + uint64_t u, v, free, occ; occ = PieceAll; - free = ~occ; - if (me == White) { - if (T(Current->castle_flags & CanCastle_OO) && F(occ & 0x60) && F(Current->att[Black] & 0x70)) AddHistoryP(IKing(White),4,6,FlagCastling) - if (T(Current->castle_flags & CanCastle_OOO) && F(occ & 0xE) && F(Current->att[Black] & 0x1C)) AddHistoryP(IKing(White),4,2,FlagCastling) - } else { - if (T(Current->castle_flags & CanCastle_oo) && F(occ & 0x6000000000000000) && F(Current->att[White] & 0x7000000000000000)) AddHistoryP(IKing(Black),60,62,FlagCastling) - if (T(Current->castle_flags & CanCastle_ooo) && F(occ & 0x0E00000000000000) && F(Current->att[White] & 0x1C00000000000000)) AddHistoryP(IKing(Black),60,58,FlagCastling) - } - for (v = Shift(me,Pawn(me)) & free & (~Line(me,7)); T(v); Cut(v)) { + free = ~occ; + if (me == White) { + if (T(Current->castle_flags & CanCastle_OO) && F(occ & 0x60) && F(Current->att[Black] & 0x70)) AddHistoryP(IKing(White),4,6,FlagCastling) + if (T(Current->castle_flags & CanCastle_OOO) && F(occ & 0xE) && F(Current->att[Black] & 0x1C)) AddHistoryP(IKing(White),4,2,FlagCastling) + } else { + if (T(Current->castle_flags & CanCastle_oo) && F(occ & 0x6000000000000000) && F(Current->att[White] & 0x7000000000000000)) AddHistoryP(IKing(Black),60,62,FlagCastling) + if (T(Current->castle_flags & CanCastle_ooo) && F(occ & 0x0E00000000000000) && F(Current->att[White] & 0x1C00000000000000)) AddHistoryP(IKing(Black),60,58,FlagCastling) + } + for (v = Shift(me,Pawn(me)) & free & (~Line(me,7)); T(v); Cut(v)) { to = lsb(v); - if (T(Bit(to) & Line(me,2)) && F(Square(to + Push(me)))) AddHistoryP(IPawn(me),to - Push(me),to + Push(me),0) - AddHistoryP(IPawn(me),to - Push(me),to,0) - } - for (u = Knight(me); T(u); Cut(u)) - for (v = free & NAtt[lsb(u)]; T(v); Cut(v)) AddHistoryP(IKnight(me),lsb(u),lsb(v),0) - for (u = Bishop(me); T(u); Cut(u)) - for (v = free & BishopAttacks(lsb(u),occ); T(v); Cut(v)) AddHistory(lsb(u),lsb(v)) - for (u = Rook(me); T(u); Cut(u)) - for (v = free & RookAttacks(lsb(u),occ); T(v); Cut(v)) AddHistoryP(IRook(me),lsb(u),lsb(v),0) - for (u = Queen(me); T(u); Cut(u)) - for (v = free & QueenAttacks(lsb(u),occ); T(v); Cut(v)) AddHistoryP(IQueen(me),lsb(u),lsb(v),0) - for (v = SArea[lsb(King(me))] & free & (~Current->att[opp]); T(v); Cut(v)) AddHistoryP(IKing(me),lsb(King(me)),lsb(v),0) - *list = 0; - return list; + if (T(Bit(to) & Line(me,2)) && F(Square(to + Push(me)))) AddHistoryP(IPawn(me),to - Push(me),to + Push(me),0) + AddHistoryP(IPawn(me),to - Push(me),to,0) + } + for (u = Knight(me); T(u); Cut(u)) + for (v = free & DATA->NAtt[lsb(u)]; T(v); Cut(v)) AddHistoryP(IKnight(me),lsb(u),lsb(v),0) + for (u = Bishop(me); T(u); Cut(u)) + for (v = free & BishopAttacks(lsb(u),occ); T(v); Cut(v)) AddHistory(lsb(u),lsb(v)) + for (u = Rook(me); T(u); Cut(u)) + for (v = free & RookAttacks(lsb(u),occ); T(v); Cut(v)) AddHistoryP(IRook(me),lsb(u),lsb(v),0) + for (u = Queen(me); T(u); Cut(u)) + for (v = free & QueenAttacks(lsb(u),occ); T(v); Cut(v)) AddHistoryP(IQueen(me),lsb(u),lsb(v),0) + for (v = DATA->SArea[lsb(King(me))] & free & (~Current->att[opp]); T(v); Cut(v)) AddHistoryP(IKing(me),lsb(King(me)),lsb(v),0) + *list = 0; + return list; } template int * gen_checks(int * list) { - int king, from; - uint64 u, v, target, b_target, r_target, clear, xray; + int king, from; + uint64_t u, v, target, b_target, r_target, clear, xray; - clear = ~(Piece(me) | Current->mask); + clear = ~(Piece(me) | Current->mask); king = lsb(King(opp)); - for (u = Current->xray[me] & Piece(me); T(u); Cut(u)) { - from = lsb(u); - target = clear & (~FullLine[king][from]); - if (Square(from) == IPawn(me)) { - if (F(Bit(from + Push(me)) & Line(me,7))) { - if (T(Bit(from + Push(me)) & target) && F(Square(from + Push(me)))) AddMove(from,from + Push(me),0,MvvLvaXray) - for (v = PAtt[me][from] & target & Piece(opp); T(v); Cut(v)) AddMove(from,lsb(v),0,MvvLvaXrayCap(Square(lsb(v)))) - } - } else { - if (Square(from) < WhiteLight) v = NAtt[from] & target; - else if (Square(from) < WhiteRook) v = BishopAttacks(from,PieceAll) & target; - else if (Square(from) < WhiteQueen) v = RookAttacks(from,PieceAll) & target; - else if (Square(from) < WhiteKing) v = QueenAttacks(from,PieceAll) & target; - else v = SArea[from] & target & (~Current->att[opp]); - for ( ; T(v); Cut(v)) AddMove(from,lsb(v),0,MvvLvaXrayCap(Square(lsb(v)))) - } - } - xray = ~(Current->xray[me] & Board->bb[me]); - for (u = Knight(me) & NArea[king] & xray; T(u); Cut(u)) - for (v = NAtt[king] & NAtt[lsb(u)] & clear; T(v); Cut(v)) AddCaptureP(IKnight(me),lsb(u),lsb(v),0) - for (u = DArea[king] & Pawn(me) & (~Line(me,6)) & xray; T(u); Cut(u)) { - from = lsb(u); - for (v = PAtt[me][from] & PAtt[opp][king] & clear & Piece(opp); T(v); Cut(v)) AddCaptureP(IPawn(me),from,lsb(v),0) - if (F(Square(from + Push(me))) && T(Bit(from + Push(me)) & PAtt[opp][king])) AddMove(from,from + Push(me),0,0) - } - b_target = BishopAttacks(king,PieceAll) & clear; - r_target = RookAttacks(king,PieceAll) & clear; - for (u = (Odd(king ^ Rank(king)) ? Board->bb[WhiteLight | me] : Board->bb[WhiteDark | me]) & xray; T(u); Cut(u)) - for (v = BishopAttacks(lsb(u),PieceAll) & b_target; T(v); Cut(v)) AddCapture(lsb(u),lsb(v),0) - for (u = Rook(me) & xray; T(u); Cut(u)) - for (v = RookAttacks(lsb(u),PieceAll) & r_target; T(v); Cut(v)) AddCaptureP(IRook(me),lsb(u),lsb(v),0) - for (u = Queen(me) & xray; T(u); Cut(u)) - for (v = QueenAttacks(lsb(u),PieceAll) & (b_target | r_target); T(v); Cut(v)) AddCaptureP(IQueen(me),lsb(u),lsb(v),0) - *list = 0; - return list; + for (u = Current->xray[me] & Piece(me); T(u); Cut(u)) { + from = lsb(u); + target = clear & (~DATA->FullLine[king][from]); + if (Square(from) == IPawn(me)) { + if (F(Bit(from + Push(me)) & Line(me,7))) { + if (T(Bit(from + Push(me)) & target) && F(Square(from + Push(me)))) AddMove(from,from + Push(me),0,MvvLvaXray) + for (v = DATA->PAtt[me][from] & target & Piece(opp); T(v); Cut(v)) AddMove(from,lsb(v),0,MvvLvaXrayCap(Square(lsb(v)))) + } + } else { + if (Square(from) < WhiteLight) v = DATA->NAtt[from] & target; + else if (Square(from) < WhiteRook) v = BishopAttacks(from,PieceAll) & target; + else if (Square(from) < WhiteQueen) v = RookAttacks(from,PieceAll) & target; + else if (Square(from) < WhiteKing) v = QueenAttacks(from,PieceAll) & target; + else v = DATA->SArea[from] & target & (~Current->att[opp]); + for ( ; T(v); Cut(v)) AddMove(from,lsb(v),0,MvvLvaXrayCap(Square(lsb(v)))) + } + } + xray = ~(Current->xray[me] & Board->bb[me]); + for (u = Knight(me) & DATA->NArea[king] & xray; T(u); Cut(u)) + for (v = DATA->NAtt[king] & DATA->NAtt[lsb(u)] & clear; T(v); Cut(v)) AddCaptureP(IKnight(me),lsb(u),lsb(v),0) + for (u = DATA->DArea[king] & Pawn(me) & (~Line(me,6)) & xray; T(u); Cut(u)) { + from = lsb(u); + for (v = DATA->PAtt[me][from] & DATA->PAtt[opp][king] & clear & Piece(opp); T(v); Cut(v)) AddCaptureP(IPawn(me),from,lsb(v),0) + if (F(Square(from + Push(me))) && T(Bit(from + Push(me)) & DATA->PAtt[opp][king])) AddMove(from,from + Push(me),0,0) + } + b_target = BishopAttacks(king,PieceAll) & clear; + r_target = RookAttacks(king,PieceAll) & clear; + for (u = (Odd(king ^ Rank(king)) ? Board->bb[WhiteLight | me] : Board->bb[WhiteDark | me]) & xray; T(u); Cut(u)) + for (v = BishopAttacks(lsb(u),PieceAll) & b_target; T(v); Cut(v)) AddCapture(lsb(u),lsb(v),0) + for (u = Rook(me) & xray; T(u); Cut(u)) + for (v = RookAttacks(lsb(u),PieceAll) & r_target; T(v); Cut(v)) AddCaptureP(IRook(me),lsb(u),lsb(v),0) + for (u = Queen(me) & xray; T(u); Cut(u)) + for (v = QueenAttacks(lsb(u),PieceAll) & (b_target | r_target); T(v); Cut(v)) AddCaptureP(IQueen(me),lsb(u),lsb(v),0) + *list = 0; + return list; } template int * gen_delta_moves(int * list) { - int to; - uint64 u, v, free, occ; + int to; + uint64_t u, v, free, occ; occ = PieceAll; - free = ~occ; - if (me == White) { - if (T(Current->castle_flags & CanCastle_OO) && F(occ & 0x60) && F(Current->att[Black] & 0x70)) AddCDeltaP(IKing(White),4,6,FlagCastling) - if (T(Current->castle_flags & CanCastle_OOO) && F(occ & 0xE) && F(Current->att[Black] & 0x1C)) AddCDeltaP(IKing(White),4,2,FlagCastling) - } else { - if (T(Current->castle_flags & CanCastle_oo) && F(occ & 0x6000000000000000) && F(Current->att[White] & 0x7000000000000000)) AddCDeltaP(IKing(Black),60,62,FlagCastling) - if (T(Current->castle_flags & CanCastle_ooo) && F(occ & 0x0E00000000000000) && F(Current->att[White] & 0x1C00000000000000)) AddCDeltaP(IKing(Black),60,58,FlagCastling) - } - for (v = Shift(me,Pawn(me)) & free & (~Line(me,7)); T(v); Cut(v)) { + free = ~occ; + if (me == White) { + if (T(Current->castle_flags & CanCastle_OO) && F(occ & 0x60) && F(Current->att[Black] & 0x70)) AddCDeltaP(IKing(White),4,6,FlagCastling) + if (T(Current->castle_flags & CanCastle_OOO) && F(occ & 0xE) && F(Current->att[Black] & 0x1C)) AddCDeltaP(IKing(White),4,2,FlagCastling) + } else { + if (T(Current->castle_flags & CanCastle_oo) && F(occ & 0x6000000000000000) && F(Current->att[White] & 0x7000000000000000)) AddCDeltaP(IKing(Black),60,62,FlagCastling) + if (T(Current->castle_flags & CanCastle_ooo) && F(occ & 0x0E00000000000000) && F(Current->att[White] & 0x1C00000000000000)) AddCDeltaP(IKing(Black),60,58,FlagCastling) + } + for (v = Shift(me,Pawn(me)) & free & (~Line(me,7)); T(v); Cut(v)) { to = lsb(v); - if (T(Bit(to) & Line(me,2)) && F(Square(to + Push(me)))) AddCDeltaP(IPawn(me),to - Push(me),to + Push(me),0) - AddCDeltaP(IPawn(me),to - Push(me),to,0) - } - for (u = Knight(me); T(u); Cut(u)) - for (v = free & NAtt[lsb(u)]; T(v); Cut(v)) AddCDeltaP(IKnight(me),lsb(u),lsb(v),0) - for (u = Bishop(me); T(u); Cut(u)) - for (v = free & BishopAttacks(lsb(u),occ); T(v); Cut(v)) AddCDelta(lsb(u),lsb(v)) - for (u = Rook(me); T(u); Cut(u)) - for (v = free & RookAttacks(lsb(u),occ); T(v); Cut(v)) AddCDeltaP(IRook(me),lsb(u),lsb(v),0) - for (u = Queen(me); T(u); Cut(u)) - for (v = free & QueenAttacks(lsb(u),occ); T(v); Cut(v)) AddCDeltaP(IQueen(me),lsb(u),lsb(v),0) - for (v = SArea[lsb(King(me))] & free & (~Current->att[opp]); T(v); Cut(v)) AddCDeltaP(IKing(me),lsb(King(me)),lsb(v),0) - *list = 0; - return list; + if (T(Bit(to) & Line(me,2)) && F(Square(to + Push(me)))) AddCDeltaP(IPawn(me),to - Push(me),to + Push(me),0) + AddCDeltaP(IPawn(me),to - Push(me),to,0) + } + for (u = Knight(me); T(u); Cut(u)) + for (v = free & DATA->NAtt[lsb(u)]; T(v); Cut(v)) AddCDeltaP(IKnight(me),lsb(u),lsb(v),0) + for (u = Bishop(me); T(u); Cut(u)) + for (v = free & BishopAttacks(lsb(u),occ); T(v); Cut(v)) AddCDelta(lsb(u),lsb(v)) + for (u = Rook(me); T(u); Cut(u)) + for (v = free & RookAttacks(lsb(u),occ); T(v); Cut(v)) AddCDeltaP(IRook(me),lsb(u),lsb(v),0) + for (u = Queen(me); T(u); Cut(u)) + for (v = free & QueenAttacks(lsb(u),occ); T(v); Cut(v)) AddCDeltaP(IQueen(me),lsb(u),lsb(v),0) + for (v = DATA->SArea[lsb(King(me))] & free & (~Current->att[opp]); T(v); Cut(v)) AddCDeltaP(IKing(me),lsb(King(me)),lsb(v),0) + *list = 0; + return list; } template int singular_extension(int ext, int prev_ext, int margin_one, int margin_two, int depth, int killer) { - int value = -MateValue; - int singular = 0; - if (ext < 1 + (prev_ext < 1)) { - if (Check(me)) value = search_evasion(margin_one, depth, killer); - else value = search(margin_one, depth, killer); - if (value < margin_one) singular = 1; - } - if (value < margin_one && ext < 2 + (prev_ext < 1) - (prev_ext >= 2)) { - if (Check(me)) value = search_evasion(margin_two, depth, killer); - else value = search(margin_two, depth, killer); - if (value < margin_two) singular = 2; - } - return singular; + int value = -MateValue; + int singular = 0; + if (ext < 1 + (prev_ext < 1)) { + if (Check(me)) value = search_evasion(margin_one, depth, killer); + else value = search(margin_one, depth, killer); + if (value < margin_one) singular = 1; + } + if (value < margin_one && ext < 2 + (prev_ext < 1) - (prev_ext >= 2)) { + if (Check(me)) value = search_evasion(margin_two, depth, killer); + else value = search(margin_two, depth, killer); + if (value < margin_two) singular = 2; + } + return singular; } -template __forceinline void capture_margin(int alpha, int &score) { - if (Current->score + 200 < alpha) { - if (Current->att[me] & Pawn(opp)) { - Current->mask ^= Pawn(opp); - score = Current->score + 200; - } - if (Current->score + 500 < alpha) { - if (Current->att[me] & Minor(opp)) { - Current->mask ^= Minor(opp); - score = Current->score + 500; - } - if (Current->score + 700 < alpha) { - if (Current->att[me] & Rook(opp)) { - Current->mask ^= Rook(opp); - score = Current->score + 700; - } - if (Current->score + 1400 < alpha && (Current->att[me] & Queen(opp))) { - Current->mask ^= Queen(opp); - score = Current->score + 1400; - } - } - } - } +template inline void capture_margin(int alpha, int &score) { + if (Current->score + 200 < alpha) { + if (Current->att[me] & Pawn(opp)) { + Current->mask ^= Pawn(opp); + score = Current->score + 200; + } + if (Current->score + 500 < alpha) { + if (Current->att[me] & Minor(opp)) { + Current->mask ^= Minor(opp); + score = Current->score + 500; + } + if (Current->score + 700 < alpha) { + if (Current->att[me] & Rook(opp)) { + Current->mask ^= Rook(opp); + score = Current->score + 700; + } + if (Current->score + 1400 < alpha && (Current->att[me] & Queen(opp))) { + Current->mask ^= Queen(opp); + score = Current->score + 1400; + } + } + } + } } template int q_search(int alpha, int beta, int depth, int flags) { - int i, value, score, move, hash_move, hash_depth, cnt; - GEntry * Entry; + int i, value, score, move, hash_move, hash_depth, cnt; + GEntry * Entry; + + if (flags & FlagHaltCheck) halt_check; + if (flags & FlagCallEvaluation) evaluate(); + if (Check(me)) return q_evasion(alpha, beta, depth, FlagHashCheck); + score = Current->score + 3; + if (score > alpha) { + alpha = score; + if (score >= beta) return score; + } - if (flags & FlagHaltCheck) halt_check; -#ifdef CPU_TIMING -#ifndef TIMING - if (nodes > check_node + 0x4000) { -#else - if (nodes > check_node + 0x100) { -#endif - check_node = nodes; -#ifdef TIMING - if (LastDepth >= 6) -#endif - check_time(1); -#ifdef TUNER - if (nodes > 64 * 1024 * 1024) longjmp(Jump, 1); -#endif - } -#endif + hash_move = hash_depth = 0; + if (flags & FlagHashCheck) { + for (i = 0, Entry = HASH + (High32(Current->key) & hash_mask); i < 4; Entry++, i++) { + if (Low32(Current->key) == Entry->key) { + if (T(Entry->low_depth)) { + if (Entry->low >= beta && !pv) return Entry->low; + if (Entry->low_depth > hash_depth && T(Entry->move)) { + hash_move = Entry->move; + hash_depth = Entry->low_depth; + } + } + if (T(Entry->high_depth) && Entry->high <= alpha && !pv) return Entry->high; + break; + } + } + } - if (flags & FlagCallEvaluation) evaluate(); - if (Check(me)) return q_evasion(alpha, beta, depth, FlagHashCheck); - score = Current->score + 3; - if (score > alpha) { - alpha = score; - if (score >= beta) return score; - } - - hash_move = hash_depth = 0; - if (flags & FlagHashCheck) { - for (i = 0, Entry = Hash + (High32(Current->key) & hash_mask); i < 4; Entry++, i++) { - if (Low32(Current->key) == Entry->key) { - if (T(Entry->low_depth)) { - if (Entry->low >= beta && !pv) return Entry->low; - if (Entry->low_depth > hash_depth && T(Entry->move)) { - hash_move = Entry->move; - hash_depth = Entry->low_depth; - } - } - if (T(Entry->high_depth) && Entry->high <= alpha && !pv) return Entry->high; - break; - } - } - } - - Current->mask = Piece(opp); - capture_margin(alpha, score); - - cnt = 0; - if (T(hash_move)) { - if (F(Bit(To(hash_move)) & Current->mask) && F(hash_move & 0xE000) && (depth < -8 || (Current->score + DeltaM(hash_move) <= alpha && F(is_check(hash_move))))) goto skip_hash_move; - if (is_legal(move = hash_move)) { - if (IsIllegal(me,move)) goto skip_hash_move; - if (SeeValue[Square(To(move))] > SeeValue[Square(From(move))]) cnt++; - do_move(move); - value = -q_search(-beta, -alpha, depth - 1, FlagNeatSearch); - undo_move(move); - if (value > score) { - score = value; - if (value > alpha) { - alpha = value; - if (value >= beta) goto cut; - } - } - if (F(Bit(To(hash_move)) & Current->mask) && F(hash_move & 0xE000) && (depth < -2 || depth <= -1 && Current->score + 50 < alpha) && alpha >= beta - 1 && !pv) return alpha; - } - } + Current->mask = Piece(opp); + capture_margin(alpha, score); + + cnt = 0; + if (T(hash_move)) { + if (F(Bit(To(hash_move)) & Current->mask) && F(hash_move & 0xE000) && (depth < -8 || (Current->score + DeltaM(hash_move) <= alpha && F(is_check(hash_move))))) goto skip_hash_move; + if (is_legal(move = hash_move)) { + if (IsIllegal(me,move)) goto skip_hash_move; + if (SeeValue[Square(To(move))] > SeeValue[Square(From(move))]) cnt++; + do_move(move); + value = -q_search(-beta, -alpha, depth - 1, FlagNeatSearch); + undo_move(move); + if (value > score) { + score = value; + if (value > alpha) { + alpha = value; + if (value >= beta) goto cut; + } + } + if (F(Bit(To(hash_move)) & Current->mask) && F(hash_move & 0xE000) && (depth < -2 || depth <= -1 && Current->score + 50 < alpha) && alpha >= beta - 1 && !pv) return alpha; + } + } skip_hash_move: - gen_captures(Current->moves); - Current->current = Current->moves; - while (move = pick_move()) { - if (move == hash_move) continue; - if (IsIllegal(me,move)) continue; - if (F(see(move,-50))) continue; - if (SeeValue[Square(To(move))] > SeeValue[Square(From(move))]) cnt++; - do_move(move); - value = -q_search(-beta, -alpha, depth - 1, FlagNeatSearch); - undo_move(move); - if (value > score) { - score = value; - if (value > alpha) { - alpha = value; - if (value >= beta) goto cut; - } - } - } - - if (depth < -2) goto finish; - if (depth <= -1 && Current->score + 50 < alpha) goto finish; - gen_checks(Current->moves); - Current->current = Current->moves; - while (move = pick_move()) { - if (move == hash_move) continue; - if (IsIllegal(me,move)) continue; - if (IsRepetition(alpha + 1,move)) continue; - if (F(see(move,-50))) continue; - do_move(move); - value = -q_evasion(-beta, -alpha, depth - 1, FlagNeatSearch); - undo_move(move); - if (value > score) { - score = value; - if (value > alpha) { - alpha = value; - if (value >= beta) goto cut; - } - } - } - - if (T(cnt) || Current->score + 30 < alpha || T(Current->threat & Piece(me)) || T((Current->xray[opp] | Current->pin[opp]) & NonPawn(opp)) - || T(Pawn(opp) & Line(me, 1) & Shift(me,~PieceAll))) goto finish; - Current->margin = alpha - Current->score + 6; - gen_delta_moves(Current->moves); - Current->current = Current->moves; - while (move = pick_move()) { - if (move == hash_move) continue; - if (IsIllegal(me,move)) continue; - if (IsRepetition(alpha + 1,move)) continue; - if (F(see(move,-50))) continue; - cnt++; - do_move(move); - value = -q_search(-beta, -alpha, depth - 1, FlagNeatSearch); - undo_move(move); - if (value > score) { - score = value; - if (value > alpha) { - alpha = value; - if (value >= beta) { - if (Current->killer[1] != move) { - Current->killer[2] = Current->killer[1]; - Current->killer[1] = move; - } - goto cut; - } - } - } - if (cnt >= 3) break; - } + gen_captures(Current->moves); + Current->current = Current->moves; + while (move = pick_move()) { + if (move == hash_move) continue; + if (IsIllegal(me,move)) continue; + if (F(see(move,-50))) continue; + if (SeeValue[Square(To(move))] > SeeValue[Square(From(move))]) cnt++; + do_move(move); + value = -q_search(-beta, -alpha, depth - 1, FlagNeatSearch); + undo_move(move); + if (value > score) { + score = value; + if (value > alpha) { + alpha = value; + if (value >= beta) goto cut; + } + } + } + + if (depth < -2) goto finish; + if (depth <= -1 && Current->score + 50 < alpha) goto finish; + gen_checks(Current->moves); + Current->current = Current->moves; + while (move = pick_move()) { + if (move == hash_move) continue; + if (IsIllegal(me,move)) continue; + if (IsRepetition(alpha + 1,move)) continue; + if (F(see(move,-50))) continue; + do_move(move); + value = -q_evasion(-beta, -alpha, depth - 1, FlagNeatSearch); + undo_move(move); + if (value > score) { + score = value; + if (value > alpha) { + alpha = value; + if (value >= beta) goto cut; + } + } + } + + if (T(cnt) || Current->score + 30 < alpha || T(Current->threat & Piece(me)) || T((Current->xray[opp] | Current->pin[opp]) & NonPawn(opp)) + || T(Pawn(opp) & Line(me, 1) & Shift(me,~PieceAll))) goto finish; + Current->margin = alpha - Current->score + 6; + gen_delta_moves(Current->moves); + Current->current = Current->moves; + while (move = pick_move()) { + if (move == hash_move) continue; + if (IsIllegal(me,move)) continue; + if (IsRepetition(alpha + 1,move)) continue; + if (F(see(move,-50))) continue; + cnt++; + do_move(move); + value = -q_search(-beta, -alpha, depth - 1, FlagNeatSearch); + undo_move(move); + if (value > score) { + score = value; + if (value > alpha) { + alpha = value; + if (value >= beta) { + if (Current->killer[1] != move) { + Current->killer[2] = Current->killer[1]; + Current->killer[1] = move; + } + goto cut; + } + } + } + if (cnt >= 3) break; + } finish: - if (depth >= -2 && (depth >= 0 || Current->score + 50 >= alpha)) hash_high(score, 1); - return score; + if (depth >= -2 && (depth >= 0 || Current->score + 50 >= alpha)) hash_high(score, 1); + return score; cut: - hash_low(move, score, 1); - return score; + hash_low(move, score, 1); + return score; } template int q_evasion(int alpha, int beta, int depth, int flags) { - int i, value, pext, score, move, cnt, hash_move, hash_depth; - int *p; - GEntry * Entry; - - score = Convert((Current - Data),int) - MateValue; - if (flags & FlagHaltCheck) halt_check; - - hash_move = hash_depth = 0; - if (flags & FlagHashCheck) { - for (i = 0, Entry = Hash + (High32(Current->key) & hash_mask); i < 4; Entry++, i++) { - if (Low32(Current->key) == Entry->key) { - if (T(Entry->low_depth)) { - if (Entry->low >= beta && !pv) return Entry->low; - if (Entry->low_depth > hash_depth && T(Entry->move)) { - hash_move = Entry->move; - hash_depth = Entry->low_depth; - } - } - if (T(Entry->high_depth) && Entry->high <= alpha && !pv) return Entry->high; - break; - } - } - } - - if (flags & FlagCallEvaluation) evaluate(); - Current->mask = Filled; - if (Current->score - 10 <= alpha && !pv) { - Current->mask = Piece(opp); - score = Current->score - 10; - capture_margin(alpha, score); - } - - alpha = Max(score, alpha); - pext = 0; - gen_evasions(Current->moves); - Current->current = Current->moves; - if (F(Current->moves[0])) return score; - if (F(Current->moves[1])) pext = 1; - else { - Current->ref[0] = RefM(Current->move).check_ref[0]; - Current->ref[1] = RefM(Current->move).check_ref[1]; - mark_evasions(Current->moves); - if (T(hash_move) && (T(Bit(To(hash_move)) & Current->mask) || T(hash_move & 0xE000))) { - for (p = Current->moves; T(*p); p++) { - if (((*p) & 0xFFFF) == hash_move) { - *p |= 0x7FFF0000; - break; - } - } - } - } - cnt = 0; - while (move = pick_move()) { - if (IsIllegal(me,move)) continue; - cnt++; - if (IsRepetition(alpha + 1,move)) { - score = Max(0, score); - continue; - } - if (F(Square(To(move))) && F(move & 0xE000)) { - if (cnt > 3 && F(is_check(move)) && !pv) continue; - if ((value = Current->score + DeltaM(move) + 10) <= alpha && !pv) { - score = Max(value, score); - continue; - } - } - do_move(move); - value = -q_search(-beta, -alpha, depth - 1 + pext, FlagNeatSearch); - undo_move(move); - if (value > score) { - score = value; - if (value > alpha) { - alpha = value; - if (value >= beta) goto cut; - } - } - } - return score; + int i, value, pext, score, move, cnt, hash_move, hash_depth; + int *p; + GEntry * Entry; + + score = Convert((Current - Data),int) - MateValue; + if (flags & FlagHaltCheck) halt_check; + + hash_move = hash_depth = 0; + if (flags & FlagHashCheck) { + for (i = 0, Entry = HASH + (High32(Current->key) & hash_mask); i < 4; Entry++, i++) { + if (Low32(Current->key) == Entry->key) { + if (T(Entry->low_depth)) { + if (Entry->low >= beta && !pv) return Entry->low; + if (Entry->low_depth > hash_depth && T(Entry->move)) { + hash_move = Entry->move; + hash_depth = Entry->low_depth; + } + } + if (T(Entry->high_depth) && Entry->high <= alpha && !pv) return Entry->high; + break; + } + } + } + + if (flags & FlagCallEvaluation) evaluate(); + Current->mask = Filled; + if (Current->score - 10 <= alpha && !pv) { + Current->mask = Piece(opp); + score = Current->score - 10; + capture_margin(alpha, score); + } + + alpha = Max(score, alpha); + pext = 0; + gen_evasions(Current->moves); + Current->current = Current->moves; + if (F(Current->moves[0])) return score; + if (F(Current->moves[1])) pext = 1; + else { + Current->ref[0] = RefM(Current->move).check_ref[0]; + Current->ref[1] = RefM(Current->move).check_ref[1]; + mark_evasions(Current->moves); + if (T(hash_move) && (T(Bit(To(hash_move)) & Current->mask) || T(hash_move & 0xE000))) { + for (p = Current->moves; T(*p); p++) { + if (((*p) & 0xFFFF) == hash_move) { + *p |= 0x7FFF0000; + break; + } + } + } + } + cnt = 0; + while (move = pick_move()) { + if (IsIllegal(me,move)) continue; + cnt++; + if (IsRepetition(alpha + 1,move)) { + score = Max(0, score); + continue; + } + if (F(Square(To(move))) && F(move & 0xE000)) { + if (cnt > 3 && F(is_check(move)) && !pv) continue; + if ((value = Current->score + DeltaM(move) + 10) <= alpha && !pv) { + score = Max(value, score); + continue; + } + } + do_move(move); + value = -q_search(-beta, -alpha, depth - 1 + pext, FlagNeatSearch); + undo_move(move); + if (value > score) { + score = value; + if (value > alpha) { + alpha = value; + if (value >= beta) goto cut; + } + } + } + return score; cut: - return score; + return score; } void send_position(GPos * Pos) { - Pos->Position->key = Current->key; - Pos->Position->pawn_key = Current->pawn_key; - Pos->Position->move = Current->move; - Pos->Position->capture = Current->capture; - Pos->Position->turn = Current->turn; - Pos->Position->castle_flags = Current->castle_flags; - Pos->Position->ply = Current->ply; - Pos->Position->ep_square = Current->ep_square; - Pos->Position->piece = Current->piece; - Pos->Position->pst = Current->pst; - Pos->Position->material = Current->material; - for (int i = 0; i < 64; i++) Pos->Position->square[i] = Board->square[i]; - Pos->date = date; - Pos->sp = sp; - for (int i = 0; i <= Current->ply; i++) Pos->stack[i] = Stack[sp - i]; - for (int i = 0; i < Min(16, 126 - (int)(Current - Data)); i++) { - Pos->killer[i][0] = (Current + i + 1)->killer[1]; - Pos->killer[i][1] = (Current + i + 1)->killer[2]; - } - for (int i = Min(16, 126 - (int)(Current - Data)); i < 16; i++) Pos->killer[i][0] = Pos->killer[i][1] = 0; + Pos->Position->key = Current->key; + Pos->Position->pawn_key = Current->pawn_key; + Pos->Position->move = Current->move; + Pos->Position->capture = Current->capture; + Pos->Position->turn = Current->turn; + Pos->Position->castle_flags = Current->castle_flags; + Pos->Position->ply = Current->ply; + Pos->Position->ep_square = Current->ep_square; + Pos->Position->piece = Current->piece; + Pos->Position->pst = Current->pst; + Pos->Position->material = Current->material; + for (int i = 0; i < 64; i++) Pos->Position->square[i] = Board->square[i]; + Pos->date = SHARED->date; + Pos->sp = sp; + for (int i = 0; i <= Current->ply; i++) Pos->stack[i] = Stack[sp - i]; + for (int i = 0; i < Min(16, 126 - (int)(Current - Data)); i++) { + Pos->killer[i][0] = (Current + i + 1)->killer[1]; + Pos->killer[i][1] = (Current + i + 1)->killer[2]; + } + for (int i = Min(16, 126 - (int)(Current - Data)); i < 16; i++) Pos->killer[i][0] = Pos->killer[i][1] = 0; } void retrieve_board(GPos * Pos) { - for (int i = 0; i < 16; i++) Board->bb[i] = 0; - for (int i = 0; i < 64; i++) { - int piece = Pos->Position->square[i]; - Board->square[i] = piece; - if (piece) { - Board->bb[piece & 1] |= Bit(i); - Board->bb[piece] |= Bit(i); - } - } + for (int i = 0; i < 16; i++) Board->bb[i] = 0; + for (int i = 0; i < 64; i++) { + int piece = Pos->Position->square[i]; + Board->square[i] = piece; + if (piece) { + Board->bb[piece & 1] |= Bit(i); + Board->bb[piece] |= Bit(i); + } + } } void retrieve_position(GPos * Pos, int copy_stack) { - Current->key = Pos->Position->key; - Current->pawn_key = Pos->Position->pawn_key; - Current->move = Pos->Position->move; - Current->capture = Pos->Position->capture; - Current->turn = Pos->Position->turn; - Current->castle_flags = Pos->Position->castle_flags; - Current->ply = Pos->Position->ply; - Current->ep_square = Pos->Position->ep_square; - Current->piece = Pos->Position->piece; - Current->pst = Pos->Position->pst; - Current->material = Pos->Position->material; - retrieve_board(Pos); - date = Pos->date; - if (copy_stack) { - sp = Current->ply; - for (int i = 0; i <= sp; i++) Stack[sp - i] = Pos->stack[i]; - } else sp = Pos->sp; - for (int i = 0; i < 16; i++) { - (Current + i + 1)->killer[1] = Pos->killer[i][0]; - (Current + i + 1)->killer[2] = Pos->killer[i][1]; - } -} - -void halt_all(GSP * Sp, int locked) { - GMove * M; - if (!locked) LOCK(Sp->lock); - if (Sp->active) { - for (int i = 0; i < Sp->move_number; i++) { - M = &Sp->move[i]; - if ((M->flags & FlagClaimed) && !(M->flags & FlagFinished) && M->id != Id) SET_BIT_64(Smpi->stop, M->id); - } - Sp->active = Sp->claimed = 0; - ZERO_BIT_64(Smpi->active_sp, (int)(Sp - Smpi->Sp)); - } - if (!locked) UNLOCK(Sp->lock); + Current->key = Pos->Position->key; + Current->pawn_key = Pos->Position->pawn_key; + Current->move = Pos->Position->move; + Current->capture = Pos->Position->capture; + Current->turn = Pos->Position->turn; + Current->castle_flags = Pos->Position->castle_flags; + Current->ply = Pos->Position->ply; + Current->ep_square = Pos->Position->ep_square; + Current->piece = Pos->Position->piece; + Current->pst = Pos->Position->pst; + Current->material = Pos->Position->material; + retrieve_board(Pos); + SHARED->date = Pos->date; + if (copy_stack) { + sp = Current->ply; + for (int i = 0; i <= sp; i++) Stack[sp - i] = Pos->stack[i]; + } else sp = Pos->sp; + for (int i = 0; i < 16; i++) { + (Current + i + 1)->killer[1] = Pos->killer[i][0]; + (Current + i + 1)->killer[2] = Pos->killer[i][1]; + } } -void halt_all(int from, int to) { - for (uint64 u = Smpi->active_sp; u; Cut(u)) { - GSP * Sp = &Smpi->Sp[lsb(u)]; - LOCK(Sp->lock); - if (Sp->height >= from && Sp->height <= to) halt_all(Sp, 1); - UNLOCK(Sp->lock); - } -} +template int search(int beta, int depth, int flags) { + int i, value, cnt, flag, moves_to_play, check, score, move, ext, margin, hash_move, singular, played, + high_depth, high_value, hash_value, new_depth, move_back, hash_depth, *p; + int height = (int)(Current - Data); -void init_sp(GSP * Sp, int alpha, int beta, int depth, int pv, int singular, int height) { - Sp->claimed = 1; - Sp->active = Sp->finished = 0; - Sp->best_move = 0; - Sp->alpha = alpha; - Sp->beta = beta; - Sp->depth = depth; - Sp->split = 0; - Sp->singular = singular; - Sp->height = height; - Sp->move_number = 0; - Sp->pv = pv; -} + check_for_stop(); -template int smp_search(GSP * Sp) { - int i, value, move, alpha, iter = 0; - if (!Sp->move_number) return Sp->alpha; - send_position(Sp->Pos); - if (setjmp(Sp->jump)) { - LOCK(Sp->lock); - halt_all(Sp, 1); - UNLOCK(Sp->lock); - halt_all(Sp->height + 1, 127); - Current = Data + Sp->height; - sp = Sp->Pos->sp; - retrieve_board(Sp->Pos); - return Sp->beta; - } - LOCK(Sp->lock); - SET_BIT_64(Smpi->active_sp, (int)(Sp - Smpi->Sp)); - Sp->active = 1; - Sp->claimed = Sp->finished = 0; -loop: - for (i = 0; i < Sp->move_number; i++) { - GMove * M = &Sp->move[i]; - if (!iter) Sp->current = i; - if (M->flags & FlagFinished) continue; - if (!iter) { - if (M->flags & FlagClaimed) continue; - M->flags |= FlagClaimed; - M->id = Id; - } else if (M->flags & FlagClaimed) { - SET_BIT_64(Smpi->stop, M->id); - M->id = Id; - } - move = M->move; - alpha = Sp->alpha; - UNLOCK(Sp->lock); - do_move(move); - value = -search(-alpha, M->reduced_depth, FlagNeatSearch | ExtFlag(M->ext)); - if (value > alpha && (Sp->pv || M->reduced_depth < M->research_depth)) { - if (Sp->pv) value = -pv_search(-Sp->beta, -Sp->alpha, M->research_depth, FlagNeatSearch | ExtFlag(M->ext)); - else value = -search(-alpha, M->research_depth, FlagNeatSearch | FlagDisableNull | ExtFlag(M->ext)); - } - undo_move(move); - LOCK(Sp->lock); - if (Sp->finished) goto cut; - M->flags |= FlagFinished; - if (value > Sp->alpha) { - Sp->best_move = move; - Sp->alpha = Min(value, Sp->beta); - if (value >= Sp->beta) goto cut; - } - } - if (!iter) { - iter++; - goto loop; - } - halt_all(Sp, 1); - UNLOCK(Sp->lock); - return Sp->alpha; -cut: - halt_all(Sp, 1); - UNLOCK(Sp->lock); - return Sp->beta; -} + if (depth <= 1) return q_search(beta - 1, beta, 1, flags); + if (flags & FlagHaltCheck) { + if (height - MateValue >= beta) return beta; + if (MateValue - height < beta) return beta - 1; + halt_check; + } -template int search(int beta, int depth, int flags) { - int i, value, cnt, flag, moves_to_play, check, score, move, ext, margin, hash_move, do_split, sp_init, singular, played, - high_depth, high_value, hash_value, new_depth, move_back, hash_depth, *p; - int height = (int)(Current - Data); - GSP * Sp; + if (exclusion) { + cnt = high_depth = singular = played = 0; + flag = 1; + score = beta - 1; + high_value = MateValue; + hash_value = -MateValue; + hash_depth = -1; + hash_move = flags & 0xFFFF; + goto skip_hash_move; + } -#ifndef TUNER - if (nodes > check_node_smp + 0x10) { -#ifndef W32_BUILD - builtin_sync_fetch_and_add(&Smpi->nodes, (long long)(nodes)-(long long)(check_node_smp)); -#else - Smpi->nodes += (long long)(nodes)-(long long)(check_node_smp); -#endif - check_node_smp = nodes; - check_state(); - if (nodes > check_node + 0x4000 && parent) { - builtin_sync_fetch_and_add(&Smpi->tb_hits, tb_hits); - tb_hits = 0; - check_node = nodes; - check_time(1); - if (Searching) SET_BIT_64(Smpi->searching, Id); // BUG, don't know why this is necessary - } - } -#endif + if (flags & FlagCallEvaluation) evaluate(); + if (Check(me)) return search_evasion(beta, depth, flags & (~(FlagHaltCheck | FlagCallEvaluation))); + + if ((value = Current->score - 90 - (depth << 3) - (Max(depth - 5, 0) << 5)) >= beta && F(Pawn(opp) & Line(me, 1) & Shift(me,~PieceAll)) && T(NonPawnKing(me)) && F(flags & (FlagReturnBestMove | FlagDisableNull)) && depth <= 13) return value; + if ((value = Current->score + 50) < beta && depth <= 3) return MaxF(value, q_search(beta - 1, beta, 1, FlagHashCheck | (flags & 0xFFFF))); + + high_depth = 0; + high_value = MateValue; + hash_value = -MateValue; + hash_depth = -1; + Current->best = hash_move = flags & 0xFFFF; + if (GEntry * Entry = probe_hash()) { + if (Entry->high_depth > high_depth) { + high_depth = Entry->high_depth; + high_value = Entry->high; + } + if (Entry->high < beta && Entry->high_depth >= depth) return Entry->high; + if (T(Entry->move) && Entry->low_depth > hash_depth) { + Current->best = hash_move = Entry->move; + hash_depth = Entry->low_depth; + if (Entry->low_depth) hash_value = Entry->low; + } + if (Entry->low >= beta && Entry->low_depth >= depth) { + if (Entry->move) { + Current->best = Entry->move; + if (F(Square(To(Entry->move))) && F(Entry->move & 0xE000)) { + if (Current->killer[1] != Entry->move && F(flags & FlagNoKillerUpdate)) { + Current->killer[2] = Current->killer[1]; + Current->killer[1] = Entry->move; + } + UpdateRef(Entry->move); + } + return Entry->low; + } + if (F(flags & FlagReturnBestMove)) return Entry->low; + } + } - if (depth <= 1) return q_search(beta - 1, beta, 1, flags); - if (flags & FlagHaltCheck) { - if (height - MateValue >= beta) return beta; - if (MateValue - height < beta) return beta - 1; - halt_check; - } - - if (exclusion) { - cnt = high_depth = do_split = sp_init = singular = played = 0; - flag = 1; - score = beta - 1; - high_value = MateValue; - hash_value = -MateValue; - hash_depth = -1; - hash_move = flags & 0xFFFF; - goto skip_hash_move; - } - - if (flags & FlagCallEvaluation) evaluate(); - if (Check(me)) return search_evasion(beta, depth, flags & (~(FlagHaltCheck | FlagCallEvaluation))); - - if ((value = Current->score - 90 - (depth << 3) - (Max(depth - 5, 0) << 5)) >= beta && F(Pawn(opp) & Line(me, 1) & Shift(me,~PieceAll)) && T(NonPawnKing(me)) && F(flags & (FlagReturnBestMove | FlagDisableNull)) && depth <= 13) return value; - if ((value = Current->score + 50) < beta && depth <= 3) return MaxF(value, q_search(beta - 1, beta, 1, FlagHashCheck | (flags & 0xFFFF))); - - high_depth = 0; - high_value = MateValue; - hash_value = -MateValue; - hash_depth = -1; - Current->best = hash_move = flags & 0xFFFF; - if (GEntry * Entry = probe_hash()) { - if (Entry->high_depth > high_depth) { - high_depth = Entry->high_depth; - high_value = Entry->high; - } - if (Entry->high < beta && Entry->high_depth >= depth) return Entry->high; - if (T(Entry->move) && Entry->low_depth > hash_depth) { - Current->best = hash_move = Entry->move; - hash_depth = Entry->low_depth; - if (Entry->low_depth) hash_value = Entry->low; - } - if (Entry->low >= beta && Entry->low_depth >= depth) { - if (Entry->move) { - Current->best = Entry->move; - if (F(Square(To(Entry->move))) && F(Entry->move & 0xE000)) { - if (Current->killer[1] != Entry->move && F(flags & FlagNoKillerUpdate)) { - Current->killer[2] = Current->killer[1]; - Current->killer[1] = Entry->move; - } - UpdateRef(Entry->move); - } - return Entry->low; - } - if (F(flags & FlagReturnBestMove)) return Entry->low; - } - } - -#if TB - if (hash_depth < 0 && TB_LARGEST > 0 && popcnt(PieceAll) <= TB_LARGEST) { - unsigned res = tb_probe_wdl(Piece(White), Piece(Black), - King(White) | King(Black), - Queen(White) | Queen(Black), - Rook(White) | Rook(Black), - Bishop(White) | Bishop(Black), - Knight(White) | Knight(Black), - Pawn(White) | Pawn(Black), - Current->ply, - Current->castle_flags, - Current->ep_square, - (me == White)); - if (res != TB_RESULT_FAILED) { - tb_hits++; - hash_high(TbValues[res], TbDepth); - hash_low(0, TbValues[res], TbDepth); - return TbValues[res]; - } - } -#endif + if (hash_depth < 0 && depth >= SETTINGS->syzygyProbeDepth && + TB_LARGEST > 0 && popcount(PieceAll) <= TB_LARGEST) + { + unsigned res = tb_probe_wdl(Piece(White), Piece(Black), + King(White) | King(Black), + Queen(White) | Queen(Black), + Rook(White) | Rook(Black), + Bishop(White) | Bishop(Black), + Knight(White) | Knight(Black), + Pawn(White) | Pawn(Black), + Current->ply, + Current->castle_flags, + Current->ep_square, + (me == White)); + if (res != TB_RESULT_FAILED) + { + INFO->tbHits++; + hash_high(TbValues[res], TbDepth); + hash_low(0, TbValues[res], TbDepth); + return TbValues[res]; + } + } if (depth >= 20) if (GPVEntry * PVEntry = probe_pv_hash()) { - hash_low(PVEntry->move,PVEntry->value,PVEntry->depth); - hash_high(PVEntry->value,PVEntry->depth); - if (PVEntry->depth >= depth) { - if (PVEntry->move) Current->best = PVEntry->move; - if (F(flags & FlagReturnBestMove) && ((Current->ply <= 50 && PVEntry->ply <= 50) || (Current->ply >= 50 && PVEntry->ply >= 50))) return PVEntry->value; - } - if (T(PVEntry->move) && PVEntry->depth > hash_depth) { - Current->best = hash_move = PVEntry->move; - hash_depth = PVEntry->depth; - hash_value = PVEntry->value; - } - } - if (depth < 10) score = height - MateValue; - else score = beta - 1; - if (depth >= 12 && (F(hash_move) || hash_value < beta || hash_depth < depth - 12) && (high_value >= beta || high_depth < depth - 12) && F(flags & FlagDisableNull)) { - new_depth = depth - 8; - value = search(beta, new_depth, FlagHashCheck | FlagNoKillerUpdate | FlagDisableNull | FlagReturnBestMove | hash_move); - if (value >= beta) { - if (Current->best) hash_move = Current->best; - hash_depth = new_depth; - hash_value = beta; - } - } - if (depth >= 4 && Current->score + 3 >= beta && F(flags & (FlagDisableNull | FlagReturnBestMove)) - && (high_value >= beta || high_depth < depth - 10) && (depth < 12 || (hash_value >= beta && hash_depth >= depth - 12)) && beta > -EvalValue && T(NonPawnKing(me))) { - new_depth = depth - 8; - do_null(); - value = -search(1 - beta, new_depth, FlagHashCheck); - undo_null(); - if (value >= beta) { - if (depth < 12) hash_low(0, value, depth); - return value; - } - } - - cnt = flag = singular = played = 0; - if (T(hash_move) && is_legal(move = hash_move)) { - if (IsIllegal(me,move)) goto skip_hash_move; - cnt++; - check = is_check(move); - if (check) ext = 1 + (depth < 16); - else ext = extension<0>(move, depth); - if (depth >= 16 && hash_value >= beta && hash_depth >= (new_depth = depth - Min(12, depth/2))) { - int margin_one = beta - ExclSingle(depth); - int margin_two = beta - ExclDouble(depth); - int prev_ext = Ext(flags); - singular = singular_extension(ext,prev_ext,margin_one,margin_two,new_depth,hash_move); - if (singular) ext = Max(ext, singular + (prev_ext < 1) - (singular >= 2 && prev_ext >= 2)); - } - if (depth < 16 && To(move) == To(Current->move) && T(Square(To(move)))) ext = Max(ext, 2); - new_depth = depth - 2 + ext; - do_move(move); - value = -search(1 - beta, new_depth, FlagNeatSearch | ((hash_value >= beta && hash_depth >= depth - 12) ? FlagDisableNull : 0) | ExtFlag(ext)); - undo_move(move); - played++; - if (value > score) { - score = value; - if (value >= beta) goto cut; - } - } + hash_low(PVEntry->move,PVEntry->value,PVEntry->depth); + hash_high(PVEntry->value,PVEntry->depth); + if (PVEntry->depth >= depth) { + if (PVEntry->move) Current->best = PVEntry->move; + if (F(flags & FlagReturnBestMove) && ((Current->ply <= 50 && PVEntry->ply <= 50) || (Current->ply >= 50 && PVEntry->ply >= 50))) return PVEntry->value; + } + if (T(PVEntry->move) && PVEntry->depth > hash_depth) { + Current->best = hash_move = PVEntry->move; + hash_depth = PVEntry->depth; + hash_value = PVEntry->value; + } + } + if (depth < 10) score = height - MateValue; + else score = beta - 1; + if (depth >= 12 && (F(hash_move) || hash_value < beta || hash_depth < depth - 12) && (high_value >= beta || high_depth < depth - 12) && F(flags & FlagDisableNull)) { + new_depth = depth - 8; + value = search(beta, new_depth, FlagHashCheck | FlagNoKillerUpdate | FlagDisableNull | FlagReturnBestMove | hash_move); + if (value >= beta) { + if (Current->best) hash_move = Current->best; + hash_depth = new_depth; + hash_value = beta; + } + } + if (depth >= 4 && Current->score + 3 >= beta && F(flags & (FlagDisableNull | FlagReturnBestMove)) + && (high_value >= beta || high_depth < depth - 10) && (depth < 12 || (hash_value >= beta && hash_depth >= depth - 12)) && beta > -EvalValue && T(NonPawnKing(me))) { + new_depth = depth - 8; + do_null(); + value = -search(1 - beta, new_depth, FlagHashCheck); + undo_null(); + if (value >= beta) { + if (depth < 12) hash_low(0, value, depth); + return value; + } + } + + cnt = flag = singular = played = 0; + if (T(hash_move) && is_legal(move = hash_move)) { + if (IsIllegal(me,move)) goto skip_hash_move; + cnt++; + check = is_check(move); + if (check) ext = 1 + (depth < 16); + else ext = extension<0>(move, depth); + if (depth >= 16 && hash_value >= beta && hash_depth >= (new_depth = depth - Min(12, depth/2))) { + int margin_one = beta - ExclSingle(depth); + int margin_two = beta - ExclDouble(depth); + int prev_ext = Ext(flags); + singular = singular_extension(ext,prev_ext,margin_one,margin_two,new_depth,hash_move); + if (singular) ext = Max(ext, singular + (prev_ext < 1) - (singular >= 2 && prev_ext >= 2)); + } + if (depth < 16 && To(move) == To(Current->move) && T(Square(To(move)))) ext = Max(ext, 2); + new_depth = depth - 2 + ext; + do_move(move); + value = -search(1 - beta, new_depth, FlagNeatSearch | ((hash_value >= beta && hash_depth >= depth - 12) ? FlagDisableNull : 0) | ExtFlag(ext)); + undo_move(move); + played++; + if (value > score) { + score = value; + if (value >= beta) goto cut; + } + } skip_hash_move: - Current->killer[0] = 0; - Current->stage = stage_search; - Current->gen_flags = 0; - Current->ref[0] = RefM(Current->move).ref[0]; - Current->ref[1] = RefM(Current->move).ref[1]; - move_back = 0; - if (beta > 0 && Current->ply >= 2) { - if (F((Current - 1)->move & 0xF000)) { - move_back = (To((Current - 1)->move) << 6) | From((Current - 1)->move); - if (Square(To(move_back))) move_back = 0; - } - } - moves_to_play = 3 + (depth * depth)/6; - margin = Current->score + 70 + (depth << 3) + (Max(depth - 7, 0) << 5); - if ((value = margin) < beta && depth <= 19) { - flag = 1; - score = Max(value, score); - Current->stage = stage_razoring; - Current->mask = Piece(opp); - if ((value = Current->score + 200 + (depth << 5)) < beta) { - score = Max(value, score); - Current->mask ^= Pawn(opp); - } - } - Current->current = Current->moves; - Current->moves[0] = 0; - if (depth <= 5) Current->gen_flags |= FlagNoBcSort; - - do_split = sp_init = 0; - if (depth >= SplitDepth && PrN > 1 && parent && !exclusion) do_split = 1; - - while (move = get_move()) { - if (move == hash_move) continue; - if (IsIllegal(me,move)) continue; - cnt++; - if (move == move_back) { - score = Max(0, score); - continue; - } - if (Current->stage == r_checks) check = 1; - else check = is_check(move); - if (T(check) && T(see(move, 0))) ext = 1 + (depth < 16); - else ext = extension<0>(move, depth); - new_depth = depth - 2 + ext; - if (F(Square(To(move))) && F(move & 0xE000)) { - if (move != Current->killer[1] && move != Current->killer[2]) { - if (F(check) && cnt > moves_to_play) { - Current->gen_flags &= ~FlagSort; - continue; - } - if (depth >= 6) { - int reduction = msb(cnt); - if (move == Current->ref[0] || move == Current->ref[1]) reduction = Max(0, reduction - 1); - if (reduction >= 2 && !(Queen(White) | Queen(Black)) && popcnt(NonPawnKingAll) <= 4) reduction += reduction / 2; - if (new_depth - reduction > 3) - if (F(see(move, -50))) reduction += 2; - if (T(reduction) && reduction < 2 && new_depth - reduction > 3) { - if (cnt > 3) reduction = 2; - else reduction = 0; - } - new_depth = Max(3, new_depth - reduction); - } - } - if (F(check)) { - if ((value = Current->score + DeltaM(move) + 10) < beta && depth <= 3) { - score = Max(value, score); - continue; - } - if (cnt > 7 && (value = margin + DeltaM(move) - 25 * msb(cnt)) < beta && depth <= 19) { - score = Max(value, score); - continue; - } - } - if (depth <= 9 && T(NonPawnKing(me)) && F(see(move,-50))) continue; - } else { - if (Current->stage == r_cap) { - if (F(check) && depth <= 9 && F(see(move,-50))) continue; - } else if (Current->stage == s_bad_cap && F(check) && depth <= 5) continue; - } - if (do_split && played >= 1) { - if (!sp_init) { - sp_init = 1; - uint64 u = ~Smpi->active_sp; - if (!u) { - do_split = 0; - goto make_move; - } - Sp = &Smpi->Sp[lsb(u)]; - init_sp(Sp, beta - 1, beta, depth, 0, singular, height); - } - GMove * M = &Sp->move[Sp->move_number++]; - M->ext = ext; - M->flags = 0; - M->move = move; - M->reduced_depth = new_depth; - M->research_depth = depth - 2 + ext; - M->stage = Current->stage; - continue; - } + Current->killer[0] = 0; + Current->stage = stage_search; + Current->gen_flags = 0; + Current->ref[0] = RefM(Current->move).ref[0]; + Current->ref[1] = RefM(Current->move).ref[1]; + move_back = 0; + if (beta > 0 && Current->ply >= 2) { + if (F((Current - 1)->move & 0xF000)) { + move_back = (To((Current - 1)->move) << 6) | From((Current - 1)->move); + if (Square(To(move_back))) move_back = 0; + } + } + moves_to_play = 3 + (depth * depth)/6; + margin = Current->score + 70 + (depth << 3) + (Max(depth - 7, 0) << 5); + if ((value = margin) < beta && depth <= 19) { + flag = 1; + score = Max(value, score); + Current->stage = stage_razoring; + Current->mask = Piece(opp); + if ((value = Current->score + 200 + (depth << 5)) < beta) { + score = Max(value, score); + Current->mask ^= Pawn(opp); + } + } + Current->current = Current->moves; + Current->moves[0] = 0; + if (depth <= 5) Current->gen_flags |= FlagNoBcSort; + + while (move = get_move()) { + if (move == hash_move) continue; + if (IsIllegal(me,move)) continue; + cnt++; + if (move == move_back) { + score = Max(0, score); + continue; + } + if (Current->stage == r_checks) check = 1; + else check = is_check(move); + if (T(check) && T(see(move, 0))) ext = 1 + (depth < 16); + else ext = extension<0>(move, depth); + new_depth = depth - 2 + ext; + if (F(Square(To(move))) && F(move & 0xE000)) { + if (move != Current->killer[1] && move != Current->killer[2]) { + if (F(check) && cnt > moves_to_play) { + Current->gen_flags &= ~FlagSort; + continue; + } + if (depth >= 6) { + int reduction = msb(cnt); + if (move == Current->ref[0] || move == Current->ref[1]) reduction = Max(0, reduction - 1); + if (reduction >= 2 && !(Queen(White) | Queen(Black)) && popcount(NonPawnKingAll) <= 4) reduction += reduction / 2; + if (new_depth - reduction > 3) + if (F(see(move, -50))) reduction += 2; + if (T(reduction) && reduction < 2 && new_depth - reduction > 3) { + if (cnt > 3) reduction = 2; + else reduction = 0; + } + new_depth = Max(3, new_depth - reduction); + } + } + if (F(check)) { + if ((value = Current->score + DeltaM(move) + 10) < beta && depth <= 3) { + score = Max(value, score); + continue; + } + if (cnt > 7 && (value = margin + DeltaM(move) - 25 * msb(cnt)) < beta && depth <= 19) { + score = Max(value, score); + continue; + } + } + if (depth <= 9 && T(NonPawnKing(me)) && F(see(move,-50))) continue; + } else { + if (Current->stage == r_cap) { + if (F(check) && depth <= 9 && F(see(move,-50))) continue; + } else if (Current->stage == s_bad_cap && F(check) && depth <= 5) continue; + } make_move: - do_move(move); - value = -search(1 - beta, new_depth, FlagNeatSearch | ExtFlag(ext)); - if (value >= beta && new_depth < depth - 2 + ext) value = -search(1 - beta, depth - 2 + ext, FlagNeatSearch | FlagDisableNull | ExtFlag(ext)); - undo_move(move); - played++; - if (value > score) { - score = value; - if (value >= beta) goto cut; - } - } - if (do_split && sp_init) { - value = smp_search(Sp); - if (value >= beta && Sp->best_move) { - score = beta; - Current->best = move = Sp->best_move; - for (i = 0; i < Sp->move_number; i++) { - GMove * M = &Sp->move[i]; - if ((M->flags & FlagFinished) && M->stage == s_quiet && M->move != move) HistoryBad(M->move); - } - } - if (value >= beta) goto cut; - } - if (F(cnt) && F(flag)) { - hash_high(0, 127); - hash_low(0, 0, 127); - return 0; - } - if (F(exclusion)) hash_high(score, depth); - return score; + do_move(move); + value = -search(1 - beta, new_depth, FlagNeatSearch | ExtFlag(ext)); + if (value >= beta && new_depth < depth - 2 + ext) value = -search(1 - beta, depth - 2 + ext, FlagNeatSearch | FlagDisableNull | ExtFlag(ext)); + undo_move(move); + played++; + if (value > score) { + score = value; + if (value >= beta) goto cut; + } + } + if (F(cnt) && F(flag)) { + hash_high(0, 127); + hash_low(0, 0, 127); + return 0; + } + if (F(exclusion)) hash_high(score, depth); + return score; cut: - if (exclusion) return score; - Current->best = move; - if (depth >= 10) score = Min(beta, score); - hash_low(move, score, depth); - if (F(Square(To(move))) && F(move & 0xE000)) { - if (Current->killer[1] != move && F(flags & FlagNoKillerUpdate)) { - Current->killer[2] = Current->killer[1]; - Current->killer[1] = move; - } - HistoryGood(move); - if (move != hash_move && Current->stage == s_quiet && !sp_init) for (p = Current->start; p < (Current->current - 1); p++) HistoryBad(*p); - UpdateRef(move); - } - return score; + if (exclusion) return score; + Current->best = move; + if (depth >= 10) score = Min(beta, score); + hash_low(move, score, depth); + if (F(Square(To(move))) && F(move & 0xE000)) { + if (Current->killer[1] != move && F(flags & FlagNoKillerUpdate)) { + Current->killer[2] = Current->killer[1]; + Current->killer[1] = move; + } + HistoryGood(move); + if (move != hash_move && Current->stage == s_quiet) for (p = Current->start; p < (Current->current - 1); p++) HistoryBad(*p); + UpdateRef(move); + } + return score; } template int search_evasion(int beta, int depth, int flags) { - int i, value, score, pext, move, cnt, hash_value = -MateValue, hash_depth, hash_move, new_depth, ext, check, moves_to_play; - int height = (int)(Current - Data); - - if (depth <= 1) return q_evasion(beta - 1, beta, 1, flags); - score = height - MateValue; - if (flags & FlagHaltCheck) { - if (score >= beta) return beta; - if (MateValue - height < beta) return beta - 1; - halt_check; - } - - hash_depth = -1; - hash_move = flags & 0xFFFF; - if (exclusion) { - cnt = pext = 0; - score = beta - 1; - gen_evasions(Current->moves); - if (F(Current->moves[0])) return score; - goto skip_hash_move; - } - Current->best = hash_move; - if (GEntry * Entry = probe_hash()) { - if (Entry->high < beta && Entry->high_depth >= depth) return Entry->high; - if (T(Entry->move) && Entry->low_depth > hash_depth) { - Current->best = hash_move = Entry->move; - hash_depth = Entry->low_depth; - } - if (Entry->low >= beta && Entry->low_depth >= depth) { - if (Entry->move) { - Current->best = Entry->move; - if (F(Square(To(Entry->move))) && F(Entry->move & 0xE000)) UpdateCheckRef(Entry->move); - } - return Entry->low; - } - if (Entry->low_depth >= depth - 8 && Entry->low > hash_value) hash_value = Entry->low; - } - - if (depth >= 20) if (GPVEntry * PVEntry = probe_pv_hash()) { - hash_low(PVEntry->move,PVEntry->value,PVEntry->depth); - hash_high(PVEntry->value,PVEntry->depth); - if (PVEntry->depth >= depth) { - if (PVEntry->move) Current->best = PVEntry->move; - return PVEntry->value; - } - if (T(PVEntry->move) && PVEntry->depth > hash_depth) { - Current->best = hash_move = PVEntry->move; - hash_depth = PVEntry->depth; - hash_value = PVEntry->value; - } - } - -#if TB - if (hash_depth < 0 && TB_LARGEST > 0 && popcnt(PieceAll) <= TB_LARGEST) { - unsigned res = tb_probe_wdl(Piece(White), Piece(Black), - King(White) | King(Black), - Queen(White) | Queen(Black), - Rook(White) | Rook(Black), - Bishop(White) | Bishop(Black), - Knight(White) | Knight(Black), - Pawn(White) | Pawn(Black), - Current->ply, - Current->castle_flags, - Current->ep_square, - (me == White)); - if (res != TB_RESULT_FAILED) { - tb_hits++; - hash_high(TbValues[res], TbDepth); - hash_low(0, TbValues[res], TbDepth); - return TbValues[res]; - } - } -#endif + int i, value, score, pext, move, cnt, hash_value = -MateValue, hash_depth, hash_move, new_depth, ext, check, moves_to_play; + int height = (int)(Current - Data); + + if (depth <= 1) return q_evasion(beta - 1, beta, 1, flags); + score = height - MateValue; + if (flags & FlagHaltCheck) { + if (score >= beta) return beta; + if (MateValue - height < beta) return beta - 1; + halt_check; + } + + hash_depth = -1; + hash_move = flags & 0xFFFF; + if (exclusion) { + cnt = pext = 0; + score = beta - 1; + gen_evasions(Current->moves); + if (F(Current->moves[0])) return score; + goto skip_hash_move; + } + Current->best = hash_move; + if (GEntry * Entry = probe_hash()) { + if (Entry->high < beta && Entry->high_depth >= depth) return Entry->high; + if (T(Entry->move) && Entry->low_depth > hash_depth) { + Current->best = hash_move = Entry->move; + hash_depth = Entry->low_depth; + } + if (Entry->low >= beta && Entry->low_depth >= depth) { + if (Entry->move) { + Current->best = Entry->move; + if (F(Square(To(Entry->move))) && F(Entry->move & 0xE000)) UpdateCheckRef(Entry->move); + } + return Entry->low; + } + if (Entry->low_depth >= depth - 8 && Entry->low > hash_value) hash_value = Entry->low; + } - if (hash_depth >= depth && hash_value > -EvalValue) score = Min(beta - 1, Max(score, hash_value)); - if (flags & FlagCallEvaluation) evaluate(); - - Current->mask = Filled; - if (Current->score - 10 < beta && depth <= 3) { - Current->mask = Piece(opp); - score = Current->score - 10; - capture_margin(beta, score); - } - cnt = 0; - pext = 0; + if (depth >= 20) if (GPVEntry * PVEntry = probe_pv_hash()) { + hash_low(PVEntry->move,PVEntry->value,PVEntry->depth); + hash_high(PVEntry->value,PVEntry->depth); + if (PVEntry->depth >= depth) { + if (PVEntry->move) Current->best = PVEntry->move; + return PVEntry->value; + } + if (T(PVEntry->move) && PVEntry->depth > hash_depth) { + Current->best = hash_move = PVEntry->move; + hash_depth = PVEntry->depth; + hash_value = PVEntry->value; + } + } + + if (hash_depth < 0 && depth >= SETTINGS->syzygyProbeDepth && + TB_LARGEST > 0 && popcount(PieceAll) <= TB_LARGEST) + { + unsigned res = tb_probe_wdl(Piece(White), Piece(Black), + King(White) | King(Black), + Queen(White) | Queen(Black), + Rook(White) | Rook(Black), + Bishop(White) | Bishop(Black), + Knight(White) | Knight(Black), + Pawn(White) | Pawn(Black), + Current->ply, + Current->castle_flags, + Current->ep_square, + (me == White)); + if (res != TB_RESULT_FAILED) + { + INFO->tbHits++; + hash_high(TbValues[res], TbDepth); + hash_low(0, TbValues[res], TbDepth); + return TbValues[res]; + } + } + + if (hash_depth >= depth && hash_value > -EvalValue) score = Min(beta - 1, Max(score, hash_value)); + if (flags & FlagCallEvaluation) evaluate(); + + Current->mask = Filled; + if (Current->score - 10 < beta && depth <= 3) { + Current->mask = Piece(opp); + score = Current->score - 10; + capture_margin(beta, score); + } + cnt = 0; + pext = 0; gen_evasions(Current->moves); - if (F(Current->moves[0])) return score; - if (F(Current->moves[1])) pext = 2; - - if (T(hash_move) && is_legal(move = hash_move)) { - if (IsIllegal(me,move)) goto skip_hash_move; - cnt++; - check = is_check(move); - if (check) ext = Max(pext, 1 + (depth < 16)); - else ext = MaxF(pext, extension<0>(move, depth)); - if (depth >= 16 && hash_value >= beta && hash_depth >= (new_depth = depth - Min(12, depth/2))) { - int margin_one = beta - ExclSingle(depth); - int margin_two = beta - ExclDouble(depth); - int prev_ext = Ext(flags); - int singular = singular_extension(ext,prev_ext,margin_one,margin_two,new_depth,hash_move); - if (singular) ext = Max(ext, singular + (prev_ext < 1) - (singular >= 2 && prev_ext >= 2)); - } - new_depth = depth - 2 + ext; - do_move(move); - evaluate(); - if (Current->att[opp] & King(me)) { - undo_move(move); - cnt--; - goto skip_hash_move; - } - value = -search(1 - beta, new_depth, FlagHaltCheck | FlagHashCheck | ((hash_value >= beta && hash_depth >= depth - 12) ? FlagDisableNull : 0) | ExtFlag(ext)); - undo_move(move); - if (value > score) { - score = value; - if (value >= beta) goto cut; - } - } + if (F(Current->moves[0])) return score; + if (F(Current->moves[1])) pext = 2; + + if (T(hash_move) && is_legal(move = hash_move)) { + if (IsIllegal(me,move)) goto skip_hash_move; + cnt++; + check = is_check(move); + if (check) ext = Max(pext, 1 + (depth < 16)); + else ext = MaxF(pext, extension<0>(move, depth)); + if (depth >= 16 && hash_value >= beta && hash_depth >= (new_depth = depth - Min(12, depth/2))) { + int margin_one = beta - ExclSingle(depth); + int margin_two = beta - ExclDouble(depth); + int prev_ext = Ext(flags); + int singular = singular_extension(ext,prev_ext,margin_one,margin_two,new_depth,hash_move); + if (singular) ext = Max(ext, singular + (prev_ext < 1) - (singular >= 2 && prev_ext >= 2)); + } + new_depth = depth - 2 + ext; + do_move(move); + evaluate(); + if (Current->att[opp] & King(me)) { + undo_move(move); + cnt--; + goto skip_hash_move; + } + value = -search(1 - beta, new_depth, FlagHaltCheck | FlagHashCheck | ((hash_value >= beta && hash_depth >= depth - 12) ? FlagDisableNull : 0) | ExtFlag(ext)); + undo_move(move); + if (value > score) { + score = value; + if (value >= beta) goto cut; + } + } skip_hash_move: - moves_to_play = 3 + ((depth * depth) / 6); - Current->ref[0] = RefM(Current->move).check_ref[0]; - Current->ref[1] = RefM(Current->move).check_ref[1]; - mark_evasions(Current->moves); - Current->current = Current->moves; - while (move = pick_move()) { - if (move == hash_move) continue; - if (IsIllegal(me,move)) continue; - cnt++; - if (IsRepetition(beta,move)) { - score = Max(0, score); - continue; - } - check = is_check(move); - if (check) ext = Max(pext, 1 + (depth < 16)); - else ext = MaxF(pext, extension<0>(move, depth)); - new_depth = depth - 2 + ext; - if (F(Square(To(move))) && F(move & 0xE000)) { - if (F(check)) { - if (cnt > moves_to_play) continue; - if ((value = Current->score + DeltaM(move) + 10) < beta && depth <= 3) { - score = Max(value, score); - continue; - } - } - if (depth >= 6 && cnt > 3) { - int reduction = msb(cnt); - if (reduction >= 2 && !(Queen(White) | Queen(Black)) && popcnt(NonPawnKingAll) <= 4) reduction += reduction / 2; - new_depth = Max(3, new_depth - reduction); - } - } - do_move(move); - value = -search(1 - beta, new_depth, FlagNeatSearch | ExtFlag(ext)); - if (value >= beta && new_depth < depth - 2 + ext) value = -search(1 - beta, depth - 2 + ext, FlagNeatSearch | FlagDisableNull | ExtFlag(ext)); - undo_move(move); - if (value > score) { - score = value; - if (value >= beta) goto cut; - } - } - if (F(exclusion)) hash_high(score, depth); - return score; + moves_to_play = 3 + ((depth * depth) / 6); + Current->ref[0] = RefM(Current->move).check_ref[0]; + Current->ref[1] = RefM(Current->move).check_ref[1]; + mark_evasions(Current->moves); + Current->current = Current->moves; + while (move = pick_move()) { + if (move == hash_move) continue; + if (IsIllegal(me,move)) continue; + cnt++; + if (IsRepetition(beta,move)) { + score = Max(0, score); + continue; + } + check = is_check(move); + if (check) ext = Max(pext, 1 + (depth < 16)); + else ext = MaxF(pext, extension<0>(move, depth)); + new_depth = depth - 2 + ext; + if (F(Square(To(move))) && F(move & 0xE000)) { + if (F(check)) { + if (cnt > moves_to_play) continue; + if ((value = Current->score + DeltaM(move) + 10) < beta && depth <= 3) { + score = Max(value, score); + continue; + } + } + if (depth >= 6 && cnt > 3) { + int reduction = msb(cnt); + if (reduction >= 2 && !(Queen(White) | Queen(Black)) && popcount(NonPawnKingAll) <= 4) reduction += reduction / 2; + new_depth = Max(3, new_depth - reduction); + } + } + do_move(move); + value = -search(1 - beta, new_depth, FlagNeatSearch | ExtFlag(ext)); + if (value >= beta && new_depth < depth - 2 + ext) value = -search(1 - beta, depth - 2 + ext, FlagNeatSearch | FlagDisableNull | ExtFlag(ext)); + undo_move(move); + if (value > score) { + score = value; + if (value >= beta) goto cut; + } + } + if (F(exclusion)) hash_high(score, depth); + return score; cut: - if (exclusion) return score; - Current->best = move; - hash_low(move, score, depth); - if (F(Square(To(move))) && F(move & 0xE000)) UpdateCheckRef(move); - return score; + if (exclusion) return score; + Current->best = move; + hash_low(move, score, depth); + if (F(Square(To(move))) && F(move & 0xE000)) UpdateCheckRef(move); + return score; } template int pv_search(int alpha, int beta, int depth, int flags) { - int i, value, move, cnt, pext = 0, ext, check, hash_value = -MateValue, margin, do_split = 0, sp_init = 0, singular = 0, played = 0, - new_depth, hash_move, hash_depth, old_alpha = alpha, old_best, ex_depth = 0, ex_value = 0, start_knodes = (nodes >> 10); - GSP * Sp; - int height = (int)(Current - Data); - - if (root) { - depth = Max(depth, 2); - flags |= ExtFlag(1); - if (F(RootList[0])) return 0; - if (Print) { - fprintf(stdout,"info depth %d\n",(depth/2)); - fflush(stdout); - } - int * p; - for (p = RootList; *p; p++); - sort_moves(RootList,p); - for (p = RootList; *p; p++) *p &= 0xFFFF; - SetScore(RootList[0],2); - goto check_hash; - } - if (depth <= 1) return q_search(alpha, beta, 1, FlagNeatSearch); - if (Convert((Current - Data),int) - MateValue >= beta) return beta; - if (MateValue - Convert((Current - Data),int) <= alpha) return alpha; - halt_check; + int i, value, move, cnt, pext = 0, ext, check, hash_value = -MateValue, margin, singular = 0, played = 0, new_depth, hash_move, hash_depth, old_alpha = alpha, old_best, ex_depth = 0, ex_value = 0, start_knodes = (INFO->nodes >> 10); + int height = (int)(Current - Data); + + if (root) { + depth = Max(depth, 2); + flags |= ExtFlag(1); + if (F(RootList[0])) return 0; + if (INFO->id == 0) + { + char line[128]; + int len = snprintf(line, sizeof(line)-1, "info depth %d\n", + depth/2); + if (len > 0 && len < sizeof(line)-1) + { + mutex_lock(&SHARED->mutex); + put_line(line, len); + mutex_unlock(&SHARED->mutex); + } + } + int * p; + for (p = RootList; *p; p++); + sort_moves(RootList,p); + for (p = RootList; *p; p++) *p &= 0xFFFF; + SetScore(RootList[0],2); + goto check_hash; + } + if (depth <= 1) return q_search(alpha, beta, 1, FlagNeatSearch); + if (Convert((Current - Data),int) - MateValue >= beta) return beta; + if (MateValue - Convert((Current - Data),int) <= alpha) return alpha; + halt_check; check_hash: - hash_depth = -1; - Current->best = hash_move = 0; + hash_depth = -1; + Current->best = hash_move = 0; if (GPVEntry * PVEntry = probe_pv_hash()) { - hash_low(PVEntry->move,PVEntry->value,PVEntry->depth); - hash_high(PVEntry->value,PVEntry->depth); - if (PVEntry->depth >= depth && T(PVHashing)) { - if (PVEntry->move) Current->best = PVEntry->move; - if ((Current->ply <= 50 && PVEntry->ply <= 50) || (Current->ply >= 50 && PVEntry->ply >= 50)) if (!PVEntry->value || !draw_in_pv()) return PVEntry->value; - } - if (T(PVEntry->move) && PVEntry->depth > hash_depth) { - Current->best = hash_move = PVEntry->move; - hash_depth = PVEntry->depth; - hash_value = PVEntry->value; - } - } - if (GEntry * Entry = probe_hash()) { - if (T(Entry->move) && Entry->low_depth > hash_depth) { - Current->best = hash_move = Entry->move; - hash_depth = Entry->low_depth; - if (Entry->low_depth) hash_value = Entry->low; - } - } - - if (root) { - hash_move = RootList[0]; - hash_value = Previous; - hash_depth = Max(0, depth - 2); - } - - evaluate(); - - if (F(root) && depth >= 6 && (F(hash_move) || hash_value <= alpha || hash_depth < depth - 8)) { - if (F(hash_move)) new_depth = depth - 2; - else new_depth = depth - 4; - value = pv_search(alpha, beta, new_depth, hash_move); - if (value > alpha) { + hash_low(PVEntry->move,PVEntry->value,PVEntry->depth); + hash_high(PVEntry->value,PVEntry->depth); + if (PVEntry->depth >= depth && T(PVHashing)) { + if (PVEntry->move) Current->best = PVEntry->move; + if ((Current->ply <= 50 && PVEntry->ply <= 50) || (Current->ply >= 50 && PVEntry->ply >= 50)) if (!PVEntry->value || !draw_in_pv()) return PVEntry->value; + } + if (T(PVEntry->move) && PVEntry->depth > hash_depth) { + Current->best = hash_move = PVEntry->move; + hash_depth = PVEntry->depth; + hash_value = PVEntry->value; + } + } + if (GEntry * Entry = probe_hash()) { + if (T(Entry->move) && Entry->low_depth > hash_depth) { + Current->best = hash_move = Entry->move; + hash_depth = Entry->low_depth; + if (Entry->low_depth) hash_value = Entry->low; + } + } + + if (hash_depth < 0 && depth >= SETTINGS->syzygyProbeDepth && + TB_LARGEST > 0 && popcount(PieceAll) <= TB_LARGEST) + { + unsigned res = tb_probe_wdl(Piece(White), Piece(Black), + King(White) | King(Black), + Queen(White) | Queen(Black), + Rook(White) | Rook(Black), + Bishop(White) | Bishop(Black), + Knight(White) | Knight(Black), + Pawn(White) | Pawn(Black), + Current->ply, + Current->castle_flags, + Current->ep_square, + (me == White)); + if (res != TB_RESULT_FAILED) + { + INFO->tbHits++; + hash_high(TbValues[res], TbDepth); + hash_low(0, TbValues[res], TbDepth); + return TbValues[res]; + } + } + + if (root) { + hash_move = RootList[0]; + hash_value = Previous; + hash_depth = Max(0, depth - 2); + } + + evaluate(); + + if (F(root) && depth >= 6 && (F(hash_move) || hash_value <= alpha || hash_depth < depth - 8)) { + if (F(hash_move)) new_depth = depth - 2; + else new_depth = depth - 4; + value = pv_search(alpha, beta, new_depth, hash_move); + if (value > alpha) { hash_move_found: - if (Current->best) hash_move = Current->best; - hash_depth = new_depth; - hash_value = value; - goto skip_iid; - } else { - i = 0; - new_depth = depth - 8; + if (Current->best) hash_move = Current->best; + hash_depth = new_depth; + hash_value = value; + goto skip_iid; + } else { + i = 0; + new_depth = depth - 8; iid_loop: - margin = alpha - (8 << i); - if (T(hash_move) && hash_depth >= Min(new_depth, depth - 8) && hash_value >= margin) goto skip_iid; - value = search(margin, new_depth, FlagHashCheck | FlagNoKillerUpdate | FlagDisableNull | FlagReturnBestMove | hash_move); - if (value >= margin) goto hash_move_found; - i++; - if (i < 5) goto iid_loop; - } - } + margin = alpha - (8 << i); + if (T(hash_move) && hash_depth >= Min(new_depth, depth - 8) && hash_value >= margin) goto skip_iid; + value = search(margin, new_depth, FlagHashCheck | FlagNoKillerUpdate | FlagDisableNull | FlagReturnBestMove | hash_move); + if (value >= margin) goto hash_move_found; + i++; + if (i < 5) goto iid_loop; + } + } skip_iid: - if (F(root) && Check(me)) { - alpha = Max(Convert((Current - Data),int) - MateValue, alpha); - Current->mask = Filled; - gen_evasions(Current->moves); - if (F(Current->moves[0])) return Convert((Current - Data),int) - MateValue; - if (F(Current->moves[1])) pext = 2; - } - - cnt = 0; - if (hash_move && is_legal(move = hash_move)) { - cnt++; - if (root) { -#ifndef TUNER - memset(Data + 1, 0, 127 * sizeof(GData)); -#endif - move_to_string(move,score_string); - if (Print) sprintf(info_string,"info currmove %s currmovenumber %d\n",score_string,cnt); - } - check = is_check(move); - if (check) ext = 2; - else ext = MaxF(pext, extension<1>(move, depth)); - if (depth >= 12 && hash_value > alpha && hash_depth >= (new_depth = depth - Min(12,depth/2))) { - int margin_one = hash_value - ExclSinglePV(depth); - int margin_two = hash_value - ExclDoublePV(depth); - int prev_ext = Ext(flags); - singular = singular_extension(root ? 0 : ext,root ? 0 : prev_ext,margin_one,margin_two,new_depth,hash_move); - if (singular) { - ext = Max(ext, singular + (prev_ext < 1) - (singular >= 2 && prev_ext >= 2)); - if (root) CurrentSI->Singular = singular; - ex_depth = new_depth; - ex_value = (singular >= 2 ? margin_two : margin_one) - 1; - } - } - new_depth = depth - 2 + ext; - do_move(move); - if (PrN > 1) { - evaluate(); - if (Current->att[opp] & King(me)) { - undo_move(move); - cnt--; - goto skip_hash_move; - } - } - value = -pv_search(-beta, -alpha, new_depth, ExtFlag(ext)); - undo_move(move); - played++; - if (value > alpha) { - if (root) { - CurrentSI->FailLow = 0; - best_move = move; - best_score = value; - hash_low(best_move,value,depth); - if (depth >= 14 || T(Console)) send_pv(depth/2, old_alpha, beta, value); - } - alpha = value; - Current->best = move; - if (value >= beta) goto cut; - } else if (root) { - CurrentSI->FailLow = 1; - CurrentSI->FailHigh = 0; - CurrentSI->Singular = 0; - if (depth >= 14 || T(Console)) send_pv(depth/2, old_alpha, beta, value); - } - } + if (F(root) && Check(me)) { + alpha = Max(Convert((Current - Data),int) - MateValue, alpha); + Current->mask = Filled; + gen_evasions(Current->moves); + if (F(Current->moves[0])) return Convert((Current - Data),int) - MateValue; + if (F(Current->moves[1])) pext = 2; + } + + cnt = 0; + if (hash_move && is_legal(move = hash_move)) { + cnt++; + if (root) + { + memset(Data + 1, 0, 127 * sizeof(GData)); + send_curr_move(move, cnt); + } + check = is_check(move); + if (check) ext = 2; + else ext = MaxF(pext, extension<1>(move, depth)); + if (depth >= 12 && hash_value > alpha && hash_depth >= (new_depth = depth - Min(12,depth/2))) { + int margin_one = hash_value - ExclSinglePV(depth); + int margin_two = hash_value - ExclDoublePV(depth); + int prev_ext = Ext(flags); + singular = singular_extension(root ? 0 : ext,root ? 0 : prev_ext,margin_one,margin_two,new_depth,hash_move); + if (singular) { + ext = Max(ext, singular + (prev_ext < 1) - (singular >= 2 && prev_ext >= 2)); + if (root) CurrentSI->Singular = singular; + ex_depth = new_depth; + ex_value = (singular >= 2 ? margin_two : margin_one) - 1; + } + } + new_depth = depth - 2 + ext; + do_move(move); + if (SETTINGS->numThreads > 1) { // XXX + evaluate(); + if (Current->att[opp] & King(me)) { + undo_move(move); + cnt--; + goto skip_hash_move; + } + } + value = -pv_search(-beta, -alpha, new_depth, ExtFlag(ext)); + undo_move(move); + played++; + if (value > alpha) { + if (root) { + CurrentSI->FailLow = 0; + INFO->bestMove = move; + INFO->bestScore = value; + hash_low(move,value,depth); + if (depth >= 14) + send_pv(depth/2, old_alpha, beta, value); + } + alpha = value; + Current->best = move; + if (value >= beta) goto cut; + } else if (root) { + CurrentSI->FailLow = 1; + CurrentSI->FailHigh = 0; + CurrentSI->Singular = 0; + if (depth >= 14) + send_pv(depth/2, old_alpha, beta, value); + } + } skip_hash_move: - Current->gen_flags = 0; - if (F(Check(me))) { - Current->stage = stage_search; - Current->ref[0] = RefM(Current->move).ref[0]; - Current->ref[1] = RefM(Current->move).ref[1]; - } else { - Current->stage = stage_evasion; - Current->ref[0] = RefM(Current->move).check_ref[0]; - Current->ref[1] = RefM(Current->move).check_ref[1]; - } - Current->killer[0] = 0; - Current->moves[0] = 0; - if (root) Current->current = RootList + 1; - else Current->current = Current->moves; - - if (PrN > 1 && !root && parent && depth >= SplitDepthPV) do_split = 1; - - while (move = get_move()) { - if (move == hash_move) continue; - if (IsIllegal(me,move)) continue; - cnt++; - if (root) { -#ifndef TUNER - memset(Data + 1, 0, 127 * sizeof(GData)); -#endif - move_to_string(move,score_string); - if (Print) sprintf(info_string,"info currmove %s currmovenumber %d\n",score_string,cnt); - } - if (IsRepetition(alpha + 1,move)) continue; - check = is_check(move); - if (check) ext = 2; - else ext = MaxF(pext, extension<1>(move, depth)); - new_depth = depth - 2 + ext; - if (depth >= 6 && F(move & 0xE000) && F(Square(To(move))) && (T(root) || (move != Current->killer[1] && move != Current->killer[2]) || T(Check(me))) && cnt > 3) { - int reduction = msb(cnt) - 1; - if (move == Current->ref[0] || move == Current->ref[1]) reduction = Max(0, reduction - 1); - if (reduction >= 2 && !(Queen(White) | Queen(Black)) && popcnt(NonPawnKingAll) <= 4) reduction += reduction / 2; - new_depth = Max(3, new_depth - reduction); - } - if (do_split && played >= 1) { - if (!sp_init) { - sp_init = 1; - uint64 u = ~Smpi->active_sp; - if (!u) { - do_split = 0; - goto make_move; - } - Sp = &Smpi->Sp[lsb(u)]; - init_sp(Sp, alpha, beta, depth, 1, singular, height); - } - GMove * M = &Sp->move[Sp->move_number++]; - M->ext = ext; - M->flags = 0; - M->move = move; - M->reduced_depth = new_depth; - M->research_depth = depth - 2 + ext; - M->stage = Current->stage; - continue; - } + Current->gen_flags = 0; + if (F(Check(me))) { + Current->stage = stage_search; + Current->ref[0] = RefM(Current->move).ref[0]; + Current->ref[1] = RefM(Current->move).ref[1]; + } else { + Current->stage = stage_evasion; + Current->ref[0] = RefM(Current->move).check_ref[0]; + Current->ref[1] = RefM(Current->move).check_ref[1]; + } + Current->killer[0] = 0; + Current->moves[0] = 0; + if (root) Current->current = RootList + 1; + else Current->current = Current->moves; + + while (move = get_move()) { + if (move == hash_move) continue; + if (IsIllegal(me,move)) continue; + cnt++; + if (root) { + memset(Data + 1, 0, 127 * sizeof(GData)); + send_curr_move(move, cnt); + } + if (IsRepetition(alpha + 1,move)) continue; + check = is_check(move); + if (check) ext = 2; + else ext = MaxF(pext, extension<1>(move, depth)); + new_depth = depth - 2 + ext; + if (depth >= 6 && F(move & 0xE000) && F(Square(To(move))) && (T(root) || (move != Current->killer[1] && move != Current->killer[2]) || T(Check(me))) && cnt > 3) { + int reduction = msb(cnt) - 1; + if (move == Current->ref[0] || move == Current->ref[1]) reduction = Max(0, reduction - 1); + if (reduction >= 2 && !(Queen(White) | Queen(Black)) && popcount(NonPawnKingAll) <= 4) reduction += reduction / 2; + new_depth = Max(3, new_depth - reduction); + } make_move: - do_move(move); - if (new_depth <= 1) value = -pv_search(-beta, -alpha, new_depth, ExtFlag(ext)); - else value = -search(-alpha, new_depth, FlagNeatSearch | ExtFlag(ext)); - if (value > alpha && new_depth > 1) { - if (root) { - SetScore(RootList[cnt - 1],1); - CurrentSI->Early = 0; - old_best = best_move; - best_move = move; - } - new_depth = depth - 2 + ext; - value = -pv_search(-beta, -alpha, new_depth, ExtFlag(ext)); - if (T(root) && value <= alpha) best_move = old_best; - } - undo_move(move); - played++; - if (value > alpha) { - if (root) { - SetScore(RootList[cnt - 1],cnt + 3); - CurrentSI->Change = 1; - CurrentSI->FailLow = 0; - best_move = move; - best_score = value; - hash_low(best_move,value,depth); - if (depth >= 14 || T(Console)) send_pv(depth/2, old_alpha, beta, value); - } - alpha = value; - Current->best = move; - if (value >= beta) goto cut; - } - } - if (do_split && sp_init) { - value = smp_search(Sp); - if (value > alpha && Sp->best_move) { - alpha = value; - Current->best = move = Sp->best_move; - } - if (value >= beta) goto cut; - } - if (F(cnt) && F(Check(me))) { - hash_high(0, 127); - hash_low(0, 0, 127); - hash_exact(0, 0, 127, 0, 0, 0); - return 0; - } - if (F(root) || F(SearchMoves)) hash_high(alpha, depth); - if (alpha > old_alpha) { - hash_low(Current->best,alpha,depth); - if (Current->best != hash_move) ex_depth = 0; - if (F(root) || F(SearchMoves)) hash_exact(Current->best,alpha,depth,ex_value,ex_depth,Convert(nodes >> 10,int) - start_knodes); - } - return alpha; + do_move(move); + if (new_depth <= 1) value = -pv_search(-beta, -alpha, new_depth, ExtFlag(ext)); + else value = -search(-alpha, new_depth, FlagNeatSearch | ExtFlag(ext)); + if (value > alpha && new_depth > 1) { + if (root) { + SetScore(RootList[cnt - 1],1); + CurrentSI->Early = 0; + old_best = INFO->bestMove; + INFO->bestMove = move; + } + new_depth = depth - 2 + ext; + value = -pv_search(-beta, -alpha, new_depth, ExtFlag(ext)); + if (T(root) && value <= alpha) INFO->bestMove = old_best; + } + undo_move(move); + played++; + if (value > alpha) { + if (root) { + SetScore(RootList[cnt - 1],cnt + 3); + CurrentSI->Change = 1; + CurrentSI->FailLow = 0; + INFO->bestMove = move; + INFO->bestScore = value; + if (depth >= 14) + send_pv(depth/2, old_alpha, beta, value); + } + alpha = value; + Current->best = move; + if (value >= beta) goto cut; + } + } + if (F(cnt) && F(Check(me))) { + hash_high(0, 127); + hash_low(0, 0, 127); + hash_exact(0, 0, 127, 0, 0, 0); + return 0; + } + if (F(root) || F(SearchMoves)) hash_high(alpha, depth); + if (alpha > old_alpha) { + hash_low(Current->best,alpha,depth); + if (Current->best != hash_move) ex_depth = 0; + if (F(root) || F(SearchMoves)) hash_exact(Current->best,alpha,depth,ex_value,ex_depth,Convert(INFO->nodes >> 10,int) - start_knodes); + } + return alpha; cut: - hash_low(move, alpha, depth); - return alpha; -} - -template void root() { - int i, depth, value, alpha, beta, delta, start_depth = 2, hash_depth = 0, hash_value, store_time = 0, time_est, ex_depth = 0, ex_value, prev_time = 0, knodes = 0; - sint64 time; - GPVEntry * PVEntry; - - date++; - tb_hits = nodes = check_node = check_node_smp = 0; -#ifndef TUNER - if (parent) Smpi->tb_hits = Smpi->nodes = 0; -#endif - memcpy(Data,Current,sizeof(GData)); - Current = Data; - -#ifdef TB - if (popcnt(PieceAll) <= TB_LARGEST) { - unsigned res = tb_probe_root(Piece(White), Piece(Black), - King(White) | King(Black), - Queen(White) | Queen(Black), - Rook(White) | Rook(Black), - Bishop(White) | Bishop(Black), - Knight(White) | Knight(Black), - Pawn(White) | Pawn(Black), - Current->ply, - Current->castle_flags, - Current->ep_square, - (me == White), NULL); - if (res != TB_RESULT_FAILED) { - best_score = TbValues[TB_GET_WDL(res)]; - int flags = 0; - unsigned to = TB_GET_TO(res); - switch (TB_GET_PROMOTES(res)) { - case TB_PROMOTES_QUEEN: - flags |= FlagPQueen; break; - case TB_PROMOTES_ROOK: - flags |= FlagPRook; break; - case TB_PROMOTES_BISHOP: - flags |= (Bit(to) & LightArea? FlagPLight: FlagPDark); - case TB_PROMOTES_KNIGHT: - flags |= FlagPKnight; break; - default: - break; - } - best_move = (TB_GET_FROM(res) << 6) | to | flags; - char str[32]; - move_to_string(best_move,str); - printf("info depth 1 seldepth 1 score cp %d nodes 1 nps 0 tbhits 1 pv %s\n", best_score, str); // Fake PV - send_best_move(); - Searching = 0; - if (MaxPrN > 1) ZERO_BIT_64(Smpi->searching, 0); - return; - } - } -#endif - - evaluate(); - gen_root_moves(); - if (PVN > 1) { - memset(MultiPV,0,128 * sizeof(int)); - for (i = 0; MultiPV[i] = RootList[i]; i++); - } - best_move = RootList[0]; - if (F(best_move)) return; - if (F(Infinite) && !RootList[1]) { - Infinite = 1; - value = pv_search(-MateValue, MateValue, 4, FlagNeatSearch); - Infinite = 0; - LastDepth = 128; - send_pv(6, -MateValue, MateValue, value); - send_best_move(); - Searching = 0; - if (MaxPrN > 1) ZERO_BIT_64(Smpi->searching, 0); - return; - } - - memset(CurrentSI,0,sizeof(GSearchInfo)); - memset(BaseSI,0,sizeof(GSearchInfo)); - Previous = -MateValue; - if (PVEntry = probe_pv_hash()) { - if (is_legal(PVEntry->move) && PVEntry->move == best_move && PVEntry->depth > hash_depth) { - hash_depth = PVEntry->depth; - hash_value = PVEntry->value; - ex_depth = PVEntry->ex_depth; - ex_value = PVEntry->exclusion; - knodes = PVEntry->knodes; - } - } - if (T(hash_depth) && PVN == 1) { - Previous = best_score = hash_value; - depth = hash_depth; - if (PVHashing) { - send_pv(depth/2, -MateValue, MateValue, best_score); - start_depth = (depth + 2) & (~1); - } - if ((depth >= LastDepth - 8 || T(store_time)) && LastValue >= LastExactValue && hash_value >= LastExactValue && T(LastTime) && T(LastSpeed)) { - time = TimeLimit1; - if (ex_depth >= depth - Min(12, depth/2) && ex_value <= hash_value - ExclSinglePV(depth)) { - BaseSI->Early = 1; - BaseSI->Singular = 1; - if (ex_value <= hash_value - ExclDoublePV(depth)) { - time = (time * TimeSingTwoMargin)/100; - BaseSI->Singular = 2; - } - else time = (time * TimeSingOneMargin)/100; - } - time_est = Min(LastTime,(knodes << 10)/LastSpeed); - time_est = Max(time_est, store_time); -set_prev_time: - LastTime = prev_time = time_est; - if (prev_time >= time && F(Infinite)) { - InstCnt++; - if (time_est <= store_time) InstCnt = 0; - if (InstCnt > 2) { - if (T(store_time) && store_time < time_est) { - time_est = store_time; - goto set_prev_time; - } - LastSpeed = 0; - LastTime = 0; - prev_time = 0; - goto set_jump; - } - if (hash_value > 0 && Current->ply >= 2 && F(Square(To(best_move))) && F(best_move & 0xF000) && PrevMove == ((To(best_move) << 6) | From(best_move))) goto set_jump; - do_move(best_move); - if (Current->ply >= 100) { - undo_move(best_move); - goto set_jump; - } - for (i = 4; i <= Current->ply; i+=2) if (Stack[sp-i] == Current->key) { - undo_move(best_move); - goto set_jump; - } - undo_move(best_move); - LastDepth = depth; - LastTime = prev_time; - LastValue = LastExactValue = hash_value; - send_best_move(); - Searching = 0; - if (MaxPrN > 1) ZERO_BIT_64(Smpi->searching, 0); - return; - } else goto set_jump; - } - } - LastTime = 0; -set_jump: - memcpy(SaveBoard,Board,sizeof(GBoard)); - memcpy(SaveData,Data,sizeof(GData)); - save_sp = sp; - if (setjmp(Jump)) { - Current = Data; - Searching = 0; - if (MaxPrN > 1) { - halt_all(0, 127); - ZERO_BIT_64(Smpi->searching, 0); - } - memcpy(Board,SaveBoard,sizeof(GBoard)); - memcpy(Data,SaveData,sizeof(GData)); - sp = save_sp; - send_best_move(); - return; - } - for (depth = start_depth; depth < DepthLimit; depth += 2) { -#ifndef TUNER - memset(Data + 1, 0, 127 * sizeof(GData)); -#endif - CurrentSI->Early = 1; - CurrentSI->Change = CurrentSI->FailHigh = CurrentSI->FailLow = CurrentSI->Singular = 0; - if (PVN > 1) value = multipv(depth); - else if ((depth/2) < 7 || F(Aspiration)) LastValue = LastExactValue = value = pv_search(-MateValue, MateValue, depth, FlagNeatSearch); - else { - delta = 8; - alpha = Previous - delta; - beta = Previous + delta; -loop: - if (delta >= 16 * 32) { - LastValue = LastExactValue = value = pv_search(-MateValue, MateValue, depth, FlagNeatSearch); - goto finish; - } - value = pv_search(alpha, beta, depth, FlagNeatSearch); - if (value <= alpha) { - CurrentSI->FailHigh = 0; - CurrentSI->FailLow = 1; - alpha -= delta; - delta *= 2; - LastValue = value; - memcpy(BaseSI,CurrentSI,sizeof(GSearchInfo)); - goto loop; - } else if (value >= beta) { - CurrentSI->FailHigh = 1; - CurrentSI->FailLow = 0; - CurrentSI->Early = 1; - CurrentSI->Change = 0; - CurrentSI->Singular = Max(CurrentSI->Singular, 1); - beta += delta; - delta *= 2; - LastDepth = depth; - LastTime = MaxF(prev_time,get_time() - StartTime); - LastSpeed = nodes/Max(LastTime, 1); - if (depth + 2 < DepthLimit) depth += 2; - InstCnt = 0; -#ifdef TIMING - if (depth >= 6) -#endif - check_time(LastTime,0); -#ifndef TUNER - memset(Data + 1, 0, 127 * sizeof(GData)); -#endif - LastValue = value; - memcpy(BaseSI,CurrentSI,sizeof(GSearchInfo)); - goto loop; - } else LastValue = LastExactValue = value; - } -finish: - if (value < Previous - 50) CurrentSI->Bad = 1; - else CurrentSI->Bad = 0; - memcpy(BaseSI,CurrentSI,sizeof(GSearchInfo)); - LastDepth = depth; - LastTime = MaxF(prev_time,get_time() - StartTime); - LastSpeed = nodes/Max(LastTime, 1); - Previous = value; - InstCnt = 0; -#ifdef TIMING - if (depth >= 6) -#endif - check_time(LastTime,0); - } - Searching = 0; - if (MaxPrN > 1) ZERO_BIT_64(Smpi->searching, 0); - if (F(Infinite) || DepthLimit < 128) send_best_move(); + hash_low(move, alpha, depth); + return alpha; } template int multipv(int depth) { - int move, low = MateValue, value, i, cnt, ext, new_depth = depth; - fprintf(stdout,"info depth %d\n",(depth/2)); fflush(stdout); - for (cnt = 0; cnt < PVN && T(move = (MultiPV[cnt] & 0xFFFF)); cnt++) { - MultiPV[cnt] = move; - move_to_string(move,score_string); - if (T(Print)) sprintf(info_string,"info currmove %s currmovenumber %d\n",score_string,cnt + 1); - new_depth = depth - 2 + (ext = extension<1>(move, depth)); - do_move(move); - value = -pv_search(-MateValue,MateValue,new_depth,ExtFlag(ext)); - MultiPV[cnt] |= value << 16; - if (value < low) low = value; - undo_move(move); - for (i = cnt - 1; i >= 0; i--) { - if ((MultiPV[i] >> 16) < value) { - MultiPV[i + 1] = MultiPV[i]; - MultiPV[i] = move | (value << 16); - } - } - best_move = MultiPV[0] & 0xFFFF; - Current->score = MultiPV[0] >> 16; - send_multipv((depth/2), cnt); - } - for (;T(move = (MultiPV[cnt] & 0xFFFF)); cnt++) { - MultiPV[cnt] = move; - move_to_string(move,score_string); - if (T(Print)) sprintf(info_string,"info currmove %s currmovenumber %d\n",score_string,cnt + 1); - new_depth = depth - 2 + (ext = extension<1>(move, depth)); - do_move(move); - value = -search(-low, new_depth, FlagNeatSearch | ExtFlag(ext)); - if (value > low) value = -pv_search(-MateValue,-low,new_depth,ExtFlag(ext)); - MultiPV[cnt] |= value << 16; - undo_move(move); - if (value > low) { - for (i = cnt; i >= PVN; i--) MultiPV[i] = MultiPV[i - 1]; - MultiPV[PVN - 1] = move | (value << 16); - for (i = PVN - 2; i >= 0; i--) { - if ((MultiPV[i] >> 16) < value) { - MultiPV[i + 1] = MultiPV[i]; - MultiPV[i] = move | (value << 16); - } - } - best_move = MultiPV[0] & 0xFFFF; - Current->score = MultiPV[0] >> 16; - low = MultiPV[PVN - 1] >> 16; - send_multipv((depth/2), cnt); - } - } - return Current->score; -} - -void send_pv(int depth, int alpha, int beta, int score) { - int i, pos, move, mate = 0, mate_score, sel_depth; - sint64 nps, snodes, tbhits = 0; - if (F(Print)) return; - for (sel_depth = 1; sel_depth < 127 && T((Data + sel_depth)->att[0]); sel_depth++); - sel_depth--; - pv_length = 64; - if (F(move = best_move)) move = RootList[0]; - if (F(move)) return; - PV[0] = move; - if (Current->turn) do_move<1>(move); - else do_move<0>(move); - pvp = 1; - pick_pv(); - if (Current->turn ^ 1) undo_move<1>(move); - else undo_move<0>(move); - pos = 0; - for (i = 0; i < 64 && T(PV[i]); i++) { - if (pos > 0) { - pv_string[pos] = ' '; - pos++; - } - move = PV[i]; - pv_string[pos++] = ((move >> 6) & 7) + 'a'; - pv_string[pos++] = ((move >> 9) & 7) + '1'; - pv_string[pos++] = (move & 7) + 'a'; - pv_string[pos++] = ((move >> 3) & 7) + '1'; - if (IsPromotion(move)) { - if ((move & 0xF000) == FlagPQueen) pv_string[pos++] = 'q'; - else if ((move & 0xF000) == FlagPRook) pv_string[pos++] = 'r'; - else if ((move & 0xF000) == FlagPLight || (move & 0xF000) == FlagPDark) pv_string[pos++] = 'b'; - else if ((move & 0xF000) == FlagPKnight) pv_string[pos++] = 'n'; - } - pv_string[pos] = 0; - } - score_string[0] = 'c'; - score_string[1] = 'p'; - if (score > EvalValue) { - mate = 1; - strcpy(score_string,"mate "); - mate_score = (MateValue - score + 1)/2; - score_string[6] = 0; - } else if (score < -EvalValue) { - mate = 1; - strcpy(score_string,"mate "); - mate_score = -(score + MateValue + 1)/2; - score_string[6] = 0; - } else { - score_string[0] = 'c'; - score_string[1] = 'p'; - score_string[2] = ' '; - score_string[3] = 0; - } - nps = get_time() - StartTime; -#ifdef MP_NPS - snodes = Smpi->nodes; - tbhits = Smpi->tb_hits; -#else - snodes = nodes; + fprintf(stderr, "NYI...\n"); + abort(); +#if 0 + int move, low = MateValue, value, i, cnt, ext, new_depth = depth; + fprintf(stdout,"info depth %d\n",(depth/2)); fflush(stdout); + for (cnt = 0; cnt < PVN && T(move = (MultiPV[cnt] & 0xFFFF)); cnt++) { + MultiPV[cnt] = move; + move_to_string(move,score_string); + if (T(Print)) sprintf(info_string,"info currmove %s currmovenumber %d\n",score_string,cnt + 1); + new_depth = depth - 2 + (ext = extension<1>(move, depth)); + do_move(move); + value = -pv_search(-MateValue,MateValue,new_depth,ExtFlag(ext)); + MultiPV[cnt] |= value << 16; + if (value < low) low = value; + undo_move(move); + for (i = cnt - 1; i >= 0; i--) { + if ((MultiPV[i] >> 16) < value) { + MultiPV[i + 1] = MultiPV[i]; + MultiPV[i] = move | (value << 16); + } + } + INFO->bestMove = MultiPV[0] & 0xFFFF; + Current->score = MultiPV[0] >> 16; + send_multipv((depth/2), cnt); + } + for (;T(move = (MultiPV[cnt] & 0xFFFF)); cnt++) { + MultiPV[cnt] = move; + move_to_string(move,score_string); + if (T(Print)) sprintf(info_string,"info currmove %s currmovenumber %d\n",score_string,cnt + 1); + new_depth = depth - 2 + (ext = extension<1>(move, depth)); + do_move(move); + value = -search(-low, new_depth, FlagNeatSearch | ExtFlag(ext)); + if (value > low) value = -pv_search(-MateValue,-low,new_depth,ExtFlag(ext)); + MultiPV[cnt] |= value << 16; + undo_move(move); + if (value > low) { + for (i = cnt; i >= PVN; i--) MultiPV[i] = MultiPV[i - 1]; + MultiPV[PVN - 1] = move | (value << 16); + for (i = PVN - 2; i >= 0; i--) { + if ((MultiPV[i] >> 16) < value) { + MultiPV[i + 1] = MultiPV[i]; + MultiPV[i] = move | (value << 16); + } + } + INFO->bestMove = MultiPV[0] & 0xFFFF; + Current->score = MultiPV[0] >> 16; + low = MultiPV[PVN - 1] >> 16; + send_multipv((depth/2), cnt); + } + } + return Current->score; #endif - if (nps) nps = (snodes * 1000)/nps; - if (score < beta) { - if (score <= alpha) fprintf(stdout,"info depth %d seldepth %d score %s%d upperbound nodes %lld nps %lld tbhits %lld pv %s\n",depth,sel_depth,score_string,(mate ? mate_score : score),snodes,nps,tbhits,pv_string); - else fprintf(stdout,"info depth %d seldepth %d score %s%d nodes %lld nps %lld tbhits %lld pv %s\n",depth,sel_depth,score_string,(mate ? mate_score : score),snodes,nps,tbhits,pv_string); - } else fprintf(stdout,"info depth %d seldepth %d score %s%d lowerbound nodes %lld nps %lld tbhits %lld pv %s\n",depth,sel_depth,score_string,(mate ? mate_score : score),snodes,nps,tbhits,pv_string); - fflush(stdout); } void send_multipv(int depth, int curr_number) { - int i, j, pos, move, score; - sint64 nps, snodes, tbhits = 0; - if (F(Print)) return; - for (j = 0; j < PVN && T(MultiPV[j]); j++) { - pv_length = 63; - pvp = 0; - move = MultiPV[j] & 0xFFFF; - score = MultiPV[j] >> 16; - memset(PV,0,64 * sizeof(uint16)); - if (Current->turn) do_move<1>(move); - else do_move<0>(move); - pick_pv(); - if (Current->turn ^ 1) undo_move<1>(move); - else undo_move<0>(move); - for (i = 63; i > 0; i--) PV[i] = PV[i - 1]; - PV[0] = move; - pos = 0; - for (i = 0; i < 64 && T(PV[i]); i++) { - if (pos > 0) { - pv_string[pos] = ' '; - pos++; - } - move = PV[i]; - pv_string[pos++] = ((move >> 6) & 7) + 'a'; - pv_string[pos++] = ((move >> 9) & 7) + '1'; - pv_string[pos++] = (move & 7) + 'a'; - pv_string[pos++] = ((move >> 3) & 7) + '1'; - if (IsPromotion(move)) { - if ((move & 0xF000) == FlagPQueen) pv_string[pos++] = 'q'; - else if ((move & 0xF000) == FlagPRook) pv_string[pos++] = 'r'; - else if ((move & 0xF000) == FlagPLight || (move & 0xF000) == FlagPDark) pv_string[pos++] = 'b'; - else if ((move & 0xF000) == FlagPKnight) pv_string[pos++] = 'n'; - } - pv_string[pos] = 0; - } - score_string[0] = 'c'; - score_string[1] = 'p'; - if (score > EvalValue) { - strcpy(score_string,"mate "); - score = (MateValue - score + 1)/2; - score_string[6] = 0; - } else if (score < -EvalValue) { - strcpy(score_string,"mate "); - score = -(score + MateValue + 1)/2; - score_string[6] = 0; - } else { - score_string[0] = 'c'; - score_string[1] = 'p'; - score_string[2] = ' '; - score_string[3] = 0; - } - nps = get_time() - StartTime; -#ifdef MP_NPS - snodes = Smpi->nodes; - tbhits = Smpi->tb_hits; -#else - snodes = nodes; -#endif - if (nps) nps = (snodes * 1000)/nps; - fprintf(stdout,"info multipv %d depth %d score %s%d nodes %lld nps %lld tbhits %lld pv %s\n",j + 1,(j <= curr_number ? depth : depth - 1),score_string,score,snodes,nps,tbhits,pv_string); - fflush(stdout); - } -} - -void send_best_move() { - uint64 snodes; - int ponder; -#ifdef CPU_TIMING - GlobalTime[GlobalTurn] -= Convert(get_time() - StartTime, int) - GlobalInc[GlobalTurn]; - if (GlobalTime[GlobalTurn] < GlobalInc[GlobalTurn]) GlobalTime[GlobalTurn] = GlobalInc[GlobalTurn]; -#endif - if (F(Print)) return; -#ifdef MP_NPS - snodes = Smpi->nodes; -#else - snodes = nodes; -#endif - snodes += (snodes == 0); - fprintf(stdout,"info nodes %lld score cp %d\n",snodes,best_score); - if (!best_move) return; - Current = Data; - evaluate(); - if (Current->turn) do_move<1>(best_move); - else do_move<0>(best_move); - pv_length = 1; - pvp = 0; - pick_pv(); - ponder = PV[0]; - if (Current->turn ^ 1) undo_move<1>(best_move); - else undo_move<0>(best_move); - move_to_string(best_move,pv_string); - if (ponder) { - move_to_string(ponder,score_string); - fprintf(stdout,"bestmove %s ponder %s\n",pv_string,score_string); - } else fprintf(stdout,"bestmove %s\n",pv_string); - fflush(stdout); -} - -void get_position(char string[]) { - const char * fen; - char * moves; - const char * ptr; - int move, move1 = 0; - - fen = strstr(string,"fen "); - moves = strstr(string,"moves "); - if (fen != NULL) get_board(fen+4); - else get_board("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); - PrevMove = 0; - if (moves != NULL) { - ptr = moves+6; - while (*ptr != 0) { - pv_string[0] = *ptr++; - pv_string[1] = *ptr++; - pv_string[2] = *ptr++; - pv_string[3] = *ptr++; - if (*ptr == 0 || *ptr == ' ') pv_string[4] = 0; - else { - pv_string[4] = *ptr++; - pv_string[5] = 0; - } - evaluate(); - move = move_from_string(pv_string); - PrevMove = move1; - move1 = move; - if (Current->turn) do_move<1>(move); - else do_move<0>(move); - memcpy(Data,Current,sizeof(GData)); - Current = Data; - while (*ptr == ' ') ptr++; - } - } - memcpy(Stack, Stack + sp - Current->ply, (Current->ply + 1) * sizeof(uint64)); - sp = Current->ply; -} - -void get_time_limit(char string[]) { - const char * ptr; - int i, time, inc, wtime, btime, winc, binc, moves, pondering, movetime = 0, exp_moves = MovesTg - 1; - - Infinite = 1; - MoveTime = 0; - SearchMoves = 0; - SMPointer = 0; - pondering = 0; - TimeLimit1 = 0; - TimeLimit2 = 0; - wtime = btime = 0; - winc = binc = 0; - moves = 0; - Stop = 0; - DepthLimit = 128; - ptr = strtok(string," "); - for (ptr = strtok(NULL," "); ptr != NULL; ptr = strtok(NULL," ")) { - if (!strcmp(ptr,"binc")) { - ptr = strtok(NULL," "); - binc = atoi(ptr); - Infinite = 0; - } else if (!strcmp(ptr,"btime")) { - ptr = strtok(NULL," "); - btime = atoi(ptr); - Infinite = 0; - } else if (!strcmp(ptr,"depth")) { - ptr = strtok(NULL," "); - DepthLimit = 2 * atoi(ptr) + 2; - Infinite = 1; - } else if (!strcmp(ptr,"infinite")) { - Infinite = 1; - } else if (!strcmp(ptr,"movestogo")) { - ptr = strtok(NULL," "); - moves = atoi(ptr); - Infinite = 0; - } else if (!strcmp(ptr,"winc")) { - ptr = strtok(NULL," "); - winc = atoi(ptr); - Infinite = 0; - } else if (!strcmp(ptr,"wtime")) { - ptr = strtok(NULL," "); - wtime = atoi(ptr); - Infinite = 0; - } else if (!strcmp(ptr,"movetime")) { - ptr = strtok(NULL," "); - movetime = atoi(ptr); - MoveTime = 1; - Infinite = 0; - } else if (!strcmp(ptr,"searchmoves")) { - if (F(SearchMoves)) { - for (i = 0; i < 256; i++) SMoves[i] = 0; - } - SearchMoves = 1; - ptr += 12; - while (ptr != NULL && ptr[0] >= 'a' && ptr[0] <= 'h' && ptr[1] >= '1' && ptr[1] <= '8') { - pv_string[0] = *ptr++; - pv_string[1] = *ptr++; - pv_string[2] = *ptr++; - pv_string[3] = *ptr++; - if (*ptr == 0 || *ptr == ' ') pv_string[4] = 0; - else { - pv_string[4] = *ptr++; - pv_string[5] = 0; - } - SMoves[SMPointer] = move_from_string(pv_string); - SMPointer++; - ptr = strtok(NULL," "); - } - } else if (!strcmp(ptr,"ponder")) pondering = 1; - } - if (pondering) Infinite = 1; - if (Current->turn == White) { - time = wtime; - inc = winc; - } else { - time = btime; - inc = binc; - } -#ifdef CPU_TIMING - if (CpuTiming) { - time = GlobalTime[GlobalTurn]; - inc = GlobalInc[GlobalTurn]; - if (UciMaxDepth) DepthLimit = 2 * UciMaxDepth + 2; - } + fprintf(stderr, "NYI...\n"); + abort(); +#if 0 + int i, j, pos, move, score; + int64_t nps, snodes, tbhits = 0; + if (F(Print)) return; + for (j = 0; j < PVN && T(MultiPV[j]); j++) { + pv_length = 63; + pvp = 0; + move = MultiPV[j] & 0xFFFF; + score = MultiPV[j] >> 16; + memset(PV,0,64 * sizeof(uint16_t)); + if (Current->turn) do_move<1>(move); + else do_move<0>(move); + pick_pv(); + if (Current->turn ^ 1) undo_move<1>(move); + else undo_move<0>(move); + for (i = 63; i > 0; i--) PV[i] = PV[i - 1]; + PV[0] = move; + pos = 0; + for (i = 0; i < 64 && T(PV[i]); i++) { + if (pos > 0) { + pv_string[pos] = ' '; + pos++; + } + move = PV[i]; + pv_string[pos++] = ((move >> 6) & 7) + 'a'; + pv_string[pos++] = ((move >> 9) & 7) + '1'; + pv_string[pos++] = (move & 7) + 'a'; + pv_string[pos++] = ((move >> 3) & 7) + '1'; + if (IsPromotion(move)) { + if ((move & 0xF000) == FlagPQueen) pv_string[pos++] = 'q'; + else if ((move & 0xF000) == FlagPRook) pv_string[pos++] = 'r'; + else if ((move & 0xF000) == FlagPLight || (move & 0xF000) == FlagPDark) pv_string[pos++] = 'b'; + else if ((move & 0xF000) == FlagPKnight) pv_string[pos++] = 'n'; + } + pv_string[pos] = 0; + } + score_string[0] = 'c'; + score_string[1] = 'p'; + if (score > EvalValue) { + strcpy(score_string,"mate "); + score = (MateValue - score + 1)/2; + score_string[6] = 0; + } else if (score < -EvalValue) { + strcpy(score_string,"mate "); + score = -(score + MateValue + 1)/2; + score_string[6] = 0; + } else { + score_string[0] = 'c'; + score_string[1] = 'p'; + score_string[2] = ' '; + score_string[3] = 0; + } + nps = get_time() - StartTime; + snodes = 0; + for (int i = 0; i < SETTINGS->numThreads; i++) + { + snodes += THREADS[i]->nodes; + tbhits += THREADS[i]->tbHits; + } + if (nps) nps = (snodes * 1000)/nps; + fprintf(stdout,"info multipv %d depth %d score %s%d nodes %lld nps %lld tbhits %lld pv %s\n",j + 1,(j <= curr_number ? depth : depth - 1),score_string,score,snodes,nps,tbhits,pv_string); + fflush(stdout); + } #endif - if (moves) moves = Max(moves - 1, 1); - int time_max = Max(time - Min(1000, time/2), 0); - int nmoves; - if (moves) nmoves = moves; - else { - nmoves = MovesTg - 1; - if (Current->ply > 40) nmoves += Min(Current->ply - 40, (100 - Current->ply)/2); - exp_moves = nmoves; - } - TimeLimit1 = Min(time_max, (time_max + (Min(exp_moves, nmoves) * inc))/Min(exp_moves, nmoves)); - TimeLimit2 = Min(time_max, (time_max + (Min(exp_moves, nmoves) * inc))/Min(3,Min(exp_moves, nmoves))); - TimeLimit1 = Min(time_max, (TimeLimit1 * TimeRatio)/100); - if (Ponder) TimeLimit1 = (TimeLimit1 * PonderRatio)/100; - if (MoveTime) { - TimeLimit2 = movetime; - TimeLimit1 = TimeLimit2 * 100; - } - InfoTime = StartTime = get_time(); - Searching = 1; - if (MaxPrN > 1) SET_BIT_64(Smpi->searching, 0); - if (F(Infinite)) PVN = 1; - if (Current->turn == White) root<0>(); else root<1>(); } int time_to_stop(GSearchInfo * SI, int time, int searching) { - if (Infinite) return 0; - if (time > TimeLimit2) return 1; - if (searching) return 0; - if (2 * time > TimeLimit2 && F(MoveTime)) return 1; - if (SI->Bad) return 0; - if (time > TimeLimit1) return 1; - if (T(SI->Change) || T(SI->FailLow)) return 0; - if (time * 100 > TimeLimit1 * TimeNoChangeMargin) return 1; - if (F(SI->Early)) return 0; - if (time * 100 > TimeLimit1 * TimeNoPVSCOMargin) return 1; - if (SI->Singular < 1) return 0; - if (time * 100 > TimeLimit1 * TimeSingOneMargin) return 1; - if (SI->Singular < 2) return 0; - if (time * 100 > TimeLimit1 * TimeSingTwoMargin) return 1; - return 0; -} + if (SHARED->ponder) return 0; + if (time > SHARED->hardTimeLimit) return 1; + if (searching) return 0; + if (2 * time > SHARED->hardTimeLimit /*&& F(MoveTime)*/) return 1; + if (SI->Bad) return 0; + if (time > SHARED->softTimeLimit) return 1; + if (T(SI->Change) || T(SI->FailLow)) return 0; + if (time * 100 > SHARED->softTimeLimit * TimeNoChangeMargin) return 1; + if (F(SI->Early)) return 0; + if (time * 100 > SHARED->softTimeLimit * TimeNoPVSCOMargin) return 1; + if (SI->Singular < 1) return 0; + if (time * 100 > SHARED->softTimeLimit * TimeSingOneMargin) return 1; + if (SI->Singular < 2) return 0; + if (time * 100 > SHARED->softTimeLimit * TimeSingTwoMargin) return 1; + return 0; +} + +static void worker(void) +{ + setjmp(CheckJump); + while (true) + { + Current = Data; + mutex_lock(&SHARED->mutex); + assert(INFO->stop); + while (INFO->stop) + { + if (SHARED->state > STOPPED) + { + SHARED->state--; + if (SHARED->state == STOPPED && !SHARED->ponder) + send_best_move(); + } + wait_for_go(); + } -void check_time(int searching) { -#ifdef CPU_TIMING - if (CpuTiming && UciMaxKNodes && nodes > UciMaxKNodes * 1024) Stop = 1; -#endif -#ifdef TUNER -#ifndef TIMING - return; -#endif -#else - while (!Stop && input()) uci(); -#endif - int Time = 0; - if (Stop) goto jump; - CurrTime = get_time(); - Time = Convert(CurrTime - StartTime,int); - if (T(Print) && Time > InfoLag && CurrTime - InfoTime > InfoDelay) { - InfoTime = CurrTime; - if (info_string[0]) { - fprintf(stdout,"%s",info_string); - info_string[0] = 0; - fflush(stdout); - } - } - if (time_to_stop(CurrentSI, Time, searching)) goto jump; - return; -jump: - Stop = 1; - longjmp(Jump,1); -} + bool newGame = INFO->newGame; + INFO->newGame = false; -void check_time(int time, int searching) { -#ifdef TUNER -#ifndef TIMING - return; -#endif -#else - while (!Stop && input()) uci(); -#endif - int Time = 0; - if (Stop) goto jump; - CurrTime = get_time(); - Time = Convert(CurrTime - StartTime,int); - if (T(Print) && Time > InfoLag && CurrTime - InfoTime > InfoDelay) { - InfoTime = CurrTime; - if (info_string[0]) { - fprintf(stdout,"%s",info_string); - info_string[0] = 0; - fflush(stdout); - } - } - if (time_to_stop(CurrentSI, time, searching)) goto jump; - return; -jump: - Stop = 1; - longjmp(Jump,1); -} + mutex_unlock(&SHARED->mutex); -void check_state() { - GSP *Sp, *Spc; - int n, nc, score, best, pv, alpha, beta, new_depth, r_depth, ext, move, value; - GMove * M; - - if (parent) { - for (uint64 u = TEST_RESET(Smpi->fail_high); u; Cut(u)) { - Sp = &Smpi->Sp[lsb(u)]; - LOCK(Sp->lock); - if (Sp->active && Sp->finished) { - UNLOCK(Sp->lock); - longjmp(Sp->jump, 1); - } - UNLOCK(Sp->lock); - } - return; - } + if (newGame) + init_search(false); + + memcpy(Board, &SHARED->rootBoard, sizeof(GBoard)); + memcpy(Current, &SHARED->rootData, sizeof(GData)); + memcpy(Stack, &SHARED->rootStack, SHARED->rootSp * sizeof(uint64_t)); + sp = SHARED->rootSp; + Stack[sp] = Current->key; -start: - if (TEST_RESET_BIT(Smpi->stop, Id)) longjmp(CheckJump, 1); - if (Smpi->searching & Bit(Id)) return; - if (!(Smpi->searching & 1)) { - msleep(1); - return; - } - while ((Smpi->searching & 1) && !Smpi->active_sp) _mm_pause(); - while ((Smpi->searching & 1) && !(Smpi->searching & Bit(Id - 1))) _mm_pause(); - - Sp = NULL; best = -0x7FFFFFFF; - for (uint64 u = Smpi->active_sp; u; Cut(u)) { - Spc = &Smpi->Sp[lsb(u)]; - if (!Spc->active || Spc->finished || Spc->lock) continue; - for (nc = Spc->current + 1; nc < Spc->move_number; nc++) if (!(Spc->move[nc].flags & FlagClaimed)) break; - if (nc < Spc->move_number) score = 1024 * 1024 + 512 * 1024 * (Spc->depth >= 20) + 128 * 1024 * (!(Spc->split)) - + ((Spc->depth + 2 * Spc->singular) * 1024) - (((16 * 1024) * (nc - Spc->current)) / nc); - else continue; - if (score > best) { - best = score; - Sp = Spc; - n = nc; - } - } - - if (Sp == NULL) goto start; - if (!Sp->active || Sp->finished || (Sp->move[n].flags & FlagClaimed) || n <= Sp->current || n >= Sp->move_number) goto start; - if (Sp->lock) goto start; - - LOCK(Sp->lock); - if (!Sp->active || Sp->finished || (Sp->move[n].flags & FlagClaimed) || n <= Sp->current || n >= Sp->move_number) { - UNLOCK(Sp->lock); - goto start; - } - - M = &Sp->move[n]; - M->flags |= FlagClaimed; - M->id = Id; - Sp->split |= Bit(Id); - pv = Sp->pv; - alpha = Sp->alpha; - beta = Sp->beta; - new_depth = M->reduced_depth; - r_depth = M->research_depth; - ext = M->ext; - move = M->move; - - Current = Data; - retrieve_position(Sp->Pos, 1); - evaluate(); - SET_BIT_64(Smpi->searching, Id); - UNLOCK(Sp->lock); - - if (setjmp(CheckJump)) { - ZERO_BIT_64(Smpi->searching, Id); - return; - } - if (Current->turn == White) { - do_move<0>(move); - if (pv) { - value = -search<1, 0>(-alpha, new_depth, FlagNeatSearch | ExtFlag(ext)); - if (value > alpha) value = -pv_search<1, 0>(-beta, -alpha, r_depth, ExtFlag(ext)); - } else { - value = -search<1, 0>(1 - beta, new_depth, FlagNeatSearch | ExtFlag(ext)); - if (value >= beta && new_depth < r_depth) value = -search<1, 0>(1 - beta, r_depth, FlagNeatSearch | FlagDisableNull | ExtFlag(ext)); - } - undo_move<0>(move); - } else { - do_move<1>(move); - if (pv) { - value = -search<0, 0>(-alpha, new_depth, FlagNeatSearch | ExtFlag(ext)); - if (value > alpha) value = -pv_search<0, 0>(-beta, -alpha, r_depth, ExtFlag(ext)); - } else { - value = -search<0, 0>(1 - beta, new_depth, FlagNeatSearch | ExtFlag(ext)); - if (value >= beta && new_depth < r_depth) value = -search<0, 0>(1 - beta, r_depth, FlagNeatSearch | FlagDisableNull | ExtFlag(ext)); - } - undo_move<1>(move); - } - - LOCK(Sp->lock); - ZERO_BIT_64(Smpi->searching, Id); - if (TEST_RESET_BIT(Smpi->stop, Id)) { - UNLOCK(Sp->lock); - return; - } - M->flags |= FlagFinished; - if (value > Sp->alpha) { - Sp->alpha = Min(value, beta); - Sp->best_move = move; - if (value >= beta) { - Sp->finished = 1; - SET_BIT_64(Smpi->fail_high, (int)(Sp - Smpi->Sp)); - } - } - UNLOCK(Sp->lock); + if (Current->turn == White) + root<0>(); + else + root<1>(); + } } -void epd_test(const char *string, int time_limit) { - int n = 0, positions = 4000; - uint64 Time, all_nodes = 0, new_time, total_time; - double prod = 0.0; - char * ptr; - FILE * f = fopen(string, "r"); - if (f == NULL) { - fprintf(stdout, "File not found\n"); - return; - } - Infinite = 1; - Time = get_time(); - int total_depth = 0; - Print = 0; - Input = 0; - total_time = 1; - while (!feof(f) && n < positions) { - new_position: - (void)fgets(mstring, 65536, f); - ptr = strchr(mstring, '\n'); - if (ptr != NULL) *ptr = 0; - get_board(mstring); - evaluate(); - if (Current->turn == White) { - gen_root_moves<0>(); - } else { - gen_root_moves<1>(); - } - Infinite = 0; - MoveTime = TimeLimit1 = 100000000; -#ifndef TIME_TO_DEPTH - TimeLimit2 = time_limit; -#else - TimeLimit2 = TimeLimit1; -#endif - DepthLimit = 127; - n++; - Stop = 0; - Smpi->nodes = nodes = check_node = check_node_smp = 0; - StartTime = get_time(); - if (setjmp(Jump)) { - halt_all(0, 127); - stop_searching: - ZERO_BIT_64(Smpi->searching, Id); - Searching = 0; - Current = Data; - new_time = Max(get_time() - StartTime, 1); - total_time += new_time; -#ifdef MP_NPS - all_nodes += Smpi->nodes; -#else - all_nodes += nodes; -#endif - total_depth += LastDepth / 2; -#ifndef TIME_TO_DEPTH - fprintf(stdout, "Position %d: %d [%lf, %d]\n", n, LastDepth / 2, ((double)total_depth) / ((double)n), (all_nodes * Convert(1000, uint64)) / total_time); -#else - prod += log((double)new_time); - fprintf(stdout, "Position %d: %lld [%.0lf, %lld]\n", n, new_time, exp(prod / (double)n), (all_nodes * Convert(1000, uint64)) / total_time); -#endif - goto new_position; - } - for (int d = 4; d < 128; d += 2) { - LastDepth = d; - Searching = 1; - SET_BIT_64(Smpi->searching, Id); - if (Current->turn == White) { - pv_search<0, 1>(-MateValue, MateValue, d, FlagNeatSearch); - } else { - pv_search<1, 1>(-MateValue, MateValue, d, FlagNeatSearch); - } -#ifdef TIME_TO_DEPTH - if (d >= (time_limit * 2)) goto stop_searching; -#endif - } - } - if (n == 0) { - fprintf(stdout, "Empty file\n"); - return; - } - fclose(f); -} +template void root(void) +{ + int i, depth, value, alpha, beta, delta, start_depth = 2, hash_depth = 0, hash_value, store_time = 0, time_est, ex_depth = 0, ex_value, prev_time = 0, knodes = 0; + int64_t time; + GPVEntry * PVEntry; -void bench(int argc, char **argv) { - if (argc == 0) exit(1); - unsigned depth = atoi(argv[0]); - long long t0 = get_time(); - for (int i = 1; i < argc; i++) { - get_board(argv[i]); - sprintf(mstring, "go depth %u\n", depth); - get_time_limit(mstring); - } - fprintf(stderr, "time: %lld\n", get_time() - t0); - exit(0); -} + evaluate(); + gen_root_moves(); + if (PVN > 1) { +// memset(MultiPV,0,128 * sizeof(int)); +// for (i = 0; MultiPV[i] = RootList[i]; i++); + fprintf(stderr, "NYI...\n"); + abort(); + } + INFO->bestMove = RootList[0]; + if (F(INFO->bestMove)) + { + mutex_lock(&SHARED->mutex); + INFO->stop = true; + mutex_unlock(&SHARED->mutex); + return; + } + if (!RootList[1]) + { + value = pv_search(-MateValue, MateValue, 4, FlagNeatSearch); + LastDepth = 128; + send_pv(6, -MateValue, MateValue, value); + mutex_lock(&SHARED->mutex); + INFO->stop = true; + mutex_unlock(&SHARED->mutex); + return; + } -void uci() { - char *ptr = NULL; - int i; - sint64 value; - - (void)fgets(mstring, 65536, stdin); - if (feof(stdin)) exit(0); - ptr = strchr(mstring, '\n'); - if (ptr != NULL) *ptr = 0; - if (!strcmp(mstring, "uci")) { -#ifdef TB -#ifndef W32_BUILD - fprintf(stdout,"id name Gull 3 x64 (syzygy)\n"); -#else - fprintf(stdout,"id name Gull 3 (syzygy)\n"); -#endif -#else -#ifndef W32_BUILD - fprintf(stdout,"id name Gull 3 x64\n"); -#else - fprintf(stdout,"id name Gull 3\n"); -#endif -#endif - fprintf(stdout,"id author ThinkingALot\n"); -#ifndef W32_BUILD - fprintf(stdout,"option name Hash type spin min 1 max 65536 default 16\n"); -#else - fprintf(stdout,"option name Hash type spin min 1 max 1024 default 16\n"); -#endif - fprintf(stdout,"option name Ponder type check default false\n"); - fprintf(stdout,"option name MultiPV type spin min 1 max 64 default 1\n"); - fprintf(stdout,"option name Clear Hash type button\n"); - fprintf(stdout,"option name PV Hash type check default true\n"); - fprintf(stdout,"option name Aspiration window type check default true\n"); -#ifdef CPU_TIMING - fprintf(stdout, "option name CPUTiming type check default false\n"); - fprintf(stdout, "option name MaxDepth type spin min 0 max 128 default 0\n"); - fprintf(stdout, "option name MaxKNodes type spin min 0 max 65536 default 0\n"); - fprintf(stdout, "option name BaseTime type spin min 0 max 1000000 default 1000\n"); - fprintf(stdout, "option name IncTime type spin min 0 max 1000000 default 5\n"); -#endif - fprintf(stdout, "option name Threads type spin min 1 max %d default %d\n", Min(CPUs, MaxPrN), PrN); -#ifdef LARGE_PAGES - fprintf(stdout, "option name Large memory pages type check default true\n"); -#endif -#ifdef TB - fprintf(stdout, "option name SyzygyPath type string default \n"); -#endif - fprintf(stdout,"uciok\n"); - if (F(Searching)) init_search(1); - } else if (!strcmp(mstring,"ucinewgame")) { - Stop = 0; - init_search(1); - } else if (!strcmp(mstring,"isready")) { - fprintf(stdout,"readyok\n"); - fflush(stdout); - } else if (!memcmp(mstring,"position",8)) { - if (F(Searching)) get_position(mstring); - } else if (!memcmp(mstring,"go",2)) { - if (F(Searching)) get_time_limit(mstring); - } else if (!memcmp(mstring,"setoption",9)) { - ptr = strtok(mstring," "); - for (ptr = strtok(NULL," "); ptr != NULL; ptr = strtok(NULL," ")) { - if (!memcmp(ptr,"Hash",4) && !Searching) { - ptr += 11; - value = atoi(ptr); - if (value < 1) value = 1; -#ifdef W32_BUILD - if (value > 1024) value = 1024; -#else - if (value > 65536) value = 65536; -#endif - value = (Bit(msb(value)) * Convert(1024 * 1024, sint64)) / Convert(sizeof(GEntry), sint64); - if (value != hash_size) { - ResetHash = 1; - hash_size = value; - longjmp(ResetJump, 1); - } - } else if (!memcmp(ptr, "Threads", 7) && !Searching) { - ptr += 14; - value = atoi(ptr); - if (value != PrN) { - NewPrN = Max(1, Min(MaxPrN, value)); - ResetHash = 0; - longjmp(ResetJump, 1); - } -#ifdef TB - } else if (!memcmp(ptr, "SyzygyPath", 10)) { - ptr += 17; - strncpy(Smpi->tb_path,ptr,sizeof(Smpi->tb_path)-1); - ResetHash = 0; - longjmp(ResetJump, 1); -#endif - } else if (!memcmp(ptr, "MultiPV", 7)) { - ptr += 14; - PVN = atoi(ptr); - Stop = 1; - } else if (!memcmp(ptr,"Ponder",6)) { - ptr += 13; - if (ptr[0] == 't') Ponder = 1; - else Ponder = 0; - } else if (!memcmp(ptr,"Clear",5)) { - init_search(1); - break; - } else if (!memcmp(ptr,"PV",2)) { - ptr += 14; - if (ptr[0] == 't') PVHashing = 1; - else PVHashing = 0; - } else if (!memcmp(ptr, "Large", 5) && !Searching) { - ptr += 25; - if (ptr[0] == 't') { - if (LargePages) return; - LargePages = 1; - } else { - if (!LargePages) return; - LargePages = 0; - } - ResetHash = 1; - longjmp(ResetJump, 1); - } else if (!memcmp(ptr, "Aspiration", 10)) { - ptr += 24; - if (ptr[0] == 't') Aspiration = 1; - else Aspiration = 0; - } -#ifdef CPU_TIMING - else if (!memcmp(ptr, "CPUTiming", 9)) { - ptr += 16; - if (ptr[0] == 't') CpuTiming = 1; - else CpuTiming = 0; - } else if (!memcmp(ptr, "MaxDepth", 8)) UciMaxDepth = atoi(ptr + 15); - else if (!memcmp(ptr, "MaxKNodes", 9)) UciMaxKNodes = atoi(ptr + 16); - else if (!memcmp(ptr, "BaseTime", 8)) UciBaseTime = atoi(ptr + 15); - else if (!memcmp(ptr, "IncTime", 7)) UciIncTime = atoi(ptr + 14); -#endif + memset(CurrentSI,0,sizeof(GSearchInfo)); + memset(BaseSI,0,sizeof(GSearchInfo)); + Previous = -MateValue; + if (PVEntry = probe_pv_hash()) + { + if (is_legal(PVEntry->move) && + PVEntry->move == INFO->bestMove && + PVEntry->depth > hash_depth) + { + hash_depth = PVEntry->depth; + hash_value = PVEntry->value; + ex_depth = PVEntry->ex_depth; + ex_value = PVEntry->exclusion; + knodes = PVEntry->knodes; } - } else if (!strcmp(mstring,"stop")) { - Stop = 1; - if (F(Searching)) send_best_move(); - } else if (!strcmp(mstring,"ponderhit")) { - Infinite = 0; - if (!RootList[1]) Stop = 1; - if (F(CurrentSI->Bad) && F(CurrentSI->FailLow) && time_to_stop(BaseSI, LastTime, 0)) Stop = 1; - if (F(Searching)) send_best_move(); - } else if (!strcmp(mstring, "quit")) { -#ifdef WINDOWS - for (i = 1; i < PrN; i++) { - TerminateProcess(ChildPr[i], 0); - CloseHandle(ChildPr[i]); - } -#endif - exit(0); - } else if (!memcmp(mstring, "epd", 3)) { - ptr = mstring + 4; - value = atoi(ptr); - epd_test("op.epd", value); - } -} - -int main(int argc, char *argv[]) { - int i, HT = 0, dobench = 0; - - if (argc >= 2) if (!memcmp(argv[1], "child", 5)) { - child = 1; parent = 0; - WinParId = atoi(argv[2]); - Id = atoi(argv[3]); - } - if (argc >= 2) if (!memcmp(argv[1], "bench", 5)) dobench = 1; - - unsigned a, b, c, d; - builtin_cpuid(1, a, b, c, d); - HardwarePopCnt = ((c >> 23) & 1); - - if (parent) { -#ifdef WINDOWS - DWORD p; - int CPUInfo[4] = { -1 }; - __cpuid(CPUInfo, 1); - if (((CPUInfo[3] >> 28) & 1) && GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation") != NULL) { - SYSTEM_LOGICAL_PROCESSOR_INFORMATION syslogprocinfo[1]; - p = sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); -#ifndef W32_BUILD - GetLogicalProcessorInformation(syslogprocinfo, &p); - if (syslogprocinfo->ProcessorCore.Flags == 1) HT = 1; -#endif - } - WinParId = GetProcessId(GetCurrentProcess()); - HANDLE JOB = CreateJobObject(NULL, NULL); - JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 }; - jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; - SetInformationJobObject(JOB, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)); - AssignProcessToJobObject(JOB, GetCurrentProcess()); - if (MaxPrN > 1) { - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - CPUs = sysinfo.dwNumberOfProcessors; - PrN = Min(CPUs, MaxPrN); - if (HT) PrN = Max(1, Min(PrN, CPUs / 2)); - } -#else // LINUX, MACOSX - WinParId = 0; - CPUs = sysconf(_SC_NPROCESSORS_ONLN); // TODO: HT? - PrN = CPUs; - atexit(cleanup); - signal(SIGHUP, handler); // TODO: better way? - signal(SIGINT, handler); - signal(SIGQUIT, handler); - signal(SIGILL, handler); - signal(SIGABRT, handler); - signal(SIGSEGV, handler); - signal(SIGPIPE, handler); - signal(SIGTERM, handler); -#endif - } - -#ifdef CPU_TIMING - SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS); -#endif - - // Read parameters from environment (optional). - const char *val; - if (parent) { - if ((val = getenv("GULL_HASH")) != NULL) - hash_size = (Bit(msb(atoi(val))) * Convert(1024 * 1024, sint64)) / - Convert(sizeof(GEntry), sint64); - if ((val = getenv("GULL_THREADS")) != NULL) - PrN = atoi(val); - } - - init(); - -#ifdef TB - if (parent && (val = getenv("GULL_SYZYGY_PATH")) != NULL) - strncpy(Smpi->tb_path,val,sizeof(Smpi->tb_path)-1); -#endif - -#ifdef WINDOWS - DWORD p; - StreamHandle = GetStdHandle(STD_INPUT_HANDLE); - Console = GetConsoleMode(StreamHandle, &p); - if (Console) { - SetConsoleMode(StreamHandle, p & (~(ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT))); - FlushConsoleInputBuffer(StreamHandle); - } -#endif - - setbuf(stdout, NULL); - setbuf(stdin, NULL); - setvbuf(stdout, NULL, _IONBF, 0); - setvbuf(stdin, NULL, _IONBF, 0); - fflush(NULL); - - if (parent) -#ifdef TB -#ifndef W32_BUILD - fprintf(stdout, "Gull 3 x64 (syzygy)\n"); -#else - fprintf(stdout, "Gull 3 (syzygy)\n"); -#endif -#else -#ifndef W32_BUILD - fprintf(stdout, "Gull 3 x64\n"); -#else - fprintf(stdout, "Gull 3\n"); -#endif + } + if (T(hash_depth) && PVN == 1) + { + Previous = INFO->bestScore = hash_value; + depth = hash_depth; + if (PVHashing) + { + send_pv(depth/2, -MateValue, MateValue, INFO->bestScore); + start_depth = (depth + 2) & (~1); + } + if ((depth >= LastDepth - 8 || T(store_time)) && + LastValue >= LastExactValue && + hash_value >= LastExactValue && + T(LastTime) && T(LastSpeed)) + { + time = SHARED->softTimeLimit; + if (ex_depth >= depth - Min(12, depth/2) && + ex_value <= hash_value - ExclSinglePV(depth)) + { + BaseSI->Early = 1; + BaseSI->Singular = 1; + if (ex_value <= hash_value - ExclDoublePV(depth)) + { + time = (time * TimeSingTwoMargin)/100; + BaseSI->Singular = 2; + } + else time = (time * TimeSingOneMargin)/100; + } + time_est = Min(LastTime,(knodes << 10)/LastSpeed); + time_est = Max(time_est, store_time); +set_prev_time: + LastTime = prev_time = time_est; +#if 0 + // This is broken so disable for now... + if (prev_time >= time) + { + InstCnt++; + if (time_est <= store_time) InstCnt = 0; + if (InstCnt > 2) + { + if (T(store_time) && store_time < time_est) + { + time_est = store_time; + goto set_prev_time; + } + LastSpeed = 0; + LastTime = 0; + prev_time = 0; + goto set_jump; + } + if (hash_value > 0 && Current->ply >= 2 && + F(Square(To(INFO->bestMove))) && + F(INFO->bestMove & 0xF000) && + PrevMove == + ((To(INFO->bestMove) << 6) | From(INFO->bestMove))) + goto set_jump; + do_move(INFO->bestMove); + if (Current->ply >= 100) + { + undo_move(INFO->bestMove); + goto set_jump; + } + for (i = 4; i <= Current->ply; i+=2) + { + if (Stack[sp-i] == Current->key) + { + undo_move(INFO->bestMove); + goto set_jump; + } + } + undo_move(INFO->bestMove); + LastDepth = depth; + LastTime = prev_time; + LastValue = LastExactValue = hash_value; + mutex_lock(&SHARED->mutex); + INFO->stop = true; + mutex_unlock(&SHARED->mutex); + return; + } + else #endif + goto set_jump; + } + } + LastTime = 0; -reset_jump: -#ifndef TUNER - if (parent) { - if (setjmp(ResetJump)) { -#ifdef WINDOWS - for (i = 1; i < PrN; i++) TerminateProcess(ChildPr[i], 0); - for (i = 1; i < PrN; i++) { - WaitForSingleObject(ChildPr[i], INFINITE); - CloseHandle(ChildPr[i]); - } -#else // LINUX, MACOSX - for (i = 1; i < PrN; i++) kill(ChildPr[i], SIGPIPE); -#endif - Smpi->searching = Smpi->active_sp = Smpi->stop = 0; - for (i = 0; i < MaxSplitPoints; i++) Smpi->Sp->active = Smpi->Sp->claimed = 0; - - Smpi->hash_size = hash_size; - if (NewPrN) Smpi->PrN = PrN = NewPrN; - goto reset_jump; - } - Smpi->hash_size = hash_size; - Smpi->PrN = PrN; - } else { - hash_size = Smpi->hash_size; - PrN = Smpi->PrN; - } -#endif - if (ResetHash) init_hash(); - init_search(0); +set_jump: + memcpy(SaveBoard,Board,sizeof(GBoard)); + memcpy(SaveData,Data,sizeof(GData)); + save_sp = sp; + for (depth = start_depth; depth < SHARED->depthLimit; depth += 2) + { + INFO->depth = depth; + uint32_t sched = + Schedule[INFO->id % (sizeof(Schedule) / sizeof(Schedule[0]))]; + unsigned idx = (SHARED->rootDepth + depth / 2) % 24; + if (((sched >> idx) & 0x1) == 0) + continue; + + memset(Data + 1, 0, 127 * sizeof(GData)); + CurrentSI->Early = 1; + CurrentSI->Change = CurrentSI->FailHigh = CurrentSI->FailLow = + CurrentSI->Singular = 0; + if (PVN > 1) + value = multipv(depth); + else if ((depth/2) < 7 || F(Aspiration)) + LastValue = LastExactValue = value = + pv_search(-MateValue, MateValue, depth, FlagNeatSearch); + else + { + delta = 8; + alpha = Previous - delta; + beta = Previous + delta; +loop: + if (delta >= 16 * 32) + { + LastValue = LastExactValue = value = + pv_search(-MateValue, MateValue, depth, + FlagNeatSearch); + goto finish; + } + value = pv_search(alpha, beta, depth, FlagNeatSearch); + if (value <= alpha) + { + CurrentSI->FailHigh = 0; + CurrentSI->FailLow = 1; + alpha -= delta; + delta *= 2; + LastValue = value; + memcpy(BaseSI,CurrentSI,sizeof(GSearchInfo)); + goto loop; + } + else if (value >= beta) + { + CurrentSI->FailHigh = 1; + CurrentSI->FailLow = 0; + CurrentSI->Early = 1; + CurrentSI->Change = 0; + CurrentSI->Singular = Max(CurrentSI->Singular, 1); + beta += delta; + delta *= 2; + LastDepth = depth; + LastTime = MaxF(prev_time,get_time() - SHARED->startTime); + LastSpeed = INFO->nodes/Max(LastTime, 1); + if (depth + 2 < SHARED->depthLimit) depth += 2; + InstCnt = 0; + if (INFO->id == 0 && time_to_stop(CurrentSI, LastTime, false)) + { + mutex_lock(&SHARED->mutex); + stop(); + mutex_unlock(&SHARED->mutex); + goto stop; + } + memset(Data + 1, 0, 127 * sizeof(GData)); + LastValue = value; + memcpy(BaseSI,CurrentSI,sizeof(GSearchInfo)); + goto loop; + } else + LastValue = LastExactValue = value; + } +finish: + if (value < Previous - 50) + CurrentSI->Bad = 1; + else + CurrentSI->Bad = 0; + memcpy(BaseSI,CurrentSI,sizeof(GSearchInfo)); + LastDepth = depth; + LastTime = MaxF(prev_time,get_time() - SHARED->startTime); + LastSpeed = INFO->nodes/Max(LastTime, 1); + Previous = value; + InstCnt = 0; + if (INFO->id == 0 && time_to_stop(CurrentSI, LastTime, false)) + { + mutex_lock(&SHARED->mutex); + stop(); + mutex_unlock(&SHARED->mutex); + goto stop; + } + } -#ifdef TB - tb_init(Smpi->tb_path); -#endif +stop: + + Current = Data; + memcpy(Board,SaveBoard,sizeof(GBoard)); + memcpy(Data,SaveData,sizeof(GData)); + sp = save_sp; + if (!INFO->stop) + { + mutex_lock(&SHARED->mutex); + INFO->stop = true; + mutex_unlock(&SHARED->mutex); + } +} - if (dobench) bench(argc-2, argv+2); - if (child) while (true) check_state(); - if (parent) for (i = 1; i < PrN; i++) ChildPr[i] = CreateChildProcess(i); +void send_pv(int depth, int alpha, int beta, int score) +{ + int sel_depth; + for (sel_depth = 1; sel_depth < 127 && T((Data + sel_depth)->att[0]); + sel_depth++); + sel_depth--; + int move = (INFO->bestMove == 0? RootList[0]: INFO->bestMove); + mutex_lock(&SHARED->mutex); + INFO->selDepth = sel_depth; + INFO->PV[0] = move; + if (Current->turn) do_move<1>(move); else do_move<0>(move); + unsigned pvPtr = 1, pvLen = 64; + pick_pv(pvPtr, pvLen); + if (Current->turn ^ 1) undo_move<1>(move); else undo_move<0>(move); + if (INFO->id != 0) + { + mutex_unlock(&SHARED->mutex); + return; + } -#ifdef EXPLAIN_EVAL - get_board("3rr1k1/1pp2qpp/pnn1pp2/8/3PPB2/PQ3N1P/1PR2PP1/2R3K1 b - - 0 28"); - fexplain = fopen("evaluation.txt", "w"); - explain = 1; evaluate(); - fclose(fexplain); - fprintf(stdout, "Press any key...\n"); getchar(); exit(0); -#endif + size_t nodes = 0, tbHits = 0; + for (unsigned i = 0; i < SETTINGS->numThreads; i++) + { + nodes += THREADS[i]->nodes; + tbHits += THREADS[i]->tbHits; + } + send_pv(THREADS[0]->PV, nodes, tbHits, THREADS[0]->depth, + THREADS[0]->selDepth, THREADS[0]->bestScore, + THREADS[0]->bestMove, SHARED->startTime); + mutex_unlock(&SHARED->mutex); +} + +static void send_pv(const int *PV, size_t nodes, size_t tbHits, int depth, + int selDepth, int bestScore, int bestMove, uint64_t startTime) +{ + const char *scoreType = "mate"; + if (bestScore > EvalValue) + bestScore = (MateValue - bestScore + 1) / 2; + else if (bestScore < -EvalValue) + bestScore = -(bestScore + MateValue + 1) / 2; + else + scoreType = "cp"; + + uint64_t currTime = get_time(); + uint64_t elapsedTime = currTime - startTime; + if (elapsedTime == 0) + elapsedTime = 1; + + size_t nps = (nodes * 1000) / elapsedTime; + + char pvStr[BUFSIZ]; + unsigned pvPos = 0; + for (unsigned i = 0; i < MAX_PV_LEN && PV[i] != 0; i++) + { + if (pvPos >= sizeof(pvStr) - 32) + break; + int move = PV[i]; + pvStr[pvPos++] = ' '; + pvStr[pvPos++] = ((move >> 6) & 7) + 'a'; + pvStr[pvPos++] = ((move >> 9) & 7) + '1'; + pvStr[pvPos++] = (move & 7) + 'a'; + pvStr[pvPos++] = ((move >> 3) & 7) + '1'; + if (IsPromotion(move)) + { + if ((move & 0xF000) == FlagPQueen) + pvStr[pvPos++] = 'q'; + else if ((move & 0xF000) == FlagPRook) + pvStr[pvPos++] = 'r'; + else if ((move & 0xF000) == FlagPLight || + (move & 0xF000) == FlagPDark) + pvStr[pvPos++] = 'b'; + else if ((move & 0xF000) == FlagPKnight) + pvStr[pvPos++] = 'n'; + } + } + pvStr[pvPos++] = '\0'; + + char line[BUFSIZ]; + int len = snprintf(line, sizeof(line)-1, "info depth %d seldepth %d score " + "%s %d multipv 1 nodes %zu nps %zu tbhits %zu time %ld pv%s\n", + depth/2, selDepth/2, scoreType, bestScore, nodes, nps, tbHits, + currTime - startTime, pvStr); + if (len < 0 || len >= sizeof(line)-1) + return; + put_line(line, len); +} + +static void send_curr_move(int move, int cnt) +{ + if (INFO->id != 0) + return; + uint64_t currTime = get_time(); + uint64_t diffTime = currTime - SHARED->startTime; + if (currTime - SHARED->startTime <= InfoLag || + currTime - InfoTime <= InfoDelay) + return; + InfoTime = currTime; + char moveStr[16], line[BUFSIZ]; + move_to_string(move, moveStr); + int len = snprintf(line, sizeof(line)-1, + "info currmove %s currmovenumber %d\n", moveStr, cnt); + if (len > 0 && len < sizeof(line)-1) + { + mutex_lock(&SHARED->mutex); + put_line(line, len); + mutex_unlock(&SHARED->mutex); + } +} -#ifdef TUNER - if (argc >= 2) { - if (!memcmp(argv[1], "client", 6)) Client = 1; - else if (!memcmp(argv[1], "server", 6)) Server = 1; - if (Client || Server) Local = 0; - } - fprintf(stdout, Client ? "Client\n" : (Server ? "Server\n" : "Local\n")); - - uint64 ctime; QueryProcessCycleTime(GetCurrentProcess(), &ctime); srand(time(NULL) + 123 * GetProcessId(GetCurrentProcess()) + ctime); - QueryProcessCycleTime(GetCurrentProcess(), &ctime); seed = (uint64)(time(NULL) + 345 * GetProcessId(GetCurrentProcess()) + ctime); - init_openings(); - init_variables(); - - if (Client) { -#ifdef RECORD_GAMES - RecordGames = 1; - Buffer = (char*)malloc(16 * 1024 * 1024); -#endif - while (true) get_command(); - } +static void send_best_move(void) +{ + size_t nodes = THREADS[0]->nodes, tbHits = THREADS[0]->tbHits; + GThreadInfo *bestThread = THREADS[0]; - init_pst(); - init_eval(); - print_eval(); + for (unsigned i = 1; i < SETTINGS->numThreads; i++) + { + nodes += THREADS[i]->nodes; + tbHits += THREADS[i]->tbHits; + if (THREADS[i]->depth > bestThread->depth && bestThread->depth == 0) + bestThread = THREADS[i]; + } + send_best_move(bestThread->PV, nodes, tbHits, bestThread->bestScore, + bestThread->bestMove, SHARED->startTime); +} + +static void send_best_move(const int *PV, size_t nodes, size_t tbHits, + int bestScore, int bestMove, uint64_t startTime) +{ + uint64_t stopTime = get_time(); + + if (nodes == 0) + nodes = 1; + const char *scoreType = "mate"; + if (bestScore > EvalValue) + bestScore = (MateValue - bestScore + 1) / 2; + else if (bestScore < -EvalValue) + bestScore = -(bestScore + MateValue + 1) / 2; + else + scoreType = "cp"; + + char line[BUFSIZ]; + uint64_t time = stopTime - startTime; + uint64_t nps = (nodes / Max(time / 1000, 1)); + int len = snprintf(line, sizeof(line)-1, "info nodes %zu tbhits %zu " + "time %ld nps %ld score %s %d\n", nodes, tbHits, time, nps, scoreType, + bestScore); + if (len > 0 && len < sizeof(line)-1) + put_line(line, len); + + char moveStr[16], ponderStr[16]; + int ponder = (PV[0] == 0? 0: PV[1]); + move_to_string(bestMove, moveStr); + if (ponder != 0) + { + move_to_string(ponder, ponderStr); + len = snprintf(line, sizeof(line)-1, "bestmove %s ponder %s\n", + moveStr, ponderStr); + } + else + len = snprintf(line, sizeof(line)-1, "bestmove %s\n", moveStr); + if (len > 0 && len < sizeof(line)-1) + put_line(line, len); + else + { + // Giveup: + char reply[] = "bestmove 0\n"; + put_line(reply, sizeof(reply)); + } +} - //read_list("(-0.24,0.69,-3.56,14.38,-18.97,-9.43,31.93,-42.58,-84.76,-239.60,62.93,83.44,-124.95,25.59,-22.50,152.24,472.44,-652.13,-903.63,-16.63,11.50,-0.02,-202.44,29.65,-2.27,-62.69,-81.95,61.32,-492.11,-51.01,-23.03,-15.79,283.90,-116.64,-4.38,-92.49,-30.59,-48.53,-35.85,15.25,-83.44,-32.20,33.31,-14.71,27.13,215.48,-48.91,-107.82,5.28,-59.32,-9.16,-16.93,-21.26,-21.12,-35.52,-41.67,-35.52,-16.59,21.48,-1.20,-26.27,-23.81,-58.82,-9.36,38.87,-34.02,-10.33,0.07,101.64,11.30,-66.04,-4.39,10.43,-60.66,-6.41,0.68,-15.18,-69.89,-41.54,-84.48,-143.38,-46.16,-3.12,-13.96,31.00,-16.14,-89.96,100.44,-137.64,97.51,-85.03,62.93,78.39,444.37,-143.70,25.65,-74.57,-143.94,-106.03,-128.86,285.08,111.90,-24.94,-104.36,-142.29,-59.11,-92.95,-32.91,-153.55,15.40,-181.39,-35.76,14.98,-5.08,76.49,-80.38,177.51,132.39,-134.36,-6.67,49.81,-260.99,101.53,-41.31,-26.30,418.42,220.09,-127.18,762.99,-117.88,246.62,-203.99,18.52,266.32,290.73,112.16,292.84,127.11,277.25,189.46,214.95,304.06,399.54,-195.77,280.34,351.89,-485.96,-2.82,251.09,38.25,82.39,152.04,53.11,8.04,7.61,-21.45,10.43,-0.53,4.19,-9.26,13.89,14.56,19.18,7.64,-2.16,138.97,6.71,57.43,0.28,56.89,0.92,-9.14,35.31,1.05,8.57,10.12,34.71,0.23,71.71,76.05,153.65,114.23,85.39,1.34,-12.79,26.11,48.42,125.83,147.73,148.27,41.60,42.53,-14.37,6.87,-6.88,-2.23,130.20,22.09,45.46,15.40,13.11,8.80,2.28,2.99,-0.83,-3.11,-0.81,4.40,6.09,6.27,5.79,5.24,-2.88,-0.26,16.45,-2.67,11.20,7.72,6.17,1.23,3.61,0.08,-0.51,-0.25,9.09,2.08,0.69,0.35,13.18,6.69,0.52,1.58,1.56,-0.95,11.40,0.81,-6.78,3.32,-4.89,8.87,-5.50,31.67,0.30,2.94,0.18,5.42,14.11,33.51,28.03,32.65,21.20,11.16,48.32,14.90,4.31,2.41,2.18,2.69,0.78,0.05,4.27,1.51,17.77,7.82,5.21,1.29,0.15,4.35,-0.12,-0.06,-0.25,3.24,5.37,5.85,14.36,-1.62,9.45,0.47,4.07,5.19,26.33,2.20,20.31,37.81,1.02,82.85,56.61,23.77,19.82,-3.83,47.50,25.50)", Base, active_vars); - //eval_to_cpp("gd.cpp", Base); +static inline int64_t get_number(const char *token) +{ + if (token == NULL) + return 0; + return (int64_t)atoll(token); +} + +void uci(void) +{ + char line[4 * BUFSIZ]; + uint64_t currTime = get_time(); + + mutex_lock(&SHARED->mutex); + while (true) + { + while (true) + { + uint64_t timeout = UINT64_MAX; + if (SHARED->state != STOPPED) + timeout = 50; // 50ms + mutex_unlock(&SHARED->mutex); + + bool timedout = get_line(line, sizeof(line)-1, timeout); + currTime = get_time(); + + if (mutex_lock(&SHARED->mutex, 500)) + { + emergency_stop(); + mutex_lock(&SHARED->mutex); + } + if (SHARED->state != STOPPED && + currTime >= SHARED->startTime + SHARED->hardTimeLimit) + { + stop(); + wait_for_stop(); + } + if (!timedout) + break; + } + + if (line[0] == EOF) + { + nuke_children(); + exit(EXIT_SUCCESS); + } + char *saveptr = NULL; + char *token = strtok_r(line, " ", &saveptr); + if (token == NULL) + /* NOP */ ; + else if (strcmp(token, "go") == 0) + { + if (SHARED->state != STOPPED) + continue; + unsigned binc = 0, btime = 0, depth = 256, movestogo = 0, + winc = 0, wtime = 0, movetime = 0; + bool infinite = false, ponder = false; + while ((token = strtok_r(NULL, " ", &saveptr)) != NULL) + { + if (strcmp(token, "binc") == 0) + binc = get_number(strtok_r(NULL, " ", &saveptr)); + else if (strcmp(token, "btime") == 0) + btime = get_number(strtok_r(NULL, " ", &saveptr)); + else if (strcmp(token, "winc") == 0) + winc = get_number(strtok_r(NULL, " ", &saveptr)); + else if (strcmp(token, "wtime") == 0) + wtime = get_number(strtok_r(NULL, " ", &saveptr)); + else if (strcmp(token, "movetime") == 0) + movetime = get_number(strtok_r(NULL, " ", &saveptr)); + else if (strcmp(token, "movetogo") == 0) + movestogo = get_number(strtok_r(NULL, " ", &saveptr)); + else if (strcmp(token, "depth") == 0) + depth = get_number(strtok_r(NULL, " ", &saveptr)); + else if (strcmp(token, "infinite") == 0) + infinite = true; + else if (strcmp(token, "ponder") == 0) + ponder = true; + } + unsigned time = (Current->turn == White? wtime: btime); + unsigned inc = (Current->turn == White? winc: binc); + if (movetime == 0 && time == 0 && inc == 0) + infinite = true; + if (movestogo != 0) + movestogo = Max(movestogo-1, 1); + int time_max = Max(time - Min(1000, time/2), 0); + int nmoves; + int exp_moves = MovesTg - 1; + if (movestogo != 0) + nmoves = movestogo; + else + { + nmoves = MovesTg - 1; + if (Current->ply > 40) + nmoves += Min(Current->ply - 40, (100 - Current->ply)/2); + exp_moves = nmoves; + } + uint64_t softTimeLimit = 0, hardTimeLimit = 0; + softTimeLimit = Min(time_max, + (time_max + (Min(exp_moves, nmoves) * inc)) / + Min(exp_moves, nmoves)); + hardTimeLimit = Min(time_max, + (time_max + (Min(exp_moves, nmoves) * inc)) / + Min(3, Min(exp_moves, nmoves))); + softTimeLimit = Min(time_max, (softTimeLimit * TimeRatio)/100); + if (movetime != 0) + { + hardTimeLimit = movetime; + softTimeLimit = UINT32_MAX; + } + else if (infinite) + hardTimeLimit = softTimeLimit = UINT32_MAX; + SHARED->ponder = ponder; + SHARED->softTimeLimit = softTimeLimit; + SHARED->hardTimeLimit = hardTimeLimit; + SHARED->depthLimit = 2 * depth + 2; + SHARED->startTime = currTime; + go(); + } + else if (strcmp(token, "isready") == 0) + { + char reply[] = "readyok\n"; + put_line(reply, sizeof(reply)-1); + } + else if (strcmp(token, "stop") == 0) + { + if (SHARED->state == STOPPED) + continue; + stop(); + wait_for_stop(); + } + else if (strcmp(token, "ponderhit") == 0) + { + SHARED->ponder = false; + if (SHARED->state == STOPPED) + send_best_move(); + } + else if (strcmp(token, "position") == 0) + { + token = strtok_r(NULL, " ", &saveptr); + if (token == NULL) + goto bad_command; + char *moves; + if (strcmp(token, "fen") == 0) + { + char *fen = token + strlen(token) + 1; + moves = (char *)get_board(fen); + } + else if (strcmp(token, "startpos") == 0) + { + moves = saveptr; + get_board( + "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); + } + else + goto bad_command; + token = strtok_r(moves, " ", &saveptr); + if (token == NULL || strcmp(token, "moves") != 0) + goto bad_command; + while ((token = strtok_r(NULL, " ", &saveptr)) != NULL) + { + int move = move_from_string(token); + if (Current->turn) do_move<1>(move); else do_move<0>(move); + memcpy(Data, Current, sizeof(GData)); + Current = Data; + SHARED->rootDepth++; + } + memcpy(Stack, Stack + sp - Current->ply, + (Current->ply + 1) * sizeof(uint64_t)); + sp = Current->ply; + } + else if (strcmp(token, "setoption") == 0) + { + token = strtok_r(NULL, " ", &saveptr); + if (token == NULL || strcmp(token, "name") != 0) + goto bad_command; + const char *name = strtok_r(NULL, " ", &saveptr); + if (name == NULL) + goto bad_command; + token = strtok_r(NULL, " ", &saveptr); + if (token == NULL || strcmp(token, "value") != 0) + goto bad_command; + if (token == NULL) + goto bad_command; + unsigned numThreads = SETTINGS->numThreads; + unsigned syzygyProbeDepth = SETTINGS->syzygyProbeDepth; + size_t hashSize = SETTINGS->hashSize; + int64_t n = 0; + if (strcmp(name, "Hash") == 0) + { + uint64_t n = get_number(strtok_r(NULL, " ", &saveptr)); + hashSize = HASH_SIZE(n); + } + else if (strcmp(name, "Threads") == 0) + numThreads = get_number(strtok_r(NULL, " ", &saveptr)); + else if (strcmp(name, "SyzygyPath") == 0) + { + if (saveptr != NULL && strlen(saveptr) < sizeof(SyzygyPath)-1) + memcpy(SyzygyPath, saveptr, strlen(saveptr)+1); + } + else if (strcmp(name, "SyzygyProbeDepth") == 0) + syzygyProbeDepth = get_number(strtok_r(NULL, " ", &saveptr)); + else + goto bad_command; + reset(numThreads, syzygyProbeDepth, hashSize, SyzygyPath); + } + else if (strcmp(token, "ucinewgame") == 0) + { + if (SHARED->state != STOPPED) + continue; + init_search(true); + for (unsigned i = 0; i < SETTINGS->numThreads; i++) + THREADS[i]->newGame = true; + } + else if (strcmp(token, "uci") == 0) + { + char reply[] = + "id name LazyGull\n" + "id author ThinkingALot\n" + "option name Hash type spin min 1 max 8388608 default 128\n" + "option name Threads type spin min 1 max 64 default 4\n" + "option name SyzygyPath type string default \n" + "option name SyzygyProbeDepth type spin min 0 max 64 " + "default 6\n" + "uciok\n"; + put_line(reply, sizeof(reply)-1); + } + else if (strcmp(token, "quit") == 0) + { + nuke_children(); + exit(EXIT_SUCCESS); + } + else + { +bad_command: + log("warning: unknown command\n"); + } + } +} - save_list(Base); +int main(int argc, char **argv) +{ + if (argc > 1) + { + if (argc != 10) + { + usage: + fprintf(stderr, "usage: %s\n", argv[0]); + exit(EXIT_FAILURE); + } + if (strcmp(argv[1], "child") != 0) + goto usage; + + // CHILD: + const char + *hashStr = argv[2], + *pvHashStr = argv[3], + *pawnHashStr = argv[4], + *dataStr = argv[5], + *settingsStr = argv[6], + *sharedStr = argv[7], + *infoStr = argv[8], + *tbPath = argv[9]; + init_object(dataStr, sizeof(GGlobalData), DATA, false, true, true, + NULL); + init_object(settingsStr, sizeof(GSettings), SETTINGS, false, + true, true, NULL); + init_object(sharedStr, sizeof(GSharedInfo), SHARED, false, false, + true, NULL); + init_object(hashStr, SETTINGS->hashSize, HASH, false, false, true, + NULL); + init_object(pvHashStr, pvHashSize, PVHASH, false, false, true, + NULL); + init_object(pawnHashStr, pawnHashSize, PAWNHASH, false, false, + true, NULL); + init_object(infoStr, sizeof(GThreadInfo), INFO, false, false, true, + NULL); + INFO->pid = get_pid(); + tb_init(tbPath); + for (unsigned i = 0; i < SETTINGS->numThreads; i++) + { + if (i == INFO->id) + { + THREADS[i] = INFO; + continue; + } + char infoName[256] = {0}; + init_object_name(infoName, sizeof(infoName)-1, "INFO", i); + THREADS[i] = (GThreadInfo *)init_object(infoName, + sizeof(GThreadInfo), NULL, false, false, true, NULL); + } + init_search(false); - //pgn_stat(); -#ifdef RECORD_GAMES - match_los(Base, Base, 4 * 64 * 1024, 512, 7, 0.0, 0.0, 0.0, 0.0, MatchInfo, 1); -#endif + // Signal that we are initialized. + mutex_lock(&SHARED->mutex); + SHARED->init--; + if (SHARED->init == 0) + cond_signal(&SHARED->initCondVar); + mutex_unlock(&SHARED->mutex); - double NormalizedVar[MaxVariables]; NormalizeVar(Base,Var,2,256,10.0,20.0,NormalizedVar); double_to_double(Var,NormalizedVar,active_vars); - //read_list("(4.10,3.41,7.24,11.13,44.59,41.51,67.17,126.38,183.25,328.40,95.55,442.95,110.04,439.85,199.82,506.49,1000.00,531.27,1000.00,94.70,40.64,96.88,182.65,154.15,152.52,490.96,231.09,605.53,1000.00,36.49,55.68,30.62,35.70,21.40,18.08,38.61,48.23,17.96,33.78,25.56,31.86,16.40,22.84,18.78,35.36,26.99,27.03,27.50,41.10,24.01,21.96,28.26,24.41,19.37,21.28,49.80,30.27,10.66,12.25,43.65,28.65,35.98,75.89,26.88,47.37,8.62,37.29,22.31,60.45,28.59,18.53,100.00,54.22,9.86,10.63,83.68,25.20,124.05,121.47,93.76,81.23,48.30,56.78,56.15,67.16,78.24,169.91,68.80,114.34,43.30,55.89,95.85,122.56,102.36,77.96,112.11,88.70,53.74,76.44,47.93,46.64,70.83,57.70,137.88,108.52,125.92,79.97,33.71,49.84,44.58,192.99,129.64,271.09,79.00,145.01,69.40,193.09,156.78,186.59,391.22,150.93,346.72,80.75,230.85,128.81,46.74,49.53,19.18,39.71,27.84,39.56,60.18,55.76,40.46,31.10,34.48,41.23,25.69,22.04,14.65,27.90,31.79,85.75,49.45,100.00,48.27,25.91,60.07,62.46)", Var, active_vars); + worker(); // Wait for work from parent. + } - GD(Base,Var,7,5.0,1.0,50.0,16 * 1024,16 * 1024,3.0,2.0,2.0,0.0); + // PARENT: + printf("LazyGull\n"); + + // Read override parameters from the environment (useful for debugging) + unsigned numThreads = get_num_cpus(); + size_t hashSize = 128 * (1 << 20); // 128MB + size_t syzygyProbeDepth = 6; + SyzygyPath[0] = '\0'; + const char *val; + if ((val = getenv("GULL_HASH_SIZE")) != NULL) + hashSize = HASH_SIZE((size_t)atoi(val)); + if ((val = getenv("GULL_THREADS")) != NULL) + numThreads = atoi(val); + if ((val = getenv("GULL_SYZYGY_PATH")) != NULL) + strncpy(SyzygyPath, val, sizeof(SyzygyPath)-1); + if ((val = getenv("GULL_SYZYGY_PROBE_DEPTH")) != NULL) + syzygyProbeDepth = atoi(val); + + PVN = 1; // XXX NYI + + create_children(numThreads, syzygyProbeDepth, hashSize, SyzygyPath); + init_search(false); + + while (true) + uci(); + return 0; +} + +/* + * Create the child processes. + */ +static void create_children(size_t numThreads, size_t syzygyProbeDepth, + size_t hashSize, const char *tbPath) +{ + const size_t maxHashSize = 8 * ((size_t)1 << 40); // 8TB + const size_t maxNumThreads = 256; + const size_t maxSyzygyProbeDepth = 64; + hashSize = Min(maxHashSize, hashSize); + numThreads = Min(maxNumThreads, numThreads); + syzygyProbeDepth = Min(maxSyzygyProbeDepth, syzygyProbeDepth); + + log("settings: numThreads=%zu, hashSize=%zu, " + "syzygyProbeDepth=%zu, syzygyPath=\"%s\"\n", + numThreads, hashSize, syzygyProbeDepth, tbPath); + + // Create shared objects: + char dataName[256] = {0}; + init_object_name(dataName, sizeof(dataName)-1, "DATA", 0); + init_object(dataName, sizeof(GGlobalData), DATA, true, false, true, NULL); + init_data(); + + char settingsName[256] = {0}; + init_object_name(settingsName, sizeof(settingsName)-1, "SETTINGS", 0); + GSettings settings; + settings.numThreads = numThreads; + settings.syzygyProbeDepth = syzygyProbeDepth; + settings.hashSize = hashSize; + init_object(settingsName, sizeof(settings), SETTINGS, true, true, true, + &settings); + + char hashName[256] = {0}; + init_object_name(hashName, sizeof(hashName)-1, "HASH", 0); + init_object(hashName, hashSize, HASH, true, false, true, NULL); + + char pvHashName[256] = {0}; + init_object_name(pvHashName, sizeof(pvHashName)-1, "PVHASH", 0); + init_object(pvHashName, pvHashSize, PVHASH, true, false, true, NULL); + + char pawnHashName[256] = {0}; + init_object_name(pawnHashName, sizeof(pawnHashName)-1, "PAWNHASH", 0); + init_object(pawnHashName, pawnHashSize, PAWNHASH, true, false, true, + NULL); + + char sharedName[256] = {0}; + init_object_name(sharedName, sizeof(sharedName)-1, "SHARED", 0); + init_object(sharedName, sizeof(GSharedInfo), SHARED, true, false, true, + NULL); + SHARED->init = numThreads; + mutex_init(&SHARED->mutex); + cond_init(&SHARED->goCondVar); + cond_init(&SHARED->initCondVar); + + // Create children: + for (size_t i = 0; i < numThreads; i++) + { + char infoName[256] = {0}; + init_object_name(infoName, sizeof(infoName)-1, "INFO", i); + THREADS[i] = (GThreadInfo *)init_object(infoName, sizeof(GThreadInfo), + NULL, true, false, true, NULL); + THREADS[i]->stop = true; + THREADS[i]->newGame = true; + THREADS[i]->id = (unsigned)i; + } + for (size_t i = 0; i < numThreads; i++) + { + char infoName[256] = {0}; + init_object_name(infoName, sizeof(infoName)-1, "INFO", i); + create_child(hashName, pvHashName, pawnHashName, dataName, + settingsName, sharedName, infoName, tbPath); + } - double New[1024]; read_list("(5.07,27.02,27.37,15.16,28.60,14.62,40.93,8.61,14.02,172.58,178.09,180.83,457.03,128.24,172.66,178.21,343.44,1281.53,45.85)", New, active_vars); - for (i = 7; i < 64; i++) { - fprintf(stdout, "\ndepth = %d/%d: \n", i, i + 1); - match_los(New, Base, 4 * 1024, 128, i, 3.0, 3.0, 0.0, 0.0, MatchInfo, 1); - } -#endif + init_object(NULL, sizeof(GThreadInfo), INFO, true, false, true, NULL); + tb_init(SyzygyPath); + + // Wait for threads to finish initializing: + mutex_lock(&SHARED->mutex); + while (SHARED->init != 0) + cond_wait(&SHARED->initCondVar, &SHARED->mutex); + mutex_unlock(&SHARED->mutex); + + // Cleanup: + remove_object(dataName); + remove_object(settingsName); + remove_object(hashName); + remove_object(pvHashName); + remove_object(pawnHashName); + remove_object(sharedName); + for (size_t i = 0; i < numThreads; i++) + { + char infoName[256] = {0}; + init_object_name(infoName, sizeof(infoName)-1, "INFO", i); + remove_object(infoName); + } +} - while (true) uci(); +/* + * Kill all children ungracefully. + */ +static void nuke_children(void) +{ + for (size_t i = 0; i < SETTINGS->numThreads; i++) + nuke_child(THREADS[i]->pid); + delete_object(HASH, SETTINGS->hashSize); + delete_object(PAWNHASH, pawnHashSize); + for (size_t i = 0; i < SETTINGS->numThreads; i++) + delete_object(THREADS[i], sizeof(GThreadInfo)); + delete_object(DATA, sizeof(GGlobalData)); + delete_object(SETTINGS, sizeof(GSettings)); + delete_object(SHARED, sizeof(GSharedInfo)); +} + +/* + * Reset (e.g. change of parameters). + */ +static void reset(size_t numThreads, size_t syzygyProbeDepth, size_t hashSize, + const char *tbPath) +{ + nuke_children(); + create_children(numThreads, syzygyProbeDepth, hashSize, tbPath); } + diff --git a/src/Linux.cpp b/src/Linux.cpp index 77751ed..59c9583 100644 --- a/src/Linux.cpp +++ b/src/Linux.cpp @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -36,8 +38,12 @@ #include #include -#include +#include #include +#include + +#define UINT64_MAX 0xFFFFFFFFFFFFFFFFull // XXX +#define UINT32_MAX 0xFFFFFFFF #ifdef MACOSX // MacOSX: #include @@ -50,117 +56,154 @@ __asm__ __volatile__ ("cpuid" : "=a" (ax), "=b" (bx), "=c" (cx), \ "=d" (dx) : "a" (f)) -#define builtin_popcnt_u64(x) _mm_popcnt_u64((x)) +#define PAGE_SIZE 4096 +#define SIZE(size) ((((size)-1) / PAGE_SIZE) * PAGE_SIZE + PAGE_SIZE) + +/* + * Log a message. + */ +static void log(const char *format, ...) +{ + FILE *stream = fopen("gull.log", "a"); + if (stream == NULL) + return; + va_list ap; + va_start(ap, format); + vfprintf(stream, format, ap); + va_end(ap); + fclose(stream); +} /* - * Replacements for the Windows Interlocked* functions. + * Print an error message. */ -#define builtin_sync_fetch_and_add(x, y) \ - __sync_fetch_and_add((x), (y)) -#define builtin_sync_fetch_and_or(x, y) \ - __sync_fetch_and_or((x), (y)) -#define builtin_sync_fetch_and_and(x, y) \ - __sync_fetch_and_and((x), (y)) -#define builtin_sync_bit_test_and_reset(x, y) \ - ((__sync_fetch_and_and((x), ~(1 << (y))) & (1 << (y))) != 0) -#define builtin_sync_lock_test_and_set(x, y) \ - __sync_lock_test_and_set((x), (y)) -#define builtin_sync_val_compare_and_swap(x, y, z) \ - __sync_val_compare_and_swap((x), (z), (y)) +#define error(format, ...) \ + do { \ + log("error: " format "\n", ##__VA_ARGS__); \ + fprintf(stderr, "error: " format "\n", ##__VA_ARGS__); \ + abort(); \ + } while (false) /* - * Initialize the hash table. + * Init an object name. */ -void init_hash() +void init_object_name(char *name, size_t len, const char *basename, int idx) { - static sint64 old_size = 0; - sint64 size = hash_size * sizeof(GEntry); - if (parent && Hash != NULL) - munmap(Hash, old_size); - old_size = size; - if (parent) - { - // Unlike Windows Gull there is no need to create a file for this - // mapping. Instead, the child process will simply inherit the - // mapping after the fork(). - int prot = PROT_READ | PROT_WRITE, - flags = MAP_SHARED | MAP_ANONYMOUS; - Hash = (GEntry *)mmap(NULL, size, prot, flags, -1, 0); - assert(Hash != MAP_FAILED); - } - hash_mask = hash_size - 4; + int r = snprintf(name, len, "/GULL_%s_%d", basename, idx); + if (r < 0 || r >= len) + error("failed to create object name: %s\n", strerror(errno)); } /* - * Initialize shared memory regions. + * Init an object. */ -void init_shared() +void *init_object(const char *object, size_t size, void *addr, + bool create, bool readonly, bool map, const void *value) { - // This is similar to init_hash(). - static sint64 old_size = 0; - sint64 size = SharedPVHashOffset + pv_hash_size * sizeof(GPVEntry); - if (parent && Smpi != NULL) - munmap(Smpi, old_size); - old_size = size; - if (parent) + int fd = -1; + int flags = 0; + if (object != NULL) + { + if (create) + fd = shm_open(object, O_RDWR | O_CREAT | O_CLOEXEC, + S_IRUSR | S_IWUSR); + else + fd = shm_open(object, O_RDWR | O_CLOEXEC, 0); + if (fd < 0) + error("failed to open object %s: %s", object, strerror(errno)); + if (create && ftruncate(fd, SIZE(size)) != 0) + error("failed to truncate object %s: %s", object, strerror(errno)); + flags |= MAP_SHARED; + } + else + flags |= MAP_PRIVATE | MAP_ANONYMOUS; + if (map) { - int prot = PROT_READ | PROT_WRITE, - flags = MAP_SHARED | MAP_ANONYMOUS; - Smpi = (GSMPI *)mmap(NULL, size, prot, flags, -1, 0); - assert(Smpi != MAP_FAILED); + int prot = PROT_READ | (readonly && value == NULL? 0: PROT_WRITE); + flags |= (addr == NULL? 0: MAP_FIXED); + void *ptr = mmap(addr, SIZE(size), prot, flags, fd, 0); + if (ptr == MAP_FAILED) + error("failed to map object %s: %s", object, strerror(errno)); + if (value != NULL) + { + memcpy(ptr, value, size); + if (readonly && mprotect(ptr, SIZE(size), PROT_READ) != 0) + error("failed to protect object %s: %s", object, + strerror(errno)); + } + if (fd > 0) + close(fd); + return ptr; } - Material = (GMaterial*)(((char*)Smpi) + SharedMaterialOffset); - MagicAttacks = (uint64*)(((char*)Smpi) + SharedMagicOffset); - PVHash = (GPVEntry*)(((char*)Smpi) + SharedPVHashOffset); + if (fd > 0) + close(fd); + return NULL; } /* - * Test if input is available. + * Remove object. */ -int input() +void remove_object(const char *object) { - struct pollfd fds; - int ret; - fds.fd = 0; // stdin - fds.events = POLLIN; - return poll(&fds, 1, 0); + if (shm_unlink(object) != 0) + error("failed to unlink object %s: %s", object, strerror(errno)); } /* - * Create a child process and return its ID. + * Delete an object. */ -int main(int argc, char **argv); // Forward decl. -GProcess CreateChildProcess(int child_id) +void delete_object(void *addr, size_t size) { - GProcess id = fork(); - if (id != 0) - return id; + if (munmap(addr, SIZE(size)) != 0) + error("failed to unmap object: %s", strerror(errno)); +} - close(0); // No need for stdin, stdout, stderr - close(1); - close(2); +/* + * Create a child process. + */ +void create_child(const char *hashName, const char *pvHashName, + const char *pawnHashName, const char *dataName, const char *settingsName, + const char *sharedName, const char *infoName, const char *tbPath) +{ + pid_t pid = fork(); + if (pid < 0) + error("failed to fork: %s", strerror(errno)); + if (pid != 0) + return; + prctl(PR_SET_PDEATHSIG, SIGHUP); + char exe[BUFSIZ]; + ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe)-1); + if (len < 0) + error("failed to read link: %s", strerror(errno)); + exe[len] = '\0'; + execl(exe, "Gull", "child", hashName, pvHashName, pawnHashName, + dataName, settingsName, sharedName, infoName, tbPath, NULL); + error("failed to exec: %s", strerror(errno)); +} -#ifndef MACOSX - // Linux: - prctl(PR_SET_PDEATHSIG, SIGHUP); // Ensure that the child dies with - // the parent. (necessary?) -#endif +/* + * Get the process ID. + */ +unsigned get_pid(void) +{ + return (unsigned)getpid(); +} - // Gull expects the child process to enter through main(). - // So we simply call main() here: - char child_id_buf[32]; - int ret = snprintf(child_id_buf, sizeof(child_id_buf)-1, "%d", child_id); - assert(ret > 0 && ret < sizeof(child_id_buf)-1); - const char *argv[] = - { - "Gull", // Ignored, can be anything. - "child", - "0", - child_id_buf, - NULL - }; - ret = main(4, (char **)argv); - exit(ret); +/* + * Get the number of CPUs. + */ +unsigned get_num_cpus(void) +{ + return (unsigned)sysconf(_SC_NPROCESSORS_ONLN); +} + +/* + * Nuke a chold process. + */ +static void nuke_child(unsigned pid) +{ + kill((pid_t)pid, SIGKILL); + waitpid(pid, NULL, 0); } /* @@ -174,41 +217,152 @@ static void msleep(unsigned ms) /* * Get the time in milliseconds. */ -sint64 get_time() +int64_t get_time() { #ifndef MACOSX // Linux: struct timespec ts; unsigned tick = 0; - clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + clock_gettime(CLOCK_MONOTONIC, &ts); tick = ts.tv_nsec / 1000000; tick += ts.tv_sec * 1000; return tick; #else // MacOSX: - return (sint64)mach_absolute_time() / 1000000; + return (int64_t)mach_absolute_time() / 1000000; #endif } /* - * Cleanup child processes. + * Threads. */ -void cleanup(void) +#include +#include + +static void mutex_init(GMutex *mutex) { - if (!parent) - return; - int i; - for (i = 1; i < PrN; i++) - kill(ChildPr[i], SIGPIPE); + pthread_mutexattr_t attrs; + pthread_mutexattr_init(&attrs); + pthread_mutexattr_setpshared(&attrs, PTHREAD_PROCESS_SHARED); + pthread_mutex_init(mutex, &attrs); +} + +static void cond_init(GCondVar *condVar) +{ + pthread_condattr_t attrs; + pthread_condattr_init(&attrs); + pthread_condattr_setpshared(&attrs, PTHREAD_PROCESS_SHARED); + pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC); + pthread_cond_init(condVar, &attrs); +} + +#define mutex_unlock pthread_mutex_unlock +#define cond_signal pthread_cond_signal +#define cond_broadcast pthread_cond_broadcast +#define cond_wait pthread_cond_wait + +static void mutex_lock(GMutex *mutex) +{ + pthread_mutex_lock(mutex); +} + +static bool mutex_lock(GMutex *mutex, uint64_t timeout) +{ + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts) != 0) + { + // Backup strat. + mutex_lock(mutex); + return false; + } + ts.tv_nsec += timeout * 1000000; + int r = pthread_mutex_timedlock(mutex, &ts); + return (r == ETIMEDOUT); } /* - * Deadly signal handler. + * Input. */ -void handler(int sig) +static bool get_line(char *line, unsigned linelen, uint64_t timeout) { - cleanup(); - signal(sig, SIG_DFL); - raise(sig); + static char buf[4 * BUFSIZ]; + static unsigned ptr = 0, end = 0; + unsigned i = 0; + + while (true) + { + bool space = false; + while (ptr < end) + { + if (i >= linelen) + error("input buffer overflow"); + char c = buf[ptr++]; + switch (c) + { + case ' ': case '\r': case '\t': case '\n': + if (!space) + { + line[i++] = ' '; + space = true; + } + if (c == '\n') + { + line[i-1] = '\0'; + return false; + } + continue; + default: + space = false; + line[i++] = c; + continue; + } + } + + struct timeval tv; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + fd_set fds; + FD_ZERO(&fds); + FD_SET(STDIN_FILENO, &fds); + ssize_t res = select(STDIN_FILENO+1, &fds, NULL, NULL, &tv); + if (res < 0) + error("failed to wait for input: %s", strerror(errno)); + if (res == 0) + return true; // Timeout + + do + { + res = read(STDIN_FILENO, buf, sizeof(buf)); + } + while (res < 0 && errno == EINTR); + + if (res == 0) + { + line[0] = EOF; + return false; + } + if (res < 0) + error("failed to read input: %s", strerror(errno)); + + ptr = 0; + end = res; + } +} + +/* + * Output. + */ +static void put_line(char *line, unsigned linelen) +{ + unsigned ptr = 0; + while (ptr < linelen) + { + int res = write(STDOUT_FILENO, line + ptr, linelen - ptr); + if (res < 0 && errno == EINTR) + continue; + if (res < 0) + error("failed to write output: %s", strerror(errno)); + ptr += (unsigned)res; + } } diff --git a/src/Linux.h b/src/Linux.h index ca284f3..d8124d9 100644 --- a/src/Linux.h +++ b/src/Linux.h @@ -24,13 +24,27 @@ #ifndef LINUX_H #define LINUX_H +#include #include #include +#include typedef int *GHandle; typedef int GProcess; +typedef pthread_mutex_t GMutex; +typedef pthread_cond_t GCondVar; #define __forceinline inline #define __align(x) __attribute__((aligned(x))) +#define PATH_MAX 4096 + +#define INFO ((GThreadInfo *)0x300000) +#define SETTINGS ((GSettings *)0x301000) +#define SHARED ((GSharedInfo *)0x302000) +#define DATA ((GGlobalData *)0x8000000) +#define PAWNHASH ((GPawnEntry *)0x10000000) +#define PVHASH ((GPVEntry *)0x20000000) +#define HASH ((GEntry *)0x40000000) + #endif diff --git a/src/Makefile b/src/Makefile index 4388d44..9248c6b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -13,50 +13,17 @@ ifeq ($(UNAME),Darwin) endif CC=g++ STRIP=strip -CFLAGS=-msse4.1 -mpopcnt -fno-exceptions -fno-rtti -Wno-parentheses -O3 +CFLAGS=-msse4.1 -mpopcnt -fno-exceptions -fno-rtti -Wno-parentheses -O3 \ + -lpthread -lrt main: $(TARGET) -syzygy: $(TARGET_SYZYGY) - -gull.linux: - $(CC) $(CFLAGS) -D LINUX Gull.cpp -o Gull - $(STRIP) Gull - cp Gull Gull.linux - -gull.syzygy.linux: tbprobe.o - $(CC) $(CFLAGS) -D LINUX -D TB Gull.cpp tbprobe.o -o Gull - $(STRIP) Gull - cp Gull Gull.syzygy.linux - -gull.macosx: - $(CC) $(CFLAGS) -D MACOSX Gull.cpp -o Gull - $(STRIP) Gull - cp Gull Gull.macosx - -gull.syzygy.macosx: tbprobe.o - $(CC) $(CFLAGS) -D MACOSX -D TB Gull.cpp tbprobe.o -o Gull - $(STRIP) Gull - cp Gull Gull.syzygy.macosx - -gull.windows: CC=x86_64-w64-mingw32-g++ -gull.windows: STRIP=x86_64-w64-mingw32-strip -gull.windows: - $(CC) $(CFLAGS) -D WINDOWS Gull.cpp -o Gull.exe - $(STRIP) Gull.exe - -gull.syzygy.windows: CC=x86_64-w64-mingw32-g++ -gull.syzygy.windows: STRIP=x86_64-w64-mingw32-strip -gull.syzygy.windows: tbprobe_windows.o - $(CC) $(CFLAGS) -D WINDOWS -D TB Gull.cpp tbprobe_windows.o -o Gull.exe - $(STRIP) Gull.exe +gull.linux: tbprobe.o + $(CC) $(CFLAGS) -D LINUX Gull.cpp tbprobe.o -o LazyGull + $(STRIP) LazyGull tbprobe.o: tbprobe.c tbcore.c - $(CC) $(CFLAGS) -c tbprobe.c - -tbprobe_windows.o: CC=x86_64-w64-mingw32-g++ -tbprobe_windows.o: tbprobe.c tbcore.c - $(CC) $(CFLAGS) -c tbprobe.c -o tbprobe_windows.o + $(CC) $(CFLAGS) -D LINUX -c tbprobe.c tbprobe.c: Fathom-master.zip unzip -o -j Fathom-master.zip "Fathom-master/src/tbprobe.h" -d "./" @@ -71,5 +38,5 @@ Fathom-master.zip: -O Fathom-master.zip clean: - rm -f Gull + rm -f LazyGull tbprobe.o diff --git a/src/data.c b/src/data.c new file mode 100644 index 0000000..87c1af6 --- /dev/null +++ b/src/data.c @@ -0,0 +1,715 @@ +#include + +uint64_t BMagicAttacks(int i, uint64_t occ) +{ + uint64_t att = 0; + for (uint64_t u = DATA->BMask[i]; T(u); Cut(u)) + if (F(DATA->Between[i][lsb(u)] & occ)) + att |= DATA->Between[i][lsb(u)] | Bit(lsb(u)); + return att; +} + +uint64_t RMagicAttacks(int i, uint64_t occ) +{ + uint64_t att = 0; + for (uint64_t u = DATA->RMask[i]; T(u); Cut(u)) + if (F(DATA->Between[i][lsb(u)] & occ)) + att |= DATA->Between[i][lsb(u)] | Bit(lsb(u)); + return att; +} + +static void init_magic(void) +{ + int i, j, k, index, bits, bit_list[16]; + uint64_t u; + + for (i = 0; i < 64; i++) + { + bits = 64 - BShift[i]; + for (u = DATA->BMagicMask[i], j = 0; T(u); Cut(u), j++) + bit_list[j] = lsb(u); + for (j = 0; j < Bit(bits); j++) + { + u = 0; + for (k = 0; k < bits; k++) + if (Odd(j >> k)) Add(u,bit_list[k]); + index = Convert(BOffset[i] + ((BMagic[i] * u) >> BShift[i]),int); + DATA->MagicAttacks[index] = BMagicAttacks(i, u); + } + bits = 64 - RShift[i]; + for (u = DATA->RMagicMask[i], j = 0; T(u); Cut(u), j++) + bit_list[j] = lsb(u); + for (j = 0; j < Bit(bits); j++) + { + u = 0; + for (k = 0; k < bits; k++) + if (Odd(j >> k)) Add(u,bit_list[k]); + index = Convert(ROffset[i] + ((RMagic[i] * u) >> RShift[i]),int); + DATA->MagicAttacks[index] = RMagicAttacks(i, u); + } + } + for (int i = 0; i < 64; i++) + { + DATA->BOffsetPointer[i] = DATA->MagicAttacks + BOffset[i]; + DATA->ROffsetPointer[i] = DATA->MagicAttacks + ROffset[i]; + } + memcpy(DATA->BMagic, BMagic, sizeof(DATA->BMagic)); + memcpy(DATA->RMagic, RMagic, sizeof(DATA->RMagic)); + memcpy(DATA->BShift, BShift, sizeof(DATA->BShift)); + memcpy(DATA->RShift, RShift, sizeof(DATA->RShift)); +} + +static void init_misc(void) +{ + int i, j, k, l, n; + uint64_t u; + + for (i = 0; i < 8; i++) + { + DATA->File[i] = FileA << i; + DATA->Line[i] = Line0 << (8 * i); + } + for (i = 0; i < 64; i++) for (j = 0; j < 64; j++) if (i != j) + { + u = Bit(j); + if (File(i) == File(j)) DATA->VLine[i] |= u; + if (Rank(i) == Rank(j)) DATA->HLine[i] |= u; + if (NDiag(i) == NDiag(j)) DATA->NDiag[i] |= u; + if (SDiag(i) == SDiag(j)) DATA->SDiag[i] |= u; + if (Dist(i,j) <= 2) + { + DATA->DArea[i] |= u; + if (Dist(i,j) <= 1) DATA->SArea[i] |= u; + if (Abs(Rank(i)-Rank(j)) + Abs(File(i)-File(j)) == 3) + DATA->NAtt[i] |= u; + } + if (j == i + 8) DATA->PMove[0][i] |= u; + if (j == i - 8) DATA->PMove[1][i] |= u; + if (Abs(File(i) - File(j)) == 1) + { + if (Rank(j) >= Rank(i)) + { + DATA->PSupport[1][i] |= u; + if (Rank(j) - Rank(i) == 1) DATA->PAtt[0][i] |= u; + } + if (Rank(j) <= Rank(i)) + { + DATA->PSupport[0][i] |= u; + if (Rank(i) - Rank(j) == 1) DATA->PAtt[1][i] |= u; + } + } else if (File(i) == File(j)) + { + if (Rank(j) > Rank(i)) DATA->PWay[0][i] |= u; + else DATA->PWay[1][i] |= u; + } + } + for (i = 0; i < 64; i++) + { + DATA->RMask[i] = DATA->HLine[i] | DATA->VLine[i]; + DATA->BMask[i] = DATA->NDiag[i] | DATA->SDiag[i]; + DATA->QMask[i] = DATA->RMask[i] | DATA->BMask[i]; + DATA->BMagicMask[i] = DATA->BMask[i] & Interior; + DATA->RMagicMask[i] = DATA->RMask[i]; + if (File(i) > 0) DATA->RMagicMask[i] &= ~DATA->File[0]; + if (Rank(i) > 0) DATA->RMagicMask[i] &= ~DATA->Line[0]; + if (File(i) < 7) DATA->RMagicMask[i] &= ~DATA->File[7]; + if (Rank(i) < 7) DATA->RMagicMask[i] &= ~DATA->Line[7]; + for (j = 0; j < 64; j++) if (DATA->NAtt[i] & DATA->NAtt[j]) + Add(DATA->NArea[i], j); + } + for (i = 0; i < 8; i++) + { + DATA->West[i] = 0; + DATA->East[i] = 0; + DATA->Forward[0][i] = DATA->Forward[1][i] = 0; + DATA->PIsolated[i] = 0; + for (j = 0; j < 8; j++) + { + if (i < j) DATA->Forward[0][i] |= DATA->Line[j]; + else if (i > j) DATA->Forward[1][i] |= DATA->Line[j]; + if (i < j) DATA->East[i] |= DATA->File[j]; + else if (i > j) DATA->West[i] |= DATA->File[j]; + } + if (i > 0) DATA->PIsolated[i] |= DATA->File[i - 1]; + if (i < 7) DATA->PIsolated[i] |= DATA->File[i + 1]; + } + for (i = 0; i < 64; i++) + { + for (u = DATA->QMask[i]; T(u); Cut(u)) + { + j = lsb(u); + k = Sgn(Rank(j)-Rank(i)); + l = Sgn(File(j)-File(i)); + for (n = i + 8 * k + l; n != j; n += (8 * k + l)) + Add(DATA->Between[i][j], n); + } + for (u = DATA->BMask[i]; T(u); Cut(u)) + { + j = lsb(u); + DATA->FullLine[i][j] = DATA->BMask[i] & DATA->BMask[j]; + } + for (u = DATA->RMask[i]; T(u); Cut(u)) + { + j = lsb(u); + DATA->FullLine[i][j] = DATA->RMask[i] & DATA->RMask[j]; + } + DATA->BishopForward[0][i] |= DATA->PWay[0][i]; + DATA->BishopForward[1][i] |= DATA->PWay[1][i]; + for (j = 0; j < 64; j++) + { + if ((DATA->PWay[1][j] | Bit(j)) & + DATA->BMask[i] & DATA->Forward[0][Rank(i)]) + DATA->BishopForward[0][i] |= Bit(j); + if ((DATA->PWay[0][j] | Bit(j)) & DATA->BMask[i] & + DATA->Forward[1][Rank(i)]) + DATA->BishopForward[1][i] |= Bit(j); + } + } + + for (i = 0; i < 16; i++) for (j = 0; j < 16; j++) + { + if (j < WhitePawn) DATA->MvvLva[i][j] = 0; + else if (j < WhiteKnight) + DATA->MvvLva[i][j] = PawnCaptureMvvLva(i) << 26; + else if (j < WhiteLight) + DATA->MvvLva[i][j] = KnightCaptureMvvLva(i) << 26; + else if (j < WhiteRook) + DATA->MvvLva[i][j] = BishopCaptureMvvLva(i) << 26; + else if (j < WhiteQueen) + DATA->MvvLva[i][j] = RookCaptureMvvLva(i) << 26; + else DATA->MvvLva[i][j] = QueenCaptureMvvLva(i) << 26; + } + + DATA->PieceFromChar['B'] = WhiteLight; + DATA->PieceFromChar['K'] = WhiteKing; + DATA->PieceFromChar['N'] = WhiteKnight; + DATA->PieceFromChar['P'] = WhitePawn; + DATA->PieceFromChar['Q'] = WhiteQueen; + DATA->PieceFromChar['R'] = WhiteRook; + DATA->PieceFromChar['b'] = BlackLight; + DATA->PieceFromChar['k'] = BlackKing; + DATA->PieceFromChar['n'] = BlackKnight; + DATA->PieceFromChar['p'] = BlackPawn; + DATA->PieceFromChar['q'] = BlackQueen; + DATA->PieceFromChar['r'] = BlackRook; + + DATA->TurnKey = rand64(); + for (i = 0; i < 8; i++) DATA->EPKey[i] = rand64(); + for (i = 0; i < 16; i++) DATA->CastleKey[i] = rand64(); + for (i = 0; i < 16; i++) for (j = 0; j < 64; j++) { + if (i == 0) DATA->PieceKey[i][j] = 0; + else DATA->PieceKey[i][j] = rand64(); + } + for (i = 0; i < 16; i++) + DATA->LogDist[i] = (int)(10.0 * log(1.01 + (double)i)); + + memcpy(DATA->UpdateCastling, UpdateCastling, + sizeof(DATA->UpdateCastling)); +} + +static void init_kpk(void) +{ + int turn, wp, wk, bk, to, cnt, old_cnt, un; + uint64_t bwp, bwk, bbk, u; + uint8_t Kpk_gen[2][64][64][64]; + + memset(Kpk_gen, 0, sizeof(Kpk_gen)); + + cnt = 0; + old_cnt = 1; +start: + if (cnt == old_cnt) goto end; + old_cnt = cnt; + cnt = 0; + for (turn = 0; turn < 2; turn++) + { + for (wp = 0; wp < 64; wp++) + { + for (wk = 0; wk < 64; wk++) + { + for (bk = 0; bk < 64; bk++) + { + if (Kpk_gen[turn][wp][wk][bk]) continue; + cnt++; + if (wp < 8 || wp >= 56) goto set_draw; + if (wp == wk || wk == bk || bk == wp) goto set_draw; + bwp = Bit(wp); + bwk = Bit(wk); + bbk = Bit(bk); + if (DATA->PAtt[White][wp] & bbk) + { + if (turn == White) goto set_draw; + else if (F(DATA->SArea[wk] & bwp)) goto set_draw; + } + un = 0; + if (turn == Black) + { + u = DATA->SArea[bk] & + (~(DATA->SArea[wk] | DATA->PAtt[White][wp])); + if (F(u)) goto set_draw; + for (; T(u); Cut(u)) + { + to = lsb(u); + if (Kpk_gen[turn ^ 1][wp][wk][to] == 1) + goto set_draw; + else if (Kpk_gen[turn ^ 1][wp][wk][to] == 0) + un++; + } + if (F(un)) goto set_win; + } + else + { + for (u = DATA->SArea[wk] & (~(DATA->SArea[bk] | bwp)); + T(u); Cut(u)) + { + to = lsb(u); + if (Kpk_gen[turn ^ 1][wp][to][bk] == 2) + goto set_win; + else if (Kpk_gen[turn ^ 1][wp][to][bk] == 0) + un++; + } + to = wp + 8; + if (to != wk && to != bk) + { + if (to >= 56) + { + if (F(DATA->SArea[to] & bbk)) goto set_win; + if (DATA->SArea[to] & bwk) goto set_win; + } + else + { + if (Kpk_gen[turn ^ 1][to][wk][bk] == 2) + goto set_win; + else if (Kpk_gen[turn ^ 1][to][wk][bk] == 0) + un++; + if (to < 24) + { + to += 8; + if (to != wk && to != bk) + { + if (Kpk_gen[turn ^ 1][to][wk][bk] == 2) + goto set_win; + else if ( + Kpk_gen[turn ^ 1][to][wk][bk] == 0) + un++; + } + } + } + } + if (F(un)) goto set_draw; + } + continue; + set_draw: + Kpk_gen[turn][wp][wk][bk] = 1; + continue; + set_win: + Kpk_gen[turn][wp][wk][bk] = 2; + continue; + } + } + } + } + if (cnt) goto start; +end: + for (turn = 0; turn < 2; turn++) + { + for (wp = 0; wp < 64; wp++) + { + for (wk = 0; wk < 64; wk++) + { + DATA->Kpk[turn][wp][wk] = 0; + for (bk = 0; bk < 64; bk++) + { + if (Kpk_gen[turn][wp][wk][bk] == 2) + DATA->Kpk[turn][wp][wk] |= Bit(bk); + } + } + } + } +} + +#define pst_idx(piece, sq) (((piece) << 6) | (sq)) +static void init_pst(void) +{ + int i, j, k, op, eg, index, r, f, d, e, distQ[4], distL[4], distM[2]; + + for (i = 0; i < 64; i++) + { + r = Rank(i); + f = File(i); + d = Abs(f - r); + e = Abs(f + r - 7); + distQ[0] = DistC[f] * DistC[f]; distL[0] = DistC[f]; + distQ[1] = DistC[r] * DistC[r]; distL[1] = DistC[r]; + distQ[2] = RankR[d] * RankR[d] + RankR[e] * RankR[e]; distL[2] = + RankR[d] + RankR[e]; + distQ[3] = RankR[r] * RankR[r]; distL[3] = RankR[r]; + distM[0] = DistC[f] * DistC[r]; distM[1] = DistC[f] * RankR[r]; + for (j = 2; j < 16; j += 2) + { + index = PieceType[j]; + op = eg = 0; + for (k = 0; k < 2; k++) + { + op += Av(PstQuadMixedWeights, 4, index, (k * 2)) * distM[k]; + eg += Av(PstQuadMixedWeights, 4, index, (k * 2) + 1) * distM[k]; + } + for (k = 0; k < 4; k++) + { + op += Av(PstQuadWeights,8,index,(k * 2)) * distQ[k]; + eg += Av(PstQuadWeights,8,index,(k * 2) + 1) * distQ[k]; + op += Av(PstLinearWeights,8,index,(k * 2)) * distL[k]; + eg += Av(PstLinearWeights,8,index,(k * 2) + 1) * distL[k]; + } + DATA->Pst[pst_idx(j, i)] = Compose(op/64, eg/64); + } + } + + DATA->Pst[pst_idx(WhiteKnight, 56)] -= Compose(100, 0); + DATA->Pst[pst_idx(WhiteKnight, 63)] -= Compose(100, 0); + for (i = 0; i < 64; i++) + { + for (j = 3; j < 16; j+=2) + { + op = Opening(DATA->Pst[pst_idx(j-1, 63-i)]); + eg = Endgame(DATA->Pst[pst_idx(j-1, 63-i)]); + DATA->Pst[pst_idx(j, i)] = Compose(-op, -eg); + } + } +} + +static void init_eval() +{ + int i, j, k, index; +// memset(Mobility,0,4 * 32 * sizeof(int)); + for (i = 0; i < 4; i++) for (j = 0; j < 32; j++) + { + index = i * 2; + double op = + (double)(Av(MobilityLinear, 8, 0, index) * j) + + log(1.01 + (double)j) * (double)(Av(MobilityLog, 8, 0, index)); + index = i * 2 + 1; + double eg = + (double)(Av(MobilityLinear, 8, 0, index) * j) + + log(1.01 + (double)j) * (double)(Av(MobilityLog, 8, 0, index)); + DATA->Mobility[i][j] = Compose((int)(op/64.0), (int)(eg/64.0)); + } + + for (i = 0; i < 3; i++) for (j = 7; j >= 0; j--) + { + DATA->Shelter[i][j] = 0; + if (j > 1) for (k = 1; k < Min(j, 5); k++) + DATA->Shelter[i][j] += Av(ShelterValue, 0, 0, (i * 5) + k - 1); + if (!j) + DATA->Shelter[i][j] = DATA->Shelter[i][7] + + Av(ShelterValue, 0, 0, (i * 5) + 4); + } + + for (i = 0; i < 4; i++) + { + DATA->StormBlocked[i] = + ((Sa(StormQuad, StormBlockedMul) * i * i) + + (Sa(StormLinear, StormBlockedMul) * (i + 1))) / 100; + DATA->StormShelterAtt[i] = + ((Sa(StormQuad, StormShelterAttMul) * i * i) + + (Sa(StormLinear, StormShelterAttMul) * (i + 1))) / 100; + DATA->StormConnected[i] = + ((Sa(StormQuad, StormConnectedMul) * i * i) + + (Sa(StormLinear, StormConnectedMul) * (i + 1))) / 100; + DATA->StormOpen[i] = + ((Sa(StormQuad, StormOpenMul) * i * i) + + (Sa(StormLinear, StormOpenMul) * (i + 1))) / 100; + DATA->StormFree[i] = + ((Sa(StormQuad, StormFreeMul) * i * i) + + (Sa(StormLinear, StormFreeMul) * (i + 1))) / 100; + } + + for (i = 0; i < 8; i++) + { + int l = Max(i - 2, 0); + int q = l * l; + DATA->PasserGeneral[i] = Compose16( + Av(PasserQuad, 2, 0, 0) * q + Av(PasserLinear, 2, 0, 0) * l, + Av(PasserQuad, 2, 0, 1) * q + Av(PasserLinear, 2, 0, 1) * l); + DATA->PasserBlocked[i] = Compose16( + Av(PasserQuad, 2, 1, 0) * q + Av(PasserLinear, 2, 1, 0) * l, + Av(PasserQuad, 2, 1, 1) * q + Av(PasserLinear, 2, 1, 1) * l); + DATA->PasserFree[i] = Compose16( + Av(PasserQuad, 2, 2, 0) * q + Av(PasserLinear, 2, 2, 0) * l, + Av(PasserQuad, 2, 2, 1) * q + Av(PasserLinear, 2, 2, 1) * l); + DATA->PasserSupported[i] = Compose16( + Av(PasserQuad, 2, 3, 0) * q + Av(PasserLinear, 2, 3, 0) * l, + Av(PasserQuad, 2, 3, 1) * q + Av(PasserLinear, 2, 3, 1) * l); + DATA->PasserProtected[i] = Compose16( + Av(PasserQuad, 2, 4, 0) * q + Av(PasserLinear, 2, 4, 0) * l, + Av(PasserQuad, 2, 4, 1) * q + Av(PasserLinear, 2, 4, 1) * l); + DATA->PasserConnected[i] = Compose16( + Av(PasserQuad, 2, 5, 0) * q + Av(PasserLinear, 2, 5, 0) * l, + Av(PasserQuad, 2, 5, 1) * q + Av(PasserLinear, 2, 5, 1) * l); + DATA->PasserOutside[i] = Compose16( + Av(PasserQuad, 2, 6, 0) * q + Av(PasserLinear, 2, 6, 0) * l, + Av(PasserQuad, 2, 6, 1) * q + Av(PasserLinear, 2, 6, 1) * l); + DATA->PasserCandidate[i] = Compose16( + Av(PasserQuad, 2, 7, 0) * q + Av(PasserLinear, 2, 7, 0) * l, + Av(PasserQuad, 2, 7, 1) * q + Av(PasserLinear, 2, 7, 1) * l); + DATA->PasserClear[i] = Compose16( + Av(PasserQuad, 2, 8, 0) * q + Av(PasserLinear, 2, 8, 0) * l, + Av(PasserQuad, 2, 8, 1) * q + Av(PasserLinear, 2, 8, 1) * l); + DATA->PasserAtt[i] = Av(PasserAttDefQuad, 2, 0, 0) * q + + Av(PasserAttDefLinear, 2, 0, 0) * l; + DATA->PasserDef[i] = Av(PasserAttDefQuad, 2, 1, 0) * q + + Av(PasserAttDefLinear, 2, 1, 0) * l; + DATA->PasserAttLog[i] = Av(PasserAttDefQuad, 2, 0, 1) * q + + Av(PasserAttDefLinear, 2, 0, 1) * l; + DATA->PasserDefLog[i] = Av(PasserAttDefQuad, 2, 1, 1) * q + + Av(PasserAttDefLinear, 2, 1, 1) * l; + } +} + +void calc_material(int index) +{ + int pawns[2], knights[2], light[2], dark[2], rooks[2], queens[2], + bishops[2], major[2], minor[2], tot[2], mat[2], mul[2], quad[2], + score, phase, me, i = index; + + queens[White] = i % 3; i /= 3; + queens[Black] = i % 3; i /= 3; + rooks[White] = i % 3; i /= 3; + rooks[Black] = i % 3; i /= 3; + light[White] = i % 2; i /= 2; + light[Black] = i % 2; i /= 2; + dark[White] = i % 2; i /= 2; + dark[Black] = i % 2; i /= 2; + knights[White] = i % 3; i /= 3; + knights[Black] = i % 3; i /= 3; + pawns[White] = i % 9; i /= 9; + pawns[Black] = i % 9; + for (me = 0; me < 2; me++) + { + bishops[me] = light[me] + dark[me]; + major[me] = rooks[me] + queens[me]; + minor[me] = bishops[me] + knights[me]; + tot[me] = 3 * minor[me] + 5 * rooks[me] + 9 * queens[me]; + mat[me] = mul[me] = 32; + quad[me] = 0; + } + score = + (SeeValue[WhitePawn] + Av(MatLinear, 0, 0, 0)) * + (pawns[White] - pawns[Black]) + + (SeeValue[WhiteKnight] + Av(MatLinear, 0, 0, 1)) * + (knights[White] - knights[Black]) + + (SeeValue[WhiteLight] + Av(MatLinear, 0, 0, 2)) * + (bishops[White] - bishops[Black]) + + (SeeValue[WhiteRook] + Av(MatLinear, 0, 0, 3)) * + (rooks[White] - rooks[Black]) + + (SeeValue[WhiteQueen] + Av(MatLinear, 0, 0, 4)) * + (queens[White] - queens[Black]) + + 50 * ((bishops[White] / 2) - (bishops[Black] / 2)); + phase = + Phase[PieceType[WhitePawn]] * (pawns[White] + pawns[Black]) + + Phase[PieceType[WhiteKnight]] * (knights[White] + knights[Black]) + + Phase[PieceType[WhiteLight]] * (bishops[White] + bishops[Black]) + + Phase[PieceType[WhiteRook]] * (rooks[White] + rooks[Black]) + + Phase[PieceType[WhiteQueen]] * (queens[White] + queens[Black]); + DATA->Material[index].phase = + Min((Max(phase - PhaseMin, 0) * 128) / (PhaseMax - PhaseMin), 128); + int special = 0; + for (me = 0; me < 2; me++) + { + if (queens[me] == queens[opp]) + { + if (rooks[me] - rooks[opp] == 1) + { + if (knights[me] == knights[opp] && + bishops[opp] - bishops[me] == 1) + IncV(special, Ca(MatSpecial, MatRB)); + else if (bishops[me] == bishops[opp] && + knights[opp] - knights[me] == 1) + IncV(special, Ca(MatSpecial, MatRN)); + else if (knights[me] == knights[opp] && + bishops[opp] - bishops[me] == 2) + DecV(special, Ca(MatSpecial, MatBBR)); + else if (bishops[me] == bishops[opp] && + knights[opp] - knights[me] == 2) + DecV(special, Ca(MatSpecial, MatNNR)); + else if (bishops[opp] - bishops[me] == 1 && + knights[opp] - knights[me] == 1) + DecV(special, Ca(MatSpecial, MatBNR)); + } + else if (rooks[me] == rooks[opp] && + minor[me] - minor[opp] == 1) + IncV(special, Ca(MatSpecial, MatM)); + } + else if (queens[me] - queens[opp] == 1) + { + if (rooks[opp] - rooks[me] == 2 && + minor[opp] - minor[me] == 0) + IncV(special, Ca(MatSpecial, MatQRR)); + else if (rooks[opp] - rooks[me] == 1 && + knights[opp] == knights[me] && + bishops[opp] - bishops[me] == 1) + IncV(special, Ca(MatSpecial, MatQRB)); + else if (rooks[opp] - rooks[me] == 1 && + knights[opp] - knights[me] == 1 && + bishops[opp] == bishops[me]) + IncV(special, Ca(MatSpecial, MatQRN)); + else if ((major[opp] + minor[opp]) - (major[me] + minor[me]) >= 2) + IncV(special, Ca(MatSpecial, MatQ3)); + } + } + score += + (Opening(special) * DATA->Material[index].phase + + Endgame(special) * (128 - (int)DATA->Material[index].phase)) / 128; + + for (me = 0; me < 2; me++) + { + quad[me] += pawns[me] * (pawns[me] * TrAv(MatQuadMe, 5, 0, 0) + + knights[me] * TrAv(MatQuadMe, 5, 0, 1) + + bishops[me] * TrAv(MatQuadMe, 5, 0, 2) + + rooks[me] * TrAv(MatQuadMe, 5, 0, 3) + + queens[me] * TrAv(MatQuadMe, 5, 0, 4)); + quad[me] += knights[me] * (knights[me] * TrAv(MatQuadMe, 5, 1, 0) + + bishops[me] * TrAv(MatQuadMe, 5, 1, 1) + + rooks[me] * TrAv(MatQuadMe, 5, 1, 2) + + queens[me] * TrAv(MatQuadMe, 5, 1, 3)); + quad[me] += bishops[me] * (bishops[me] * TrAv(MatQuadMe, 5, 2, 0) + + rooks[me] * TrAv(MatQuadMe, 5, 2, 1) + + queens[me] * TrAv(MatQuadMe, 5, 2, 2)); + quad[me] += rooks[me] * (rooks[me] * TrAv(MatQuadMe, 5, 3, 0) + + queens[me] * TrAv(MatQuadMe, 5, 3, 1)); + quad[me] += pawns[me] * (knights[opp] * TrAv(MatQuadOpp, 4, 0, 0) + + bishops[opp] * TrAv(MatQuadOpp, 4, 0, 1) + + rooks[opp] * TrAv(MatQuadOpp, 4, 0, 2) + + queens[opp] * TrAv(MatQuadOpp, 4, 0, 3)); + quad[me] += knights[me] * (bishops[opp] * TrAv(MatQuadOpp, 4, 1, 0) + + rooks[opp] * TrAv(MatQuadOpp, 4, 1, 1) + + queens[opp] * TrAv(MatQuadOpp, 4, 1, 2)); + quad[me] += bishops[me] * (rooks[opp] * TrAv(MatQuadOpp, 4, 2, 0) + + queens[opp] * TrAv(MatQuadOpp, 4, 2, 1)); + quad[me] += rooks[me] * queens[opp] * TrAv(MatQuadOpp, 4, 3, 0); + + if (bishops[me] >= 2) + quad[me] += pawns[me] * Av(BishopPairQuad, 0, 0, 0) + + knights[me] * Av(BishopPairQuad, 0, 0, 1) + + rooks[me] * Av(BishopPairQuad, 0, 0, 2) + + queens[me] * Av(BishopPairQuad, 0, 0, 3) + + pawns[opp] * Av(BishopPairQuad, 0, 0, 4) + + knights[opp] * Av(BishopPairQuad, 0, 0, 5) + + bishops[opp] * Av(BishopPairQuad, 0, 0, 6) + + rooks[opp] * Av(BishopPairQuad, 0, 0, 7) + + queens[opp] * Av(BishopPairQuad, 0, 0, 8); + } + score += (quad[White] - quad[Black]) / 100; + + for (me = 0; me < 2; me++) + { + if (tot[me] - tot[opp] <= 3) + { + if (!pawns[me]) + { + if (tot[me] <= 3) mul[me] = 0; + if (tot[me] == tot[opp] && major[me] == major[opp] && + minor[me] == minor[opp]) + mul[me] = major[me] + minor[me] <= 2 ? 0 : + (major[me] + minor[me] <= 3 ? 16 : 32); + else if (minor[me] + major[me] <= 2) + { + if (bishops[me] < 2) + mat[me] = (bishops[me] && rooks[me]) ? 8 : 1; + else if (bishops[opp] + rooks[opp] >= 1) mat[me] = 1; + else mat[me] = 32; + } + else if (tot[me] - tot[opp] < 3 && + minor[me] + major[me] - minor[opp] - major[opp] <= 1) + mat[me] = 4; + else if (minor[me] + major[me] <= 3) + mat[me] = 8 * (1 + bishops[me]); + else mat[me] = 8 * (2 + bishops[me]); + } + if (pawns[me] <= 1) + { + mul[me] = Min(28, mul[me]); + if (rooks[me] == 1 && queens[me] + minor[me] == 0 && + rooks[opp] == 1) + mat[me] = Min(23, mat[me]); + } + } + if (!major[me]) + { + if (!minor[me]) + { + if (!tot[me] && pawns[me] < pawns[opp]) + DecV(score, (pawns[opp] - pawns[me]) * SeeValue[WhitePawn]); + } + else if (minor[me] == 1) + { + if (pawns[me] <= 1 && minor[opp] >= 1) mat[me] = 1; + if (bishops[me] == 1) + { + if (minor[opp] == 1 && bishops[opp] == 1 && + light[me] != light[opp]) + { + mul[me] = Min(mul[me], 15); + if (pawns[me] - pawns[opp] <= 1) + mul[me] = Min(mul[me], 11); + } + } + } + else if (!pawns[me] && knights[me] == 2 && !bishops[me]) + { + if (!tot[opp] && pawns[opp]) mat[me] = 6; + else mul[me] = 0; + } + } + if (!mul[me]) mat[me] = 0; + if (mat[me] <= 1 && tot[me] != tot[opp]) mul[me] = Min(mul[me], 8); + } + if (bishops[White] == 1 && bishops[Black] == 1 && + light[White] != light[Black]) + { + mul[White] = Min(mul[White], 24 + 2 * (knights[Black] + major[Black])); + mul[Black] = Min(mul[Black], 24 + 2 * (knights[White] + major[White])); + } + else if (!minor[White] && !minor[Black] && major[White] == 1 && + major[Black] == 1 && rooks[White] == rooks[Black]) + { + mul[White] = Min(mul[White], 25); + mul[Black] = Min(mul[Black], 25); + } + for (me = 0; me < 2; me++) + { + DATA->Material[index].mul[me] = mul[me]; + DATA->Material[index].pieces[me] = major[me] + minor[me]; + } + if (score > 0) score = (score * mat[White]) / 32; + else score = (score * mat[Black]) / 32; + DATA->Material[index].score = score; + for (me = 0; me < 2; me++) + { + if (major[me] == 0 && minor[me] == bishops[me] && minor[me] <= 1) + DATA->Material[index].flags |= VarC(FlagSingleBishop, me); + if (((major[me] == 0 || minor[me] == 0) && + major[me] + minor[me] <= 1) || major[opp] + minor[opp] == 0 || + (!pawns[me] && major[me] == rooks[me] && major[me] == 1 && + minor[me] == bishops[me] && minor[me] == 1 && + rooks[opp] == 1 && !minor[opp] && !queens[opp])) + DATA->Material[index].flags |= VarC(FlagCallEvalEndgame, me); + } +} + +static void init_material(void) +{ + for (int index = 0; index < TotalMat; index++) + calc_material(index); +} + +static void init_data(void) +{ + init_misc(); + init_magic(); + init_kpk(); + init_pst(); + init_eval(); + init_material(); +} + diff --git a/src/data.h b/src/data.h new file mode 100644 index 0000000..298fb8b --- /dev/null +++ b/src/data.h @@ -0,0 +1,118 @@ +#ifndef __DATA_H +#define __DATA_H + +#include + +#define GULL_MAGIC_BITBOARDS +typedef struct +{ + int16_t score; + uint8_t phase; + uint8_t flags; + uint8_t mul[2]; + uint8_t pieces[2]; +} GMaterial; +#define MatWQ 1 +#define MatBQ 3 +#define MatWR (3 * 3) +#define MatBR (3 * 3 * 3) +#define MatWL (3 * 3 * 3 * 3) +#define MatBL (3 * 3 * 3 * 3 * 2) +#define MatWD (3 * 3 * 3 * 3 * 2 * 2) +#define MatBD (3 * 3 * 3 * 3 * 2 * 2 * 2) +#define MatWN (3 * 3 * 3 * 3 * 2 * 2 * 2 * 2) +#define MatBN (3 * 3 * 3 * 3 * 2 * 2 * 2 * 2 * 3) +#define MatWP (3 * 3 * 3 * 3 * 2 * 2 * 2 * 2 * 3 * 3) +#define MatBP (3 * 3 * 3 * 3 * 2 * 2 * 2 * 2 * 3 * 3 * 9) +#define TotalMat ((2*(MatWQ+MatBQ)+MatWL+MatBL+MatWD+MatBD+2*(MatWR+MatBR+MatWN+MatBN)+8*(MatWP+MatBP)) + 1) + +#define MagicSize 107648 + +typedef struct +{ + uint64_t Forward[2][8]; + uint64_t West[8]; + uint64_t East[8]; + uint64_t PIsolated[8]; + uint64_t HLine[64]; + uint64_t VLine[64]; + uint64_t NDiag[64]; + uint64_t SDiag[64]; + uint64_t RMask[64]; + uint64_t BMask[64]; + uint64_t QMask[64]; + uint64_t NAtt[64]; + uint64_t SArea[64]; + uint64_t DArea[64]; + uint64_t NArea[64]; + uint64_t BishopForward[2][64]; + uint64_t PAtt[2][64]; + uint64_t PMove[2][64]; + uint64_t PWay[2][64]; + uint64_t PSupport[2][64]; + uint64_t Between[64][64]; + uint64_t FullLine[64][64]; + uint64_t File[8]; + uint64_t Line[8]; + uint8_t UpdateCastling[64]; + int32_t Mobility[4][32]; + int32_t Shelter[3][8]; + int32_t StormHof[2]; + int32_t StormBlocked[4]; + int32_t StormShelterAtt[4]; + int32_t StormConnected[4]; + int32_t StormOpen[4]; + int32_t StormFree[4]; + int32_t LogDist[16]; + int32_t PasserSpecial[4]; + int32_t PasserGeneral[8]; + int32_t PasserBlocked[8]; + int32_t PasserFree[8]; + int32_t PasserSupported[8]; + int32_t PasserProtected[8]; + int32_t PasserConnected[8]; + int32_t PasserOutside[8]; + int32_t PasserCandidate[8]; + int32_t PasserClear[8]; + int32_t PasserAtt[8]; + int32_t PasserDef[8]; + int32_t PasserAttLog[8]; + int32_t PasserDefLog[8]; + int32_t Isolated[10]; + int32_t Unprotected[6]; + int32_t Backward[4]; + int32_t Doubled[4]; + int32_t RookSpecial[20]; + int32_t Tactical[12]; + int32_t KingDefence[8]; + int32_t PawnSpecial[8]; + int32_t BishopSpecial[4]; + uint64_t Outpost[2]; + int32_t KnightSpecial[10]; + int32_t Pin[10]; + int32_t KingRay[6]; + int32_t KingAttackWeight[7]; + int32_t KingAttackScale[16]; + uint64_t TurnKey; + uint64_t PieceKey[16][64]; + uint64_t CastleKey[16]; + uint64_t EPKey[8]; + uint8_t PieceFromChar[256]; + uint64_t Kpk[2][64][64]; + int32_t Pst[16 * 64]; + int32_t MvvLva[16][16]; + GMaterial Material[TotalMat]; +#ifdef GULL_MAGIC_BITBOARDS + uint64_t BMagic[64]; + uint64_t RMagic[64]; + uint32_t BShift[64]; + uint32_t RShift[64]; + uint64_t BMagicMask[64]; + uint64_t RMagicMask[64]; + uint64_t *BOffsetPointer[64]; + uint64_t *ROffsetPointer[64]; + uint64_t MagicAttacks[MagicSize]; +#endif +} GGlobalData; + +#endif diff --git a/src/tbconfig.h b/src/tbconfig.h index b32a6ec..7db9871 100644 --- a/src/tbconfig.h +++ b/src/tbconfig.h @@ -50,8 +50,15 @@ /* ENGINE INTEGRATION CONFIG */ /***************************************************************************/ -#include -#define uint64 unsigned long long +#ifdef LINUX +#include "Linux.h" +#endif + +#ifdef WINDOWS +#include "Windows.h" +#endif + +#include "data.h" /* * If you are integrating tbprobe into an engine, you can replace some of @@ -65,30 +72,27 @@ * Define TB_KING_ATTACKS(square) to return the king attacks bitboard for a * king at `square'. */ -extern uint64 SArea[64]; -#define TB_KING_ATTACKS(square) SArea[(square)] +//extern uint64 SArea[64]; +#define TB_KING_ATTACKS(square) DATA->SArea[(square)] /* * Define TB_KNIGHT_ATTACKS(square) to return the knight attacks bitboard for * a knight at `square'. */ -extern uint64 NAtt[64]; -#define TB_KNIGHT_ATTACKS(square) NAtt[(square)] +//extern uint64 NAtt[64]; +#define TB_KNIGHT_ATTACKS(square) DATA->NAtt[(square)] /* * Define TB_ROOK_ATTACKS(square, occ) to return the rook attacks bitboard * for a rook at `square' assuming the given `occ' occupancy bitboard. */ -extern const uint64 RMagic[64]; -extern uint64 RMagicMask[64]; -extern const int RShift[64]; -extern uint64 *ROffsetPointer[64]; #ifndef HNI -#define TB_ROOK_ATTACKS(square, occ) \ - (*(ROffsetPointer[(square)] + (((RMagicMask[(square)] & (occ)) * \ - RMagic[(square)]) >> RShift[(square)]))) +#define TB_ROOK_ATTACKS(square, occ) \ + (*(DATA->ROffsetPointer[(square)] + \ + (((DATA->RMagicMask[(square)] & (occ)) * \ + DATA->RMagic[(square)]) >> DATA->RShift[(square)]))) #else -#define TB_ROOK_ATTACKS(square, occ) \ +#define TB_ROOK_ATTACKS(square, occ) \ (*(ROffsetPointer[(square)] + _pext_u64((occ), RMagicMask[(square)]))) #endif @@ -96,16 +100,13 @@ extern uint64 *ROffsetPointer[64]; * Define TB_BISHOP_ATTACKS(square, occ) to return the bishop attacks bitboard * for a bishop at `square' assuming the given `occ' occupancy bitboard. */ -extern const uint64 BMagic[64]; -extern uint64 BMagicMask[64]; -extern const int BShift[64]; -extern uint64 *BOffsetPointer[64]; #ifndef HNI -#define TB_BISHOP_ATTACKS(square, occ) \ - (*(BOffsetPointer[(square)] + (((BMagicMask[(square)] & (occ)) * \ - BMagic[(square)]) >> BShift[(square)]))) +#define TB_BISHOP_ATTACKS(square, occ) \ + (*(DATA->BOffsetPointer[(square)] + \ + (((DATA->BMagicMask[(square)] & (occ)) * \ + DATA->BMagic[(square)]) >> DATA->BShift[(square)]))) #else -#define TB_BISHOP_ATTACKS(square, occ) \ +#define TB_BISHOP_ATTACKS(square, occ) \ (*(BOffsetPointer[(square)] + _pext_u64((occ), BMagicMask[(square)]))) #endif @@ -115,7 +116,7 @@ extern uint64 *BOffsetPointer[64]; * NOTE: If no definition is provided then tbprobe will use: * TB_ROOK_ATTACKS(square, occ) | TB_BISHOP_ATTACKS(square, occ) */ -#define TB_QUEEN_ATTACKS(square, occ) \ +#define TB_QUEEN_ATTACKS(square, occ) \ (TB_ROOK_ATTACKS(square, occ) | TB_BISHOP_ATTACKS(square, occ)) /* @@ -125,9 +126,7 @@ extern uint64 *BOffsetPointer[64]; * a white pawn on e1 attacks d2 and f2. A black pawn on e1 attacks * nothing. Etc. */ -extern uint64 PAtt[2][64]; -#define TB_PAWN_ATTACKS(square, color) PAtt[!(color)][(square)] - -#undef uint64 +//extern uint64 PAtt[2][64]; +#define TB_PAWN_ATTACKS(square, color) DATA->PAtt[!(color)][(square)] #endif From 3b8ec86bb34a3a3597d18aee0f6fcf4da7817bc7 Mon Sep 17 00:00:00 2001 From: basil00 Date: Mon, 26 Sep 2016 21:11:07 +0800 Subject: [PATCH 2/9] (Re)add a "bench" mode to Gull. --- src/Gull.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 5 deletions(-) diff --git a/src/Gull.cpp b/src/Gull.cpp index 699acda..bca401a 100644 --- a/src/Gull.cpp +++ b/src/Gull.cpp @@ -1205,7 +1205,6 @@ void init_search(int clear_hash) { hash_mask = hash_size - 4; get_board("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); -// best_move = best_score = 0; LastTime = LastValue = LastExactValue = InstCnt = 0; LastSpeed = 0; PVN = 1; @@ -1321,6 +1320,36 @@ const char *get_board(const char fen[]) { return fen + pos; } +static void dump_board(void) +{ + for (int i = 56; i >= 0; i -= 8) + for (int j = 0; j < 8; j++) + { + int piece = Square(i+j); + switch (piece) + { + case WhiteKing: putc('K', stderr); break; + case BlackKing: putc('k', stderr); break; + case WhiteQueen: putc('Q', stderr); break; + case BlackQueen: putc('q', stderr); break; + case WhiteRook: putc('R', stderr); break; + case BlackRook: putc('r', stderr); break; + case WhiteLight: putc('B', stderr); break; + case BlackLight: putc('b', stderr); break; + case WhiteDark: putc('B', stderr); break; + case BlackDark: putc('b', stderr); break; + case WhiteKnight: putc('N', stderr); break; + case BlackKnight: putc('n', stderr); break; + case WhitePawn: putc('P', stderr); break; + case BlackPawn: putc('p', stderr); break; + default: putc('.', stderr); break; + } + putc(' ', stderr); + if (j+1 == 8) putc('\n', stderr); + } + putc('\n', stderr); +} + inline GEntry * probe_hash() { for (GEntry * Entry = HASH + (High32(Current->key) & hash_mask); Entry < (HASH + (High32(Current->key) & hash_mask)) + 4; Entry++) if (Low32(Current->key) == Entry->key) { Entry->date = SHARED->date; @@ -5102,7 +5131,7 @@ void uci(void) int main(int argc, char **argv) { - if (argc > 1) + if (argc > 1 && strcmp(argv[1], "child") == 0) { if (argc != 10) { @@ -5110,8 +5139,6 @@ int main(int argc, char **argv) fprintf(stderr, "usage: %s\n", argv[0]); exit(EXIT_FAILURE); } - if (strcmp(argv[1], "child") != 0) - goto usage; // CHILD: const char @@ -5162,6 +5189,47 @@ int main(int argc, char **argv) worker(); // Wait for work from parent. } + else if (argc > 1 && strcmp(argv[1], "bench") == 0) + { + init_object(NULL, sizeof(GGlobalData), DATA, true, false, true, NULL); + init_data(); + GSettings settings; + memset(&settings, 0, sizeof(settings)); + settings.numThreads = 1; + settings.hashSize = 8 * (1 << 20); // 8MB + init_object(NULL, sizeof(GSettings), SETTINGS, true, true, true, + &settings); + init_object(NULL, sizeof(GSharedInfo), SHARED, true, false, true, + NULL); + mutex_init(&SHARED->mutex); + cond_init(&SHARED->goCondVar); + init_object(NULL, SETTINGS->hashSize, HASH, true, false, true, NULL); + init_object(NULL, pvHashSize, PVHASH, true, false, true, NULL); + init_object(NULL, pawnHashSize, PAWNHASH, true, false, true, NULL); + init_object(NULL, sizeof(GThreadInfo), INFO, true, false, true, NULL); + INFO->pid = get_pid(); + THREADS[0] = INFO; + + const int benchDepth = 14; + uint64_t t0 = get_time(); + for (int i = 2; i < argc; i++) + { + init_search(false); + get_board(argv[i]); + INFO->stop = false; + SHARED->depthLimit = 2 * benchDepth + 2; + SHARED->softTimeLimit = UINT32_MAX; + SHARED->hardTimeLimit = UINT32_MAX; + SHARED->startTime = t0; + if (Current->turn == White) root<0>(); else root<1>(); + send_best_move(); + } + uint64_t t1 = get_time(); + printf("TIME: %ldms\n", t1 - t0); + exit(EXIT_SUCCESS); + } + else if (argc > 1) + goto usage; // PARENT: printf("LazyGull\n"); @@ -5172,7 +5240,7 @@ int main(int argc, char **argv) size_t syzygyProbeDepth = 6; SyzygyPath[0] = '\0'; const char *val; - if ((val = getenv("GULL_HASH_SIZE")) != NULL) + if ((val = getenv("GULL_HASH")) != NULL) hashSize = HASH_SIZE((size_t)atoi(val)); if ((val = getenv("GULL_THREADS")) != NULL) numThreads = atoi(val); From e716cc852bafe1327972f3e19a4691727b5ca8c5 Mon Sep 17 00:00:00 2001 From: basil00 Date: Fri, 7 Oct 2016 22:47:56 +0800 Subject: [PATCH 3/9] Cleanup, PDEP bitboards, and Windows port. --- README.md | 22 +- src/Gull.cpp | 163 +++++++----- src/Linux.cpp | 38 ++- src/Linux.h | 3 + src/Makefile | 42 ---- src/Makefile.linux | 84 +++++++ src/Windows.cpp | 603 +++++++++++++++++++++++++++++++++++---------- src/Windows.h | 17 +- src/data.c | 45 ++++ src/data.h | 38 ++- src/tbconfig.h | 20 +- 11 files changed, 803 insertions(+), 272 deletions(-) delete mode 100644 src/Makefile create mode 100644 src/Makefile.linux diff --git a/README.md b/README.md index 3769365..18b188a 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,20 @@ -Gull 3 Chess (SYZYGY + LAZYSMP) -=============================== +The LazyGull Chess Engine +========================= -This is a portable (Linux/MacOSX/Windows) version the Gull chess engine -version 3. +LazyGull is a free UCI chess engine derived from Gull 3. Compared to Gull, +LazyGull implements the following new features: -To build simply run `make` (from a terminal) in the `src` directory. +* Syzygy Tablebase support; +* LazySMP implementation; +* PDEP Bitboards for modern CPUs; and +* Portable to Windows, Linux and MacOSX. -To build syzygy Gull run `make syzygy` (from a terminal) in the `src` -directory. Note that the `Makefile` uses `wget` to automatically download -the Fathom dependency (https://github.com/basil00/Fathom). +To build simply run the following commands in the `src` directory: + + make -f Makefile.linux + make -f Makefile.windows + +And follow the instructions. Pre-built binaries are available here: https://github.com/basil00/Gull/releases diff --git a/src/Gull.cpp b/src/Gull.cpp index bca401a..e6b66ca 100644 --- a/src/Gull.cpp +++ b/src/Gull.cpp @@ -65,7 +65,7 @@ #define PVarC(prefix,var,me) ((me) ? (prefix.var##_b) : (prefix.var##_w)) #define Bit(x) (Convert(1,uint64_t) << (x)) -#ifndef HNI +#ifndef GULL_PDEP_BITBOARDS #define Cut(x) (x &= (x) - 1) #else #define Cut(x) (x = _blsr_u64(x)) @@ -253,19 +253,6 @@ const int32_t ROffset[64] = }; #endif -#ifndef HNI -#define BishopAttacks(sq, occ) \ - (*(DATA->BOffsetPointer[sq] + \ - (((DATA->BMagicMask[sq] & (occ)) * \ - DATA->BMagic[sq]) >> DATA->BShift[sq]))) -#define RookAttacks(sq, occ) \ - (*(DATA->ROffsetPointer[sq] + \ - (((DATA->RMagicMask[sq] & (occ)) * \ - DATA->RMagic[sq]) >> DATA->RShift[sq]))) -#else -#define BishopAttacks(sq,occ) (*(BOffsetPointer[sq] + _pext_u64(occ,BMagicMask[sq]))) -#define RookAttacks(sq,occ) (*(ROffsetPointer[sq] + _pext_u64(occ,RMagicMask[sq]))) -#endif #define QueenAttacks(sq, occ) (BishopAttacks(sq, occ) | RookAttacks(sq, occ)) #define FlagUnusualMaterial (1 << 30) @@ -431,7 +418,7 @@ typedef struct { int margin, *start, *current; int moves[230]; } GData; -__align(64) GData Data[128]; +__align(64) GData Data[256]; GData *Current = Data; #define FlagSort (1 << 0) #define FlagNoBcSort (1 << 1) @@ -561,9 +548,6 @@ int Aspiration = 1, LargePages = 1; int64_t InfoTime; uint16_t SMoves[256]; -jmp_buf Jump, ResetJump; -GHandle StreamHandle; - #define ExclSingle(depth) 8 #define ExclDouble(depth) 16 #define ExclSinglePV(depth) 8 @@ -827,6 +811,9 @@ typedef struct int selDepth; int bestMove; int bestScore; +#ifdef WINDOWS + GEvent goEvent; +#endif int PV[]; } GThreadInfo; #define MAX_PV_LEN ((PAGE_SIZE - sizeof(GThreadInfo)) / sizeof(int)) @@ -836,6 +823,7 @@ typedef struct unsigned numThreads; unsigned syzygyProbeDepth; size_t hashSize; + unsigned parentPid; } GSettings; typedef struct @@ -844,8 +832,13 @@ typedef struct int init; uint16_t date; GMutex mutex; +#ifdef LINUX GCondVar goCondVar; GCondVar initCondVar; +#endif +#ifdef WINDOWS + GEvent initEvent; +#endif unsigned rootDepth; unsigned depthLimit; uint64_t startTime; @@ -1043,7 +1036,7 @@ uint64_t rand64(void) return key | Convert(rand16(),uint64_t); } -static char SyzygyPath[BUFSIZ] = {'\0'}; +static char SyzygyPath[PATH_MAX] = {'\0'}; #define MAX_THREADS (PAGE_SIZE / sizeof(GThreadInfo *)) static GThreadInfo *THREADS[MAX_THREADS] = {NULL}; @@ -1089,7 +1082,7 @@ static void go(void) int bestMove = (TB_GET_FROM(res) << 6) | to | flags; char movStr[16]; move_to_string(bestMove, movStr); - char line[BUFSIZ]; + char line[IOSIZE]; int len = snprintf(line, sizeof(line)-1, "info depth 1 seldepth 1 " "score cp %d nodes 1 tbhits 1 pv %s\n", bestScore, movStr); if (len > 0 && len < sizeof(line)-1) @@ -1119,12 +1112,24 @@ static void go(void) THREADS[i]->PV[0] = 0; } SHARED->state = SETTINGS->numThreads; +#ifdef LINUX cond_broadcast(&SHARED->goCondVar); +#endif +#ifdef WINDOWS + for (int i = 0; i < SETTINGS->numThreads; i++) + event_signal(&THREADS[i]->goEvent); +#endif } static void wait_for_go(void) { +#ifdef LINUX cond_wait(&SHARED->goCondVar, &SHARED->mutex); +#endif +#ifdef WINDOWS + event_wait(&INFO->goEvent, &SHARED->mutex); + mutex_lock(&SHARED->mutex); +#endif } static void wait_for_stop(void) @@ -1168,6 +1173,7 @@ static void emergency_stop(void) log("warning: threads crashed or deadlocked; initiating emergency reset\n"); reset(SETTINGS->numThreads, SETTINGS->syzygyProbeDepth, SETTINGS->hashSize, SyzygyPath); + mutex_lock(&SHARED->mutex); if (!go) return; char line[32], moveStr[16]; @@ -4094,8 +4100,7 @@ template int pv_search(int alpha, int beta, int depth, int } } - if (hash_depth < 0 && depth >= SETTINGS->syzygyProbeDepth && - TB_LARGEST > 0 && popcount(PieceAll) <= TB_LARGEST) + if (hash_depth < 0 && TB_LARGEST > 0 && popcount(PieceAll) <= TB_LARGEST) { unsigned res = tb_probe_wdl(Piece(White), Piece(Black), King(White) | King(Black), @@ -4617,7 +4622,8 @@ template void root(void) memcpy(SaveBoard,Board,sizeof(GBoard)); memcpy(SaveData,Data,sizeof(GData)); save_sp = sp; - for (depth = start_depth; depth < SHARED->depthLimit; depth += 2) + for (depth = start_depth; depth < SHARED->depthLimit && depth < 256; + depth += 2) { INFO->depth = depth; uint32_t sched = @@ -4771,7 +4777,7 @@ static void send_pv(const int *PV, size_t nodes, size_t tbHits, int depth, size_t nps = (nodes * 1000) / elapsedTime; - char pvStr[BUFSIZ]; + char pvStr[IOSIZE]; unsigned pvPos = 0; for (unsigned i = 0; i < MAX_PV_LEN && PV[i] != 0; i++) { @@ -4798,9 +4804,10 @@ static void send_pv(const int *PV, size_t nodes, size_t tbHits, int depth, } pvStr[pvPos++] = '\0'; - char line[BUFSIZ]; + char line[IOSIZE]; int len = snprintf(line, sizeof(line)-1, "info depth %d seldepth %d score " - "%s %d multipv 1 nodes %zu nps %zu tbhits %zu time %ld pv%s\n", + "%s %d multipv 1 nodes %" SIZE_T " nps %" SIZE_T " tbhits %" SIZE_T + " time %ld pv%s\n", depth/2, selDepth/2, scoreType, bestScore, nodes, nps, tbHits, currTime - startTime, pvStr); if (len < 0 || len >= sizeof(line)-1) @@ -4818,7 +4825,7 @@ static void send_curr_move(int move, int cnt) currTime - InfoTime <= InfoDelay) return; InfoTime = currTime; - char moveStr[16], line[BUFSIZ]; + char moveStr[16], line[IOSIZE]; move_to_string(move, moveStr); int len = snprintf(line, sizeof(line)-1, "info currmove %s currmovenumber %d\n", moveStr, cnt); @@ -4861,12 +4868,12 @@ static void send_best_move(const int *PV, size_t nodes, size_t tbHits, else scoreType = "cp"; - char line[BUFSIZ]; + char line[IOSIZE]; uint64_t time = stopTime - startTime; uint64_t nps = (nodes / Max(time / 1000, 1)); - int len = snprintf(line, sizeof(line)-1, "info nodes %zu tbhits %zu " - "time %ld nps %ld score %s %d\n", nodes, tbHits, time, nps, scoreType, - bestScore); + int len = snprintf(line, sizeof(line)-1, "info nodes %" SIZE_T + " tbhits %" SIZE_T " time %ld nps %ld score %s %d\n", nodes, tbHits, + time, nps, scoreType, bestScore); if (len > 0 && len < sizeof(line)-1) put_line(line, len); @@ -4900,7 +4907,7 @@ static inline int64_t get_number(const char *token) void uci(void) { - char line[4 * BUFSIZ]; + char line[4 * IOSIZE]; uint64_t currTime = get_time(); mutex_lock(&SHARED->mutex); @@ -4917,12 +4924,9 @@ void uci(void) currTime = get_time(); if (mutex_lock(&SHARED->mutex, 500)) - { emergency_stop(); - mutex_lock(&SHARED->mutex); - } if (SHARED->state != STOPPED && - currTime >= SHARED->startTime + SHARED->hardTimeLimit) + currTime >= SHARED->startTime + SHARED->hardTimeLimit / 2) { stop(); wait_for_stop(); @@ -5046,15 +5050,16 @@ void uci(void) else goto bad_command; token = strtok_r(moves, " ", &saveptr); - if (token == NULL || strcmp(token, "moves") != 0) - goto bad_command; - while ((token = strtok_r(NULL, " ", &saveptr)) != NULL) + if (token != NULL && strcmp(token, "moves") == 0) { - int move = move_from_string(token); - if (Current->turn) do_move<1>(move); else do_move<0>(move); - memcpy(Data, Current, sizeof(GData)); - Current = Data; - SHARED->rootDepth++; + while ((token = strtok_r(NULL, " ", &saveptr)) != NULL) + { + int move = move_from_string(token); + if (Current->turn) do_move<1>(move); else do_move<0>(move); + memcpy(Data, Current, sizeof(GData)); + Current = Data; + SHARED->rootDepth++; + } } memcpy(Stack, Stack + sp - Current->ply, (Current->ply + 1) * sizeof(uint64_t)); @@ -5094,6 +5099,7 @@ void uci(void) else goto bad_command; reset(numThreads, syzygyProbeDepth, hashSize, SyzygyPath); + mutex_lock(&SHARED->mutex); } else if (strcmp(token, "ucinewgame") == 0) { @@ -5112,7 +5118,7 @@ void uci(void) "option name Threads type spin min 1 max 64 default 4\n" "option name SyzygyPath type string default \n" "option name SyzygyProbeDepth type spin min 0 max 64 " - "default 6\n" + "default 1\n" "uciok\n"; put_line(reply, sizeof(reply)-1); } @@ -5174,7 +5180,8 @@ int main(int argc, char **argv) continue; } char infoName[256] = {0}; - init_object_name(infoName, sizeof(infoName)-1, "INFO", i); + init_object_name(infoName, sizeof(infoName)-1, "INFO", + SETTINGS->parentPid, i); THREADS[i] = (GThreadInfo *)init_object(infoName, sizeof(GThreadInfo), NULL, false, false, true, NULL); } @@ -5184,7 +5191,14 @@ int main(int argc, char **argv) mutex_lock(&SHARED->mutex); SHARED->init--; if (SHARED->init == 0) + { +#ifdef LINUX cond_signal(&SHARED->initCondVar); +#endif +#ifdef WINDOWS + event_signal(&SHARED->initEvent); +#endif + } mutex_unlock(&SHARED->mutex); worker(); // Wait for work from parent. @@ -5202,7 +5216,9 @@ int main(int argc, char **argv) init_object(NULL, sizeof(GSharedInfo), SHARED, true, false, true, NULL); mutex_init(&SHARED->mutex); +#ifdef LINUX cond_init(&SHARED->goCondVar); +#endif init_object(NULL, SETTINGS->hashSize, HASH, true, false, true, NULL); init_object(NULL, pvHashSize, PVHASH, true, false, true, NULL); init_object(NULL, pawnHashSize, PAWNHASH, true, false, true, NULL); @@ -5233,11 +5249,12 @@ int main(int argc, char **argv) // PARENT: printf("LazyGull\n"); + init_os(); // Read override parameters from the environment (useful for debugging) unsigned numThreads = get_num_cpus(); size_t hashSize = 128 * (1 << 20); // 128MB - size_t syzygyProbeDepth = 6; + size_t syzygyProbeDepth = 1; SyzygyPath[0] = '\0'; const char *val; if ((val = getenv("GULL_HASH")) != NULL) @@ -5271,63 +5288,73 @@ static void create_children(size_t numThreads, size_t syzygyProbeDepth, hashSize = Min(maxHashSize, hashSize); numThreads = Min(maxNumThreads, numThreads); syzygyProbeDepth = Min(maxSyzygyProbeDepth, syzygyProbeDepth); + unsigned pid = get_pid(); - log("settings: numThreads=%zu, hashSize=%zu, " - "syzygyProbeDepth=%zu, syzygyPath=\"%s\"\n", + log("settings: numThreads=%" SIZE_T ", hashSize=%" SIZE_T ", " + "syzygyProbeDepth=%" SIZE_T ", syzygyPath=\"%s\"\n", numThreads, hashSize, syzygyProbeDepth, tbPath); // Create shared objects: char dataName[256] = {0}; - init_object_name(dataName, sizeof(dataName)-1, "DATA", 0); + init_object_name(dataName, sizeof(dataName)-1, "DATA", pid, 0); init_object(dataName, sizeof(GGlobalData), DATA, true, false, true, NULL); init_data(); char settingsName[256] = {0}; - init_object_name(settingsName, sizeof(settingsName)-1, "SETTINGS", 0); + init_object_name(settingsName, sizeof(settingsName)-1, "SETTINGS", pid, 0); GSettings settings; settings.numThreads = numThreads; settings.syzygyProbeDepth = syzygyProbeDepth; settings.hashSize = hashSize; + settings.parentPid = pid; init_object(settingsName, sizeof(settings), SETTINGS, true, true, true, &settings); char hashName[256] = {0}; - init_object_name(hashName, sizeof(hashName)-1, "HASH", 0); + init_object_name(hashName, sizeof(hashName)-1, "HASH", pid, 0); init_object(hashName, hashSize, HASH, true, false, true, NULL); char pvHashName[256] = {0}; - init_object_name(pvHashName, sizeof(pvHashName)-1, "PVHASH", 0); + init_object_name(pvHashName, sizeof(pvHashName)-1, "PVHASH", pid, 0); init_object(pvHashName, pvHashSize, PVHASH, true, false, true, NULL); char pawnHashName[256] = {0}; - init_object_name(pawnHashName, sizeof(pawnHashName)-1, "PAWNHASH", 0); + init_object_name(pawnHashName, sizeof(pawnHashName)-1, "PAWNHASH", pid, 0); init_object(pawnHashName, pawnHashSize, PAWNHASH, true, false, true, NULL); char sharedName[256] = {0}; - init_object_name(sharedName, sizeof(sharedName)-1, "SHARED", 0); + init_object_name(sharedName, sizeof(sharedName)-1, "SHARED", pid, 0); init_object(sharedName, sizeof(GSharedInfo), SHARED, true, false, true, NULL); SHARED->init = numThreads; mutex_init(&SHARED->mutex); +#ifdef LINUX cond_init(&SHARED->goCondVar); cond_init(&SHARED->initCondVar); +#endif +#ifdef WINDOWS + event_init(&SHARED->initEvent); +#endif // Create children: for (size_t i = 0; i < numThreads; i++) { char infoName[256] = {0}; - init_object_name(infoName, sizeof(infoName)-1, "INFO", i); + init_object_name(infoName, sizeof(infoName)-1, "INFO", pid, i); THREADS[i] = (GThreadInfo *)init_object(infoName, sizeof(GThreadInfo), NULL, true, false, true, NULL); THREADS[i]->stop = true; THREADS[i]->newGame = true; THREADS[i]->id = (unsigned)i; +#ifdef WINDOWS + event_init(&THREADS[i]->goEvent); +#endif } for (size_t i = 0; i < numThreads; i++) { char infoName[256] = {0}; - init_object_name(infoName, sizeof(infoName)-1, "INFO", i); + init_object_name(infoName, sizeof(infoName)-1, "INFO", pid, i); create_child(hashName, pvHashName, pawnHashName, dataName, settingsName, sharedName, infoName, tbPath); } @@ -5338,7 +5365,15 @@ static void create_children(size_t numThreads, size_t syzygyProbeDepth, // Wait for threads to finish initializing: mutex_lock(&SHARED->mutex); while (SHARED->init != 0) + { +#ifdef LINUX cond_wait(&SHARED->initCondVar, &SHARED->mutex); +#endif +#ifdef WINDOWS + event_wait(&SHARED->initEvent, &SHARED->mutex); + mutex_lock(&SHARED->mutex); +#endif + } mutex_unlock(&SHARED->mutex); // Cleanup: @@ -5351,7 +5386,7 @@ static void create_children(size_t numThreads, size_t syzygyProbeDepth, for (size_t i = 0; i < numThreads; i++) { char infoName[256] = {0}; - init_object_name(infoName, sizeof(infoName)-1, "INFO", i); + init_object_name(infoName, sizeof(infoName)-1, "INFO", pid, i); remove_object(infoName); } } @@ -5364,12 +5399,24 @@ static void nuke_children(void) for (size_t i = 0; i < SETTINGS->numThreads; i++) nuke_child(THREADS[i]->pid); delete_object(HASH, SETTINGS->hashSize); + delete_object(PVHASH, pvHashSize); delete_object(PAWNHASH, pawnHashSize); + mutex_free(&SHARED->mutex); +#ifdef LINUX + cond_free(&SHARED->goCondVar); + cond_free(&SHARED->initCondVar); +#endif for (size_t i = 0; i < SETTINGS->numThreads; i++) + { +#ifdef WINDOWS + event_free(&THREADS[i]->goEvent); +#endif delete_object(THREADS[i], sizeof(GThreadInfo)); + } delete_object(DATA, sizeof(GGlobalData)); delete_object(SETTINGS, sizeof(GSettings)); delete_object(SHARED, sizeof(GSharedInfo)); + delete_object(INFO, sizeof(GThreadInfo)); } /* diff --git a/src/Linux.cpp b/src/Linux.cpp index 59c9583..4f5b8a3 100644 --- a/src/Linux.cpp +++ b/src/Linux.cpp @@ -64,7 +64,7 @@ */ static void log(const char *format, ...) { - FILE *stream = fopen("gull.log", "a"); + FILE *stream = fopen("lazygull.log", "a"); if (stream == NULL) return; va_list ap; @@ -87,11 +87,12 @@ static void log(const char *format, ...) /* * Init an object name. */ -void init_object_name(char *name, size_t len, const char *basename, int idx) +void init_object_name(char *name, size_t len, const char *basename, + unsigned id, int idx) { - int r = snprintf(name, len, "/GULL_%s_%d", basename, idx); + int r = snprintf(name, len, "/LazyGull_%u_%s_%d", id, basename, idx); if (r < 0 || r >= len) - error("failed to create object name: %s\n", strerror(errno)); + error("failed to create object name: %s", strerror(errno)); } /* @@ -171,7 +172,7 @@ void create_child(const char *hashName, const char *pvHashName, if (pid != 0) return; prctl(PR_SET_PDEATHSIG, SIGHUP); - char exe[BUFSIZ]; + char exe[PATH_MAX]; ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe)-1); if (len < 0) error("failed to read link: %s", strerror(errno)); @@ -257,9 +258,6 @@ static void cond_init(GCondVar *condVar) } #define mutex_unlock pthread_mutex_unlock -#define cond_signal pthread_cond_signal -#define cond_broadcast pthread_cond_broadcast -#define cond_wait pthread_cond_wait static void mutex_lock(GMutex *mutex) { @@ -280,12 +278,26 @@ static bool mutex_lock(GMutex *mutex, uint64_t timeout) return (r == ETIMEDOUT); } +static void mutex_free(GMutex *mutex) +{ + // NOP +} + +#define cond_signal pthread_cond_signal +#define cond_broadcast pthread_cond_broadcast +#define cond_wait pthread_cond_wait + +static void cond_free(GCondVar *mutex) +{ + // NOP +} + /* * Input. */ static bool get_line(char *line, unsigned linelen, uint64_t timeout) { - static char buf[4 * BUFSIZ]; + static char buf[4 * IOSIZE]; static unsigned ptr = 0, end = 0; unsigned i = 0; @@ -366,3 +378,11 @@ static void put_line(char *line, unsigned linelen) } } +/* + * O/S specific init. + */ +static void init_os(void) +{ + // NOP. +} + diff --git a/src/Linux.h b/src/Linux.h index d8124d9..2927074 100644 --- a/src/Linux.h +++ b/src/Linux.h @@ -38,6 +38,7 @@ typedef pthread_cond_t GCondVar; #define __align(x) __attribute__((aligned(x))) #define PATH_MAX 4096 +#define SIZE_T "zu" #define INFO ((GThreadInfo *)0x300000) #define SETTINGS ((GSettings *)0x301000) @@ -47,4 +48,6 @@ typedef pthread_cond_t GCondVar; #define PVHASH ((GPVEntry *)0x20000000) #define HASH ((GEntry *)0x40000000) +#define IOSIZE 4096 + #endif diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index 9248c6b..0000000 --- a/src/Makefile +++ /dev/null @@ -1,42 +0,0 @@ -UNAME=$(shell uname -s) -ifeq ($(UNAME),Linux) - TARGET=gull.linux -endif -ifeq ($(UNAME),Darwin) - TARGET=gull.macosx -endif -ifeq ($(UNAME),Linux) - TARGET_SYZYGY=gull.syzygy.linux -endif -ifeq ($(UNAME),Darwin) - TARGET_SYZYGY=gull.syzygy.macosx -endif -CC=g++ -STRIP=strip -CFLAGS=-msse4.1 -mpopcnt -fno-exceptions -fno-rtti -Wno-parentheses -O3 \ - -lpthread -lrt - -main: $(TARGET) - -gull.linux: tbprobe.o - $(CC) $(CFLAGS) -D LINUX Gull.cpp tbprobe.o -o LazyGull - $(STRIP) LazyGull - -tbprobe.o: tbprobe.c tbcore.c - $(CC) $(CFLAGS) -D LINUX -c tbprobe.c - -tbprobe.c: Fathom-master.zip - unzip -o -j Fathom-master.zip "Fathom-master/src/tbprobe.h" -d "./" - unzip -o -j Fathom-master.zip "Fathom-master/src/tbprobe.c" -d "./" - -tbcore.c: Fathom-master.zip - unzip -o -j Fathom-master.zip "Fathom-master/src/tbcore.h" -d "./" - unzip -o -j Fathom-master.zip "Fathom-master/src/tbcore.c" -d "./" - -Fathom-master.zip: - wget https://github.com/basil00/Fathom/archive/master.zip \ - -O Fathom-master.zip - -clean: - rm -f LazyGull tbprobe.o - diff --git a/src/Makefile.linux b/src/Makefile.linux new file mode 100644 index 0000000..2091fe9 --- /dev/null +++ b/src/Makefile.linux @@ -0,0 +1,84 @@ +ifeq ($(COMP),) + CC=g++ +else + CC=$(COMP) +endif + +ifeq ($(ARCH),) + ARCH=x86-64 +endif + +CFLAGS=-fno-exceptions -fno-rtti -Wno-parentheses -lpthread -lrt +ifeq ($(ARCH),x86-64) + CFLAGS += -msse4.1 -mpopcnt -D GULL_MAGIC_BITBOARDS +endif + +ifeq ($(ARCH),x86-64-bmi2) + CFLAGS += -msse4.2 -mpopcnt -mavx2 -mbmi -mbmi2 -D GULL_PDEP_BITBOARDS +endif + +STRIP=strip + +help: + @echo + @echo "To build LazyGull, run:" + @echo + @echo " make -f Makefile.linux TARGET [ARCH=arch] [COMP=compiler]" + @echo + @echo "Where:" + @echo + @echo " TARGET=build" + @echo " Standard build." + @echo " TARGET=pgo-build" + @echo " Profile Guided Optimization (PGO) build." + @echo " TARGET=debug" + @echo " Debug build." + @echo + @echo " ARCH=x86-64" + @echo " Standard x86-64 (with popcnt and SSE4.1 support). [DEFAULT]" + @echo " ARCH=x86-64-bmi2" + @echo " Modern x86-64 (with popcnt, SSE4.2, BMI, BMI2, AVX2"\ + "support)." + @echo + @echo " COMP=g++" + @echo " Use the GNU C++ compiler [DEFAULT]" + @echo " COMP=clang++" + @echo " Use LLVM Clang++ compiler" + @echo + @echo "To do a basic build, simply run:" + @echo + @echo " make -f Makefile.linux build" + @echo + +build: tbprobe.c + $(CC) $(CFLAGS) -O3 -D LINUX Gull.cpp tbprobe.c -o LazyGull + $(STRIP) LazyGull + +pgo-build: tbprobe.c + rm -f *.gcda + $(CC) $(CFLAGS) -O3 -fprofile-generate -D LINUX Gull.cpp tbprobe.c -o \ + LazyGull + ./LazyGull bench \ + "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" + $(CC) $(CFLAGS) -O3 -fprofile-use -fno-peel-loops -fno-tracer -D LINUX \ + Gull.cpp tbprobe.c -o LazyGull + $(STRIP) LazyGull + +debug: tbprobe.c + $(CC) $(CFLAGS) -O0 -g -D LINUX Gull.cpp tbprobe.c -o LazyGull + +tbprobe.c: Fathom-master.zip + unzip -o -j Fathom-master.zip "Fathom-master/src/tbprobe.h" -d "./" + unzip -o -j Fathom-master.zip "Fathom-master/src/tbprobe.c" -d "./" + +tbcore.c: Fathom-master.zip + unzip -o -j Fathom-master.zip "Fathom-master/src/tbcore.h" -d "./" + unzip -o -j Fathom-master.zip "Fathom-master/src/tbcore.c" -d "./" + +Fathom-master.zip: + wget https://github.com/basil00/Fathom/archive/master.zip \ + -O Fathom-master.zip + +clean: + rm -f LazyGull tbprobe.o + diff --git a/src/Windows.cpp b/src/Windows.cpp index aa21cb4..bbfa68f 100644 --- a/src/Windows.cpp +++ b/src/Windows.cpp @@ -1,7 +1,7 @@ /* * Windows.cpp * Original Gull code is in the "public domain". - * New code: Copyright (c) 2015 the copyright holders + * New code: Copyright (c) 2016 the copyright holders * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -22,6 +22,7 @@ * DEALINGS IN THE SOFTWARE. */ +#include #include #include #include @@ -32,157 +33,491 @@ #include #include +#define UINT64_MAX 0xFFFFFFFFFFFFFFFFull // XXX +#define UINT32_MAX 0xFFFFFFFF + #define builtin_cpuid(f, ax, bx, cx, dx) \ __asm__ __volatile__ ("cpuid" : "=a" (ax), "=b" (bx), "=c" (cx), \ "=d" (dx) : "a" (f)) -#define builtin_popcnt_u64(x) _mm_popcnt_u64((x)) - -#define builtin_sync_fetch_and_add(x, y) \ - __sync_fetch_and_add((x), (y)) -#define builtin_sync_fetch_and_or(x, y) \ - __sync_fetch_and_or((x), (y)) -#define builtin_sync_fetch_and_and(x, y) \ - __sync_fetch_and_and((x), (y)) -#define builtin_sync_bit_test_and_reset(x, y) \ - ((__sync_fetch_and_and((x), ~(1 << (y))) & (1 << (y))) != 0) -#define builtin_sync_lock_test_and_set(x, y) \ - __sync_lock_test_and_set((x), (y)) -#define builtin_sync_val_compare_and_swap(x, y, z) \ - __sync_val_compare_and_swap((x), (z), (y)) - -void init_hash() { -#ifdef TUNER - return; -#endif +#define PAGE_SIZE 4096 +#define SIZE(size) ((((size)-1) / PAGE_SIZE) * PAGE_SIZE + PAGE_SIZE) + +/* + * Log a message. + */ +static void log(const char *format, ...) +{ + FILE *stream = fopen("lazygull.log", "a"); + if (stream == NULL) + return; + va_list ap; + va_start(ap, format); + vfprintf(stream, format, ap); + va_end(ap); + fclose(stream); +} + +/* + * Print an error message. + */ +#define error(format, ...) \ + do { \ + log("error: " format "\n", ##__VA_ARGS__); \ + fprintf(stderr, "error: " format "\n", ##__VA_ARGS__); \ + abort(); \ + } while (false) + +/* + * Init an object name. + */ +void init_object_name(char *name, size_t len, const char *basename, + unsigned id, int idx) +{ + int r = snprintf(name, len, "Local\\LazyGull_%u_%s_%d", id, basename, idx); + if (r < 0 || r >= len) + error("failed to create object name (%d)", GetLastError()); +} + +/* + * Init an object. + */ +typedef struct +{ char name[256]; - sint64 size = (hash_size * sizeof(GEntry)); - int min_page_size; - HINSTANCE hDll; - sprintf(name, "GULL_HASH_%d", WinParId); - int initialized = 0; - if (parent && HASH != NULL) { - initialized = 1; - UnmapViewOfFile(Hash); - CloseHandle(HASH); + HANDLE handle; +} GHandleInfo; + +static GHandleInfo handleInfo[16] = {0}; + +void *init_object(const char *object, size_t size, void *addr, + bool create, bool readonly, bool map, const void *value) +{ + size_t size2 = SIZE(size); + HANDLE handle = INVALID_HANDLE_VALUE; + if (object != NULL) + { + if (create) + { + handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, (DWORD)(size2 >> 32), + (DWORD)(size2 & 0xFFFFFFFF), object); + for (unsigned i = 0; + i < sizeof(handleInfo) / sizeof(handleInfo[0]); i++) + { + if (handleInfo[i].name[0] == '\0') + { + strncpy(handleInfo[i].name, object, + sizeof(handleInfo[i].name)-1); + handleInfo[i].handle = handle; + break; + } + } + } + else + handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, object); } - if (parent) { - if (!LargePages) goto no_lp; -#ifndef LARGE_PAGES - goto no_lp; -#endif - typedef int(*GETLARGEPAGEMINIMUM)(void); - GETLARGEPAGEMINIMUM pGetLargePageMinimum; - hDll = LoadLibrary(TEXT("kernel32.dll")); - if (hDll == NULL) goto no_lp; - pGetLargePageMinimum = (GETLARGEPAGEMINIMUM)GetProcAddress(hDll, "GetLargePageMinimum"); - if (pGetLargePageMinimum == NULL) goto no_lp; - min_page_size = (*pGetLargePageMinimum)(); - if (size < min_page_size) size = min_page_size; - if (!initialized) { - TOKEN_PRIVILEGES tp; - HANDLE hToken; - OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken); - LookupPrivilegeValue(NULL, "SeLockMemoryPrivilege", &tp.Privileges[0].Luid); - tp.PrivilegeCount = 1; - tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0); + else + handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, + (DWORD)(size2 >> 32), (DWORD)(size2 & 0xFFFFFFFF), NULL); + if ((handle == INVALID_HANDLE_VALUE || handle == NULL) && + (create || GetLastError() != ERROR_ALREADY_EXISTS)) + error("failed to open file mapping \"%s\" (%d)", object, + GetLastError()); + void *ptr = NULL; + if (map) + { + DWORD access = FILE_MAP_READ | + (readonly && value == NULL? 0: FILE_MAP_WRITE); + ptr = MapViewOfFileEx(handle, access, 0, 0, size2, addr); + if (ptr == NULL) + error("failed to map file mapping \"%s\" (%d)", object, + GetLastError()); + if (value != NULL) + { + memcpy(ptr, value, size); + DWORD old_prot; + if (readonly && + !VirtualProtect(ptr, size2, PAGE_READONLY, &old_prot)) + error("failed to protect object \"%s\" (%d)", object, + GetLastError()); } - HASH = NULL; - HASH = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE | SEC_COMMIT | SEC_LARGE_PAGES, size >> 32, size & 0xFFFFFFFF, name); - if (HASH != NULL) { - fprintf(stdout, "Large page hash\n"); - goto hash_allocated; + } + if (!create || object == NULL) + CloseHandle(handle); + return ptr; +} + +/* + * Remove object. + */ +void remove_object(const char *object) +{ + for (unsigned i = 0; i < i < sizeof(handleInfo) / sizeof(handleInfo[0]); + i++) + { + if (strcmp(handleInfo[i].name, object) == 0) + { + handleInfo[i].name[0] = '\0'; + CloseHandle(handleInfo[i].handle); + handleInfo[i].handle = NULL; + return; } - no_lp: - HASH = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, size >> 32, size & 0xFFFFFFFF, name); - } else HASH = OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, name); -hash_allocated: - Hash = (GEntry*)MapViewOfFile(HASH, FILE_MAP_ALL_ACCESS, 0, 0, size); - if (parent) memset(Hash, 0, size); - hash_mask = hash_size - 4; -} - -void init_shared() { -#ifdef TUNER - return; -#endif - char name[256]; - sint64 size = SharedPVHashOffset + pv_hash_size * sizeof(GPVEntry); - sprintf(name, "GULL_SHARED_%d", WinParId); - if (parent && SHARED != NULL) { - UnmapViewOfFile(Smpi); - CloseHandle(SHARED); } - if (parent) SHARED = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, name); - else SHARED = OpenFileMapping(FILE_MAP_ALL_ACCESS, 0, name); - Smpi = (GSMPI*)MapViewOfFile(SHARED, FILE_MAP_ALL_ACCESS, 0, 0, size); - if (parent) memset(Smpi, 0, size); - Material = (GMaterial*)(((char*)Smpi) + SharedMaterialOffset); - MagicAttacks = (uint64*)(((char*)Smpi) + SharedMagicOffset); - PVHash = (GPVEntry*)(((char*)Smpi) + SharedPVHashOffset); - if (parent) memset(PVHash, 0, pv_hash_size * sizeof(GPVEntry)); -} - -int input() { - if (child) return 0; - DWORD p; - if (F(Input)) return 0; - if (F(Console)) { - if (PeekNamedPipe(StreamHandle,NULL,0,NULL,&p,NULL)) return (p > 0); - else return 1; - } else return 0; -} - -HANDLE CreateChildProcess(int child_id) { - char name[1024]; - TCHAR szCmdline[1024]; - PROCESS_INFORMATION piProcInfo; - STARTUPINFO siStartInfo; - BOOL bSuccess = FALSE; + error("failed to remove object \"%s\"", object); +} + +/* + * Delete an object. + */ +void delete_object(void *addr, size_t size) +{ + if (!UnmapViewOfFile(addr)) + error("failed to unmap object (%d)", GetLastError()); +} + +/* + * Create a child process. + */ +void create_child(const char *hashName, const char *pvHashName, + const char *pawnHashName, const char *dataName, const char *settingsName, + const char *sharedName, const char *infoName, const char *tbPath) +{ + char name[PATH_MAX]; + char command[10 * PATH_MAX]; + PROCESS_INFORMATION procInfo; + STARTUPINFO startInfo; - ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); - ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); - ZeroMemory(szCmdline, 1024 * sizeof(TCHAR)); - ZeroMemory(name, 1024); - - siStartInfo.cb = sizeof(STARTUPINFO); - siStartInfo.dwFlags |= STARTF_USESTDHANDLES; + memset(&procInfo, 0, sizeof(procInfo)); + memset(&startInfo, 0, sizeof(startInfo)); - GetModuleFileName(NULL, name, 1024); - sprintf(szCmdline, " child %d %d", WinParId, child_id); - - bSuccess = CreateProcess(TEXT(name), TEXT(szCmdline), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &siStartInfo, &piProcInfo); + startInfo.cb = sizeof(STARTUPINFO); + startInfo.dwFlags |= STARTF_USESTDHANDLES; + startInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + startInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + startInfo.hStdInput = INVALID_HANDLE_VALUE; - if (bSuccess) { - CloseHandle(piProcInfo.hThread); - return piProcInfo.hProcess; - } else { - fprintf(stdout, "Error %d\n", GetLastError()); - return NULL; - } + if (GetModuleFileName(NULL, name, sizeof(name)-1) >= sizeof(name)-1) + error("failed to get module name"); + int len = snprintf(command, sizeof(command)-1, + "\"%s\" child \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"", + name, hashName, pvHashName, pawnHashName, dataName, settingsName, + sharedName, infoName, tbPath); + if (len < 0 || len >= sizeof(command)-1) + error("failed to create command line for child"); + + BOOL success = CreateProcess(NULL, command, NULL, NULL, TRUE, + 0, NULL, NULL, &startInfo, &procInfo); + if (!success) + error("failed to create child process (%d)", GetLastError()); + CloseHandle(procInfo.hThread); +} + +/* + * Get the process ID. + */ +unsigned get_pid(void) +{ + return (unsigned)GetCurrentProcessId(); } +/* + * Get the number of CPUs. + */ +unsigned get_num_cpus(void) +{ + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + return (unsigned)sysinfo.dwNumberOfProcessors; +} + +/* + * Nuke a chold process. + */ +static void nuke_child(unsigned pid) +{ + HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid); + if (handle == NULL) + return; + TerminateProcess(handle, EXIT_SUCCESS); + if (WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0) + error("failed to terminate child (%d)", GetLastError()); + CloseHandle(handle); +} + +/* + * Sleep for `ms' milliseconds. + */ static void msleep(unsigned ms) { Sleep(ms); } -sint64 get_time() { -#ifdef CPU_TIMING -#ifndef TIMING - if (CpuTiming) { -#endif - uint64 ctime; - QueryProcessCycleTime(GetCurrentProcess(), &ctime); -#ifdef TIMING - return ctime / (CyclesPerMSec / 1000); -#endif - return (ctime / CyclesPerMSec); -#ifndef TIMING - } -#endif -#endif - return GetTickCount(); +/* + * Get the time in milliseconds. + */ +int64_t get_time(void) +{ + return GetTickCount64(); +} + +/* + * Threads. + */ +typedef HANDLE GMutex; +typedef HANDLE GEvent; + +static void mutex_init(GMutex *mutex) +{ + SECURITY_ATTRIBUTES attr; + memset(&attr, 0, sizeof(attr)); + attr.nLength = sizeof(attr); + attr.bInheritHandle = TRUE; + *mutex = CreateMutex(&attr, FALSE, NULL); + if (*mutex == NULL) + error("failed to create mutex (%d)", GetLastError()); +} + +static void mutex_lock(GMutex *mutex) +{ + if (WaitForSingleObject(*mutex, INFINITE) != WAIT_OBJECT_0) + error("failed to lock mutex (%d)", GetLastError()); +} + +static bool mutex_lock(GMutex *mutex, uint64_t timeout) +{ + switch (WaitForSingleObject(*mutex, (DWORD)timeout)) + { + case WAIT_OBJECT_0: + return false; + case WAIT_TIMEOUT: + return true; + default: + error("failed to lock mutex (%d)", GetLastError()); + } +} + +static void mutex_unlock(GMutex *mutex) +{ + if (!ReleaseMutex(*mutex)) + error("failed to unlock mutex (%d)", GetLastError()); +} + +static void mutex_free(GMutex *mutex) +{ + CloseHandle(*mutex); +} + +static void event_init(GEvent *event) +{ + SECURITY_ATTRIBUTES attr; + memset(&attr, 0, sizeof(attr)); + attr.nLength = sizeof(attr); + attr.bInheritHandle = TRUE; + *event = CreateEvent(&attr, FALSE, FALSE, NULL); + if (*event == NULL) + error("failed to create event (%d)", GetLastError()); +} + +static void event_signal(GEvent *event) +{ + SetEvent(*event); +} + +static void event_wait(GEvent *event, GMutex *mutex) +{ + if (SignalObjectAndWait(*mutex, *event, INFINITE, FALSE) != + WAIT_OBJECT_0) + error("failed to wait for event (%d)", GetLastError()); +} + +static void event_free(GEvent *event) +{ + CloseHandle(*event); +} + +/* + * Input + */ +static DWORD forward(LPVOID param) +{ + char buf[4 * IOSIZE]; + HANDLE in = GetStdHandle(STD_INPUT_HANDLE); + HANDLE out = (HANDLE)param; + while (true) + { + DWORD len; + if (!ReadFile(in, buf, sizeof(buf), &len, NULL)) + error("failed to read input (%d)", GetLastError()); + if (len == 0) + { + CloseHandle(out); + return 0; + } + + DWORD ptr = 0; + while (ptr < len) + { + DWORD writelen; + if (!WriteFile(out, buf + ptr, len - ptr, &writelen, NULL)) + error("failed to forward input (%d)", GetLastError()); + ptr += writelen; + } + + FlushFileBuffers(out); + } +} + +static bool get_line(char *line, unsigned linelen, uint64_t timeout) +{ + static char buf[4 * IOSIZE]; + static unsigned ptr = 0, end = 0; + unsigned i = 0; + + static HANDLE handle = INVALID_HANDLE_VALUE; + static GEvent event = NULL; + static bool init = false; + if (!init) + { + handle = GetStdHandle(STD_INPUT_HANDLE); + if (GetFileType(handle) == FILE_TYPE_PIPE) + { + char name[256]; + int res = snprintf(name, sizeof(name)-1, + "\\\\.\\pipe\\LazyGull_%u_pipe", get_pid()); + if (res < 0 || res >= sizeof(name)-1) + error("failed to create pipe name"); + HANDLE out = CreateNamedPipe(name, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 2, + 4 * IOSIZE, 4 * IOSIZE, 0, NULL); + if (out == INVALID_HANDLE_VALUE) + error("failed to create named pipe #1 (%d)", GetLastError()); + handle = CreateFile(name, GENERIC_READ, 0, NULL, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + if (handle == INVALID_HANDLE_VALUE) + error("failed to create named pipe #2 (%d)", GetLastError()); + HANDLE thread = CreateThread(NULL, 0, forward, (LPVOID)out, 0, + NULL); + if (thread == NULL) + error("failed to create thread (%d)", GetLastError()); + } + event_init(&event); + init = true; + } + + while (true) + { + bool space = false; + while (ptr < end) + { + if (i >= linelen) + error("input buffer overflow"); + char c = buf[ptr++]; + switch (c) + { + case ' ': case '\r': case '\t': case '\n': + if (!space) + { + line[i++] = ' '; + space = true; + } + if (c == '\n') + { + line[i-1] = '\0'; + return false; + } + continue; + default: + space = false; + line[i++] = c; + continue; + } + } + + OVERLAPPED overlapped; + memset(&overlapped, 0, sizeof(overlapped)); + overlapped.hEvent = event; + DWORD len; + if (!ReadFile(handle, buf, sizeof(buf), &len, &overlapped)) + { + if (GetLastError() != ERROR_IO_PENDING) + error("failed to read input (%d)", GetLastError()); + bool timedout = false; + + switch (WaitForSingleObject(event, timeout)) + { + case WAIT_TIMEOUT: + if (!CancelIo(handle)) + error("failed to cancel input (%d)", GetLastError()); + timedout = true; + break; + case WAIT_OBJECT_0: + break; + default: + error("failed to wait for input (%d)", GetLastError()); + } + if (!GetOverlappedResult(handle, &overlapped, &len, FALSE)) + { + if (timedout && GetLastError() == ERROR_OPERATION_ABORTED) + return true; + error("failed to get input result (%d)", GetLastError()); + } + } + + if (len == 0) + { + line[0] = EOF; + return false; + } + + ptr = 0; + end = len; + } +} + +/* + * Output + */ +static void put_line(char *line, unsigned linelen) +{ + unsigned ptr = 0; + HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); + while (ptr < linelen) + { + DWORD len; + if (!WriteFile(handle, line + ptr, linelen - ptr, &len, NULL)) + error("failed to write output (%d)", GetLastError()); + ptr += (unsigned)len; + } + FlushFileBuffers(handle); +} + +/* + * O/S specific init. + */ +static void init_os(void) +{ + HANDLE handle = GetStdHandle(STD_INPUT_HANDLE); + DWORD mode; + if (GetConsoleMode(handle, &mode)) + { + mode &= ~ENABLE_MOUSE_INPUT; + mode &= ~ENABLE_WINDOW_INPUT; + mode |= ENABLE_LINE_INPUT; + mode |= ENABLE_ECHO_INPUT; + SetConsoleMode(handle, mode); + FlushConsoleInputBuffer(handle); + } + + HANDLE job = CreateJobObject(NULL, NULL); + if (job == NULL) + error("failed to create job object (%d)", GetLastError()); + JOBOBJECT_EXTENDED_LIMIT_INFORMATION info; + memset(&info, 0, sizeof(info)); + info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + SetInformationJobObject(job, JobObjectExtendedLimitInformation, &info, + sizeof(info)); + AssignProcessToJobObject(job, GetCurrentProcess()); // Allowed to fail } diff --git a/src/Windows.h b/src/Windows.h index b90709c..460bd05 100644 --- a/src/Windows.h +++ b/src/Windows.h @@ -29,9 +29,22 @@ #include #include -typedef HANDLE GHandle; -typedef HANDLE GProcess; +typedef HANDLE GMutex; +typedef HANDLE GEvent; #define __align(x) __attribute__((aligned(x))) +#define strtok_r strtok_s +#define SIZE_T "Iu" + +#define INFO ((GThreadInfo *)0x51010000) +#define SETTINGS ((GSettings *) 0x51000000) +#define SHARED ((GSharedInfo *)0x51020000) +#define DATA ((GGlobalData *)0x50000000) +#define PAWNHASH ((GPawnEntry *) 0x54000000) +#define PVHASH ((GPVEntry *) 0x58000000) +#define HASH ((GEntry *) 0x81230000) + +#define IOSIZE 4096 + #endif diff --git a/src/data.c b/src/data.c index 87c1af6..1ba2657 100644 --- a/src/data.c +++ b/src/data.c @@ -18,6 +18,7 @@ uint64_t RMagicAttacks(int i, uint64_t occ) return att; } +#ifdef GULL_MAGIC_BITBOARDS static void init_magic(void) { int i, j, k, index, bits, bit_list[16]; @@ -58,6 +59,48 @@ static void init_magic(void) memcpy(DATA->BShift, BShift, sizeof(DATA->BShift)); memcpy(DATA->RShift, RShift, sizeof(DATA->RShift)); } +#endif + +#ifdef GULL_PDEP_BITBOARDS +static void init_magic(void) +{ + unsigned offset = 0; + for (unsigned i = 0; i < 64; i++) + { + GAttackInfo *info = DATA->BAttacks + i; + info->data = DATA->MagicAttacks + offset; + uint64_t postmask = DATA->BMask[i]; + uint64_t premask = postmask & Interior; + info->premask = premask; + unsigned bits = (1 << popcount(premask)); + for (unsigned j = 0; j < bits; j++) + { + uint64_t occ = pdep(j, premask); + uint64_t att = BMagicAttacks(i, occ); + DATA->MagicAttacks[offset++] = (uint16_t)pext(att, postmask); + } + } + for (unsigned i = 0; i < 64; i++) + { + GAttackInfo *info = DATA->RAttacks + i; + info->data = DATA->MagicAttacks + offset; + uint64_t postmask = DATA->RMask[i]; + uint64_t premask = postmask; + if (File(i) > 0) premask &= ~DATA->File[0]; + if (Rank(i) > 0) premask &= ~DATA->Line[0]; + if (File(i) < 7) premask &= ~DATA->File[7]; + if (Rank(i) < 7) premask &= ~DATA->Line[7]; + info->premask = premask; + unsigned bits = (1 << popcount(premask)); + for (unsigned j = 0; j < bits; j++) + { + uint64_t occ = pdep(j, premask); + uint64_t att = RMagicAttacks(i, occ); + DATA->MagicAttacks[offset++] = (uint16_t)pext(att, postmask); + } + } +} +#endif static void init_misc(void) { @@ -108,12 +151,14 @@ static void init_misc(void) DATA->RMask[i] = DATA->HLine[i] | DATA->VLine[i]; DATA->BMask[i] = DATA->NDiag[i] | DATA->SDiag[i]; DATA->QMask[i] = DATA->RMask[i] | DATA->BMask[i]; +#ifdef GULL_MAGIC_BITBOARDS DATA->BMagicMask[i] = DATA->BMask[i] & Interior; DATA->RMagicMask[i] = DATA->RMask[i]; if (File(i) > 0) DATA->RMagicMask[i] &= ~DATA->File[0]; if (Rank(i) > 0) DATA->RMagicMask[i] &= ~DATA->Line[0]; if (File(i) < 7) DATA->RMagicMask[i] &= ~DATA->File[7]; if (Rank(i) < 7) DATA->RMagicMask[i] &= ~DATA->Line[7]; +#endif for (j = 0; j < 64; j++) if (DATA->NAtt[i] & DATA->NAtt[j]) Add(DATA->NArea[i], j); } diff --git a/src/data.h b/src/data.h index 298fb8b..748d1ea 100644 --- a/src/data.h +++ b/src/data.h @@ -3,7 +3,6 @@ #include -#define GULL_MAGIC_BITBOARDS typedef struct { int16_t score; @@ -28,6 +27,38 @@ typedef struct #define MagicSize 107648 +#ifdef GULL_MAGIC_BITBOARDS +#define BishopAttacks(sq, occ) \ + (*(DATA->BOffsetPointer[sq] + \ + (((DATA->BMagicMask[sq] & (occ)) * \ + DATA->BMagic[sq]) >> DATA->BShift[sq]))) +#define RookAttacks(sq, occ) \ + (*(DATA->ROffsetPointer[sq] + \ + (((DATA->RMagicMask[sq] & (occ)) * \ + DATA->RMagic[sq]) >> DATA->RShift[sq]))) +#endif /* GULL_MAGIC_BITBOARDS */ + +#ifdef GULL_PDEP_BITBOARDS +typedef struct +{ + const uint16_t *data; + uint64_t premask; +} GAttackInfo; + +#include + +#define pdep(x, mask) _pdep_u64((x), (mask)) +#define pext(x, mask) _pext_u64((x), (mask)) + +#define BishopAttacks(sq, occ) \ + pdep(DATA->BAttacks[sq].data[pext(occ, DATA->BAttacks[sq].premask)],\ + DATA->BMask[sq]) +#define RookAttacks(sq, occ) \ + pdep(DATA->RAttacks[sq].data[pext(occ, DATA->RAttacks[sq].premask)],\ + DATA->RMask[sq]) + +#endif /* GULL_PDEP_BITBOARDS */ + typedef struct { uint64_t Forward[2][8]; @@ -113,6 +144,11 @@ typedef struct uint64_t *ROffsetPointer[64]; uint64_t MagicAttacks[MagicSize]; #endif +#ifdef GULL_PDEP_BITBOARDS + GAttackInfo BAttacks[64]; + GAttackInfo RAttacks[64]; + uint16_t MagicAttacks[MagicSize]; +#endif } GGlobalData; #endif diff --git a/src/tbconfig.h b/src/tbconfig.h index 7db9871..a43d0d3 100644 --- a/src/tbconfig.h +++ b/src/tbconfig.h @@ -86,29 +86,13 @@ * Define TB_ROOK_ATTACKS(square, occ) to return the rook attacks bitboard * for a rook at `square' assuming the given `occ' occupancy bitboard. */ -#ifndef HNI -#define TB_ROOK_ATTACKS(square, occ) \ - (*(DATA->ROffsetPointer[(square)] + \ - (((DATA->RMagicMask[(square)] & (occ)) * \ - DATA->RMagic[(square)]) >> DATA->RShift[(square)]))) -#else -#define TB_ROOK_ATTACKS(square, occ) \ - (*(ROffsetPointer[(square)] + _pext_u64((occ), RMagicMask[(square)]))) -#endif +#define TB_ROOK_ATTACKS(square, occ) RookAttacks((square), (occ)) /* * Define TB_BISHOP_ATTACKS(square, occ) to return the bishop attacks bitboard * for a bishop at `square' assuming the given `occ' occupancy bitboard. */ -#ifndef HNI -#define TB_BISHOP_ATTACKS(square, occ) \ - (*(DATA->BOffsetPointer[(square)] + \ - (((DATA->BMagicMask[(square)] & (occ)) * \ - DATA->BMagic[(square)]) >> DATA->BShift[(square)]))) -#else -#define TB_BISHOP_ATTACKS(square, occ) \ - (*(BOffsetPointer[(square)] + _pext_u64((occ), BMagicMask[(square)]))) -#endif +#define TB_BISHOP_ATTACKS(square, occ) BishopAttacks((square), (occ)) /* * Define TB_QUEEN_ATTACKS(square, occ) to return the queen attacks bitboard From 59f7a93f501547e7a2c298260d61832823638fda Mon Sep 17 00:00:00 2001 From: basil00 Date: Fri, 7 Oct 2016 22:50:51 +0800 Subject: [PATCH 4/9] Add windows Makefile. --- src/Makefile.bmi2 | 32 ------------------- src/Makefile.windows | 75 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 32 deletions(-) delete mode 100755 src/Makefile.bmi2 create mode 100644 src/Makefile.windows diff --git a/src/Makefile.bmi2 b/src/Makefile.bmi2 deleted file mode 100755 index 2f149e9..0000000 --- a/src/Makefile.bmi2 +++ /dev/null @@ -1,32 +0,0 @@ -UNAME=$(shell uname -s) -ifeq ($(UNAME),Linux) - TARGET_SYZYGY=gull.syzygy.linux -endif -ifeq ($(UNAME),Darwin) - TARGET_SYZYGY=gull.syzygy.macosx -endif -CC=g++ -STRIP=strip -CFLAGS=-m64 -msse4.2 -mavx2 -mbmi -mbmi2 -mpopcnt -fno-exceptions -fno-rtti -Wno-parentheses -O3 -D HNI - -main: $(TARGET) - -gull.syzygy.linux: - rm -f *.gcda - $(CC) $(CFLAGS) -fprofile-generate -D LINUX -D TB Gull.cpp tbprobe.c -o Gull - ./Gull bench 16 "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" - $(CC) $(CFLAGS) -fprofile-use -fno-peel-loops -fno-tracer -D LINUX -D TB -D HNI Gull.cpp tbprobe.c -o Gull - $(STRIP) Gull - cp Gull Gull.syzygy.linux - -gull.syzygy.windows: CC=x86_64-w64-mingw32-g++ -gull.syzygy.windows: - rm -f *.gcda - $(CC) $(CFLAGS) -static -fprofile-generate -D WINDOWS -D TB Gull.cpp tbprobe.c -o Gull.exe - ./Gull.exe bench 16 "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" - $(CC) $(CFLAGS) -fprofile-use -fno-peel-loops -fno-tracer -D WINDOWS -D TB Gull.cpp tbprobe.c -o Gull.exe - $(STRIP) Gull.exe - -clean: - rm -f Gull - diff --git a/src/Makefile.windows b/src/Makefile.windows new file mode 100644 index 0000000..ac347fd --- /dev/null +++ b/src/Makefile.windows @@ -0,0 +1,75 @@ +CC=x86_64-w64-mingw32-g++ + +ifeq ($(ARCH),) + ARCH=x86-64 +endif + +CFLAGS=-fno-exceptions -fno-rtti -Wno-parentheses -D_WIN32_WINNT=0x0601 +ifeq ($(ARCH),x86-64) + CFLAGS += -msse4.1 -mpopcnt -D GULL_MAGIC_BITBOARDS +endif + +ifeq ($(ARCH),x86-64-bmi2) + CFLAGS += -msse4.2 -mpopcnt -mavx2 -mbmi -mbmi2 -D GULL_PDEP_BITBOARDS +endif + +STRIP=x86_64-w64-mingw32-strip + +help: + @echo + @echo "To build LazyGull, run:" + @echo + @echo " make -f Makefile.windows TARGET [ARCH=arch]" + @echo + @echo "Where:" + @echo + @echo " TARGET=build" + @echo " Standard build." + @echo " TARGET=pgo-build" + @echo " Profile Guided Optimization (PGO) build." + @echo " TARGET=debug" + @echo " Debug build." + @echo + @echo " ARCH=x86-64" + @echo " Standard x86-64 (with popcnt and SSE4.1 support). [DEFAULT]" + @echo " ARCH=x86-64-bmi2" + @echo " Modern x86-64 (with popcnt, SSE4.2, BMI, BMI2, AVX2"\ + "support)." + @echo + @echo "To do a basic build, simply run:" + @echo + @echo " make -f Makefile.windows build" + @echo + +build: tbprobe.c + $(CC) $(CFLAGS) -O3 -D WINDOWS Gull.cpp tbprobe.c -o LazyGull.exe + $(STRIP) LazyGull.exe + +pgo-build: tbprobe.c + rm -f *.gcda + $(CC) $(CFLAGS) -O3 -fprofile-generate -D WINDOWS Gull.cpp tbprobe.c -o \ + LazyGull.exe + LazyGull.exe bench \ + "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" + $(CC) $(CFLAGS) -O3 -fprofile-use -fno-peel-loops -fno-tracer -D WINDOWS \ + Gull.cpp tbprobe.c -o LazyGull.exe + $(STRIP) LazyGull.exe + +debug: tbprobe.c + $(CC) $(CFLAGS) -O0 -g -D WINDOWS Gull.cpp tbprobe.c -o LazyGull.exe + +tbprobe.c: Fathom-master.zip + unzip -o -j Fathom-master.zip "Fathom-master/src/tbprobe.h" -d "./" + unzip -o -j Fathom-master.zip "Fathom-master/src/tbprobe.c" -d "./" + +tbcore.c: Fathom-master.zip + unzip -o -j Fathom-master.zip "Fathom-master/src/tbcore.h" -d "./" + unzip -o -j Fathom-master.zip "Fathom-master/src/tbcore.c" -d "./" + +Fathom-master.zip: + wget https://github.com/basil00/Fathom/archive/master.zip \ + -O Fathom-master.zip + +clean: + rm -f LazyGull.exe tbprobe.o + From 83d74fa75e4be14c6e4ed17d68686ed6575e1775 Mon Sep 17 00:00:00 2001 From: basil00 Date: Sat, 8 Oct 2016 08:36:42 +0800 Subject: [PATCH 5/9] Improved build system. --- src/Gull.cpp | 2 +- src/Makefile.linux | 23 ++++++++++++++++------- src/Makefile.windows | 10 +++++++++- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/Gull.cpp b/src/Gull.cpp index e6b66ca..8870fc6 100644 --- a/src/Gull.cpp +++ b/src/Gull.cpp @@ -5230,7 +5230,7 @@ int main(int argc, char **argv) uint64_t t0 = get_time(); for (int i = 2; i < argc; i++) { - init_search(false); + init_search(true); get_board(argv[i]); INFO->stop = false; SHARED->depthLimit = 2 * benchDepth + 2; diff --git a/src/Makefile.linux b/src/Makefile.linux index 2091fe9..6763697 100644 --- a/src/Makefile.linux +++ b/src/Makefile.linux @@ -8,7 +8,7 @@ ifeq ($(ARCH),) ARCH=x86-64 endif -CFLAGS=-fno-exceptions -fno-rtti -Wno-parentheses -lpthread -lrt +CFLAGS=-fno-exceptions -fno-rtti -Wno-parentheses -pthread ifeq ($(ARCH),x86-64) CFLAGS += -msse4.1 -mpopcnt -D GULL_MAGIC_BITBOARDS endif @@ -16,6 +16,7 @@ endif ifeq ($(ARCH),x86-64-bmi2) CFLAGS += -msse4.2 -mpopcnt -mavx2 -mbmi -mbmi2 -D GULL_PDEP_BITBOARDS endif +LDFLAGS=-lrt STRIP=strip @@ -51,21 +52,29 @@ help: @echo build: tbprobe.c - $(CC) $(CFLAGS) -O3 -D LINUX Gull.cpp tbprobe.c -o LazyGull + $(CC) $(CFLAGS) -O3 -D LINUX Gull.cpp tbprobe.c $(LDFLAGS) -o LazyGull $(STRIP) LazyGull pgo-build: tbprobe.c rm -f *.gcda - $(CC) $(CFLAGS) -O3 -fprofile-generate -D LINUX Gull.cpp tbprobe.c -o \ - LazyGull + $(CC) $(CFLAGS) -O3 -fprofile-generate -D LINUX Gull.cpp tbprobe.c \ + $(LDFLAGS) -o LazyGull ./LazyGull bench \ - "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" + "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" \ + "r1bq1rk1/4bppp/p2p1n2/npp1p3/3PP3/2P2N1P/PPB2PP1/RNBQR1K1 b - d3 0 11" \ + "rnbqkb1r/1p3ppp/p2ppn2/6B1/3NPP2/2N5/PPP3PP/R2QKB1R b KQkq f3 0 7" \ + "r1r3k1/1p1n1pp1/2p1pqn1/p2p3p/N2PPP2/3P2P1/PPR2QPN/5RK1 b - - 3 22" \ + "r6r/p1pq2k1/b2p4/P1pP1pp1/2P1p3/2P1P1P1/Q4P2/1R2RBK1 w - - 4 30" \ + "1r2kb1r/pp1b2pp/4pq2/4np2/2p2B2/2N3P1/PPQ1PPBP/3R1RK1 b k - 1 15" \ + "2rr2k1/p1q2p1p/1p4pB/1B1bb3/P7/2P2QP1/1P2RP2/4R1K1 w - - 10 28" \ + "R7/3kqp2/3n3Q/2pPp2P/2P1P3/1r4P1/8/7K b - - 0 52" \ + "8/2p5/p3k3/2p1b2p/P2pK2p/1P1P3P/3B2P1/8 b - - 4 77" $(CC) $(CFLAGS) -O3 -fprofile-use -fno-peel-loops -fno-tracer -D LINUX \ - Gull.cpp tbprobe.c -o LazyGull + Gull.cpp tbprobe.c $(LDFLAGS) -o LazyGull $(STRIP) LazyGull debug: tbprobe.c - $(CC) $(CFLAGS) -O0 -g -D LINUX Gull.cpp tbprobe.c -o LazyGull + $(CC) $(CFLAGS) -O0 -g -D LINUX Gull.cpp tbprobe.c $(LDFLAGS) -o LazyGull tbprobe.c: Fathom-master.zip unzip -o -j Fathom-master.zip "Fathom-master/src/tbprobe.h" -d "./" diff --git a/src/Makefile.windows b/src/Makefile.windows index ac347fd..3bac3a8 100644 --- a/src/Makefile.windows +++ b/src/Makefile.windows @@ -50,7 +50,15 @@ pgo-build: tbprobe.c $(CC) $(CFLAGS) -O3 -fprofile-generate -D WINDOWS Gull.cpp tbprobe.c -o \ LazyGull.exe LazyGull.exe bench \ - "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" + "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" \ + "r1bq1rk1/4bppp/p2p1n2/npp1p3/3PP3/2P2N1P/PPB2PP1/RNBQR1K1 b - d3 0 11" \ + "rnbqkb1r/1p3ppp/p2ppn2/6B1/3NPP2/2N5/PPP3PP/R2QKB1R b KQkq f3 0 7" \ + "r1r3k1/1p1n1pp1/2p1pqn1/p2p3p/N2PPP2/3P2P1/PPR2QPN/5RK1 b - - 3 22" \ + "r6r/p1pq2k1/b2p4/P1pP1pp1/2P1p3/2P1P1P1/Q4P2/1R2RBK1 w - - 4 30" \ + "1r2kb1r/pp1b2pp/4pq2/4np2/2p2B2/2N3P1/PPQ1PPBP/3R1RK1 b k - 1 15" \ + "2rr2k1/p1q2p1p/1p4pB/1B1bb3/P7/2P2QP1/1P2RP2/4R1K1 w - - 10 28" \ + "R7/3kqp2/3n3Q/2pPp2P/2P1P3/1r4P1/8/7K b - - 0 52" \ + "8/2p5/p3k3/2p1b2p/P2pK2p/1P1P3P/3B2P1/8 b - - 4 77" $(CC) $(CFLAGS) -O3 -fprofile-use -fno-peel-loops -fno-tracer -D WINDOWS \ Gull.cpp tbprobe.c -o LazyGull.exe $(STRIP) LazyGull.exe From 798eed5868a18f15faae2a0a98442e2c57b4a305 Mon Sep 17 00:00:00 2001 From: basil00 Date: Sat, 8 Oct 2016 09:11:26 +0800 Subject: [PATCH 6/9] Add a POSIX compatible method for children cleanup. --- src/Linux.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Linux.cpp b/src/Linux.cpp index 4f5b8a3..15176b0 100644 --- a/src/Linux.cpp +++ b/src/Linux.cpp @@ -171,7 +171,9 @@ void create_child(const char *hashName, const char *pvHashName, error("failed to fork: %s", strerror(errno)); if (pid != 0) return; +#ifndef MACOSX prctl(PR_SET_PDEATHSIG, SIGHUP); +#endif char exe[PATH_MAX]; ssize_t len = readlink("/proc/self/exe", exe, sizeof(exe)-1); if (len < 0) @@ -383,6 +385,20 @@ static void put_line(char *line, unsigned linelen) */ static void init_os(void) { - // NOP. + int fds[2]; + if (pipe2(fds, O_CLOEXEC) != 0) + return; + pid_t pid = getpid(); + if (fork() == 0) + { +#ifndef MACOSX + prctl(PR_SET_PDEATHSIG, SIGHUP); +#endif + close(fds[1]); + char c; + int r = read(fds[0], &c, sizeof(c)); + kill(-pid, SIGKILL); + } + close(fds[0]); } From 296f29f57981c058fc6098e2bf39160e35d5c6a6 Mon Sep 17 00:00:00 2001 From: basil00 Date: Sun, 9 Oct 2016 13:02:52 +0800 Subject: [PATCH 7/9] Various improvements & cleanups. --- src/Gull.cpp | 41 ++++++++++++++++++++++++++++++----------- src/Linux.cpp | 1 + src/Linux.h | 9 --------- src/Makefile.linux | 25 +++++++++++++------------ src/Makefile.windows | 34 ++++++++++++++++++---------------- src/Windows.h | 9 --------- src/bench.sh | 33 +++++++++++++++++++++++++++++++++ src/tbconfig.h | 2 ++ 8 files changed, 97 insertions(+), 57 deletions(-) create mode 100755 src/bench.sh diff --git a/src/Gull.cpp b/src/Gull.cpp index 8870fc6..b679c49 100644 --- a/src/Gull.cpp +++ b/src/Gull.cpp @@ -36,6 +36,9 @@ #include "data.h" +#define STRING2(x) #x +#define STRING(x) STRING2(x) + #define Convert(x,type) ((type)(x)) #define Abs(x) ((x) > 0 ? (x) : (-(x))) @@ -875,6 +878,18 @@ static const uint32_t Schedule[] = 0x00878787 }; +extern GThreadInfo INFO[]; +extern GSettings SETTINGS[]; +extern GSharedInfo SHARED[]; +extern GGlobalData DATA[]; +extern GPawnEntry PAWNHASH[]; +extern GPVEntry PVHASH[]; +#ifndef WINDOWS +extern GEntry HASH[]; +#else +#define HASH ((GEntry *)0x8000000) +#endif + jmp_buf CheckJump; inline int lsb(uint64_t x); @@ -5112,7 +5127,7 @@ void uci(void) else if (strcmp(token, "uci") == 0) { char reply[] = - "id name LazyGull\n" + "id name LazyGull (" STRING(VERSION) ")\n" "id author ThinkingALot\n" "option name Hash type spin min 1 max 8388608 default 128\n" "option name Threads type spin min 1 max 64 default 4\n" @@ -5143,6 +5158,8 @@ int main(int argc, char **argv) { usage: fprintf(stderr, "usage: %s\n", argv[0]); + fprintf(stderr, " %s \"bench\" FEN1 [FEN2 ...]\n", + argv[0]); exit(EXIT_FAILURE); } @@ -5203,8 +5220,9 @@ int main(int argc, char **argv) worker(); // Wait for work from parent. } - else if (argc > 1 && strcmp(argv[1], "bench") == 0) + else if (argc > 2 && strcmp(argv[1], "bench") == 0) { + const int benchDepth = atoi(argv[2]); init_object(NULL, sizeof(GGlobalData), DATA, true, false, true, NULL); init_data(); GSettings settings; @@ -5226,9 +5244,8 @@ int main(int argc, char **argv) INFO->pid = get_pid(); THREADS[0] = INFO; - const int benchDepth = 14; - uint64_t t0 = get_time(); - for (int i = 2; i < argc; i++) + uint64_t t0 = get_time(), nodes = 0; + for (int i = 3; i < argc; i++) { init_search(true); get_board(argv[i]); @@ -5239,16 +5256,18 @@ int main(int argc, char **argv) SHARED->startTime = t0; if (Current->turn == White) root<0>(); else root<1>(); send_best_move(); + nodes += INFO->nodes; } uint64_t t1 = get_time(); - printf("TIME: %ldms\n", t1 - t0); + printf("TIME : %ldms\n", t1 - t0); + printf("NODES: %lu\n", nodes); exit(EXIT_SUCCESS); } else if (argc > 1) goto usage; // PARENT: - printf("LazyGull\n"); + printf("LazyGull (" STRING(VERSION) ")\n"); init_os(); // Read override parameters from the environment (useful for debugging) @@ -5257,13 +5276,13 @@ int main(int argc, char **argv) size_t syzygyProbeDepth = 1; SyzygyPath[0] = '\0'; const char *val; - if ((val = getenv("GULL_HASH")) != NULL) + if ((val = getenv("LAZYGULL_HASH")) != NULL) hashSize = HASH_SIZE((size_t)atoi(val)); - if ((val = getenv("GULL_THREADS")) != NULL) + if ((val = getenv("LAZYGULL_THREADS")) != NULL) numThreads = atoi(val); - if ((val = getenv("GULL_SYZYGY_PATH")) != NULL) + if ((val = getenv("LAZYGULL_SYZYGY_PATH")) != NULL) strncpy(SyzygyPath, val, sizeof(SyzygyPath)-1); - if ((val = getenv("GULL_SYZYGY_PROBE_DEPTH")) != NULL) + if ((val = getenv("LAZYGULL_SYZYGY_PROBE_DEPTH")) != NULL) syzygyProbeDepth = atoi(val); PVN = 1; // XXX NYI diff --git a/src/Linux.cpp b/src/Linux.cpp index 15176b0..69a909c 100644 --- a/src/Linux.cpp +++ b/src/Linux.cpp @@ -398,6 +398,7 @@ static void init_os(void) char c; int r = read(fds[0], &c, sizeof(c)); kill(-pid, SIGKILL); + error("failed to kill children: %s", strerror(errno)); } close(fds[0]); } diff --git a/src/Linux.h b/src/Linux.h index 2927074..cb177bb 100644 --- a/src/Linux.h +++ b/src/Linux.h @@ -39,15 +39,6 @@ typedef pthread_cond_t GCondVar; #define PATH_MAX 4096 #define SIZE_T "zu" - -#define INFO ((GThreadInfo *)0x300000) -#define SETTINGS ((GSettings *)0x301000) -#define SHARED ((GSharedInfo *)0x302000) -#define DATA ((GGlobalData *)0x8000000) -#define PAWNHASH ((GPawnEntry *)0x10000000) -#define PVHASH ((GPVEntry *)0x20000000) -#define HASH ((GEntry *)0x40000000) - #define IOSIZE 4096 #endif diff --git a/src/Makefile.linux b/src/Makefile.linux index 6763697..e9ac4d7 100644 --- a/src/Makefile.linux +++ b/src/Makefile.linux @@ -8,16 +8,26 @@ ifeq ($(ARCH),) ARCH=x86-64 endif +DATE=$(shell date +%y%m%d) CFLAGS=-fno-exceptions -fno-rtti -Wno-parentheses -pthread ifeq ($(ARCH),x86-64) CFLAGS += -msse4.1 -mpopcnt -D GULL_MAGIC_BITBOARDS + VERSION = $(DATE)-Linux-x86_64 endif ifeq ($(ARCH),x86-64-bmi2) CFLAGS += -msse4.2 -mpopcnt -mavx2 -mbmi -mbmi2 -D GULL_PDEP_BITBOARDS + VERSION = $(DATE)-Linux-x86_64-bmi2 endif -LDFLAGS=-lrt - +CFLAGS += -DVERSION=$(VERSION) +LDFLAGS=-lrt \ + -Wl,--defsym=INFO=0x300000 \ + -Wl,--defsym=SETTINGS=0x301000 \ + -Wl,--defsym=SHARED=0x302000 \ + -Wl,--defsym=DATA=0x8000000 \ + -Wl,--defsym=PAWNHASH=0x10000000 \ + -Wl,--defsym=PVHASH=0x20000000 \ + -Wl,--defsym=HASH=0x40000000 STRIP=strip help: @@ -59,16 +69,7 @@ pgo-build: tbprobe.c rm -f *.gcda $(CC) $(CFLAGS) -O3 -fprofile-generate -D LINUX Gull.cpp tbprobe.c \ $(LDFLAGS) -o LazyGull - ./LazyGull bench \ - "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" \ - "r1bq1rk1/4bppp/p2p1n2/npp1p3/3PP3/2P2N1P/PPB2PP1/RNBQR1K1 b - d3 0 11" \ - "rnbqkb1r/1p3ppp/p2ppn2/6B1/3NPP2/2N5/PPP3PP/R2QKB1R b KQkq f3 0 7" \ - "r1r3k1/1p1n1pp1/2p1pqn1/p2p3p/N2PPP2/3P2P1/PPR2QPN/5RK1 b - - 3 22" \ - "r6r/p1pq2k1/b2p4/P1pP1pp1/2P1p3/2P1P1P1/Q4P2/1R2RBK1 w - - 4 30" \ - "1r2kb1r/pp1b2pp/4pq2/4np2/2p2B2/2N3P1/PPQ1PPBP/3R1RK1 b k - 1 15" \ - "2rr2k1/p1q2p1p/1p4pB/1B1bb3/P7/2P2QP1/1P2RP2/4R1K1 w - - 10 28" \ - "R7/3kqp2/3n3Q/2pPp2P/2P1P3/1r4P1/8/7K b - - 0 52" \ - "8/2p5/p3k3/2p1b2p/P2pK2p/1P1P3P/3B2P1/8 b - - 4 77" + ./bench.sh ./LazyGull 11 $(CC) $(CFLAGS) -O3 -fprofile-use -fno-peel-loops -fno-tracer -D LINUX \ Gull.cpp tbprobe.c $(LDFLAGS) -o LazyGull $(STRIP) LazyGull diff --git a/src/Makefile.windows b/src/Makefile.windows index 3bac3a8..65063b9 100644 --- a/src/Makefile.windows +++ b/src/Makefile.windows @@ -4,15 +4,25 @@ ifeq ($(ARCH),) ARCH=x86-64 endif +DATE=$(shell date +%y%m%d) CFLAGS=-fno-exceptions -fno-rtti -Wno-parentheses -D_WIN32_WINNT=0x0601 ifeq ($(ARCH),x86-64) CFLAGS += -msse4.1 -mpopcnt -D GULL_MAGIC_BITBOARDS + VERSION = $(DATE)-Windows-x86_64 endif ifeq ($(ARCH),x86-64-bmi2) CFLAGS += -msse4.2 -mpopcnt -mavx2 -mbmi -mbmi2 -D GULL_PDEP_BITBOARDS + VERSION = $(DATE)-Windows-x86_64-bmi2 endif - +CFLAGS += -DVERSION=$(VERSION) +LDFLAGS= \ + -Wl,--defsym=INFO=0x51010000 \ + -Wl,--defsym=SETTINGS=0x51000000 \ + -Wl,--defsym=SHARED=0x51020000 \ + -Wl,--defsym=DATA=0x50000000 \ + -Wl,--defsym=PAWNHASH=0x54000000 \ + -Wl,--defsym=PVHASH=0x58000000 STRIP=x86_64-w64-mingw32-strip help: @@ -42,29 +52,21 @@ help: @echo build: tbprobe.c - $(CC) $(CFLAGS) -O3 -D WINDOWS Gull.cpp tbprobe.c -o LazyGull.exe + $(CC) $(CFLAGS) -O3 -D WINDOWS Gull.cpp tbprobe.c $(LDFLAGS) -o LazyGull.exe $(STRIP) LazyGull.exe pgo-build: tbprobe.c rm -f *.gcda - $(CC) $(CFLAGS) -O3 -fprofile-generate -D WINDOWS Gull.cpp tbprobe.c -o \ - LazyGull.exe - LazyGull.exe bench \ - "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" \ - "r1bq1rk1/4bppp/p2p1n2/npp1p3/3PP3/2P2N1P/PPB2PP1/RNBQR1K1 b - d3 0 11" \ - "rnbqkb1r/1p3ppp/p2ppn2/6B1/3NPP2/2N5/PPP3PP/R2QKB1R b KQkq f3 0 7" \ - "r1r3k1/1p1n1pp1/2p1pqn1/p2p3p/N2PPP2/3P2P1/PPR2QPN/5RK1 b - - 3 22" \ - "r6r/p1pq2k1/b2p4/P1pP1pp1/2P1p3/2P1P1P1/Q4P2/1R2RBK1 w - - 4 30" \ - "1r2kb1r/pp1b2pp/4pq2/4np2/2p2B2/2N3P1/PPQ1PPBP/3R1RK1 b k - 1 15" \ - "2rr2k1/p1q2p1p/1p4pB/1B1bb3/P7/2P2QP1/1P2RP2/4R1K1 w - - 10 28" \ - "R7/3kqp2/3n3Q/2pPp2P/2P1P3/1r4P1/8/7K b - - 0 52" \ - "8/2p5/p3k3/2p1b2p/P2pK2p/1P1P3P/3B2P1/8 b - - 4 77" + $(CC) $(CFLAGS) -O3 -fprofile-generate -D WINDOWS Gull.cpp tbprobe.c \ + $(LDFLAGS) -o LazyGull.exe + ./bench.sh LazyGull.exe 11 $(CC) $(CFLAGS) -O3 -fprofile-use -fno-peel-loops -fno-tracer -D WINDOWS \ - Gull.cpp tbprobe.c -o LazyGull.exe + Gull.cpp tbprobe.c $(LDFLAGS) -o LazyGull.exe $(STRIP) LazyGull.exe debug: tbprobe.c - $(CC) $(CFLAGS) -O0 -g -D WINDOWS Gull.cpp tbprobe.c -o LazyGull.exe + $(CC) $(CFLAGS) -O0 -g -D WINDOWS Gull.cpp tbprobe.c $(LDFLAGS) \ + -o LazyGull.exe tbprobe.c: Fathom-master.zip unzip -o -j Fathom-master.zip "Fathom-master/src/tbprobe.h" -d "./" diff --git a/src/Windows.h b/src/Windows.h index 460bd05..4692bfd 100644 --- a/src/Windows.h +++ b/src/Windows.h @@ -36,15 +36,6 @@ typedef HANDLE GEvent; #define strtok_r strtok_s #define SIZE_T "Iu" - -#define INFO ((GThreadInfo *)0x51010000) -#define SETTINGS ((GSettings *) 0x51000000) -#define SHARED ((GSharedInfo *)0x51020000) -#define DATA ((GGlobalData *)0x50000000) -#define PAWNHASH ((GPawnEntry *) 0x54000000) -#define PVHASH ((GPVEntry *) 0x58000000) -#define HASH ((GEntry *) 0x81230000) - #define IOSIZE 4096 #endif diff --git a/src/bench.sh b/src/bench.sh new file mode 100755 index 0000000..3ed330d --- /dev/null +++ b/src/bench.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +if [ $# != 2 ] +then + echo "usage: $0 " >&2 + exit 1 +fi + +$1 bench $2 \ + "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" \ + "r1bq1rk1/4bppp/p2p1n2/npp1p3/3PP3/2P2N1P/PPB2PP1/RNBQR1K1 b - d3 0 11" \ + "rnbqkb1r/1p3ppp/p2ppn2/6B1/3NPP2/2N5/PPP3PP/R2QKB1R b KQkq f3 0 7" \ + "r1bqr1k1/pppn1pbp/3p1np1/4p3/2PP4/5NP1/PPQ1PPBP/RNBR2K1 w - - 2 9" \ + "r1r3k1/1p1n1pp1/2p1pqn1/p2p3p/N2PPP2/3P2P1/PPR2QPN/5RK1 b - - 3 22" \ + "r1bqkbnr/pp1ppppp/2n5/2p5/2P5/5N2/PP1PPPPP/RNBQKB1R w KQkq - 1 3" \ + "r6r/p1pq2k1/b2p4/P1pP1pp1/2P1p3/2P1P1P1/Q4P2/1R2RBK1 w - - 4 30" \ + "1r2kb1r/pp1b2pp/4pq2/4np2/2p2B2/2N3P1/PPQ1PPBP/3R1RK1 b k - 1 15" \ + "2rr2k1/p1q2p1p/1p4pB/1B1bb3/P7/2P2QP1/1P2RP2/4R1K1 w - - 10 28" \ + "R7/3kqp2/3n3Q/2pPp2P/2P1P3/1r4P1/8/7K b - - 0 52" \ + "8/2p5/p3k3/2p1b2p/P2pK2p/1P1P3P/3B2P1/8 b - - 4 77" \ + "5k1B/5p2/1pp2P2/3n3P/8/8/P1B5/6K1 b - - 0 49" \ + "8/1p6/p3k1pp/P4p2/1P3PP1/4K1nP/3N4/8 b - - 1 43" \ + "3Q4/p7/1kp5/8/3Pq1BP/4P1KP/8/5r2 b - - 5 41" \ + "4r2k/1p3rp1/p1p1n3/3pP2N/6R1/4P3/PP5P/6RK w - - 7 28" \ + "4k3/3b4/8/3N4/1PK1P3/3n1r2/8/1R6 w - - 1 50" \ + "1r1bb1k1/2q2p1p/1p1p2r1/pP1P4/NpP1PP2/3BB2p/5Q2/1R3R1K w - - 1 32" \ + "r1b5/pppk3N/8/5RQ1/7P/P1P1B3/1P6/2K4q w - - 1 44" \ + "8/8/8/7p/k4P1P/2b2KP1/8/8 w - - 0 82" \ + "5r2/5pk1/6p1/7p/7P/6P1/5PK1/5R2 w - - 0 1" \ + "8/8/8/8/4k3/2Q4p/1K4pq/8 w - - 0 1" \ + "5k2/3p4/2p4p/1p6/1P6/P1PP4/2KP4/8 w - - 0 1" \ + "8/8/1R5p/4pk2/p7/1P3pK1/5r2/8 b - - 1 57" + diff --git a/src/tbconfig.h b/src/tbconfig.h index a43d0d3..d818fd6 100644 --- a/src/tbconfig.h +++ b/src/tbconfig.h @@ -60,6 +60,8 @@ #include "data.h" +extern GGlobalData DATA[]; + /* * If you are integrating tbprobe into an engine, you can replace some of * tbprobe's built-in functionality with that already provided by the engine. From 7d7c1d196fc0717a4260e085d7b875bb24f6ae96 Mon Sep 17 00:00:00 2001 From: basil00 Date: Tue, 11 Oct 2016 09:37:27 +0800 Subject: [PATCH 8/9] Fix Gull pawn hash bug & other improvements - Fix a bug (inherited from Gull 3) where PawnEntry->passer is never cleared. - Shrink GPawnEntry to 16 bytes (down from 24). - eval_passer() verifies PawnEntry->passer before use. --- src/Gull.cpp | 18 +++++++++++------- src/Linux.cpp | 3 ++- src/Makefile.linux | 10 +++++----- src/Windows.cpp | 3 ++- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/Gull.cpp b/src/Gull.cpp index b679c49..44c0152 100644 --- a/src/Gull.cpp +++ b/src/Gull.cpp @@ -449,9 +449,8 @@ int64_t hash_size = initial_hash_size; uint64_t hash_mask = (initial_hash_size - 4); typedef struct { - uint64_t key; - int16_t shelter[2]; - uint8_t passer[2], draw[2]; + uint64_t key:48; + uint8_t shelter[2], passer[2], draw[2]; int score; } GPawnEntry; #define pawn_hash_size (1024 * 1024) @@ -1220,6 +1219,7 @@ void init_search(int clear_hash) { SHARED->date = 1; memset(HASH,0,SETTINGS->hashSize); memset(PVHASH,0,pvHashSize); + memset(PAWNHASH,0,pawnHashSize); } hash_size = SETTINGS->hashSize / sizeof(GEntry); assert((hash_size & (hash_size - 1)) == 0); @@ -1983,7 +1983,8 @@ template inline void eval_pawns(GPawnEntry * PawnEntry, GPawnEvalInfo if (!(Pawn(me) & DATA->File[file])) shelter += Sa(StormHof, StormOfValue); } } - PawnEntry->shelter[me] = shelter; + PawnEntry->shelter[me] = (shelter > UINT8_MAX? UINT8_MAX: shelter); + PawnEntry->passer[me] = 0; uint64_t b; int min_file = 7, max_file = 0; @@ -2064,7 +2065,7 @@ template inline void eval_pawns(GPawnEntry * PawnEntry, GPawnEvalInfo void eval_pawn_structure(GPawnEntry * PawnEntry) { GPawnEvalInfo PEI; for (int i = 0; i < sizeof(GPawnEntry) / sizeof(int); i++) *(((int*)PawnEntry) + i) = 0; - PawnEntry->key = Current->pawn_key; + PawnEntry->key = (Current->pawn_key >> 16); PEI.patt_w = ShiftW(White, Pawn(White)) | ShiftE(White, Pawn(White)); PEI.patt_b = ShiftW(Black, Pawn(Black)) | ShiftE(Black, Pawn(Black)); @@ -2265,7 +2266,10 @@ template inline void eval_king(GEvalInfo &EI) { template inline void eval_passer(GEvalInfo &EI) { for (uint64_t u = EI.PawnEntry->passer[me]; T(u); Cut(u)) { int file = lsb(u); - int sq = NB(opp, DATA->File[file] & Pawn(me)); + uint64_t passer = DATA->File[file] & Pawn(me); + if (passer == 0) + continue; + int sq = NB(opp, passer); int rank = CRank(me, sq); Current->passer |= Bit(sq); if (rank <= 2) continue; @@ -2482,7 +2486,7 @@ void evaluation() { #undef me EI.PawnEntry = PAWNHASH + (Current->pawn_key & pawn_hash_mask); - if (Current->pawn_key != EI.PawnEntry->key) eval_pawn_structure(EI.PawnEntry); + if ((Current->pawn_key >> 16) != EI.PawnEntry->key) eval_pawn_structure(EI.PawnEntry); EI.score += EI.PawnEntry->score; eval_king(EI); diff --git a/src/Linux.cpp b/src/Linux.cpp index 69a909c..0199b3f 100644 --- a/src/Linux.cpp +++ b/src/Linux.cpp @@ -44,6 +44,7 @@ #define UINT64_MAX 0xFFFFFFFFFFFFFFFFull // XXX #define UINT32_MAX 0xFFFFFFFF +#define UINT8_MAX 0xFF #ifdef MACOSX // MacOSX: #include @@ -123,7 +124,7 @@ void *init_object(const char *object, size_t size, void *addr, int prot = PROT_READ | (readonly && value == NULL? 0: PROT_WRITE); flags |= (addr == NULL? 0: MAP_FIXED); void *ptr = mmap(addr, SIZE(size), prot, flags, fd, 0); - if (ptr == MAP_FAILED) + if (ptr == MAP_FAILED || (addr != NULL && ptr != addr)) error("failed to map object %s: %s", object, strerror(errno)); if (value != NULL) { diff --git a/src/Makefile.linux b/src/Makefile.linux index e9ac4d7..4b80a7a 100644 --- a/src/Makefile.linux +++ b/src/Makefile.linux @@ -9,7 +9,7 @@ ifeq ($(ARCH),) endif DATE=$(shell date +%y%m%d) -CFLAGS=-fno-exceptions -fno-rtti -Wno-parentheses -pthread +CFLAGS=-fno-exceptions -fno-rtti -fno-stack-protector -Wno-parentheses -pthread ifeq ($(ARCH),x86-64) CFLAGS += -msse4.1 -mpopcnt -D GULL_MAGIC_BITBOARDS VERSION = $(DATE)-Linux-x86_64 @@ -24,10 +24,10 @@ LDFLAGS=-lrt \ -Wl,--defsym=INFO=0x300000 \ -Wl,--defsym=SETTINGS=0x301000 \ -Wl,--defsym=SHARED=0x302000 \ - -Wl,--defsym=DATA=0x8000000 \ - -Wl,--defsym=PAWNHASH=0x10000000 \ - -Wl,--defsym=PVHASH=0x20000000 \ - -Wl,--defsym=HASH=0x40000000 + -Wl,--defsym=DATA=0x74000000 \ + -Wl,--defsym=PAWNHASH=0x78000000 \ + -Wl,--defsym=PVHASH=0x7B000000 \ + -Wl,--defsym=HASH=0x7F000000 STRIP=strip help: diff --git a/src/Windows.cpp b/src/Windows.cpp index bbfa68f..d02ea09 100644 --- a/src/Windows.cpp +++ b/src/Windows.cpp @@ -33,8 +33,9 @@ #include #include -#define UINT64_MAX 0xFFFFFFFFFFFFFFFFull // XXX +#define UINT64_MAX 0xFFFFFFFFFFFFFFFFull #define UINT32_MAX 0xFFFFFFFF +#define UINT8_MAX 0xFF #define builtin_cpuid(f, ax, bx, cx, dx) \ __asm__ __volatile__ ("cpuid" : "=a" (ax), "=b" (bx), "=c" (cx), \ From fc833e27cf8cd9e5d70cab4aac1f58bd5c128f7f Mon Sep 17 00:00:00 2001 From: basil00 Date: Mon, 17 Oct 2016 21:53:46 +0800 Subject: [PATCH 9/9] Small SMP optimiziations. - I/O no longer requires locking - it is likely unnecessary - Windows threads wait on a single event rather than an event-per-thread. - Do not clear pawnhash (for fair comparison with Gull3). --- README.md | 3 +- src/Gull.cpp | 74 ++++++++++++++++++-------------------------- src/Linux.cpp | 24 ++++++++------ src/Makefile.windows | 2 +- src/Windows.cpp | 21 ++++++++----- src/Windows.h | 4 ++- 6 files changed, 64 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 18b188a..ba800b6 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ LazyGull implements the following new features: * Syzygy Tablebase support; * LazySMP implementation; -* PDEP Bitboards for modern CPUs; and +* PDEP Bitboards for modern CPUs; +* Bug fixes; and * Portable to Windows, Linux and MacOSX. To build simply run the following commands in the `src` directory: diff --git a/src/Gull.cpp b/src/Gull.cpp index 44c0152..d8129fc 100644 --- a/src/Gull.cpp +++ b/src/Gull.cpp @@ -813,9 +813,6 @@ typedef struct int selDepth; int bestMove; int bestScore; -#ifdef WINDOWS - GEvent goEvent; -#endif int PV[]; } GThreadInfo; #define MAX_PV_LEN ((PAGE_SIZE - sizeof(GThreadInfo)) / sizeof(int)) @@ -839,6 +836,7 @@ typedef struct GCondVar initCondVar; #endif #ifdef WINDOWS + GEvent goEvent; GEvent initEvent; #endif unsigned rootDepth; @@ -1130,8 +1128,7 @@ static void go(void) cond_broadcast(&SHARED->goCondVar); #endif #ifdef WINDOWS - for (int i = 0; i < SETTINGS->numThreads; i++) - event_signal(&THREADS[i]->goEvent); + event_signal(&SHARED->goEvent); #endif } @@ -1141,8 +1138,7 @@ static void wait_for_go(void) cond_wait(&SHARED->goCondVar, &SHARED->mutex); #endif #ifdef WINDOWS - event_wait(&INFO->goEvent, &SHARED->mutex); - mutex_lock(&SHARED->mutex); + event_wait(&SHARED->goEvent, &SHARED->mutex); #endif } @@ -1187,20 +1183,21 @@ static void emergency_stop(void) log("warning: threads crashed or deadlocked; initiating emergency reset\n"); reset(SETTINGS->numThreads, SETTINGS->syzygyProbeDepth, SETTINGS->hashSize, SyzygyPath); - mutex_lock(&SHARED->mutex); - if (!go) - return; - char line[32], moveStr[16]; - move_to_string(bestMove, moveStr); - int len = snprintf(line, sizeof(line)-1, "bestmove %s\n", moveStr); - if (len > 0 && len < sizeof(line)-1) - put_line(line, len); - else + if (go) { - // Giveup: - char reply[] = "bestmove 0\n"; - put_line(reply, sizeof(reply)); + char line[32], moveStr[16]; + move_to_string(bestMove, moveStr); + int len = snprintf(line, sizeof(line)-1, "bestmove %s\n", moveStr); + if (len > 0 && len < sizeof(line)-1) + put_line(line, len); + else + { + // Giveup: + char reply[] = "bestmove 0\n"; + put_line(reply, sizeof(reply)); + } } + mutex_lock(&SHARED->mutex); } static inline void check_for_stop(void) @@ -1219,7 +1216,7 @@ void init_search(int clear_hash) { SHARED->date = 1; memset(HASH,0,SETTINGS->hashSize); memset(PVHASH,0,pvHashSize); - memset(PAWNHASH,0,pawnHashSize); +// memset(PAWNHASH,0,pawnHashSize); } hash_size = SETTINGS->hashSize / sizeof(GEntry); assert((hash_size & (hash_size - 1)) == 0); @@ -4077,11 +4074,7 @@ template int pv_search(int alpha, int beta, int depth, int int len = snprintf(line, sizeof(line)-1, "info depth %d\n", depth/2); if (len > 0 && len < sizeof(line)-1) - { - mutex_lock(&SHARED->mutex); put_line(line, len); - mutex_unlock(&SHARED->mutex); - } } int * p; for (p = RootList; *p; p++); @@ -4760,12 +4753,9 @@ void send_pv(int depth, int alpha, int beta, int score) unsigned pvPtr = 1, pvLen = 64; pick_pv(pvPtr, pvLen); if (Current->turn ^ 1) undo_move<1>(move); else undo_move<0>(move); + mutex_unlock(&SHARED->mutex); if (INFO->id != 0) - { - mutex_unlock(&SHARED->mutex); return; - } - size_t nodes = 0, tbHits = 0; for (unsigned i = 0; i < SETTINGS->numThreads; i++) { @@ -4775,7 +4765,6 @@ void send_pv(int depth, int alpha, int beta, int score) send_pv(THREADS[0]->PV, nodes, tbHits, THREADS[0]->depth, THREADS[0]->selDepth, THREADS[0]->bestScore, THREADS[0]->bestMove, SHARED->startTime); - mutex_unlock(&SHARED->mutex); } static void send_pv(const int *PV, size_t nodes, size_t tbHits, int depth, @@ -4825,7 +4814,7 @@ static void send_pv(const int *PV, size_t nodes, size_t tbHits, int depth, char line[IOSIZE]; int len = snprintf(line, sizeof(line)-1, "info depth %d seldepth %d score " - "%s %d multipv 1 nodes %" SIZE_T " nps %" SIZE_T " tbhits %" SIZE_T + "%s %d nodes %" SIZE_T " nps %" SIZE_T " tbhits %" SIZE_T " time %ld pv%s\n", depth/2, selDepth/2, scoreType, bestScore, nodes, nps, tbHits, currTime - startTime, pvStr); @@ -4849,11 +4838,7 @@ static void send_curr_move(int move, int cnt) int len = snprintf(line, sizeof(line)-1, "info currmove %s currmovenumber %d\n", moveStr, cnt); if (len > 0 && len < sizeof(line)-1) - { - mutex_lock(&SHARED->mutex); put_line(line, len); - mutex_unlock(&SHARED->mutex); - } } static void send_best_move(void) @@ -4936,7 +4921,7 @@ void uci(void) { uint64_t timeout = UINT64_MAX; if (SHARED->state != STOPPED) - timeout = 50; // 50ms + timeout = 100; // 100ms mutex_unlock(&SHARED->mutex); bool timedout = get_line(line, sizeof(line)-1, timeout); @@ -5241,6 +5226,10 @@ int main(int argc, char **argv) #ifdef LINUX cond_init(&SHARED->goCondVar); #endif +#ifdef WINDOWS + event_init(&SHARED->goEvent); +#endif + init_object(NULL, SETTINGS->hashSize, HASH, true, false, true, NULL); init_object(NULL, pvHashSize, PVHASH, true, false, true, NULL); init_object(NULL, pawnHashSize, PAWNHASH, true, false, true, NULL); @@ -5252,7 +5241,8 @@ int main(int argc, char **argv) for (int i = 3; i < argc; i++) { init_search(true); - get_board(argv[i]); + if (strcmp(argv[i], "startpos") != 0) + get_board(argv[i]); INFO->stop = false; SHARED->depthLimit = 2 * benchDepth + 2; SHARED->softTimeLimit = UINT32_MAX; @@ -5357,6 +5347,7 @@ static void create_children(size_t numThreads, size_t syzygyProbeDepth, cond_init(&SHARED->initCondVar); #endif #ifdef WINDOWS + event_init(&SHARED->goEvent); event_init(&SHARED->initEvent); #endif @@ -5370,9 +5361,6 @@ static void create_children(size_t numThreads, size_t syzygyProbeDepth, THREADS[i]->stop = true; THREADS[i]->newGame = true; THREADS[i]->id = (unsigned)i; -#ifdef WINDOWS - event_init(&THREADS[i]->goEvent); -#endif } for (size_t i = 0; i < numThreads; i++) { @@ -5394,7 +5382,6 @@ static void create_children(size_t numThreads, size_t syzygyProbeDepth, #endif #ifdef WINDOWS event_wait(&SHARED->initEvent, &SHARED->mutex); - mutex_lock(&SHARED->mutex); #endif } mutex_unlock(&SHARED->mutex); @@ -5429,13 +5416,12 @@ static void nuke_children(void) cond_free(&SHARED->goCondVar); cond_free(&SHARED->initCondVar); #endif - for (size_t i = 0; i < SETTINGS->numThreads; i++) - { #ifdef WINDOWS - event_free(&THREADS[i]->goEvent); + event_free(&SHARED->goEvent); + event_free(&SHARED->initEvent); #endif + for (size_t i = 0; i < SETTINGS->numThreads; i++) delete_object(THREADS[i], sizeof(GThreadInfo)); - } delete_object(DATA, sizeof(GGlobalData)); delete_object(SETTINGS, sizeof(GSettings)); delete_object(SHARED, sizeof(GSharedInfo)); diff --git a/src/Linux.cpp b/src/Linux.cpp index 0199b3f..d85df22 100644 --- a/src/Linux.cpp +++ b/src/Linux.cpp @@ -1,6 +1,6 @@ /* * Linux.cpp - * Copyright (c) 2015 the copyright holders + * Copyright (c) 2016 the copyright holders * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -369,16 +370,21 @@ static bool get_line(char *line, unsigned linelen, uint64_t timeout) */ static void put_line(char *line, unsigned linelen) { - unsigned ptr = 0; - while (ptr < linelen) + if (linelen > PIPE_BUF) { - int res = write(STDOUT_FILENO, line + ptr, linelen - ptr); - if (res < 0 && errno == EINTR) - continue; - if (res < 0) - error("failed to write output: %s", strerror(errno)); - ptr += (unsigned)res; + log("warning: output \"%s\" too long (max is %u, got %u)\n", line, + PIPE_BUF, linelen); + return; + } + + int res; + do + { + res = write(STDOUT_FILENO, line, linelen); } + while (res < 0 && (errno == EINTR || errno == EAGAIN)); + if (res != linelen) + error("failed to write output: %s", strerror(errno)); } /* diff --git a/src/Makefile.windows b/src/Makefile.windows index 65063b9..71bd699 100644 --- a/src/Makefile.windows +++ b/src/Makefile.windows @@ -59,7 +59,7 @@ pgo-build: tbprobe.c rm -f *.gcda $(CC) $(CFLAGS) -O3 -fprofile-generate -D WINDOWS Gull.cpp tbprobe.c \ $(LDFLAGS) -o LazyGull.exe - ./bench.sh LazyGull.exe 11 + ./bench.sh ./LazyGull.exe 11 $(CC) $(CFLAGS) -O3 -fprofile-use -fno-peel-loops -fno-tracer -D WINDOWS \ Gull.cpp tbprobe.c $(LDFLAGS) -o LazyGull.exe $(STRIP) LazyGull.exe diff --git a/src/Windows.cpp b/src/Windows.cpp index d02ea09..68f29fe 100644 --- a/src/Windows.cpp +++ b/src/Windows.cpp @@ -22,10 +22,12 @@ * DEALINGS IN THE SOFTWARE. */ +#define _POSIX_ #include #include #include #include +#include #include #include @@ -315,7 +317,7 @@ static void event_init(GEvent *event) memset(&attr, 0, sizeof(attr)); attr.nLength = sizeof(attr); attr.bInheritHandle = TRUE; - *event = CreateEvent(&attr, FALSE, FALSE, NULL); + *event = CreateEvent(&attr, TRUE, FALSE, NULL); if (*event == NULL) error("failed to create event (%d)", GetLastError()); } @@ -323,6 +325,7 @@ static void event_init(GEvent *event) static void event_signal(GEvent *event) { SetEvent(*event); + ResetEvent(*event); } static void event_wait(GEvent *event, GMutex *mutex) @@ -330,6 +333,7 @@ static void event_wait(GEvent *event, GMutex *mutex) if (SignalObjectAndWait(*mutex, *event, INFINITE, FALSE) != WAIT_OBJECT_0) error("failed to wait for event (%d)", GetLastError()); + mutex_lock(mutex); } static void event_free(GEvent *event) @@ -482,15 +486,16 @@ static bool get_line(char *line, unsigned linelen, uint64_t timeout) */ static void put_line(char *line, unsigned linelen) { - unsigned ptr = 0; - HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); - while (ptr < linelen) + if (linelen > _POSIX_PIPE_BUF) { - DWORD len; - if (!WriteFile(handle, line + ptr, linelen - ptr, &len, NULL)) - error("failed to write output (%d)", GetLastError()); - ptr += (unsigned)len; + log("warning: output \"%s\" too long (max is %u, got %u)\n", line, + PIPE_BUF, linelen); + return; } + HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD len; + if (!WriteFile(handle, line, linelen, &len, NULL) || len != linelen) + error("failed to write output (%d)", GetLastError()); FlushFileBuffers(handle); } diff --git a/src/Windows.h b/src/Windows.h index 4692bfd..6e873fa 100644 --- a/src/Windows.h +++ b/src/Windows.h @@ -1,6 +1,6 @@ /* * Windows.h - * Copyright (c) 2015 the copyright holders + * Copyright (c) 2016 the copyright holders * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -24,6 +24,8 @@ #ifndef LINUX_H #define LINUX_H +#define _POSIX_ + #include #include #include