Permalink
Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
Cannot retrieve contributors at this time.
Cannot retrieve contributors at this time
| #ifndef __SCORPIO__ | |
| #define __SCORPIO__ | |
| /*Disable some MSVC warnings*/ | |
| #ifdef _MSC_VER | |
| # define _CRT_SECURE_NO_DEPRECATE | |
| # define _SCL_SECURE_NO_DEPRECATE | |
| # pragma warning (disable: 4127) | |
| # pragma warning (disable: 4146) | |
| # pragma warning (disable: 4244) | |
| #endif | |
| /* | |
| Some definitions to include/remove code | |
| */ | |
| #ifdef _MSC_VER | |
| # define LOG_FILE | |
| # define BOOK_PROBE | |
| # define BOOK_CREATE | |
| # define EGBB | |
| # define CLUSTER | |
| # define THREAD_POLLING | |
| // # define TUNE | |
| #endif | |
| /*includes*/ | |
| #include <cstdarg> | |
| #include <cstdio> | |
| #include <cstdlib> | |
| #include <cstring> | |
| #include <csignal> | |
| #include <cctype> | |
| #include <ctime> | |
| #include <cmath> | |
| #ifdef _WIN32 | |
| # include <sys/timeb.h> | |
| #else | |
| # include <sys/time.h> | |
| #endif | |
| # include <list> | |
| #ifdef CLUSTER | |
| # include "mpi.h" | |
| #endif | |
| #ifdef TUNE | |
| # include <vector> | |
| #endif | |
| #include "my_types.h" | |
| /* | |
| parallel search options | |
| */ | |
| #ifdef PARALLEL | |
| # if !defined(MAX_CPUS) | |
| # define MAX_CPUS 64 | |
| # endif | |
| # define MAX_SEARCHERS_PER_CPU 32 | |
| # define MAX_CPUS_PER_SPLIT 8 | |
| #else | |
| # define MAX_CPUS 1 | |
| # define MAX_SEARCHERS_PER_CPU 1 | |
| #endif | |
| /* | |
| * Transposition table type | |
| * 0 - global tt | |
| * 1 - distributed tt | |
| * 2 - local tt | |
| */ | |
| #if !defined(NUMA_TT_TYPE) | |
| # define NUMA_TT_TYPE 0 | |
| #endif | |
| #if !defined(CLUSTER_TT_TYPE) | |
| # define CLUSTER_TT_TYPE 1 | |
| #endif | |
| /*typedefs*/ | |
| typedef UBMP64 HASHKEY; | |
| typedef UBMP64 BITBOARD; | |
| typedef UBMP32 MOVE; | |
| /* | |
| Scorpio board representation | |
| */ | |
| enum colors { | |
| white,black,neutral | |
| }; | |
| enum chessmen { | |
| king = 1,queen,rook,bishop,knight,pawn | |
| }; | |
| #undef blank | |
| enum occupancy { | |
| blank,wking,wqueen,wrook,wbishop,wknight,wpawn, | |
| bking,bqueen,brook,bbishop,bknight,bpawn,elephant | |
| }; | |
| enum ranks { | |
| RANK1,RANK2,RANK3,RANK4,RANK5,RANK6,RANK7,RANK8 | |
| }; | |
| enum files { | |
| FILEA,FILEB,FILEC,FILED,FILEE,FILEF,FILEG,FILEH | |
| }; | |
| enum hash_types { | |
| UNKNOWN,AVOID_NULL,HASH_HIT,HASH_GOOD,EXACT,UPPER,LOWER,CRAP | |
| }; | |
| enum results { | |
| R_UNKNOWN,R_WWIN,R_BWIN,R_DRAW | |
| }; | |
| enum node_types { | |
| PV_NODE,CUT_NODE,ALL_NODE | |
| }; | |
| enum passed_rank { | |
| LASTR, HALFR, ALLR | |
| }; | |
| enum search_states { | |
| NULL_MOVE = 1,NORMAL_MOVE = 2,MOVE_MASK = 3,PROBCUT_SEARCH = 4,IID_SEARCH = 8,SINGULAR_SEARCH = 16 | |
| }; | |
| enum move_gen_status { | |
| GEN_START, GEN_RESET, GEN_AVAIL, GEN_HASHM, GEN_CAPS, GEN_QNONCAPS, | |
| GEN_KILLERS = 6, GEN_NONCAPS, GEN_LOSCAPS, GEN_END | |
| }; | |
| enum BACKUP_TYPE { | |
| MINMAX, AVERAGE, MIX, MINMAX_MEM, AVERAGE_MEM, MIX_MEM | |
| }; | |
| enum ROLLOUT_TYPE { | |
| MCTS, ALPHABETA | |
| }; | |
| enum square_names { | |
| A1 = 0,B1,C1,D1,E1,F1,G1,H1, | |
| A2 = 16,B2,C2,D2,E2,F2,G2,H2, | |
| A3 = 32,B3,C3,D3,E3,F3,G3,H3, | |
| A4 = 48,B4,C4,D4,E4,F4,G4,H4, | |
| A5 = 64,B5,C5,D5,E5,F5,G5,H5, | |
| A6 = 80,B6,C6,D6,E6,F6,G6,H6, | |
| A7 = 96,B7,C7,D7,E7,F7,G7,H7, | |
| A8 = 112,B8,C8,D8,E8,F8,G8,H8 | |
| }; | |
| #define RR 0x01 | |
| #define LL -0x01 | |
| #define RU 0x11 | |
| #define LD -0x11 | |
| #define UU 0x10 | |
| #define DD -0x10 | |
| #define LU 0x0f | |
| #define RD -0x0f | |
| #define RRU 0x12 | |
| #define LLD -0x12 | |
| #define LLU 0x0e | |
| #define RRD -0x0e | |
| #define RUU 0x21 | |
| #define LDD -0x21 | |
| #define LUU 0x1f | |
| #define RDD -0x1f | |
| #define UUU 0x20 | |
| #define DDD -0x20 | |
| #define RRR 0x02 | |
| #define LLL -0x02 | |
| #define KM 1 | |
| #define QM 2 | |
| #define RM 4 | |
| #define BM 8 | |
| #define NM 16 | |
| #define WPM 32 | |
| #define BPM 64 | |
| #define QRBM 14 | |
| #define KNM 17 | |
| #define AGE_MASK 0xf | |
| #define MAX_STR 256 | |
| #define MAX_FILE_STR 2048 | |
| #define MAX_FEN_STR 128 | |
| #define MAX_MOVES 256 | |
| #define MAX_CAPS 64 | |
| #define MAX_PLY 64 | |
| #define MAX_HSTACK 1024 | |
| #define MATE_SCORE 20000 | |
| #define SKIP_SCORE 15000 | |
| #define WIN_SCORE 3000 | |
| #define WIN_PLY 20 | |
| #define MAX_NUMBER 16777216 | |
| #define MAX_HIST 8388608 | |
| #define MAX_UBMP64 UBMP64(0xffffffffffffffff) | |
| #define MAX_EGBB 6 | |
| #define WSC_FLAG 1 | |
| #define WLC_FLAG 2 | |
| #define BSC_FLAG 4 | |
| #define BLC_FLAG 8 | |
| #define WSLC_FLAG 3 | |
| #define BSLC_FLAG 12 | |
| #define WBC_FLAG 15 | |
| /* | |
| Depth | |
| */ | |
| #define UNITDEPTH 1 | |
| #define DEPTH(x) (x) | |
| /* | |
| Scorpio moves are 32bit long | |
| */ | |
| #define FROM_FLAG 0x000000ff | |
| #define TO_FLAG 0x0000ff00 | |
| #define PIECE_FLAG 0x000f0000 | |
| #define CAPTURE_FLAG 0x00f00000 | |
| #define PROMOTION_FLAG 0x0f000000 | |
| #define EP_FLAG 0x10000000 | |
| #define CASTLE_FLAG 0x20000000 | |
| #define FROM_TO_PROM 0x0f00ffff | |
| #define CAP_PROM 0x0ff00000 | |
| #define m_from(x) (int)((x) & FROM_FLAG) | |
| #define m_to(x) (int)(((x) & TO_FLAG) >> 8) | |
| #define m_piece(x) (int)(((x) & PIECE_FLAG) >> 16) | |
| #define m_capture(x) (int)(((x) & CAPTURE_FLAG) >> 20) | |
| #define m_promote(x) (int)(((x) & PROMOTION_FLAG) >> 24) | |
| #define is_cap(x) ((x) & CAPTURE_FLAG) | |
| #define is_prom(x) ((x) & PROMOTION_FLAG) | |
| #define is_cap_prom(x) ((x) & CAP_PROM) | |
| #define is_ep(x) ((x) & EP_FLAG) | |
| #define is_castle(x) ((x) & CASTLE_FLAG) | |
| /* | |
| Squares are of 0x88 type | |
| */ | |
| #define file(x) ((x) & 7) | |
| #define rank(x) ((x) >> 4) | |
| #define file64(x) ((x) & 7) | |
| #define rank64(x) ((x) >> 3) | |
| #define SQ(x,y) (((x) << 4) | (y)) | |
| #define SQ64(x,y) (((x) << 3) | (y)) | |
| #define SQ32(x,y) (((x) << 2) | (y)) | |
| #define SQ8864(x) (((x) + ((x) & 7)) >> 1) | |
| #define SQ6488(x) ((x) + ((x) & 070)) | |
| #define SQ6448(x) ((x) - 8) | |
| #define SQ4864(x) ((x) + 8) | |
| #define MIRRORF(sq) ((sq) ^ 0x07) | |
| #define MIRRORR(sq) ((sq) ^ 0x70) | |
| #define MIRRORD(sq) SQ(file(sq),rank(sq)) | |
| #define MIRRORF64(sq) ((sq) ^ 007) | |
| #define MIRRORR64(sq) ((sq) ^ 070) | |
| #define MIRRORD64(sq) SQ64(file64(sq),rank64(sq)) | |
| #define MV8866(x) (SQ8864(m_from(x)) | (SQ8864(m_to(x)) << 6)) | |
| #define is_light(x) ((file(x)+rank(x)) & 1) | |
| #define is_light64(x) ((file64(x)+rank64(x)) & 1) | |
| /* | |
| piece and color | |
| */ | |
| #define PCOLOR(x) ((x) > 6) | |
| #define PIECE(x) (pic_tab[x]) | |
| #define COMBINE(c,x) ((x) + (c) * 6) | |
| #define invert(x) (!(x)) | |
| /* | |
| distances | |
| */ | |
| #define MAX(a, b) (((a) > (b)) ? (a) : (b)) | |
| #define MIN(a, b) (((a) < (b)) ? (a) : (b)) | |
| #define ABS(a) abs(a) | |
| #define f_distance(x,y) ABS(file(x)-file(y)) | |
| #define r_distance(x,y) ABS(rank(x)-rank(y)) | |
| #define distance(x,y) MAX(f_distance(x,y),r_distance(x,y)) | |
| #define DISTANCE(f1,r1,f2,r2) MAX(ABS((f1) - (f2)),ABS((r1) - (r2))) | |
| /* | |
| hash keys | |
| */ | |
| #define PC_HKEY(p,sq) (piece_hkey[p][SQ8864(sq)]) | |
| #define EP_HKEY(ep) (ep_hkey[file(ep)]) | |
| #define CAST_HKEY(c) (cast_hkey[c]) | |
| /* | |
| chess clock | |
| */ | |
| typedef struct CHESS_CLOCK { | |
| int mps; | |
| int inc; | |
| int p_time; | |
| int o_time; | |
| int max_st; | |
| int max_sd; | |
| int search_time; | |
| int maximum_time; | |
| int infinite_mode; | |
| int pondering; | |
| CHESS_CLOCK(); | |
| void set_stime(int); | |
| bool is_timed(); | |
| }*PCHESS_CLOCK; | |
| /* | |
| piece list | |
| */ | |
| typedef struct LIST{ | |
| int sq; | |
| LIST* prev; | |
| LIST* next; | |
| }*PLIST; | |
| /* | |
| score | |
| */ | |
| typedef struct SCORE { | |
| BMP16 mid; | |
| BMP16 end; | |
| SCORE() {} | |
| SCORE(int m,int e) {mid = m;end = e;} | |
| void zero() {mid = 0;end = 0;} | |
| void add(SCORE s) {mid += s.mid;end += s.end;} | |
| void sub(SCORE s) {mid -= s.mid;end -= s.end;} | |
| void add(int m,int e) {mid += m;end += e;} | |
| void sub(int m,int e) {mid -= m;end -= e;} | |
| void add(int x) {mid += x;end += x;} | |
| void sub(int x) {mid -= x;end -= x;} | |
| void addm(int m) {mid += m;} | |
| void subm(int m) {mid -= m;} | |
| void adde(int e) {end += e;} | |
| void sube(int e) {end -= e;} | |
| } *PSCORE; | |
| /* | |
| hash tables | |
| */ | |
| typedef struct tagHASH { | |
| HASHKEY hash_key; | |
| union { | |
| HASHKEY data_key; | |
| struct { | |
| UBMP32 move; | |
| BMP16 score; | |
| UBMP8 depth; | |
| UBMP8 flags; | |
| }; | |
| }; | |
| }HASH,*PHASH; | |
| typedef struct tagPAWNREC { | |
| UBMP8 w_passed; | |
| UBMP8 b_passed; | |
| UBMP8 w_pawn_f; | |
| UBMP8 b_pawn_f; | |
| UBMP8 w_ksq; | |
| UBMP8 b_ksq; | |
| BMP8 w_evaled; | |
| BMP8 b_evaled; | |
| UBMP8 w_attack; | |
| UBMP8 b_attack; | |
| BMP8 w_s_attack; | |
| BMP8 b_s_attack; | |
| } PAWNREC,*PPAWNREC; | |
| typedef struct tagPAWNHASH { | |
| HASHKEY hash_key; | |
| SCORE score; | |
| PAWNREC pawnrec; | |
| } PAWNHASH, *PPAWNHASH; | |
| typedef struct tagEVALHASH { | |
| UBMP32 check_sum; | |
| BMP16 score; | |
| BMP16 age; | |
| } EVALHASH,*PEVALHASH; | |
| /* | |
| * In-memory tree | |
| */ | |
| struct Node { | |
| Node* VOLATILE child; | |
| Node* next; | |
| MOVE move; | |
| VOLATILE short alpha; | |
| VOLATILE short beta; | |
| VOLATILE unsigned int visits; | |
| VOLATILE short score; | |
| VOLATILE unsigned char flag; | |
| unsigned char rank; | |
| /*accessors*/ | |
| enum { | |
| BUSY = 1, SCOUTF = 2, PVMOVE = 4, CREATE = 8, CONSIDER = 16 | |
| }; | |
| void set_busy() { l_or8(flag,BUSY); } | |
| void clear_busy() { l_and8(flag,~BUSY); } | |
| bool is_busy() { return (flag & BUSY); } | |
| void set_pvmove() { l_or8(flag,PVMOVE); } | |
| void clear_pvmove() { l_and8(flag,~PVMOVE); } | |
| bool is_pvmove() { return (flag & PVMOVE); } | |
| bool try_failed_scout() { return !(l_or8(flag,SCOUTF) & SCOUTF); } | |
| void clear_failed_scout() { l_and8(flag,~SCOUTF); } | |
| bool is_failed_scout() { return (flag & SCOUTF); } | |
| bool try_create() { return !(l_or8(flag,CREATE) & CREATE); } | |
| void clear_create() { l_and8(flag,~CREATE); } | |
| bool is_create() { return (flag & CREATE); } | |
| void set_consider() { l_or8(flag,CONSIDER); } | |
| void clear_consider() { l_and8(flag,~CONSIDER); } | |
| bool is_consider() { return (flag & CONSIDER); } | |
| void set_bounds(short a,short b) { | |
| l_set16(alpha,a); | |
| l_set16(beta,b); | |
| } | |
| void update_visits(unsigned int v) { l_add(visits,v); } | |
| void update_score(short s) { l_set16(score,s); } | |
| void clear() { | |
| score = 0; | |
| visits = 0; | |
| child = 0; | |
| next = 0; | |
| rank = 0; | |
| flag = 0; | |
| move = MOVE(); | |
| alpha = -MATE_SCORE; | |
| beta = MATE_SCORE; | |
| } | |
| static VOLATILE unsigned int total_nodes; | |
| static unsigned int max_tree_nodes; | |
| static unsigned int max_tree_depth; | |
| static LOCK mem_lock; | |
| static std::list<Node*> mem_; | |
| static Node* allocate(); | |
| static void release(Node*); | |
| static Node* reclaim(Node*,MOVE* = 0); | |
| static void rank_children(Node*); | |
| static void reset_bounds(Node*,int,int); | |
| static Node* print_tree(Node*,int,int = 0,int = 0); | |
| static Node* Max_UCB_select(Node*); | |
| static Node* Max_AB_select(Node*,int,int,bool,bool); | |
| static Node* Best_select(Node*); | |
| static float Min_score(Node*); | |
| static float Avg_score(Node*); | |
| static float Avg_score_mem(Node*,double,int); | |
| static void Backup(Node*,double&,int,int); | |
| static void BackupLeaf(Node*,double&); | |
| static void print_xml(Node*,int); | |
| }; | |
| /* | |
| stacks | |
| */ | |
| typedef struct HIST_STACK{ | |
| MOVE move; | |
| int castle; | |
| int epsquare; | |
| int fifty; | |
| int checks; | |
| int rev_check; | |
| PLIST pCapt; | |
| PLIST pProm; | |
| SCORE pcsq_score[2]; | |
| BITBOARD all_bb; | |
| HASHKEY hash_key; | |
| HASHKEY pawn_hash_key; | |
| BITBOARD pieces_bb[2]; | |
| BITBOARD pawns_bb[2]; | |
| static char start_fen[MAX_FEN_STR]; | |
| } *PHIST_STACK; | |
| typedef struct STACK{ | |
| int pv_length; | |
| MOVE current_move; | |
| int count; | |
| int current_index; | |
| int bad_index; | |
| int gen_status; | |
| int sortm; | |
| int best_score; | |
| MOVE best_move; | |
| MOVE hash_move; | |
| int hash_flags; | |
| int hash_depth; | |
| int hash_score; | |
| int extension; | |
| int reduction; | |
| int mate_threat; | |
| int singular; | |
| int legal_moves; | |
| int alpha; | |
| int beta; | |
| int depth; | |
| int o_alpha; | |
| int o_beta; | |
| int o_depth; | |
| int node_type; | |
| int next_node_type; | |
| int flag; | |
| int search_state; | |
| int noncap_start; | |
| bool all_done; | |
| bool second_pass; | |
| MOVE killer[2]; | |
| MOVE refutation; | |
| int qcheck_depth; | |
| int actual_score; | |
| UBMP64 start_nodes; | |
| MOVE move_st[MAX_MOVES]; | |
| int score_st[MAX_MOVES]; | |
| MOVE bad_st[MAX_CAPS]; | |
| MOVE pv[MAX_PLY]; | |
| void sort(const int,const int); | |
| } *PSTACK; | |
| struct SEARCHER; | |
| struct PROCESSOR; | |
| /* | |
| * MESSAGES | |
| */ | |
| #ifdef CLUSTER | |
| /* | |
| * Messages are made to be of known size on all platforms so that | |
| * construction of MPI_datatypes is avoided. Also simple transfer of messages | |
| * in bytes i.e. sizeof(MESSAGE) * MPI_BYTE is more efficient at least in theory | |
| */ | |
| struct SPLIT_MESSAGE { | |
| BMP64 master; | |
| BMP32 depth; | |
| BMP32 alpha; | |
| BMP32 beta; | |
| BMP32 node_type; | |
| BMP32 search_state; | |
| BMP32 extension; | |
| BMP32 reduction; | |
| BMP32 pv_length; | |
| MOVE pv[MAX_PLY]; | |
| }; | |
| struct MERGE_MESSAGE { | |
| BMP64 master; | |
| UBMP64 nodes; | |
| UBMP64 qnodes; | |
| UBMP64 ecalls; | |
| UBMP64 time_check; | |
| UBMP32 splits; | |
| UBMP32 bad_splits; | |
| UBMP32 egbb_probes; | |
| MOVE best_move; | |
| BMP32 best_score; | |
| BMP32 pv_length; | |
| MOVE pv[MAX_PLY]; | |
| }; | |
| struct INIT_MESSAGE { | |
| BMP8 fen[MAX_FEN_STR]; | |
| BMP32 pv_length; | |
| MOVE pv[127]; | |
| }; | |
| struct TT_MESSAGE { | |
| UBMP64 hash_key; | |
| BMP16 score; | |
| UBMP8 depth; | |
| UBMP8 flags; | |
| UBMP8 ply; | |
| UBMP8 col; | |
| UBMP8 mate_threat; | |
| UBMP8 singular; | |
| MOVE move; | |
| BMP16 alpha; | |
| BMP16 beta; | |
| }; | |
| #define SPLIT_MESSAGE_SIZE(x) (40 + ((x).pv_length << 2)) | |
| #define RESPLIT_MESSAGE_SIZE(x) (SPLIT_MESSAGE_SIZE(x) + 4) | |
| #define MERGE_MESSAGE_SIZE(x) (64 + ((x).pv_length << 2)) | |
| #define INIT_MESSAGE_SIZE(x) (MAX_FEN_STR + 4 + ((x).pv_length << 2)) | |
| #endif | |
| /* | |
| SEARCHER | |
| */ | |
| typedef struct SEARCHER{ | |
| /* | |
| data that needs to be copied by COPY fn below | |
| */ | |
| int* const board; | |
| PSTACK pstack; | |
| int player; | |
| int opponent; | |
| int castle; | |
| int epsquare; | |
| int fifty; | |
| int hply; | |
| int ply; | |
| int stop_ply; | |
| int pawn_c[2]; | |
| int piece_c[2]; | |
| int man_c[15]; | |
| int all_man_c; | |
| BITBOARD all_bb; | |
| BITBOARD pieces_bb[2]; | |
| BITBOARD pawns_bb[2]; | |
| HASHKEY hash_key; | |
| HASHKEY pawn_hash_key; | |
| SCORE pcsq_score[2]; | |
| int temp_board[192]; | |
| PLIST list[128]; | |
| PLIST plist[15]; | |
| HIST_STACK hstack[MAX_HSTACK]; | |
| STACK stack[MAX_PLY]; | |
| /*eval data*/ | |
| PAWNREC pawnrec; | |
| /*functions*/ | |
| SEARCHER(); | |
| void COPY(SEARCHER*); | |
| void operator = (SEARCHER& right) { COPY(&right); } | |
| void set_board(const char* fen_str); | |
| void get_fen(char* fen_str) const; | |
| void new_board(); | |
| void mirror(); | |
| void init_data(); | |
| void pcAdd(int,int,PLIST = 0); | |
| void pcRemove(int,int,PLIST&); | |
| void pcSwap(int,int); | |
| void do_move(const MOVE&); | |
| void do_null(); | |
| void undo_move(); | |
| void undo_null(); | |
| void PUSH_MOVE(MOVE); | |
| void PUSH_NULL(); | |
| void POP_MOVE(); | |
| void POP_NULL(); | |
| void UPDATE_PV(MOVE); | |
| int attacks(int,int) const; | |
| int checks(MOVE,int&) const; | |
| int in_check(MOVE) const; | |
| int is_legal(MOVE&); | |
| int is_legal_fast(MOVE) const; | |
| int is_pawn_push(MOVE move) const; | |
| int pinned_on_king(int,int) const; | |
| void print_board() const; | |
| void print_history(); | |
| void print_stack(); | |
| void print_game(); | |
| void print_allmoves(); | |
| int see(MOVE); | |
| void gen_caps(bool = false); | |
| void gen_noncaps(); | |
| void gen_checks(); | |
| void gen_evasions(); | |
| void gen_all(); | |
| MOVE get_move(); | |
| MOVE get_qmove(); | |
| int draw() const; | |
| MOVE find_best(); | |
| MOVE iterative_deepening(); | |
| int be_selective(int,bool); | |
| int on_node_entry(); | |
| int on_qnode_entry(); | |
| void search(); | |
| void qsearch(); | |
| void qsearch_nn(); | |
| bool hash_cutoff(); | |
| UBMP64 perft(int); | |
| MOVE get_book_move(); | |
| void show_book_moves(); | |
| void print_pv(int); | |
| int print_result(bool); | |
| void check_quit(); | |
| int eval(bool = false); | |
| void eval_pawn_cover(int,int,UBMP8*,UBMP8*); | |
| SCORE eval_pawns(int,int,UBMP8*,UBMP8*); | |
| int eval_passed_pawns(UBMP8*,UBMP8*,UBMP8&,const BITBOARD&,const BITBOARD&); | |
| void eval_win_chance(SCORE&,SCORE&,int&,int&); | |
| static void pre_calculate(); | |
| #ifdef TUNE | |
| void update_pcsq(int,int,int); | |
| void update_pcsq_val(int,int,int); | |
| #endif | |
| void record_hash(int,const HASHKEY&,int,int,int,int,MOVE,int,int); | |
| int probe_hash(int,const HASHKEY&,int,int,int&,MOVE&,int,int,int&,int&,int&,bool); | |
| void RECORD_HASH(int,const HASHKEY&,int,int,int,int,MOVE,int,int); | |
| int PROBE_HASH(int,const HASHKEY&,int,int,int&,MOVE&,int,int,int&,int&,int&,bool); | |
| void record_pawn_hash(const HASHKEY&,const SCORE&,const PAWNREC&); | |
| int probe_pawn_hash(const HASHKEY&,SCORE&,PAWNREC&); | |
| void record_eval_hash(const HASHKEY&,int); | |
| int probe_eval_hash(const HASHKEY&,int&); | |
| void prefetch_tt(); | |
| void prefetch_qtt(); | |
| bool san_mov(MOVE& move,char* s); | |
| bool build_book(char*,char*,int,int,int); | |
| void update_history(MOVE); | |
| void clear_history(); | |
| int get_root_search_score(); | |
| int get_search_score(); | |
| void evaluate_moves(int,int,int); | |
| void generate_and_score_moves(int,int,int,bool=false); | |
| /*mcts stuff*/ | |
| void extract_pv(Node*); | |
| void create_children(Node*); | |
| void add_children(Node*); | |
| void add_null_child(Node*); | |
| void manage_tree(Node*&,HASHKEY&); | |
| void play_simulation(Node*,double&,int&); | |
| void search_mc(); | |
| void print_status(); | |
| void compute_children_nn_eval(Node*); | |
| /*counts*/ | |
| UBMP64 nodes; | |
| UBMP64 qnodes; | |
| UBMP64 ecalls; | |
| UBMP64 time_check; | |
| UBMP64 message_check; | |
| UBMP32 search_calls; | |
| UBMP32 qsearch_calls; | |
| UBMP32 splits; | |
| UBMP32 bad_splits; | |
| UBMP32 egbb_probes; | |
| VOLATILE int stop_searcher; | |
| bool finish_search; | |
| bool skip_nn; | |
| /* | |
| Parallel search | |
| */ | |
| bool used; | |
| int processor_id; | |
| #if defined(PARALLEL) || defined(CLUSTER) | |
| SEARCHER* master; | |
| void handle_fail_high(); | |
| void clear_block(); | |
| #endif | |
| #ifdef PARALLEL | |
| LOCK lock; | |
| VOLATILE int n_workers; | |
| SEARCHER* VOLATILE workers[MAX_CPUS]; | |
| int get_smp_move(); | |
| int check_split(); | |
| void attach_processor(int); | |
| void update_master(int); | |
| void stop_workers(); | |
| #endif | |
| #ifdef CLUSTER | |
| VOLATILE int n_host_workers; | |
| std::list<int> host_workers; | |
| int get_cluster_move(SPLIT_MESSAGE*,bool=false); | |
| void get_init_pos(INIT_MESSAGE*); | |
| #endif | |
| /* | |
| things that are shared among multiple searchers. | |
| */ | |
| static int search_depth; | |
| static int start_time; | |
| static int scorpio; | |
| static int pv_print_style; | |
| static int root_score; | |
| static int root_failed_low; | |
| static int last_book_move; | |
| static int first_search; | |
| static int analysis_mode; | |
| static int in_egbb; | |
| static int show_full_pv; | |
| static int abort_search; | |
| static UBMP32 poll_nodes; | |
| static MOVE expected_move; | |
| static int resign_value; | |
| static int resign_count; | |
| static CHESS_CLOCK chess_clock; | |
| static UBMP64 root_score_st[MAX_MOVES]; | |
| static CACHE_ALIGN int history[14][64]; | |
| static CACHE_ALIGN MOVE refutation[14][64]; | |
| static Node* VOLATILE root_node; | |
| static HASHKEY root_key; | |
| /* | |
| Bitbases and neural network | |
| */ | |
| void fill_list(int*,int*); | |
| int probe_bitbases(int&); | |
| int probe_neural(); | |
| bool bitbase_cutoff(); | |
| static int egbb_is_loaded; | |
| static int egbb_load_type; | |
| static int egbb_depth_limit; | |
| static int egbb_ply_limit_percent; | |
| static int egbb_ply_limit; | |
| static int egbb_cache_size; | |
| static char egbb_path[MAX_STR]; | |
| static char nn_path[MAX_STR]; | |
| static int use_nn; | |
| /* | |
| End | |
| */ | |
| } *PSEARCHER; | |
| #ifdef PARALLEL | |
| void search(PROCESSOR* const); | |
| #else | |
| void search(SEARCHER* const); | |
| #endif | |
| /* | |
| inline piece list functions | |
| */ | |
| FORCEINLINE void SEARCHER::pcAdd(int pic,int sq,PLIST pCapt) { | |
| PLIST& pHead = plist[pic]; | |
| PLIST pPc = list[sq]; | |
| if(!pHead) { | |
| pHead = pPc; | |
| pHead->next = 0; | |
| pHead->prev = 0; | |
| } else { | |
| if(pCapt) { | |
| pPc->prev = pCapt; | |
| if(pCapt->next) pCapt->next->prev = pPc; | |
| pPc->next = pCapt->next; | |
| pCapt->next = pPc; | |
| } else { | |
| pPc->next = pHead; | |
| pHead->prev = pPc; | |
| pPc->prev = 0; | |
| pHead = pPc; | |
| } | |
| } | |
| } | |
| FORCEINLINE void SEARCHER::pcRemove(int pic,int sq,PLIST& pCapt) { | |
| PLIST& pHead = plist[pic]; | |
| PLIST pPc = list[sq]; | |
| pCapt = pPc->prev; | |
| if(pPc->next) pPc->next->prev = pPc->prev; | |
| if(pPc->prev) pPc->prev->next = pPc->next; | |
| if(pHead == pPc) pHead = pHead->next; | |
| } | |
| FORCEINLINE void SEARCHER::pcSwap(int from,int to) { | |
| PLIST pPc; | |
| PLIST& pTo = list[to]; | |
| PLIST& pFrom = list[from]; | |
| pPc = pTo; | |
| pTo = pFrom; | |
| pFrom = pPc; | |
| pTo->sq = to; | |
| pFrom->sq = from; | |
| } | |
| FORCEINLINE void SEARCHER::PUSH_MOVE(MOVE move) { | |
| do_move(move); | |
| ply++; | |
| pstack++; | |
| } | |
| FORCEINLINE void SEARCHER::PUSH_NULL() { | |
| do_null(); | |
| ply++; | |
| pstack++; | |
| } | |
| FORCEINLINE void SEARCHER::POP_MOVE() { | |
| ply--; | |
| pstack--; | |
| undo_move(); | |
| } | |
| FORCEINLINE void SEARCHER::POP_NULL() { | |
| ply--; | |
| pstack--; | |
| undo_null(); | |
| } | |
| /* | |
| sort move list | |
| */ | |
| FORCEINLINE void STACK::sort(const int start,const int end) { | |
| register int i,bi = start,bs = score_st[start]; | |
| for (i = start + 1; i < end; i++) { | |
| if(score_st[i] > bs) { | |
| bi = i; | |
| bs = score_st[i]; | |
| } | |
| } | |
| if(bi != start) { | |
| MOVE tempm; | |
| int temps; | |
| tempm = move_st[start]; | |
| temps = score_st[start]; | |
| move_st[start] = move_st[bi]; | |
| score_st[start] = score_st[bi]; | |
| move_st[bi] = tempm; | |
| score_st[bi] = temps; | |
| } | |
| } | |
| /* | |
| PROCESSOR | |
| */ | |
| enum thread_states { | |
| PARK,WAIT,GO,KILL | |
| }; | |
| typedef struct PROCESSOR { | |
| /*searchers*/ | |
| SEARCHER searchers[MAX_SEARCHERS_PER_CPU]; | |
| PSEARCHER searcher; | |
| VOLATILE int state; | |
| /*processor count*/ | |
| static int n_processors; | |
| static VOLATILE int n_idle_processors; | |
| static int n_hosts; | |
| /*cluster*/ | |
| #ifdef CLUSTER | |
| enum processor_states { | |
| QUIT = 0,INIT,HELP,CANCEL,SPLIT,MERGE,PING,PONG, | |
| GOROOT, RECORD_TT,PROBE_TT,PROBE_TT_RESULT | |
| }; | |
| static const char *const message_str[12]; | |
| static int host_id; | |
| static char host_name[256]; | |
| static int help_messages; | |
| static int prev_dest; | |
| static std::list<int> available_host_workers; | |
| static VOLATILE int message_available; | |
| static void cancel_idle_hosts(); | |
| static void quit_hosts(); | |
| static int MESSAGE_POLL_NODES; | |
| static int CLUSTER_SPLIT_DEPTH; | |
| #endif | |
| /*functions*/ | |
| static void exit_scorpio(int); | |
| #ifdef PARALLEL | |
| static int SMP_SPLIT_DEPTH; | |
| static void create(int id); | |
| static void kill(int id); | |
| #endif | |
| static void set_main(); | |
| #ifdef CLUSTER | |
| static void init(int argc, char* argv[]); | |
| static void ISend(int dest,int message); | |
| static void ISend(int dest,int message,void* data,int size,MPI_Request* = 0); | |
| static void Recv(int dest,int message); | |
| static void Recv(int dest,int message,void* data,int size); | |
| static bool IProbe(int& dest,int& message_id); | |
| static void Wait(MPI_Request*); | |
| static void Barrier(); | |
| static void Sum(UBMP64* sendbuf,UBMP64* recvbuf); | |
| static void handle_message(int dest,int message_id); | |
| static void offer_help(); | |
| #endif | |
| #if defined(PARALLEL) || defined(CLUSTER) | |
| bool has_block(); | |
| void idle_loop(); | |
| static void message_idle_loop(); | |
| #endif | |
| /*hash tables*/ | |
| PHASH hash_tab[2]; | |
| PEVALHASH eval_hash_tab[2]; | |
| PPAWNHASH pawn_hash_tab; | |
| #ifdef CLUSTER | |
| TT_MESSAGE ttmsg; | |
| VOLATILE bool ttmsg_recieved; | |
| #endif | |
| static UBMP32 hash_tab_mask; | |
| static UBMP32 pawn_hash_tab_mask; | |
| static UBMP32 eval_hash_tab_mask; | |
| static int age; | |
| void reset_hash_tab(int id,UBMP32); | |
| void reset_pawn_hash_tab(UBMP32 = 0); | |
| void reset_eval_hash_tab(UBMP32 = 0); | |
| void delete_hash_tables(); | |
| static void clear_hash_tables(); | |
| /*constructor*/ | |
| PROCESSOR() { | |
| state = KILL; | |
| searcher = 0; | |
| hash_tab[white] = 0; | |
| hash_tab[black] = 0; | |
| eval_hash_tab[white] = 0; | |
| eval_hash_tab[black] = 0; | |
| pawn_hash_tab = 0; | |
| } | |
| } *PPROCESSOR; | |
| extern PPROCESSOR processors[MAX_CPUS]; | |
| /* | |
| multi processors | |
| */ | |
| #ifdef PARALLEL | |
| void init_smp(int); | |
| extern LOCK lock_smp; | |
| extern LOCK lock_io; | |
| extern int use_abdada_smp; | |
| #endif | |
| #ifdef CLUSTER | |
| extern int use_abdada_cluster; | |
| #endif | |
| /* | |
| global data | |
| */ | |
| extern const HASHKEY piece_hkey[14][64]; | |
| extern const HASHKEY ep_hkey[8]; | |
| extern const HASHKEY cast_hkey[16]; | |
| extern const int piece_cv[14]; | |
| extern const int piece_see_v[14]; | |
| extern const int pic_tab[14]; | |
| extern const int pawn_dir[2]; | |
| extern const int piece_mask[14]; | |
| extern int pcsq[14][0x80]; | |
| extern bool book_loaded; | |
| extern bool log_on; | |
| extern int scorpio_start_time; | |
| extern int montecarlo; | |
| extern int rollout_type; | |
| extern bool freeze_tree; | |
| /** search options */ | |
| extern const int use_nullmove; | |
| extern const int use_selective; | |
| extern const int use_tt; | |
| extern const int use_aspiration; | |
| extern const int use_iid; | |
| extern const int use_pvs; | |
| extern const int contempt; | |
| /* | |
| utility functions | |
| */ | |
| int get_time(); | |
| void init_io(); | |
| void remove_log_file(); | |
| void print(const char* format,...); | |
| void printH(const char* format,...); | |
| void print_log(const char* format,...); | |
| void print_std(const char* format,...); | |
| void print_move(const MOVE&); | |
| void print_move_full(const MOVE&); | |
| void print_sq(const int&); | |
| void print_pc(const int&); | |
| void print_bitboard(BITBOARD); | |
| void sq_str(const int& ,char*); | |
| void mov_strx(const MOVE& ,char*); | |
| void mov_str(const MOVE& ,char*); | |
| void str_mov(MOVE& ,char*); | |
| int tokenize(char* , char** , const char* str2 = " =\n\r\t"); | |
| bool read_line(char*); | |
| int bios_key(void); | |
| void load_book(); | |
| bool parse_commands(char**); | |
| void merge_books(char*,char*,char*,double,double); | |
| int get_number_of_cpus(); | |
| bool check_search_params(char**,char*,int&); | |
| void print_search_params(); | |
| bool check_mcts_params(char**,char*,int&); | |
| void print_mcts_params(); | |
| #ifdef TUNE | |
| extern int nParameters; | |
| extern int nModelParameters; | |
| void init_parameters(int); | |
| void allocate_jacobian(int); | |
| bool has_jacobian(); | |
| double eval_jacobian(int,int&,double*); | |
| void compute_jacobian(PSEARCHER,int,int); | |
| double get_log_likelihood(int,double); | |
| void get_log_likelihood_grad(PSEARCHER,int,double,double*,int); | |
| void readParams(double*); | |
| void writeParams(double*); | |
| void write_eval_params(); | |
| bool check_eval_params(char**,char*,int&); | |
| void print_eval_params(); | |
| void zero_params(); | |
| void bound_params(double*); | |
| #endif | |
| /* | |
| Bitbases | |
| */ | |
| int LoadEgbbLibrary(char* path,int); | |
| /* | |
| Bitboards. | |
| */ | |
| /* | |
| The following low level subroutines are taken from | |
| http://chessprogramming.wikispaces.com/Bitboards . Thanks to | |
| their respective authors. | |
| */ | |
| # ifdef ARC_64BIT | |
| #if !defined(HAS_POPCNT) | |
| FORCEINLINE int popcnt(BITBOARD b) { | |
| const BITBOARD k1 = UINT64(0x5555555555555555); | |
| const BITBOARD k2 = UINT64(0x3333333333333333); | |
| const BITBOARD k4 = UINT64(0x0f0f0f0f0f0f0f0f); | |
| const BITBOARD kf = UINT64(0x0101010101010101); | |
| b = b - ((b >> 1) & k1); | |
| b = (b & k2) + ((b >> 2) & k2); | |
| b = (b + (b >> 4)) & k4 ; | |
| return (int) ((b * kf) >> 56); | |
| } | |
| #endif | |
| #if !defined(HAS_BSF) | |
| /* | |
| 64bit LSB bitscan from Lieserson etal. | |
| Private bitscan routine (64bit deBruijin) generated using Gerd Isenberg's code. | |
| NB: Table contains squares in 0x88 format. | |
| */ | |
| const BITBOARD magic = 0x021c9a5edd467e2b; /* The 01111981 => This Number is Copyrighted by BIRTH :) */ | |
| const unsigned int table[64] = { | |
| 0, 1, 2, 7, 3,103, 82, 16, | |
| 4, 22,112, 39, 83, 33, 17, 87, | |
| 5, 80, 37, 23, 70,113,115, 48, | |
| 117, 84, 34, 55, 18, 66, 50, 96, | |
| 119, 6,102, 81, 21, 38, 32, 86, | |
| 71, 36, 69,114,116, 54, 65, 49, | |
| 118,101, 20, 85, 35, 68, 53, 64, | |
| 100, 19, 67, 52, 99, 51, 98, 97 | |
| }; | |
| FORCEINLINE unsigned int first_one(BITBOARD b) { | |
| return table[((b & -b) * magic) >> 58]; | |
| } | |
| #else | |
| FORCEINLINE unsigned int first_one(BITBOARD b) { | |
| unsigned int x = bsf(b); | |
| return SQ6488(x); | |
| } | |
| #endif | |
| # else | |
| FORCEINLINE int popcnt(BITBOARD b) { | |
| const UBMP32 k1 = (0x55555555); | |
| const UBMP32 k2 = (0x33333333); | |
| const UBMP32 k4 = (0x0f0f0f0f); | |
| const UBMP32 kf = (0x01010101); | |
| UBMP32 hi = (UBMP32) (b >> 32); | |
| UBMP32 lo = (UBMP32) (b); | |
| hi = hi - ((hi >> 1) & k1); | |
| hi = (hi & k2) + ((hi >> 2) & k2); | |
| hi = (hi + (hi >> 4)) & k4 ; | |
| lo = lo - ((lo >> 1) & k1); | |
| lo = (lo & k2) + ((lo >> 2) & k2); | |
| lo = (lo + (lo >> 4)) & k4 ; | |
| return (int) (((hi + lo) * kf) >> 24); | |
| } | |
| /*Matt taylor's bitscan , optimized for 32 bit systems*/ | |
| const unsigned int table[64] = { | |
| 119, 54, 3, 64,115, 22, 19, 65, | |
| 116, 48, 98, 17,103, 35, 37, 66, | |
| 117, 53, 2,101, 99, 39, 81, 34, | |
| 112, 52, 1, 83, 86, 51, 0, 67, | |
| 118, 55,114, 4, 5, 97,102, 6, | |
| 23,100, 20, 80, 7, 82, 85, 32, | |
| 49,113, 96, 21, 18, 71, 16, 84, | |
| 36, 87, 70, 38, 33, 69, 68, 50 | |
| }; | |
| FORCEINLINE unsigned int first_one(BITBOARD b) { | |
| unsigned int folded; | |
| b ^= (b - 1); | |
| folded = (int) (b ^ (b >> 32)); | |
| return table[folded * 0x78291ACF >> 26]; | |
| } | |
| # endif | |
| /* | |
| Brian Kernighan's sparse bitboard population count | |
| Used for king attack pattern. | |
| */ | |
| #if !defined(HAS_POPCNT) | |
| FORCEINLINE int popcnt_sparse(BITBOARD b) { | |
| register int count = 0; | |
| while (b) { | |
| count++; | |
| b &= b - 1; | |
| } | |
| return count; | |
| } | |
| #endif | |
| /* | |
| flip bitboard along a1h8. | |
| Used to rotate pawn bitboards. | |
| */ | |
| FORCEINLINE BITBOARD Rotate(BITBOARD b) { | |
| BITBOARD t; | |
| const BITBOARD k1 = UINT64(0x5500550055005500); | |
| const BITBOARD k2 = UINT64(0x3333000033330000); | |
| const BITBOARD k4 = UINT64(0x0f0f0f0f00000000); | |
| t = k4 & (b ^ (b << 28)); | |
| b ^= t ^ (t >> 28) ; | |
| t = k2 & (b ^ (b << 14)); | |
| b ^= t ^ (t >> 14) ; | |
| t = k1 & (b ^ (b << 7)); | |
| b ^= t ^ (t >> 7) ; | |
| return b; | |
| } | |
| /* | |
| Some bitboards | |
| */ | |
| extern const BITBOARD rank_mask[8]; | |
| extern const BITBOARD file_mask[8]; | |
| extern const BITBOARD __unit_bb[0x80]; | |
| extern const UBMP8 first_bit[0x100]; | |
| extern const UBMP8 last_bit[0x100]; | |
| extern const UBMP8 center_bit[0x100]; | |
| extern const UBMP8* const _sqatt_pieces; | |
| extern const BMP8* const _sqatt_step; | |
| extern BITBOARD in_between[64][64]; | |
| /* | |
| Pradu's magic tables | |
| */ | |
| extern const BITBOARD knight_magics[64]; | |
| extern const BITBOARD king_magics[64]; | |
| extern const BITBOARD magicmoves_r_magics[64]; | |
| extern const BITBOARD magicmoves_r_mask[64]; | |
| extern const BITBOARD magicmoves_b_magics[64]; | |
| extern const BITBOARD magicmoves_b_mask[64]; | |
| extern const unsigned int magicmoves_b_shift[64]; | |
| extern const unsigned int magicmoves_r_shift[64]; | |
| extern const BITBOARD* magicmoves_b_indices[64]; | |
| extern const BITBOARD* magicmoves_r_indices[64]; | |
| #define BB(sq) (__unit_bb[sq]) | |
| #define NBB(sq) (__unit_bb[sq + 8]) | |
| #define sqatt_pieces(sq) _sqatt_pieces[sq] | |
| #define sqatt_step(sq) _sqatt_step[sq] | |
| #define blocked(from,to) (in_between[SQ8864(from)][SQ8864(to)] & all_bb) | |
| #define king_attacks(sq) (king_magics[sq]) | |
| #define knight_attacks(sq) (knight_magics[sq]) | |
| #define bishop_attacks(sq,occ) (*(magicmoves_b_indices[sq]+(((occ&magicmoves_b_mask[sq])*magicmoves_b_magics[sq])>>magicmoves_b_shift[sq]))) | |
| #define rook_attacks(sq,occ) (*(magicmoves_r_indices[sq]+(((occ&magicmoves_r_mask[sq])*magicmoves_r_magics[sq])>>magicmoves_r_shift[sq]))) | |
| #define queen_attacks(sq,occ) (bishop_attacks(sq,occ) | rook_attacks(sq,occ)) | |
| void initmagicmoves(void); | |
| /* | |
| End | |
| */ | |
| #endif |