Advertisement
Guest User

main.c

a guest
Apr 20th, 2018
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 73.81 KB | None | 0 0
  1. /*
  2.    Contiene le funzioni che gestiscono le opzioni configurabili con la GUI, la comunicazione GUI-engine
  3.    e la funzione di ricerca a partire da una posizione iniziale
  4. */
  5. /*
  6. 18/06/17 Pedone 1.7
  7.  
  8. Novit? rispetto alla versione 1.6
  9. - corretto baco sulla null move
  10. - tuning
  11. - rivista valutazione pedoni passati
  12. - supporto allocazione hash tramite large pages
  13. - rivista gestione tempo alloca +10% in ponder
  14. - modificato LMP
  15. - countermove
  16. - riduzione per le catture cattive
  17. - modificata history
  18. - risolte le perdite per il tempo con la forza ridotta
  19. */
  20.  
  21. /*
  22. DA FARE:
  23. ATTENZIONE!!!! In valutazione dove ci sono shift o divisioni su costanti (ad es mobilit?) può capitare che non venga moltiplicata
  24. la mobilit? per il bonus e poi divisa, ma che venga moltiplicata per una costante gi? divisa, quindi potrebbe perdere
  25. qualcosina in precisione ottenendo valori distanti di 1 cp dai valori corretti
  26.  
  27. */
  28. /* COME USARE OPROFILE
  29.    si compila con -g ma non -pg
  30.    operf ./Pedone pgo
  31.    opreport --symbols
  32. */
  33.  
  34. /* Define per la compilazione abilitate e disabilitate tramite makefile*/
  35. //#define BMI
  36. //#define BIT32
  37. /* ATTENZIONE!!! In release definire NDEBUG */
  38. //#define NDEBUG
  39.  
  40. #include <stdlib.h>
  41. #include <string.h>
  42. #include <sys/time.h>
  43. #include <stdio.h>
  44. #include <stdint.h>
  45. #include <inttypes.h>
  46. #include <pthread.h>
  47. #include <assert.h>
  48. #include <unistd.h>
  49. #include <setjmp.h>
  50. #ifdef BMI
  51. #include <immintrin.h>
  52. #endif
  53. #ifdef _WIN32
  54. #include <windows.h>
  55. #include <conio.h>
  56. #endif
  57.  
  58. static void DefinizioneDati(){} // Serve solo per CodeBlocks
  59. /* Definizioni di Tipi, costanti e variabili globali */
  60.  
  61. /* Dimensione di default della tabella delle trasposizioni */
  62. #define MBHASHDEFAULT 256
  63. /* profondit? limite raggiungibile in ricerca */
  64. #define DEFAULTMAXDEPTH 100
  65.  
  66. /* Valutazione in ricerca massima che indica che non sono ancora stati individuati altri score */
  67. #define INFINITO 32701
  68. /* Valutazione del matto */
  69. #define MATTO 32700
  70. /* Distanza massima del matto, serve a distinguere gli score di matto dagli altri */
  71. #define MATTOMIN (MATTO-800)
  72.  
  73. /* Definizioni per il tipo pezzo salvabile nelle mosse */
  74. #define PED 1
  75. #define CAV 2
  76. #define ALF 3
  77. #define TOR 4
  78. #define REG 5
  79. #define RE 6
  80.  
  81. /* Gli score in valutazione e ricerca sono tutti in 1/4 di cp quindi per convertirli in cp si divide per FATTVAL */
  82. #define FATTVAL 4
  83. /* Genera gli scacchi da depth 0 fino a DEPTHSCACHI, in questo caso solo a depth 0 */
  84. #define DEPTHSCACCHI 0 /* 0 va meglio che -1 dai test */
  85.  
  86. /* indici che indicano il codice hash che modifica la chiave principale a seconda del tipo di mossa */
  87. /* Indici Arrocco corto bianco, lungo bianco, corto nero, lungo nero */
  88. #define CHARROCCOCB 1024
  89. #define CHARROCCOCN 1025
  90. #define CHARROCCOLB 1026
  91. #define CHARROCCOLN 1027
  92. #define CHCOLONNEENPASSANT 1028
  93. #define CHTRATTON 1036
  94.  
  95. typedef enum {false=0,true=1} bool;
  96.  
  97. /* direzioni per accedere alla matrice Direzioni */
  98. /* DX destra SX sinistra SU sù GI giù DS diagonale su DG diagonale giù AS antidiagonale sù AG antidiagonale giù */
  99. #define DX 0
  100. #define SX 1
  101. #define SU 2
  102. #define GI 3
  103. #define DS 4
  104. #define DG 5
  105. #define AS 6
  106. #define AG 7
  107.  
  108. /* Fasi della generazione mosse nella funzione di ricerca */
  109. /* ATTENZIONE ALLA NUMERAZIONE, LE KILLER DEVONO ESSERE IN SUCCESSIONE */
  110. typedef enum{HASH=0,GEN=1,CATTUREBUONE=2,KILLER10=3,KILLER11=4,COUNTERMOVE=5,KILLER20=6,KILLER21=7,GENALTRE=8,ALTREMOSSE=9} TOrdinamento;
  111.  
  112. typedef uint64_t TBB; /* rappresenta le 64 case della scacchiera */
  113. typedef uint32_t TPos; /* da 0 a 63, rappresenta l'indice del bit nella bitboard */
  114. typedef uint32_t TMossa;/* 5 Flag + 3 Prom + 3 Catt + 6 A 6 Da + 3 Pezzo*/
  115. typedef uint16_t TMossaPack;
  116.  
  117. /* Costanti per formare il tipo mossa */
  118. /* il risultato di RE|ARROCCO sar? il tipomossa arrocco
  119.   PED|CATTURA|EP sar? un enpassant
  120.   PED|PROMO|CATTURA sar? una promozione con cattura */
  121. #define SCACCO 0x02000000
  122. #define ARROCCO 0x01000000
  123. #define PROMO 0x00800000
  124. #define EP 0x00400000
  125. #define CATTURA 0x00200000
  126.  
  127. /* Score minimo per le catture */
  128. #define VALCATTURE 0x40000000
  129. /* Score minimo per le quiete */
  130. #define VALQUIETE 0x20000000
  131. /* la catture cattive hanno score negativo */
  132. /* Score da assegnare all'arrocco per portarlo davanti alle altre quiete */
  133. #define VALARROCCO 0x10000000
  134. /* score di partenza per le promozioni minori (promozioni diverse da donna) */
  135. #define VALPROMOMINORI -2000000000
  136. // il limite history è minore di 4 volte rispetto a valarrocco, così sommando in ricerca le 3 history si rimane sempre sotto a VALARROCCO
  137. #define LIMITEHISTORY 67108864
  138.  
  139. /* Definizione della struttura mossa/score composto dalla mossa e dalla valutazione di quella mossa */
  140. typedef struct
  141. {
  142.     int32_t Val;
  143.     TMossa Mossa;
  144. } TMossaVal;
  145.  
  146. /* Per salvare le destinazioni di torre e alfiere */
  147. /* Servono per le Magic Bitboard, da notare che se si usano le istruzioni BMI i campi magic e shift scompaiono */
  148. typedef struct
  149. {
  150.     const TBB Mask;
  151. #ifndef BMI
  152.     const TBB Magic;
  153.     const TBB Shift;
  154. #endif
  155.     TBB *const Dest;
  156. }TMagic;
  157.  
  158. /*
  159. tipo dati che verr? usato per aggiornare in maniera incrementare la valutazione materiale/piece sqare table
  160. e la generazione della chiave hash della posizione
  161. */
  162. typedef struct
  163. {
  164.     uint64_t Hash;
  165.     int16_t ValMg;
  166.     int16_t ValEg;
  167. } THashVal;
  168.  
  169. /* Definizione del tipo nodo in ricerca e dei valori associabili a questo tipo*/
  170. #define PVNODE  0x02
  171. #define CUTNODE 0x01
  172. #define ALLNODE 0x00
  173.  
  174. /* maschera node type per individuare il tipo nodo */
  175. #define MASKNT 0x03
  176. /* maschera ricerca, per individuare il numero di ricerca per un certo valore salvato nella hash */
  177. #define MASKRIC 0xFC
  178. /* flag per salvare la mossa nella hash in formato packed */
  179. #define PACKSCACCO 0x8000
  180. #define PACKPROMO 0x4000
  181. #define PACKEP 0x2000
  182. #define PACKARROCCO 0x1000
  183. /*
  184. Definizione dello slot salvato nella hash trasposizioni, si può accedere tramite 2 valori a 64 bit
  185. o tramite i vari campi.
  186. */
  187. typedef union
  188. {
  189.    uint64_t V[2];
  190.    struct{ // !!! ATTENZIONE !!! NRic occupa solo 6 bit, per essere sicuri ne dovrebbe utilizzare almeno 7
  191.       uint64_t Hash; // Chiave hash della posizione salvata
  192.       int16_t Val; // score salvato: può essere esatto, un limite alto o un limite basso
  193.       int16_t ValStatica; // valutazione statica per questa posizione
  194.       TMossaPack MossaPack;// 6bit sorgente + 6bit destinazione + 4bit flag
  195.       // bit flag 0123  bit 3 scacco bit 2 promo- se promo==1 bit 0 e 1 conterranno il pezzo promosso
  196.       int8_t Depth;
  197.       uint8_t NRicercaNT; // 6 bit N Ricerca + 2 bit Node Type
  198.    };
  199. } TSlotHash;
  200.  
  201. /* Definizione tipo per la hash dedicata alla posizione dei pedoni e dei 2 re */
  202. typedef union
  203. {
  204.     uint64_t V[2]; /* Hash pedoni */
  205.     struct{
  206.       uint64_t Hash; // chiave hash della posizione dei pedoni e re
  207.       int16_t ValMg; // valutazione calcolata per il mediogioco
  208.       int16_t ValEg; // valutazione calcolata per il finale
  209.       int16_t BonusRe[2]; // sicurezza dei re per entrambi i giocatori [1] chi ha il tratto [0] chi non muove
  210.     };
  211. } TSlotHashPR;
  212.  
  213. /* strutture per la scacchiera e la partita */
  214. /* definisci il colore che deve muovere */
  215. #define BIANCO 0
  216. #define NERO 8
  217. /* flag per indicare se una posizione è una ripetizione o meno */
  218. #define RIP3 0x01
  219. /* flag che indica se nella posizione corrente si è sotto scacco */
  220. #define SOTTOSCACCO 0x80
  221. /* Definizione struttura scacchiera*/
  222. typedef struct
  223. {
  224.     TBB PT; /* Tutti i pezzi del lato tratto */
  225.     TBB P0; /* Da P2 a P0 si possono ricavare tutti i pezzi, in particolar modo il tipo del pezzo */
  226.     TBB P1;
  227.     TBB P2;
  228.     uint8_t ScaccoTrattoRip3; // S...T..R 1 bit scacco, 1 bit tratto 1 bit ripetizione
  229.     uint8_t Arrocchi; /* ..rd..RD "r" "d" re e regina avversario e RE e REGINA tratto */
  230.     uint8_t EnPassant; /* numero della colonna su cui effettuare la presa, =8 se non impostato */
  231.     uint8_t Cont50Mosse; /* conta le mosse dall'ultima cattura o spinta di pedone */
  232.     int16_t ValMg;      /* valutazione materiale/tabelle pezzi della scacchiera nel mediogioco */
  233.     int16_t ValEg;    /* valutazione materiale/tabelle pezzi della scacchiera nel finale */
  234.     uint64_t Hash; /* codice hash della scacchiera */
  235.     uint64_t HashPR; /* codice hash pedoni e re */
  236. } TScacchiera;
  237.  
  238. /* Struttura dei libri polyglot per leggere questo tipo di libri di aperture */
  239. typedef struct
  240. {
  241.   uint64_t Hash; // codice hash della posizione
  242.   uint16_t Mossa; // mossa salvata nel libro
  243.   uint16_t Weight; // valutazione di questa mossa
  244.   uint32_t Learn; // non usato in genere, ma servirebbe per il learning sul libro di aperture
  245. } TSlotBook;
  246.  
  247. /* limite massimo di forza dell'engine (nel caso lo si volesse limitare in forza di gioco) */
  248. #define MAXSTRENGTH 100
  249. /* Opzioni che possono essere gestite dalla GUI per modificare varie funzionalit? */
  250. typedef struct
  251. {
  252.    int Hash; //Dimensione in Mb della trasposition table
  253.    bool Ponder; //Abilita o disabilita la possibilit? di pensare durante il turno avversario
  254.    int DrawScore; //Score da assegnare alla parit? per spingere l'engine a evitare o cercare la patta
  255.   bool OwnBook; //Abilita l'uso di un proprio libro (Polyglot)
  256.    char BookFile[512]; //Nome del file del libro di aperture
  257.    bool BookRandom; //Scegli casualmente la mossa, se a false sceglie sempre la mossa migliore
  258.    int Strength; //Forza dell'engine MAXSTRENGTH è la forza massima 1 la minima
  259.   int Threads; //Numero di thread da utilizzare per la ricerca parallela
  260.   bool LargePages;
  261.   // ci dovrebbe essere anche SyzygyPath, ma non è inclusa perchè non è necessario mantenere memorizzato il percorso
  262.   int MultiPV; //Abilit? la modalit? di analisi con la stampa di varianti multiple
  263.   bool Syzygy50MoveRule; //Abilita la regola delle 50 mosse per la tablebase o meno
  264.   int SyzygyProbeLimit; //Limite di pezzi entro il quale fare il probe della tablebase
  265. } TOpzioni;
  266.  
  267. // Definisci i tipi di ricerca con i quali può essere lanciato l'engine
  268. // NORMALE la ricerca termina dopo un certo lasso di tempo determinato all'avvio della ricerca
  269. // PONDER l'engine attende che l'avversario muova per terminare la ricerca o restare in ricerca per un certo lasso di tempo
  270. // RICINFINITA l'engine rimane in ricerca a tempo indeterminato finche non viene stoppato dalla GUI
  271. typedef enum {NORMALE,PONDER,RICINFINITA} TTipoRicerca;
  272. /*
  273. Struttura che salva le variabili relative alla ricerca
  274. */
  275. typedef struct
  276. {
  277.    TTipoRicerca TipoRicerca; // tipo di ricerca da eseguire
  278.    volatile bool TerminaRicerca; // a true se la ricerca va terminata per: stop,ponderhit con tempo trascorso,in ricerca se il tempo va oltre il limite
  279.    int64_t LimiteMSec,LimiteUltimoMSec; // limiti in msec da controllare in ricerca per non usare troppo tempo
  280.    int64_t ControlloTempo; // numero di nodi oltre il quale effettuare un controllo del tempo
  281.    int64_t NNodiCheck; // numero di nodi tra un controllo del tempo e un altro
  282.    /* maschere per individuare l'indice al quale salvare le posizioni rispettivamente nella hash e nella hash dei pedoni/re*/
  283.   uint64_t MASKHASH,MASKHASHPED;
  284.   volatile TSlotHash *TT; // indirizzo al quale comincia la trasposition table
  285.   volatile TSlotHashPR *TTPedoni; // indirizzo al quale comincia la hash dei pedoni/re
  286.   int TBLargest,TBCardinality;// massimo numero di pezzi della tablebase e massimo numero di pezzi per il quale effetture il probe della tablebase
  287.   int MultiPVReale; // numero di mosse da esaminare in multipv tenendo conto del numero complessivo di mosse
  288.   // sotto windows servono per la lettura dell'input non bloccante
  289. #ifdef _WIN32
  290.     int Pipe;
  291.     HANDLE Handle;
  292. #endif
  293.    uint8_t NRicerca; // numero progressivo di ricerca effettuato
  294. } TRicerca;
  295.  
  296. /* numero massimo di mosse per una singola posizione (il numero è molto alto per evitare sforamenti)*/
  297. #define MAXMOSSE 256
  298. // Definisci la struttura dati per salvare le info di un singolo thread
  299. typedef struct
  300. {
  301. // è sufficiente 256 visto che con il limite delle 50 mosse e il caricamento della posizione non dovrebbero esserci
  302. // più di 100 posizioni + 128 in ricerca. Per sicurezza 256
  303.    pthread_t Thread;
  304.    jmp_buf Ambiente; // salvataggio ambiente per un longjump
  305.    TScacchiera Partita[256]; // tutte le posizioni della partita a partire dalla primo azzeramento delle 50 mosse prima della posizione corrente
  306.    TScacchiera *Scacchiera; // puntatore alla posizione corrente
  307.    volatile int Depth; // depth in ricerca attualmente (volatile perchè deve venir letto da altri thread)
  308.    int16_t alpha; // score alpha alla radice della ricerca
  309.    int16_t LastScore; // ultimo score per l'aspiration window
  310.   volatile int64_t NNodi; // Numero nodi ricercati, volatile perchè vengono usati in RootSearch quelli dei thread slave dal thread master
  311.   volatile int64_t TBHits; // Numero hit della tablebase volatile per come sopra
  312.   TMossaVal mosse[MAXMOSSE]; // contine tutte le mosse legali della posizione da unalizzare
  313.   TMossaVal *pmosse; // puntatore all'ultima mossa dell'array mosse
  314.   TMossa Killer[128*2]; // salva le killer moves aggiornate in ricerca
  315.   int History[128*8*64]; // salva i punteggi per le mosse aggiornate in ricerca
  316.   TMossa CounterMoves[2*8*64*64]; // salva le countermoves [lato][pezzo][da][a]
  317. } TStructThread;
  318.  
  319. static void DichiarazioneVarGlobali() {} // Serve solo per CodeBlocks
  320.  
  321. /* Dichiarazione di tutti i dati condivisi dai moduli del programma */
  322. /* numero massimo di thread supportati dalla ricerca parallela */
  323. #define MAXTHREADS 128
  324. /* array di threads */
  325. TStructThread Threads[MAXTHREADS];
  326.  
  327. /* Posizione iniziale degli scacchi */
  328. char STARTPOS[]="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
  329.  
  330. TRicerca Ric; //dati da passare per l'avvio della ricerca
  331. TOpzioni Opz; // opzioni dell'engine
  332.  
  333. /* codici per aggiornamento della valutazione e della hash */
  334. /* numero massimo di chiavi hash differenti per generare le chiavi delle posizioni */
  335. #define DIMVETCODICIHASH 1037
  336. THashVal HashVal[DIMVETCODICIHASH]; /* 16 tipo pezzo*64 case + 1 per tratto nero + 4 per ogni arrocco possibile + 8 per ogni fila in cui è possibile l'EnPassant */
  337.  
  338. TBB Raggi[64*64]; // si accede con [da<<6+a] e ritorna una bb con a 1 i bit da "da" a "a" "da" escluso
  339. uint8_t Direzioni[64*64]; // si accede con [da<<6+a] e ritorna il numero di direzione, 8 se non sono allineate
  340. TBB DistanzaPedoni[64][7]; // [casa][distanza] genera una bitboard
  341.  
  342. /* case nelle quali deve essere presente il pedone per catturare con enpassant */
  343. const TBB EnPassant[8] = {
  344. 0x0000000200000000ULL,0x0000000500000000ULL,0x0000000A00000000ULL,0x0000001400000000ULL,
  345. 0x0000002800000000ULL,0x0000005000000000ULL,0x000000A000000000ULL,0x0000004000000000ULL
  346. };
  347. /* come prima solo che i valori sono a traverse invertite per usarli nel muovi */
  348. const TBB EnPassantM[8] = {
  349. 0x0000000002000000ULL,0x0000000005000000ULL,0x000000000A000000ULL,0x0000000014000000ULL,
  350. 0x0000000028000000ULL,0x0000000050000000ULL,0x00000000A0000000ULL,0x0000000040000000ULL
  351. };
  352.  
  353. /* bitboard con le destinazioni del cavallo */
  354. const TBB DestCavallo[64]= {0x0000000000020400ULL,0x0000000000050800ULL,0x00000000000a1100ULL,0x0000000000142200ULL,
  355.                                      0x0000000000284400ULL,0x0000000000508800ULL,0x0000000000a01000ULL,0x0000000000402000ULL,
  356.                                      0x0000000002040004ULL,0x0000000005080008ULL,0x000000000a110011ULL,0x0000000014220022ULL,
  357.                                      0x0000000028440044ULL,0x0000000050880088ULL,0x00000000a0100010ULL,0x0000000040200020ULL,
  358.                                      0x0000000204000402ULL,0x0000000508000805ULL,0x0000000a1100110aULL,0x0000001422002214ULL,
  359.                                      0x0000002844004428ULL,0x0000005088008850ULL,0x000000a0100010a0ULL,0x0000004020002040ULL,
  360.                                      0x0000020400040200ULL,0x0000050800080500ULL,0x00000a1100110a00ULL,0x0000142200221400ULL,
  361.                                      0x0000284400442800ULL,0x0000508800885000ULL,0x0000a0100010a000ULL,0x0000402000204000ULL,
  362.                                      0x0002040004020000ULL,0x0005080008050000ULL,0x000a1100110a0000ULL,0x0014220022140000ULL,
  363.                                      0x0028440044280000ULL,0x0050880088500000ULL,0x00a0100010a00000ULL,0x0040200020400000ULL,
  364.                                      0x0204000402000000ULL,0x0508000805000000ULL,0x0a1100110a000000ULL,0x1422002214000000ULL,
  365.                                      0x2844004428000000ULL,0x5088008850000000ULL,0xa0100010a0000000ULL,0x4020002040000000ULL,
  366.                                      0x0400040200000000ULL,0x0800080500000000ULL,0x1100110a00000000ULL,0x2200221400000000ULL,
  367.                                      0x4400442800000000ULL,0x8800885000000000ULL,0x100010a000000000ULL,0x2000204000000000ULL,
  368.                                      0x0004020000000000ULL,0x0008050000000000ULL,0x00110a0000000000ULL,0x0022140000000000ULL,
  369.                                      0x0044280000000000ULL,0x0088500000000000ULL,0x0010a00000000000ULL,0x0020400000000000ULL};
  370. /* bitboard con le destinazioni del re */
  371. const TBB DestRe[64] = {0x0000000000000302ULL,0x0000000000000705ULL,0x0000000000000e0aULL,0x0000000000001c14ULL,
  372.                                 0x0000000000003828ULL,0x0000000000007050ULL,0x000000000000e0a0ULL,0x000000000000c040ULL,
  373.                                 0x0000000000030203ULL,0x0000000000070507ULL,0x00000000000e0a0eULL,0x00000000001c141cULL,
  374.                                 0x0000000000382838ULL,0x0000000000705070ULL,0x0000000000e0a0e0ULL,0x0000000000c040c0ULL,
  375.                                 0x0000000003020300ULL,0x0000000007050700ULL,0x000000000e0a0e00ULL,0x000000001c141c00ULL,
  376.                                 0x0000000038283800ULL,0x0000000070507000ULL,0x00000000e0a0e000ULL,0x00000000c040c000ULL,
  377.                                 0x0000000302030000ULL,0x0000000705070000ULL,0x0000000e0a0e0000ULL,0x0000001c141c0000ULL,
  378.                                 0x0000003828380000ULL,0x0000007050700000ULL,0x000000e0a0e00000ULL,0x000000c040c00000ULL,
  379.                                 0x0000030203000000ULL,0x0000070507000000ULL,0x00000e0a0e000000ULL,0x00001c141c000000ULL,
  380.                                 0x0000382838000000ULL,0x0000705070000000ULL,0x0000e0a0e0000000ULL,0x0000c040c0000000ULL,
  381.                                 0x0003020300000000ULL,0x0007050700000000ULL,0x000e0a0e00000000ULL,0x001c141c00000000ULL,
  382.                                 0x0038283800000000ULL,0x0070507000000000ULL,0x00e0a0e000000000ULL,0x00c040c000000000ULL,
  383.                                 0x0302030000000000ULL,0x0705070000000000ULL,0x0e0a0e0000000000ULL,0x1c141c0000000000ULL,
  384.                                 0x3828380000000000ULL,0x7050700000000000ULL,0xe0a0e00000000000ULL,0xc040c00000000000ULL,
  385.                                 0x0203000000000000ULL,0x0507000000000000ULL,0x0a0e000000000000ULL,0x141c000000000000ULL,
  386.                                 0x2838000000000000ULL,0x5070000000000000ULL,0xa0e0000000000000ULL,0x40c0000000000000ULL};
  387.  
  388. TBB DestMagic[5248+102400]; /* tutte le destinazioni di Alfiere e Torre */
  389. /* usa questo trucco per dimezzare la tabella successiva Magic visto che con le BMI magic e shift non sono utilizzati */
  390. #ifndef BMI
  391. #define MASCHERAMAGIC(mask,magic,shift,dest) {mask,magic,shift,dest}
  392. #else
  393. #define MASCHERAMAGIC(mask,magic,shift,dest) {mask,dest}
  394. #endif
  395. /* Magic[0] è riferito all'Alfiere, Magic[1] è riferito alla Torre */
  396. TMagic Magic[2][64] = {
  397. {
  398. MASCHERAMAGIC(0x0040201008040200ULL,0x89a1121896040240ULL,58,&DestMagic[   0]),
  399. MASCHERAMAGIC(0x0000402010080400ULL,0x2004844802002010ULL,59,&DestMagic[  64]),
  400. MASCHERAMAGIC(0x0000004020100a00ULL,0x2068080051921000ULL,59,&DestMagic[  96]),
  401. MASCHERAMAGIC(0x0000000040221400ULL,0x62880a0220200808ULL,59,&DestMagic[ 128]),
  402. MASCHERAMAGIC(0x0000000002442800ULL,0x0004042004000000ULL,59,&DestMagic[ 160]),
  403. MASCHERAMAGIC(0x0000000204085000ULL,0x0100822020200011ULL,59,&DestMagic[ 192]),
  404. MASCHERAMAGIC(0x0000020408102000ULL,0xc00444222012000aULL,59,&DestMagic[ 224]),
  405. MASCHERAMAGIC(0x0002040810204000ULL,0x0028808801216001ULL,58,&DestMagic[ 256]),
  406. MASCHERAMAGIC(0x0020100804020000ULL,0x0400492088408100ULL,59,&DestMagic[ 320]),
  407. MASCHERAMAGIC(0x0040201008040000ULL,0x0201c401040c0084ULL,59,&DestMagic[ 352]),
  408. MASCHERAMAGIC(0x00004020100a0000ULL,0x00840800910a0010ULL,59,&DestMagic[ 384]),
  409. MASCHERAMAGIC(0x0000004022140000ULL,0x0000082080240060ULL,59,&DestMagic[ 416]),
  410. MASCHERAMAGIC(0x0000000244280000ULL,0x2000840504006000ULL,59,&DestMagic[ 448]),
  411. MASCHERAMAGIC(0x0000020408500000ULL,0x30010c4108405004ULL,59,&DestMagic[ 480]),
  412. MASCHERAMAGIC(0x0002040810200000ULL,0x1008005410080802ULL,59,&DestMagic[ 512]),
  413. MASCHERAMAGIC(0x0004081020400000ULL,0x8144042209100900ULL,59,&DestMagic[ 544]),
  414. MASCHERAMAGIC(0x0010080402000200ULL,0x0208081020014400ULL,59,&DestMagic[ 576]),
  415. MASCHERAMAGIC(0x0020100804000400ULL,0x004800201208ca00ULL,59,&DestMagic[ 608]),
  416. MASCHERAMAGIC(0x004020100a000a00ULL,0x0f18140408012008ULL,57,&DestMagic[ 640]),
  417. MASCHERAMAGIC(0x0000402214001400ULL,0x1004002802102001ULL,57,&DestMagic[ 768]),
  418. MASCHERAMAGIC(0x0000024428002800ULL,0x0841000820080811ULL,57,&DestMagic[ 896]),
  419. MASCHERAMAGIC(0x0002040850005000ULL,0x0040200200a42008ULL,57,&DestMagic[1024]),
  420. MASCHERAMAGIC(0x0004081020002000ULL,0x0000800054042000ULL,59,&DestMagic[1152]),
  421. MASCHERAMAGIC(0x0008102040004000ULL,0x88010400410c9000ULL,59,&DestMagic[1184]),
  422. MASCHERAMAGIC(0x0008040200020400ULL,0x0520040470104290ULL,59,&DestMagic[1216]),
  423. MASCHERAMAGIC(0x0010080400040800ULL,0x1004040051500081ULL,59,&DestMagic[1248]),
  424. MASCHERAMAGIC(0x0020100a000a1000ULL,0x2002081833080021ULL,57,&DestMagic[1280]),
  425. MASCHERAMAGIC(0x0040221400142200ULL,0x000400c00c010142ULL,55,&DestMagic[1408]),
  426. MASCHERAMAGIC(0x0002442800284400ULL,0x941408200c002000ULL,55,&DestMagic[1920]),
  427. MASCHERAMAGIC(0x0004085000500800ULL,0x0658810000806011ULL,57,&DestMagic[2432]),
  428. MASCHERAMAGIC(0x0008102000201000ULL,0x0188071040440a00ULL,59,&DestMagic[2560]),
  429. MASCHERAMAGIC(0x0010204000402000ULL,0x4800404002011c00ULL,59,&DestMagic[2592]),
  430. MASCHERAMAGIC(0x0004020002040800ULL,0x0104442040404200ULL,59,&DestMagic[2624]),
  431. MASCHERAMAGIC(0x0008040004081000ULL,0x0511080202091021ULL,59,&DestMagic[2656]),
  432. MASCHERAMAGIC(0x00100a000a102000ULL,0x0004022401120400ULL,57,&DestMagic[2688]),
  433. MASCHERAMAGIC(0x0022140014224000ULL,0x80c0040400080120ULL,55,&DestMagic[2816]),
  434. MASCHERAMAGIC(0x0044280028440200ULL,0x8040010040820802ULL,55,&DestMagic[3328]),
  435. MASCHERAMAGIC(0x0008500050080400ULL,0x0480810700020090ULL,57,&DestMagic[3840]),
  436. MASCHERAMAGIC(0x0010200020100800ULL,0x0102008e00040242ULL,59,&DestMagic[3968]),
  437. MASCHERAMAGIC(0x0020400040201000ULL,0x0809005202050100ULL,59,&DestMagic[4000]),
  438. MASCHERAMAGIC(0x0002000204081000ULL,0x8002024220104080ULL,59,&DestMagic[4032]),
  439. MASCHERAMAGIC(0x0004000408102000ULL,0x0431008804142000ULL,59,&DestMagic[4064]),
  440. MASCHERAMAGIC(0x000a000a10204000ULL,0x0019001802081400ULL,57,&DestMagic[4096]),
  441. MASCHERAMAGIC(0x0014001422400000ULL,0x0200014208040080ULL,57,&DestMagic[4224]),
  442. MASCHERAMAGIC(0x0028002844020000ULL,0x3308082008200100ULL,57,&DestMagic[4352]),
  443. MASCHERAMAGIC(0x0050005008040200ULL,0x041010500040c020ULL,57,&DestMagic[4480]),
  444. MASCHERAMAGIC(0x0020002010080400ULL,0x4012020c04210308ULL,59,&DestMagic[4608]),
  445. MASCHERAMAGIC(0x0040004020100800ULL,0x208220a202004080ULL,59,&DestMagic[4640]),
  446. MASCHERAMAGIC(0x0000020408102000ULL,0x0111040120082000ULL,59,&DestMagic[4672]),
  447. MASCHERAMAGIC(0x0000040810204000ULL,0x6803040141280a00ULL,59,&DestMagic[4704]),
  448. MASCHERAMAGIC(0x00000a1020400000ULL,0x2101004202410000ULL,59,&DestMagic[4736]),
  449. MASCHERAMAGIC(0x0000142240000000ULL,0x8200000041108022ULL,59,&DestMagic[4768]),
  450. MASCHERAMAGIC(0x0000284402000000ULL,0x0000021082088000ULL,59,&DestMagic[4800]),
  451. MASCHERAMAGIC(0x0000500804020000ULL,0x0002410204010040ULL,59,&DestMagic[4832]),
  452. MASCHERAMAGIC(0x0000201008040200ULL,0x0040100400809000ULL,59,&DestMagic[4864]),
  453. MASCHERAMAGIC(0x0000402010080400ULL,0x0822088220820214ULL,59,&DestMagic[4896]),
  454. MASCHERAMAGIC(0x0002040810204000ULL,0x0040808090012004ULL,58,&DestMagic[4928]),
  455. MASCHERAMAGIC(0x0004081020400000ULL,0x00910224040218c9ULL,59,&DestMagic[4992]),
  456. MASCHERAMAGIC(0x000a102040000000ULL,0x0402814422015008ULL,59,&DestMagic[5024]),
  457. MASCHERAMAGIC(0x0014224000000000ULL,0x0090014004842410ULL,59,&DestMagic[5056]),
  458. MASCHERAMAGIC(0x0028440200000000ULL,0x0001000042304105ULL,59,&DestMagic[5088]),
  459. MASCHERAMAGIC(0x0050080402000000ULL,0x0010008830412a00ULL,59,&DestMagic[5120]),
  460. MASCHERAMAGIC(0x0020100804020000ULL,0x2520081090008908ULL,59,&DestMagic[5152]),
  461. MASCHERAMAGIC(0x0040201008040200ULL,0x40102000a0a60140ULL,58,&DestMagic[5184])
  462. },
  463. {
  464. MASCHERAMAGIC(0x000101010101017eULL,0x0a8002c000108020ULL,52,&DestMagic[    0+5248]),
  465. MASCHERAMAGIC(0x000202020202027cULL,0x06c00049b0002001ULL,53,&DestMagic[ 4096+5248]),
  466. MASCHERAMAGIC(0x000404040404047aULL,0x0100200010090040ULL,53,&DestMagic[ 6144+5248]),
  467. MASCHERAMAGIC(0x0008080808080876ULL,0x2480041000800801ULL,53,&DestMagic[ 8192+5248]),
  468. MASCHERAMAGIC(0x001010101010106eULL,0x0280028004000800ULL,53,&DestMagic[10240+5248]),
  469. MASCHERAMAGIC(0x002020202020205eULL,0x0900410008040022ULL,53,&DestMagic[12288+5248]),
  470. MASCHERAMAGIC(0x004040404040403eULL,0x0280020001001080ULL,53,&DestMagic[14336+5248]),
  471. MASCHERAMAGIC(0x008080808080807eULL,0x2880002041000080ULL,52,&DestMagic[16384+5248]),
  472. MASCHERAMAGIC(0x0001010101017e00ULL,0xa000800080400034ULL,53,&DestMagic[20480+5248]),
  473. MASCHERAMAGIC(0x0002020202027c00ULL,0x0004808020004000ULL,54,&DestMagic[22528+5248]),
  474. MASCHERAMAGIC(0x0004040404047a00ULL,0x2290802004801000ULL,54,&DestMagic[23552+5248]),
  475. MASCHERAMAGIC(0x0008080808087600ULL,0x0411000d00100020ULL,54,&DestMagic[24576+5248]),
  476. MASCHERAMAGIC(0x0010101010106e00ULL,0x0402800800040080ULL,54,&DestMagic[25600+5248]),
  477. MASCHERAMAGIC(0x0020202020205e00ULL,0x000b000401004208ULL,54,&DestMagic[26624+5248]),
  478. MASCHERAMAGIC(0x0040404040403e00ULL,0x2409000100040200ULL,54,&DestMagic[27648+5248]),
  479. MASCHERAMAGIC(0x0080808080807e00ULL,0x0001002100004082ULL,53,&DestMagic[28672+5248]),
  480. MASCHERAMAGIC(0x00010101017e0100ULL,0x0022878001e24000ULL,53,&DestMagic[30720+5248]),
  481. MASCHERAMAGIC(0x00020202027c0200ULL,0x1090810021004010ULL,54,&DestMagic[32768+5248]),
  482. MASCHERAMAGIC(0x00040404047a0400ULL,0x0801030040200012ULL,54,&DestMagic[33792+5248]),
  483. MASCHERAMAGIC(0x0008080808760800ULL,0x0500808008001000ULL,54,&DestMagic[34816+5248]),
  484. MASCHERAMAGIC(0x00101010106e1000ULL,0x0a08018014000880ULL,54,&DestMagic[35840+5248]),
  485. MASCHERAMAGIC(0x00202020205e2000ULL,0x8000808004000200ULL,54,&DestMagic[36864+5248]),
  486. MASCHERAMAGIC(0x00404040403e4000ULL,0x0201008080010200ULL,54,&DestMagic[37888+5248]),
  487. MASCHERAMAGIC(0x00808080807e8000ULL,0x0801020000441091ULL,53,&DestMagic[38912+5248]),
  488. MASCHERAMAGIC(0x000101017e010100ULL,0x0000800080204005ULL,53,&DestMagic[40960+5248]),
  489. MASCHERAMAGIC(0x000202027c020200ULL,0x1040200040100048ULL,54,&DestMagic[43008+5248]),
  490. MASCHERAMAGIC(0x000404047a040400ULL,0x0000120200402082ULL,54,&DestMagic[44032+5248]),
  491. MASCHERAMAGIC(0x0008080876080800ULL,0x0d14880480100080ULL,54,&DestMagic[45056+5248]),
  492. MASCHERAMAGIC(0x001010106e101000ULL,0x0012040280080080ULL,54,&DestMagic[46080+5248]),
  493. MASCHERAMAGIC(0x002020205e202000ULL,0x0100040080020080ULL,54,&DestMagic[47104+5248]),
  494. MASCHERAMAGIC(0x004040403e404000ULL,0x9020010080800200ULL,54,&DestMagic[48128+5248]),
  495. MASCHERAMAGIC(0x008080807e808000ULL,0x0813241200148449ULL,53,&DestMagic[49152+5248]),
  496. MASCHERAMAGIC(0x0001017e01010100ULL,0x0491604001800080ULL,53,&DestMagic[51200+5248]),
  497. MASCHERAMAGIC(0x0002027c02020200ULL,0x0100401000402001ULL,54,&DestMagic[53248+5248]),
  498. MASCHERAMAGIC(0x0004047a04040400ULL,0x4820010021001040ULL,54,&DestMagic[54272+5248]),
  499. MASCHERAMAGIC(0x0008087608080800ULL,0x0400402202000812ULL,54,&DestMagic[55296+5248]),
  500. MASCHERAMAGIC(0x0010106e10101000ULL,0x0209009005000802ULL,54,&DestMagic[56320+5248]),
  501. MASCHERAMAGIC(0x0020205e20202000ULL,0x0810800601800400ULL,54,&DestMagic[57344+5248]),
  502. MASCHERAMAGIC(0x0040403e40404000ULL,0x4301083214000150ULL,54,&DestMagic[58368+5248]),
  503. MASCHERAMAGIC(0x0080807e80808000ULL,0x204026458e001401ULL,53,&DestMagic[59392+5248]),
  504. MASCHERAMAGIC(0x00017e0101010100ULL,0x0040204000808000ULL,53,&DestMagic[61440+5248]),
  505. MASCHERAMAGIC(0x00027c0202020200ULL,0x8001008040010020ULL,54,&DestMagic[63488+5248]),
  506. MASCHERAMAGIC(0x00047a0404040400ULL,0x8410820820420010ULL,54,&DestMagic[64512+5248]),
  507. MASCHERAMAGIC(0x0008760808080800ULL,0x1003001000090020ULL,54,&DestMagic[65536+5248]),
  508. MASCHERAMAGIC(0x00106e1010101000ULL,0x0804040008008080ULL,54,&DestMagic[66560+5248]),
  509. MASCHERAMAGIC(0x00205e2020202000ULL,0x0012000810020004ULL,54,&DestMagic[67584+5248]),
  510. MASCHERAMAGIC(0x00403e4040404000ULL,0x1000100200040208ULL,54,&DestMagic[68608+5248]),
  511. MASCHERAMAGIC(0x00807e8080808000ULL,0x430000a044020001ULL,53,&DestMagic[69632+5248]),
  512. MASCHERAMAGIC(0x007e010101010100ULL,0x0280009023410300ULL,53,&DestMagic[71680+5248]),
  513. MASCHERAMAGIC(0x007c020202020200ULL,0x00e0100040002240ULL,54,&DestMagic[73728+5248]),
  514. MASCHERAMAGIC(0x007a040404040400ULL,0x0000200100401700ULL,54,&DestMagic[74752+5248]),
  515. MASCHERAMAGIC(0x0076080808080800ULL,0x2244100408008080ULL,54,&DestMagic[75776+5248]),
  516. MASCHERAMAGIC(0x006e101010101000ULL,0x0008000400801980ULL,54,&DestMagic[76800+5248]),
  517. MASCHERAMAGIC(0x005e202020202000ULL,0x0002000810040200ULL,54,&DestMagic[77824+5248]),
  518. MASCHERAMAGIC(0x003e404040404000ULL,0x8010100228810400ULL,54,&DestMagic[78848+5248]),
  519. MASCHERAMAGIC(0x007e808080808000ULL,0x2000009044210200ULL,53,&DestMagic[79872+5248]),
  520. MASCHERAMAGIC(0x7e01010101010100ULL,0x4080008040102101ULL,52,&DestMagic[81920+5248]),
  521. MASCHERAMAGIC(0x7c02020202020200ULL,0x0040002080411d01ULL,53,&DestMagic[86016+5248]),
  522. MASCHERAMAGIC(0x7a04040404040400ULL,0x2005524060000901ULL,53,&DestMagic[88064+5248]),
  523. MASCHERAMAGIC(0x7608080808080800ULL,0x0502001008400422ULL,53,&DestMagic[90112+5248]),
  524. MASCHERAMAGIC(0x6e10101010101000ULL,0x489a000810200402ULL,53,&DestMagic[92160+5248]),
  525. MASCHERAMAGIC(0x5e20202020202000ULL,0x0001004400080a13ULL,53,&DestMagic[94208+5248]),
  526. MASCHERAMAGIC(0x3e40404040404000ULL,0x4000011008020084ULL,53,&DestMagic[96256+5248]),
  527. MASCHERAMAGIC(0x7e80808080808000ULL,0x0026002114058042ULL,52,&DestMagic[98304+5248])
  528. }
  529. };
  530.  
  531. /* costanti per la ricerca */
  532. // margine futility ricerca, margine futility quiescenza, margine razoring, fattore tra valori history e tabelle pezzi, margine internal iterative deepening, percentuale tempo per mossa
  533. #define FUTMARGIN 220
  534. #define FUTQMARGIN 360
  535. #define RAZORMARGIN 790
  536. #define IIDMARGIN 400
  537. #define LMPLIMIT 6
  538. #define HISTORYFACTOR 4
  539.  
  540. static inline void *ThreadSearch(void *ptr);
  541. static inline void RootSearch(int64_t msec,int64_t inc,int movestogo,int depthlimit,int mossegiocate);
  542. static inline void CaricaHashVal(void);
  543. static inline void CaricaImbalances(void);
  544. static inline void InizializzaDati(void);
  545. static inline void InizializzaMotore(uint64_t *largepagesallocated);
  546. static inline int CaricaPosizione(TStructThread *t,char *fen, char *mosse);
  547.  
  548. // COMMENTARE SE NON SI STA ESEGUENDO IL TEST EPD
  549. // definire solo per lanciare dei test con le epd, commentare per compilare  l'engine
  550. //#define EPD
  551. #ifdef EPD
  552. TMossa MosseCalcolate[6];
  553. #endif
  554.  
  555. #include "bonus.h"
  556. #include "scacchierahash.h"
  557. #include "genmosse.h"
  558. #include "muovi.h"
  559. #include "tbprobe.h"
  560. #include "valutazione.h"
  561. #include "ricerca.h"
  562. #include "libro.h"
  563. // togliere il commento qui sotto solo se si stanno usando funzioni di debug, mantenere commentato in release
  564. //#include "debug.h"
  565. #if defined(EPD)
  566. #include "tuning.h"
  567. #endif
  568.  
  569. int main(int argc, char *argv[])
  570. {
  571.    char comando[4096]; // variabile dove salvare i comandi ricevuti dalla GUI
  572.    comando[0]=0;
  573.     int mossegiocate=0; //mantiene il numero di mosse giocate caricate con il comando position
  574.    uint64_t largepagesallocated=0; // numero di byte allocati con le large pages
  575.    // Inizializza le variabili da utilizzare nella RootSearch e nella comunicazione engine-GUI
  576.     Opz.Hash=MBHASHDEFAULT;
  577.    Opz.Ponder=false;
  578.     Opz.DrawScore = -20;
  579.     Opz.OwnBook = false;
  580.    strcpy(Opz.BookFile,"./book.bin");
  581.     Opz.BookRandom = false;
  582.     Opz.Strength=MAXSTRENGTH;
  583.    Opz.Threads=1;
  584.     Opz.MultiPV=1;
  585.     Opz.LargePages=false;
  586.     Opz.Syzygy50MoveRule=true;
  587.     Opz.SyzygyProbeLimit=6;
  588.     Ric.TTPedoni=0; // inizializza a 0 il puntatore, per richiedere l'allocazione
  589.   Ric.TBLargest=0; //se non c'è la TB imposta a 0 questo limite
  590. #ifdef _WIN32
  591.    // Solo sotto windows inizializza queste variabili per la lettura dell'input non bloccante
  592.     DWORD bytes_left;
  593.   Ric.Handle = GetStdHandle(STD_INPUT_HANDLE);
  594.   Ric.Pipe = !GetConsoleMode(Ric.Handle, &bytes_left);
  595. #endif
  596.     InizializzaDati(); /* inizializza le strutture dati del motore */
  597.   //printf("Risultato: %d\n",LanciaAnalisi());
  598.   //printf("Risultato: %d\n",LanciaAnalisi());
  599.   //SommaInfoTuning(2);
  600.   //CaricaValoriValutazione();
  601.   //GeneraFileBonus();
  602.   //TrovaMaggiori();
  603.   //DividiFile(32);
  604.   //IndicazioniTuning();
  605.   //printf("Risultato: %d\n",LanciaTestProc(32));
  606.   //TestValutazione();
  607.   //return 0;
  608.   // Se l'engine è lanciato all'avvio con un parametro e questo è la stringa pgo lancia la ricerca per alcune posizioni per generare le informazioni per le profiler guided optimizations
  609.   if (argc==2 && !strncmp(argv[1],"pgo",3)) // Se lanciato con parametro pgo
  610.   {
  611.      char fentest[10][90]={{"1qr3k1/p3bppp/4pn2/1B2n3/N7/P3P2P/1P2QPP1/2R1B2K w - -"},
  612.                           {"2br2k1/r5p1/4p3/5p2/8/pP3B2/1q2RPPP/Q3R1K1 b - - "},
  613.                           {"r5k1/5p2/7p/5qP1/1P1QR3/5P2/r4RK1/8 b - - "},
  614.                           {"r4rk1/1p2bppp/p3bn2/8/Pq1BP3/1BN1Q3/1PP3PP/R3K2R w KQ - "},
  615.                           {"r2qk2r/3nbpp1/2bBp2p/p3P3/1p6/8/PPPQBPPP/1NKR3R w kq - "},
  616.                           {"3r4/3r2bk/1p4pp/pN2n3/P6P/4Q1P1/1P2B1K1/8 b - h3"},
  617.                           {"6k1/1b2bp2/p3p2p/4P1p1/1pr5/4BP1P/PP2N1P1/3R2K1 b - - "},
  618.                           {"1rr3k1/1q3pp1/pnbQp2p/1p2P3/3B1P2/2PB4/P1P2RPP/R5K1 w - - "},
  619.                           {"2r2rk1/p3qp1p/2b1pp1Q/2b5/1n6/2N2NP1/1P2PPBP/R2R2K1 w - - "},
  620.                           {"8/p4k2/1p3r2/2pPnb2/2Pr3P/PPK3P1/4B1Q1/8 b - - "}};
  621.      for (int i=0;i<10; i++)
  622.      {
  623.         InizializzaMotore(&largepagesallocated); // Azzera le varie strutture del motore
  624.         mossegiocate=CaricaPosizione(Threads,&fentest[i][0],NULL); // carica una posizione
  625.         Ric.TipoRicerca=NORMALE; // inizializza le variabili della ricerca
  626.         Threads[0].pmosse=GeneraTutteLegali(Threads,Threads[0].mosse); // carica l'array delle mosse generando solo mosse legali
  627.          RootSearch(4000000000,0,0,23,mossegiocate); // lancia la ricerca
  628.       }
  629.       strcpy(comando,"quit"); // permetti la terminazione completa senza usare l'exit
  630.   }
  631.   // Entra nel ciclo nel quale si attendono i comandi
  632.     while(strncmp(comando,"quit",4)) //esci per Comando=quit
  633.     {
  634.         fgets(comando,4096,stdin);
  635.         if (!strncmp(comando,"uci\n",4)) // invia le opzioni modificabili dalla GUI
  636.         {
  637.             printf("id name Pedone 1.7\nid author Fabio Gobbato\n");
  638.             printf("option name Hash type spin default %d min 1 max 1048576\n",MBHASHDEFAULT);
  639.             printf("option name Threads type spin default 1 min 1 max %d\n",MAXTHREADS);
  640.             printf("option name Ponder type check default false\n");
  641.             printf("option name OwnBook type check default false\n");
  642.             printf("option name BookFile type string default %s\n",Opz.BookFile);
  643.             printf("option name BookRandom type check default false\n");
  644.             printf("option name DrawScore type spin default -5 min -500 max 500\n");
  645.             printf("option name Strength type spin default %d min 1 max %d\n",MAXSTRENGTH,MAXSTRENGTH);
  646.             printf("option name MultiPV type spin default 1 min 1 max %d\n",MAXMOSSE);
  647.             printf("option name LargePages type check default false\n");
  648.             printf("option name SyzygyPath type string default <empty>\n");
  649.             printf("option name Syzygy50MoveRule type check default true\n");
  650.             printf("option name SyzygyProbeLimit type spin default 6 min 0 max 6\n");
  651.             printf("uciok\n");
  652.             fflush(stdout);
  653.         }
  654.         else if (!strncmp(comando,"setoption name ",15)) /* Gestione parametri motore */
  655.      {
  656.         // recupera il nome dell'opzione da modificare ed il valore
  657.          char *parametro,*strvalore;
  658.          char *saveptr;
  659.          parametro = strtok_r(&comando[15]," ",&saveptr);
  660.          strtok_r(NULL," ",&saveptr); /* value */
  661.          strvalore=strtok_r(NULL,"\n",&saveptr); /* la parte finale di setoption termina con \n */
  662.          if (!strvalore) continue; // se non c'è valore prosegui
  663.         // Individua quale opzione modificare
  664.         if (!strcmp(parametro,"Hash")) Opz.Hash = atoi(strvalore);
  665.         else if (!strcmp(parametro,"Threads")) Opz.Threads = atoi(strvalore);
  666.         else if (!strcmp(parametro,"Ponder")) Opz.Ponder = !strcmp(strvalore,"true") ? true : false;
  667.         else if (!strcmp(parametro,"OwnBook")) Opz.OwnBook = !strcmp(strvalore,"true") ? true : false;
  668.         else if (!strcmp(parametro,"BookFile")) strcpy(Opz.BookFile,strvalore);
  669.         else if (!strcmp(parametro,"BookRandom")) Opz.BookRandom = !strcmp(strvalore,"true") ? true : false;
  670.         else if (!strcmp(parametro,"DrawScore")) Opz.DrawScore = atoi(strvalore)*FATTVAL; // converti da cp a 1/FATTVAL cp
  671.         else if (!strcmp(parametro,"Strength")) Opz.Strength = atoi(strvalore);
  672.         else if (!strcmp(parametro,"MultiPV")) Opz.MultiPV = atoi(strvalore);
  673.         else if (!strcmp(parametro,"LargePages")) Opz.LargePages = !strcmp(strvalore,"true") ? true : false;
  674.         else if (!strcmp(parametro,"SyzygyPath")) Ric.TBLargest=initsyzygy(strvalore);
  675.         else if (!strcmp(parametro,"Syzygy50MoveRule")) Opz.Syzygy50MoveRule = !strcmp(strvalore,"true") ? true : false;
  676.         else if (!strcmp(parametro,"SyzygyProbeLimit")) Opz.SyzygyProbeLimit=atoi(strvalore);
  677.      } /* Comandi per la ricerca */
  678.         else if (!strncmp(comando,"ucinewgame",10)) InizializzaMotore(&largepagesallocated); // inizio di una nuova partita, inizializza alcune parti dell'engine
  679.         else if (!strncmp(comando,"isready",7)) { printf("readyok\n"); fflush(stdout); } // se la GUI interroga l'engine se è pronto rispondere
  680.         else if (!strncmp(comando,"position",8)) // se viene inviata la stringa con la posizione
  681.         {
  682.         if (!Ric.TTPedoni) InizializzaMotore(&largepagesallocated); /* se non c'è stato ucinewgame inizializza il motore */
  683.             char *fen=STARTPOS;
  684.             char *moves=strstr(&comando[18],"moves"); // &Comando[18] è il minimo  (position startpos )
  685.             char *saveptr;
  686.             if (moves) {*(moves-1)='\0'; moves+=6;}
  687.             if (!strncmp(strtok_r(&comando[9]," ",&saveptr),"fen",3)) fen=&comando[13];
  688.             // Dopo il parsing della stringa del comando carica la posizione nel formato interno dell'engine
  689.             mossegiocate=CaricaPosizione(Threads,fen,moves);
  690.         }
  691.         else if (!strncmp(comando,"go",2)) // avvia la ricerca per la posizione passata tramite position
  692.         {
  693.         if (!Ric.TTPedoni) // se la TT non è stata inizializzata fallo ora
  694.         {
  695.            InizializzaMotore(&largepagesallocated); /* se non c'è stato position inizializza il motore */
  696.             mossegiocate=CaricaPosizione(Threads,STARTPOS,0);
  697.          }
  698.          int64_t msec=4000000000;// impostare a questo valore nel caso di un "go depth N"
  699.          int64_t inc=0;
  700.          int movestogo=0;
  701.          int depthlimit=DEFAULTMAXDEPTH;
  702.          Threads[0].pmosse=Threads[0].mosse;
  703.          Ric.TipoRicerca=NORMALE;
  704.          char *saveptr;
  705.          // fai il parsing del comando individuando le varie informazioni
  706.          for (char *stringa=strtok_r(comando," ",&saveptr);stringa;stringa=strtok_r(NULL," ",&saveptr))
  707.          {
  708.             if (!strncmp(stringa,"ponder",6)) Ric.TipoRicerca=PONDER;
  709.             else if (!strncmp(stringa,"wtime",5) && !Tratto(Threads)) msec = atoi(strtok_r(NULL," ",&saveptr));
  710.             else if (!strncmp(stringa,"btime",5) && Tratto(Threads)) msec = atoi(strtok_r(NULL," ",&saveptr));
  711.             else if (!strncmp(stringa,"winc",4) && !Tratto(Threads)) inc = atoi(strtok_r(NULL," ",&saveptr));
  712.             else if (!strncmp(stringa,"binc",4) && Tratto(Threads)) inc = atoi(strtok_r(NULL," ",&saveptr));
  713.             else if (!strncmp(stringa,"movestogo",9)) movestogo = atoi(strtok_r(NULL," ",&saveptr));
  714.             else if (!strncmp(stringa,"depth",5)) depthlimit = atoi(strtok_r(NULL," ",&saveptr));
  715.             else if (!strncmp(stringa,"movetime",8)) {msec = atoi(strtok_r(NULL," ",&saveptr)); movestogo=1; }
  716.             else if (!strncmp(stringa,"infinite",8)) Ric.TipoRicerca=RICINFINITA;
  717.             else if (!strncmp(stringa,"searchmoves",11)) // passa le mosse da ricercare
  718.             {
  719.                for (stringa=strtok_r(NULL," ",&saveptr);stringa;stringa=strtok_r(NULL," ",&saveptr))
  720.                {
  721.                   Threads[0].pmosse->Mossa=StrToMove(Threads,stringa);
  722.                   DaScacco(Threads,&Threads[0].pmosse->Mossa);
  723.                   Threads[0].pmosse++;
  724.                }
  725.             }
  726.          } /* se non sono state passate delle mosse precise da ricercare Genera tutte le mosse legali*/
  727.          if (Threads[0].pmosse==Threads[0].mosse) Threads[0].pmosse = GeneraTutteLegali(Threads,Threads[0].mosse);
  728.          /* per ovviare ad una follia di Arena di avviare la ricerca anche su posizioni di matto */
  729.          if (Threads[0].pmosse==Threads[0].mosse) { printf("bestmove 0000\n"); fflush(stdout); }
  730.          else RootSearch(msec,inc,movestogo,depthlimit,mossegiocate); // Avvia la ricerca alla radice
  731.         }
  732.     }
  733.     // All'uscita dell'engine liberare la trasposition table
  734.     if (Ric.TTPedoni)
  735.    {
  736.       if (largepagesallocated)
  737. #ifdef _WIN32
  738.          VirtualFree((void *)Ric.TTPedoni,0,MEM_RELEASE);
  739. #else
  740.          munmap((void *)Ric.TTPedoni,largepagesallocated);
  741. #endif // _WIN32
  742.       else free((void *)Ric.TTPedoni);
  743.    }
  744.    return 0;
  745. }
  746.  
  747. static inline void CaricaHashVal(void)
  748. {
  749.     /* carica valutazioni per i pezzi da usare per aggiornare incrementalmente la valutazione materiale/tabelle pezzi */
  750.     for (int j=1;j<7;j++) // pezzi da 1 a 6
  751.     {
  752.         for (int i=0;i<64;i++) // case da 0 a 63
  753.         {
  754.             HashVal[((j+8)<<6)+i].ValMg = Val.ValorePosizione[j-1][0][i]; // carica il bianco
  755.             HashVal[((j+8)<<6)+i].ValEg = Val.ValorePosizione[j-1][1][i]; // carica il bianco
  756.             HashVal[(j<<6)+i].ValMg = Val.ValorePosizione[j-1][0][i]; // carica il nero
  757.             HashVal[(j<<6)+i].ValEg = Val.ValorePosizione[j-1][1][i]; // carica il nero
  758.         }
  759.     }
  760. }
  761.  
  762. static inline void CaricaImbalances(void)
  763. {  // Calcola gli squilibri
  764.    // per ognuna delle varie configurazioni di pezzi carica dei bonus appropriati che verranno usati in valutazione
  765.    for (int pb=0;pb<9;pb++) // da 0 a 8 pedoni bianchi
  766.    for (int pn=0;pn<9;pn++) // da 0 a 8 pedoni neri
  767.    for (int cb=0;cb<3;cb++) // da 0 a 2 cavalli bianchi
  768.    for (int cn=0;cn<3;cn++) // da 0 a 2 cavalli neri
  769.    for (int acb=0;acb<2;acb++) // da 0 a 1 alfiere campo chiaro bianco
  770.    for (int acn=0;acn<2;acn++) // da 0 a 1 alfiere campo chiaro nero
  771.    for (int asb=0;asb<2;asb++) // da 0 a 1 alfiere campo scuro bianco
  772.    for (int asn=0;asn<2;asn++) // da 0 a 1 alfiere campo scuro nero
  773.    for (int tb=0;tb<3;tb++) // da 0 a 2 torri bianche
  774.    for (int tn=0;tn<3;tn++) // da 0 a 2 torri nere
  775.    for (int db=0;db<2;db++) // da 0 a 1 donna bianca
  776.    for (int dn=0;dn<2;dn++) // da 0 a 1 donna nera
  777.    {  // ATTENZIONE!! Il punteggio è riferito al bianco (chi ha il tratto)
  778.       int16_t *corrente=&Imbalances[pb][pn][cb][cn][acb][acn][asb][asn][tb][tn][db][dn];
  779.       *corrente=0; // inizializza a 0 la configurazione corrente per caricarne nelle prossime istruzioni il valore
  780.       // Coppia alfieri
  781.       if (acb==1 && asb==1) *corrente+=Val.COPPIAALFIERI;
  782.       if (acn==1 && asn==1) *corrente-=Val.COPPIAALFIERI;
  783.       // Alfieri di colore opposto
  784.       if ((cb+cn+tb+tn+db+dn)==0 && ((acb==1 && asn==1 && asb==0 && acn==0) || (acb==0 && asn==0 && asb==1 && acn==1))) *corrente -= ((pb-pn)*Val.ValStatico[PED]*Val.ALFIERICOLOREOPPOSTO)/128;
  785.       // Regina cavallo + pedoni
  786.       if (db==1 && cb==1 && (acb+asb+tb)==0 && pb!=0) *corrente+=Val.REGINACAVALLO;
  787.       if (dn==1 && cn==1 && (acn+asn+tn)==0 && pn!=0) *corrente-=Val.REGINACAVALLO;
  788.       // Torre alfiere + pedoni
  789.       if (tb==1 && (acb+asb)==1 && (db+cb)==0 && pb!=0) *corrente+=Val.TORREALFIERE;
  790.       if (tn==1 && (acn+asn)==1 && (dn+cn)==0 && pn!=0) *corrente-=Val.TORREALFIERE;
  791.       // Re contro 2 cavalli
  792.       if (cb==2 && (pb+pn+cn+acb+acn+asb+asn+tb+tn+db+dn)==0) *corrente-=2*Val.ValStatico[CAV];
  793.       if (cn==2 && (pb+pn+cb+acb+acn+asb+asn+tb+tn+db+dn)==0) *corrente+=2*Val.ValStatico[CAV];
  794.       // Torre contro minore
  795.       if (tb==1 && (cn+acn+asn)==1 && (pb+pn+cb+acb+asb+tn+db+dn)==0) *corrente-=Val.ValStatico[TOR]-Val.ValStatico[CAV];
  796.       if (tn==1 && (cb+acb+asb)==1 && (pb+pn+cn+acn+asn+tb+db+dn)==0) *corrente+=Val.ValStatico[TOR]-Val.ValStatico[CAV];
  797.       // 2 Minori contro 1 minore
  798.       if ((cb+acb+asb)==2 && (cn+acn+asn)==1 && (pb+pn+tb+tn+db+dn)==0) *corrente-=Val.ValStatico[CAV];
  799.       if ((cn+acn+asn)==2 && (cb+acb+asb)==1 && (pb+pn+tb+tn+db+dn)==0) *corrente+=Val.ValStatico[CAV];
  800.       // Torre e minore contro torre
  801.       if (tb==1 && (cb+acb+asb)==1 && tn==1 && (pb+pn+cn+acn+asn+db+dn)==0) *corrente-=Val.ValStatico[CAV];
  802.       if (tn==1 && (cn+acn+asn)==1 && tb==1 && (pb+pn+cb+acb+asb+db+dn)==0) *corrente+=Val.ValStatico[CAV];
  803.       // Regina contro 2 minori
  804.       if ((pb+cb+acb+asb+tb+pn+tn+dn)==0 && db==1 && (cn+acn+asn)==2) *corrente-=Val.ValStatico[CAV];
  805.       if ((pn+cn+acn+asn+tn+pb+tb+db)==0 && dn==1 && (cb+acb+asb)==2) *corrente+=Val.ValStatico[CAV];
  806.       // Regina e 1 minore contro regina
  807.       if ((pb+tb+pn+tn+cn+asn+acn)==0 && db==1 && (acb+asb+cb)==1 && dn==1) *corrente-=Val.ValStatico[CAV];
  808.       if ((pn+tn+pb+tb+cb+asb+acb)==0 && dn==1 && (acn+asn+cn)==1 && db==1) *corrente+=Val.ValStatico[CAV];
  809.       // Regina contro torre e minore
  810.       if ((pb+pn+cb+acb+asb+dn)==0 && db==1 && tn==1 && (cn+acn+asn)==1) *corrente-=Val.ValStatico[REG]-Val.ValStatico[TOR]-Val.ValStatico[CAV];
  811.       if ((pn+pb+cn+acn+asn+db)==0 && dn==1 && tb==1 && (cb+acb+asb)==1) *corrente+=Val.ValStatico[REG]-Val.ValStatico[TOR]-Val.ValStatico[CAV];
  812.       // 2 torri contro torre e minore
  813.       if ((pb+pn+cb+acb+asb+db+dn)==0 && tb==2 && tn==1 && (cn+acn+asn)==1) *corrente-=Val.ValStatico[TOR]-Val.ValStatico[CAV];
  814.       if ((pn+pb+cn+acn+asn+dn+db)==0 && tn==2 && tb==1 && (cb+acb+asb)==1) *corrente+=Val.ValStatico[TOR]-Val.ValStatico[CAV];
  815.       // 2 cavalli contro un pedone
  816.       if (pb+cn+acb+acn+asb+asn+tb+tn+db+dn==0 && pn==1 && cb==2) *corrente-=2*Val.ValStatico[CAV];
  817.       if (pn+cb+acn+acb+asn+asb+tn+tb+dn+db==0 && pb==1 && cn==2) *corrente+=2*Val.ValStatico[CAV];
  818.       // 1 lato senza pedoni e l'altro con pedoni con vantaggio inferiore o uguale a un alfiere
  819.      if ((pb==0 && pn!=0) || (pb!=0 && pn==0))
  820.      {
  821.         // calcola la valutazione materiale e abbassala
  822.         int valutazione = pb*Val.ValStatico[PED]+cb*Val.ValStatico[CAV]+(acb+asb)*Val.ValStatico[ALF]+tb*Val.ValStatico[TOR]+db*Val.ValStatico[REG]
  823.                          -pn*Val.ValStatico[PED]-cn*Val.ValStatico[CAV]-(acn+asn)*Val.ValStatico[ALF]-tn*Val.ValStatico[TOR]-dn*Val.ValStatico[REG];
  824.         if (pb==0 && valutazione>0 && valutazione<=Val.ValStatico[ALF]) *corrente-=valutazione/2;
  825.         if (pn==0 && valutazione<0 && valutazione>=-Val.ValStatico[ALF]) *corrente-=valutazione/2; // ATTENZIONE!!! In entrambi i casi va sottratto
  826.      }
  827.   }
  828. }
  829.  
  830. static inline void InizializzaDati(void)
  831. {
  832.   // a partire da questi numeri casuali s0 e s1 genera tutte le chiavi hash per aggiornare incrementalmente la chiave della posizione
  833.     uint64_t s0=0x0154db043d0efc3bULL,s1=0x67efe05134828892ULL;
  834.     for (int i=0;i<DIMVETCODICIHASH;i++)    /* Inizializza i codici per generale l'hash della scacchiera */
  835.     {
  836.       uint64_t tmp = s0;
  837.       s0 = s1;
  838.       tmp ^= tmp << 23;
  839.       tmp ^= tmp >> 17;
  840.       tmp ^= s1 ^ (s1 >> 26);
  841.       HashVal[i].Hash = tmp+s1;
  842.       s1 = tmp;
  843.     }
  844.     CaricaHashVal();
  845.     // Inizializza i database delle mosse di alfiere e torre
  846.     for (int pos=0;pos<64;pos++)
  847.     {
  848.         for (int pezzo=0;pezzo<2;pezzo++)
  849.         {
  850.             int nbit = PopCount(Magic[pezzo][pos].Mask);
  851.             for (TBB index=0;index<(1ULL<<nbit);index++)
  852.             {
  853.                 // converte l'indice index di nbit in BB occupazione
  854.                 assert(pezzo>=0 && pezzo<2 && pos>=0 && pos<64);
  855.                 TBB occupazione = 0ULL, mask = Magic[pezzo][pos].Mask;
  856.                 #ifdef BMI
  857.            occupazione = pdep(index,mask);
  858.                 #else
  859.                 for(TBB k = 1; k < 1ULL<<nbit; k<<=1)
  860.                 {
  861.                     if(index & k) occupazione |= ExtractLSB(mask);
  862.                     mask=ClearLSB(mask);
  863.                 }
  864.                 #endif // BMI
  865.                 // genera la BB con le destinazioni del pezzo
  866.                 TBB destinazioni;
  867.                 if (pezzo)
  868.                 {  // genera le destinazioni di torre a partire da pos e occupazione
  869.                     TBB pezzisu=(0x0101010101010101ULL<<pos)&(occupazione|0xFF00000000000000ULL); // pezzi sopra il pezzo che muove o fine scacchiera
  870.                     TBB pezzigi=(0x8080808080808080ULL>>(63-pos))&(occupazione|0x00000000000000FFULL);
  871.                     TBB pezzidx=(0x00000000000000FFULL<<pos)&(occupazione|0x8080808080808080ULL);
  872.                     TBB pezzisx=(0xFF00000000000000ULL>>(63-pos))&(occupazione|0x0101010101010101ULL);
  873.                     destinazioni = (((0x8080808080808080ULL>>(63-Pos(pezzisu)))&(0x0101010101010101ULL<<PosInv(pezzigi))) |
  874.                                         ((0xFF00000000000000ULL>>(63-Pos(pezzidx)))&(0x00000000000000FFULL<<PosInv(pezzisx))))^(1ULL<<pos);
  875.                 }
  876.                 else
  877.                 {  // genera le destinazioni di alfiere a partire da pos e occupazione
  878.                     TBB pezzisu=(0x8040201008040201ULL<<pos)&(occupazione|0xFF80808080808080ULL);
  879.                     TBB pezzigi=(0x8040201008040201ULL>>(63-pos))&(occupazione|0x01010101010101FFULL);
  880.                     TBB pezzisx=(0x8102040810204081ULL<<pos)&(occupazione|0xFF01010101010101ULL);
  881.                     TBB pezzidx=(0x8102040810204081ULL>>(63-pos))&(occupazione|0x80808080808080FFULL);
  882.                     destinazioni = (((0x8040201008040201ULL>>(63-Pos(pezzisu)))&(0x8040201008040201ULL<<PosInv(pezzigi))) |
  883.                                         ((0x8102040810204081ULL>>(63-Pos(pezzisx)))&(0x8102040810204081ULL<<PosInv(pezzidx))))^(1ULL<<pos);
  884.                 }
  885.                 #ifdef BMI
  886.                 TBB indice = pext(occupazione,Magic[pezzo][pos].Mask);
  887.                 Magic[pezzo][pos].Dest[indice] = destinazioni;
  888.                 #else
  889.                 Magic[pezzo][pos].Dest[(occupazione*Magic[pezzo][pos].Magic)>>Magic[pezzo][pos].Shift]= destinazioni;
  890.                 #endif
  891.             }
  892.         }
  893.     }
  894.     // Inizializza Raggi, Direzioni e DistanzaPedoni
  895.     for (int i=0;i<64;i++)
  896.     {
  897.         for (int j=0;j<64;j++)
  898.         {
  899.             TBB dest=1ULL<<j;
  900.             Raggi[(i<<6)+j]=0;
  901.             Direzioni[(i<<6)+j]=8;
  902.             if (DirDs(i)&dest)      {Raggi[(i<<6)+j] = DirDs(i)^DirDs(j); Direzioni[(i<<6)+j]=DS;}
  903.             else if (DirDg(i)&dest) {Raggi[(i<<6)+j] = DirDg(i)^DirDg(j); Direzioni[(i<<6)+j]=DG;}
  904.             else if (DirAs(i)&dest) {Raggi[(i<<6)+j] = DirAs(i)^DirAs(j); Direzioni[(i<<6)+j]=AS;}
  905.             else if (DirAg(i)&dest) {Raggi[(i<<6)+j] = DirAg(i)^DirAg(j); Direzioni[(i<<6)+j]=AG;}
  906.             else if (DirDx(i)&dest) {Raggi[(i<<6)+j] = DirDx(i)^DirDx(j); Direzioni[(i<<6)+j]=DX;}
  907.             else if (DirSx(i)&dest) {Raggi[(i<<6)+j] = DirSx(i)^DirSx(j); Direzioni[(i<<6)+j]=SX;}
  908.             else if (DirSu(i)&dest) {Raggi[(i<<6)+j] = DirSu(i)^DirSu(j); Direzioni[(i<<6)+j]=SU;}
  909.             else if (DirGi(i)&dest) {Raggi[(i<<6)+j] = DirGi(i)^DirGi(j); Direzioni[(i<<6)+j]=GI;}
  910.         }
  911.      for (int j=0;j<7;j++)
  912.      {
  913.         DistanzaPedoni[i][j]=0;
  914.         for (int k=0;k<63;k++) if (Distanza(i,k)==(j+1)) DistanzaPedoni[i][j]|=(1ULL<<k);
  915.      }
  916.     }
  917.     CaricaImbalances();
  918. }
  919.  
  920. // proporzione tra tt e hash pedoni
  921. #define PROPHASHPED 16
  922. // Inizializza le strutture dati dell'engine che vanno azzerate ad inizio partita
  923. static inline void InizializzaMotore(uint64_t *largepagesallocated)
  924. {
  925.     /* inizializza le killer per i vari thread */
  926.    for (int j=0;j<Opz.Threads;j++)
  927.    {
  928.       for (int i=0;i<=(128-1);i++) Threads[j].Killer[KINDEX(i,0)]=Threads[j].Killer[KINDEX(i,1)]=0;
  929.       for (TMossa *p=&Threads[j].CounterMoves[0];p<=&Threads[j].CounterMoves[2*8*64*64-1];p++) *p=0;
  930.    }
  931.     /* Inizializza la tabella hash per la ricerca */
  932.    Ric.NRicerca = 0; // azzera il numero progressivo della ricerca
  933.    uint64_t nslothash=65536*(1ULL<<PosInv(Opz.Hash)); // n° di slot per mb * numero mb, si usa 1ULL<<PosInv(OpzHash) per approssimare ad una potenza di 2
  934.     uint64_t nslothashped=nslothash/PROPHASHPED; // la tabella hash dei pedoni/re è uguale alla dimensione della trasposition table /16
  935.     Ric.MASKHASH=nslothash-1; // Definisci le maschere e le dimensioni delle hash
  936.     Ric.MASKHASHPED=nslothashped-1;
  937.    uint64_t bytedaallocare=nslothash*sizeof(TSlotHash)+nslothashped*sizeof(TSlotHashPR);
  938.     /* fai la richiesta per hash e per hash pedoni insieme caricando l'indirizzo su TTPedoni*/
  939.     if (Ric.TTPedoni)
  940.   {
  941.      if (*largepagesallocated)
  942. #ifdef _WIN32
  943.         VirtualFree((void *)Ric.TTPedoni,0,MEM_RELEASE);
  944. #else
  945.         munmap((void *)Ric.TTPedoni,*largepagesallocated);
  946. #endif // _WIN32
  947.      else free((void *)Ric.TTPedoni);
  948.      Ric.TTPedoni=0;
  949.      *largepagesallocated=0;
  950.   }
  951.   if (Opz.LargePages)
  952.   {
  953. #ifdef _WIN32
  954.      TOKEN_PRIVILEGES tp;
  955.      HANDLE hToken;
  956.      OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
  957.      LookupPrivilegeValue(NULL, "SeLockMemoryPrivilege", &tp.Privileges[0].Luid);
  958.      tp.PrivilegeCount = 1;
  959.      tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  960.      AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
  961.      Ric.TTPedoni = VirtualAlloc(NULL, bytedaallocare, MEM_LARGE_PAGES | MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
  962. #else
  963.      Ric.TTPedoni = (TSlotHashPR *) mmap(NULL, bytedaallocare, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_HUGETLB, -1, 0);
  964.      if (Ric.TTPedoni == MAP_FAILED) Ric.TTPedoni = 0;
  965. #endif // _WIN32
  966.      if (Ric.TTPedoni)
  967.      {
  968.         *largepagesallocated=bytedaallocare;
  969. #ifndef EPD
  970.         printf("Allocated large pages\n");
  971. #endif
  972.      }
  973.   }
  974.   if (!Ric.TTPedoni) Ric.TTPedoni = (TSlotHashPR *) malloc(bytedaallocare); //alloca entrambe le hash
  975.   // se l'allocazione non va a buon fine dimezzare la dimensione e riallocare finchè non viene allocata o si arriva a 0
  976.    while (!Ric.TTPedoni && Opz.Hash>=1)
  977.    {
  978.       Opz.Hash>>=1; // dimezza la dimensione per la hash
  979.       nslothash=65536*(1ULL<<PosInv(Opz.Hash)); // n° di slot per mb * numero mb, si usa 1ULL<<PosInv(OpzHash) per approssimare ad una potenza di 2
  980.       nslothashped=nslothash/PROPHASHPED; // la tabella hash dei pedoni/re è uguale alla dimensione della trasposition table /16
  981.       Ric.MASKHASH=nslothash-1; // Definisci le maschere e le dimensioni delle hash
  982.       Ric.MASKHASHPED=nslothashped-1;
  983.       bytedaallocare=nslothash*sizeof(TSlotHash)+nslothashped*sizeof(TSlotHashPR);
  984.       Ric.TTPedoni = (TSlotHashPR *) malloc(bytedaallocare); //alloca entrambe le hash
  985.    }
  986.    // se non si è riusciti ad allocare nemmmeno 1Mb di hash termina l'engine
  987.   if (!Ric.TTPedoni) { printf("Hash allocation error\n"); exit(EXIT_FAILURE); }
  988.     Ric.TT = (TSlotHash *) &Ric.TTPedoni[nslothashped]; //calcola l'indirizzo della trasposition table
  989.     /* azzera entrambe le hash */
  990.     for (uint64_t i=0;i<nslothashped;i++) { Ric.TTPedoni[i].V[0] = 0; Ric.TTPedoni[i].V[1] = 0; }
  991.     for (uint64_t i=0;i<nslothash;i++) { Ric.TT[i].V[0] = 0; Ric.TT[i].V[1] = 0; }
  992. }
  993.  
  994. /*
  995. Carica la posizione nella struttura dati interna dell'engine a partire da una stringa fen iniziale e da una stringa di mosse
  996. Restituisce il numero di MOSSE (non semimosse) giocate
  997. ATTENZIONE!!!!! Non controlla se gli arrocchi e enpassant possano effettivamente essere eseguiti:
  998. potrebbe essere che siano su i flag di arrocco, ma che manchino le torri od il re non è in posizione.
  999. mosse viene modificato da strtok_r
  1000. */
  1001. static inline int CaricaPosizione(TStructThread *t,char *fen, char *mosse)
  1002. {
  1003.   char strfen[128];
  1004.   strcpy(strfen,fen); // copia la stringa fen per non dover alterare quella principale
  1005.  
  1006.     /* Inizializza la scacchiera */
  1007.     t->Scacchiera=t->Partita;
  1008.     t->Scacchiera->P0 = t->Scacchiera->P1 = t->Scacchiera->P2 = t->Scacchiera->PT = 0;
  1009.     t->Scacchiera->EnPassant=8;
  1010.     t->Scacchiera->ScaccoTrattoRip3=0; /* non sotto scacco 0 ripetizioni tratto BIANCO */
  1011.     t->Scacchiera->Hash=0; /*inizializza la scacchierahash per caricare i pezzi */
  1012.     t->Scacchiera->HashPR=0;
  1013.     t->Scacchiera->ValMg=0; /* inizializza la valutazione */
  1014.     t->Scacchiera->ValEg=0;
  1015.     t->Scacchiera->Arrocchi=0;
  1016.     t->Scacchiera->Cont50Mosse=0;
  1017.  
  1018.     char *saveptr=0;
  1019.     strtok_r(strfen," ",&saveptr);
  1020.     char *strtratto=strtok_r(NULL," ",&saveptr); // ricava stringa tratto
  1021.     char *strarrocchi=strtok_r(NULL," ",&saveptr); // arrocchi
  1022.     char *strep=strtok_r(NULL," ",&saveptr); // enpassant
  1023.     char *strcont50=strtok_r(NULL," ",&saveptr); // contatore 50 mosse
  1024.  
  1025.     /* carica la posizione dei pezzi nella scacchiera, con il bianco come se avesse il tratto */
  1026.     uint8_t latopezzo=BIANCO;
  1027.     uint8_t pezzo=PED;
  1028.     uint8_t latotratto=BIANCO;
  1029.     TPos posfen=0;
  1030.     for (char *p=strfen;*p;p++)
  1031.   {
  1032.      if (*p>='1' && *p<='8') posfen += *p - '0';
  1033.      else if (*p=='/') continue;
  1034.      else
  1035.      {
  1036.         // Individua il pezzo
  1037.         TPos pos = PosAvv(posfen);
  1038.         if (*p=='p') { pezzo = PED; latopezzo = NERO; }
  1039.         else if (*p=='n') { pezzo = CAV; latopezzo = NERO; }
  1040.         else if (*p=='b') { pezzo = ALF; latopezzo = NERO; }
  1041.         else if (*p=='r') { pezzo = TOR; latopezzo = NERO; }
  1042.         else if (*p=='q') { pezzo = REG; latopezzo = NERO; }
  1043.         else if (*p=='k') { pezzo = RE; latopezzo = NERO; }
  1044.         else if (*p=='P') { pezzo = PED; latopezzo = BIANCO; }
  1045.         else if (*p=='N') { pezzo = CAV; latopezzo = BIANCO; }
  1046.         else if (*p=='B') { pezzo = ALF; latopezzo = BIANCO; }
  1047.         else if (*p=='R') { pezzo = TOR; latopezzo = BIANCO; }
  1048.         else if (*p=='Q') { pezzo = REG; latopezzo = BIANCO; }
  1049.         else if (*p=='K') { pezzo = RE; latopezzo = BIANCO; }
  1050.         // Carica il pezzo nella struttura scacchiera
  1051.         t->Scacchiera->P0|=((uint64_t)pezzo&1)<<pos;
  1052.         t->Scacchiera->P1|=((uint64_t)(pezzo>>1)&1)<<pos;
  1053.         t->Scacchiera->P2|=((uint64_t)pezzo>>2)<<pos;
  1054.         if (latopezzo==BIANCO) { t->Scacchiera->PT |= 1ULL<<pos; pezzo|=NERO; }
  1055.         t->Scacchiera->Hash ^= HashVal[(pezzo<<6)+PosAss(pos,latopezzo)].Hash;
  1056.         if ((pezzo&0x07)==PED || (pezzo&0x07)==RE) t->Scacchiera->HashPR ^= HashVal[(pezzo<<6)+PosAss(pos,latopezzo)].Hash;
  1057.         t->Scacchiera->ValMg += (latopezzo==BIANCO ? 1: -1)*HashVal[(pezzo<<6)+PosAss(pos,latopezzo)].ValMg;
  1058.         t->Scacchiera->ValEg += (latopezzo==BIANCO ? 1: -1)*HashVal[(pezzo<<6)+PosAss(pos,latopezzo)].ValEg;
  1059.         posfen++;
  1060.      }
  1061.   }
  1062.   /* leggi il tratto */
  1063.   if (*strtratto=='w') latotratto=BIANCO;
  1064.     else if (*strtratto=='b') latotratto=NERO;
  1065.  
  1066.     if (*strarrocchi!='-') /* leggi gli arrocchi */
  1067.   {
  1068.      for (char *p=strarrocchi;*p;p++)
  1069.      {
  1070.             if (*p=='K') { t->Scacchiera->Arrocchi|=0x02; t->Scacchiera->Hash ^= HashVal[CHARROCCOCB].Hash; }
  1071.             else if (*p=='Q') { t->Scacchiera->Arrocchi|=0x01; t->Scacchiera->Hash ^= HashVal[CHARROCCOLB].Hash; }
  1072.             else if (*p=='k') { t->Scacchiera->Arrocchi|=0x20; t->Scacchiera->Hash ^= HashVal[CHARROCCOCN].Hash; }
  1073.             else if (*p=='q') { t->Scacchiera->Arrocchi|=0x10; t->Scacchiera->Hash ^= HashVal[CHARROCCOLN].Hash; }
  1074.      }
  1075.   }
  1076.  
  1077.     if (*strep!='-' && (Pedoni(t)&(latotratto==BIANCO ? t->Scacchiera->PT&EnPassant[*strep - 'a']: (t->Scacchiera->PT^Tutti(t))&EnPassantM[*strep - 'a'])))
  1078.     {  /* carica l'enpassant solo se ci sono pedoni avversari che possono eseguirlo (così rileva correttamente le ripetizioni)*/
  1079.       t->Scacchiera->EnPassant= *strep - 'a';
  1080.       t->Scacchiera->Hash ^= HashVal[CHCOLONNEENPASSANT+t->Scacchiera->EnPassant].Hash;
  1081.     }
  1082.    if (strcont50) t->Scacchiera->Cont50Mosse=atoi(strcont50); /* leggi contatore 50 mosse se presente */
  1083.     if (latotratto==NERO) CambiaTratto(t); /* gira la scacchiera se il tratto è del nero */
  1084.  
  1085.     /* carica le mosse */
  1086.     int mossegiocate=0;
  1087.     if (mosse)
  1088.    {  // esegui la lista delle mosse partendo dall'inizio ogni volta che viene azzerato il contatore delle 50 mosse in modo da avere in memoria solo le posizioni utili per ricercare le ripetizioni
  1089.      for (char *strmossa=strtok_r(mosse," ",&saveptr); strmossa; strmossa = strtok_r(NULL," ",&saveptr))
  1090.      {
  1091.         mossegiocate++;
  1092.         TMossa mossa = StrToMove(t,strmossa);
  1093.         Muovi(t,mossa); /* ATTENZIONE!! Non viene caricato correttamente lo scacco al re perchè non è necessario in questa fase*/
  1094.         if (t->Scacchiera->Cont50Mosse==0)
  1095.          {  /* se viene azzerato il contatore delle 50 mosse le posizioni precedenti non sono interessanti per ricercare le ripetizioni*/
  1096.            t->Partita[0]=*t->Scacchiera;
  1097.            t->Scacchiera=t->Partita;
  1098.         }
  1099.      }
  1100.   }
  1101.     mossegiocate>>=1; /* ricava il numero di mosse e non di semimosse */
  1102.     /* solo alla fine carica sotto scacco */
  1103.     if (ScaccoRe(t)) t->Scacchiera->ScaccoTrattoRip3|=SOTTOSCACCO; /* imposta il campo scacco */
  1104.   return mossegiocate;
  1105. }
  1106.  
  1107. static inline void InizializzaKillerHistory(TStructThread *t)
  1108. {
  1109.   for (int i=0;i<126;i++) // shifta killer di 2 visto che le ricerche vengono lanciate sempre a 2 semimosse di distanza
  1110.   {
  1111.      t->Killer[KINDEX(i,0)]=t->Killer[KINDEX(i+2,0)];
  1112.      t->Killer[KINDEX(i,1)]=t->Killer[KINDEX(i+2,1)];
  1113.   }
  1114.   t->Killer[KINDEX(126,0)]=t->Killer[KINDEX(126,1)]=0;
  1115.   t->Killer[KINDEX(127,0)]=t->Killer[KINDEX(127,1)]=0;
  1116.   for (int *p=&t->History[0];p<=&t->History[128*8*64-1];p++) *p=0; //Azzera History
  1117. }
  1118.  
  1119. /* La differenza di profondit? rispetto al thread master da assegnare ai thread slave, si cicla ogni 16 thread */
  1120. const int DepthThrd[16]={0,1,1,2,0,2,0,3,1,2,3,4,0,1,3,4};
  1121.  
  1122. // Funzione che viene lanciata avviando i vari threads
  1123. static inline void *ThreadSearch(void *ptr)
  1124. {
  1125.   TStructThread *t=(TStructThread *) ptr;
  1126.  
  1127.   if (t!=Threads) // se non è il thread master lascia che ogni thread si inizializzi i suoi dati
  1128.   {
  1129.      if (__builtin_setjmp(t->Ambiente)) return NULL; // salva l'ambiente per un longump !!!usare gli intrisics perchè con mingw64 crasha
  1130.       InizializzaKillerHistory(t);
  1131.       t->LastScore=0;
  1132.    }
  1133.  
  1134.    do{
  1135.       // Se non è il thread master ricava la profondit? alla quale ricercare usando gli stessi valori ogni 16 threads
  1136.       if (t!=Threads)
  1137.       {
  1138.          t->Depth=Threads[0].Depth+DepthThrd[(t-Threads)&0xF]; // cicla ogni 16
  1139.          if (t->Depth>DEFAULTMAXDEPTH) t->Depth=DEFAULTMAXDEPTH;
  1140.       }
  1141.  
  1142.       int16_t beta;
  1143.       // solo in una ricerca con MultiPV=1 carica i valori per l'aspiration window
  1144.      if (Ric.MultiPVReale==1 && t->Depth>=8 && abs(t->LastScore)<MATTOMIN) { t->alpha = t->LastScore-120; beta = t->LastScore+120; }
  1145.      else { t->alpha = -INFINITO; beta = INFINITO; }
  1146.      nuova_aspiration:
  1147.         for (TMossaVal *p=t->mosse;p<t->pmosse;p++) /* esegui tutte le mosse */
  1148.         {
  1149.             bool nonridurre = Scacco(t) || (p->Mossa&(CATTURA|PROMO|SCACCO|ARROCCO)) || p==t->mosse || p->Mossa==t->Killer[KINDEX(0,0)] || p->Mossa==t->Killer[KINDEX(0,1)];
  1150.         int riduzione=0,estensione=0;
  1151.         EstensioniRiduzioni(PVNODE,nonridurre,p->Mossa,0,t->Depth,p-t->mosse,&estensione,&riduzione);
  1152.  
  1153.             Muovi(t,p->Mossa);
  1154.  
  1155.             int nuovadepth=t->Depth-1+estensione;
  1156.             // se il numero di mossa è minore a MultiPV usa la finestra aperta
  1157.             if (p<&t->mosse[Ric.MultiPVReale]) p->Val = -Search(t,PVNODE,1,nuovadepth,-beta,-t->alpha,true,-INFINITO,p->Mossa);
  1158.             else
  1159.             {  // altrimenti usa la null window
  1160.                 p->Val = -Search(t,CUTNODE,1,nuovadepth-riduzione,-t->alpha-1,-t->alpha,true,-INFINITO,p->Mossa);
  1161.                 if (riduzione && nuovadepth>0 && p->Val>t->alpha) p->Val = -Search(t,CUTNODE,1,nuovadepth,-t->alpha-1,-t->alpha,true,-INFINITO,p->Mossa);
  1162.                 if (p->Val>t->alpha) p->Val = -Search(t,PVNODE,1,nuovadepth,-beta,-t->alpha,true,-INFINITO,p->Mossa);
  1163.             }
  1164.             t->Scacchiera--;
  1165.  
  1166.             if (Ric.MultiPVReale==1)
  1167.         {  /* ripeti se limiti fuori dall'aspiration window (usa l'aspiration window solo per MultiPV=1) */
  1168.            if (p==t->mosse && (p->Val<=t->alpha || p->Val>=beta)) { t->alpha = -INFINITO; beta = INFINITO; goto nuova_aspiration; }
  1169.            if (p!=t->mosse && p->Val>=beta) { t->alpha = -INFINITO; beta = INFINITO; goto nuova_aspiration; }
  1170.         }
  1171.  
  1172.             if (p->Val>t->alpha) // se la valutazione è la migliore incontrata fin'ora
  1173.             {
  1174.             TMossaVal mossa=*p;
  1175.             TMossaVal *inizio=t->mosse;
  1176.             for (;inizio<p && mossa.Val<=inizio->Val;inizio++); /* cerca la prima mossa con val inferiore (necessaria per supportare la MultiPV)*/
  1177.             for (TMossaVal *j=p;j>inizio;j--) *j=*(j-1); /* riordina le mosse mettendo questa in testa */
  1178.             *inizio=mossa;
  1179.             if (p>=&t->mosse[Ric.MultiPVReale-1]) t->alpha = t->mosse[Ric.MultiPVReale-1].Val;
  1180.             }
  1181.         }
  1182.  
  1183.       /* aggiorna la history */
  1184.       if (t->Depth>3 && !(t->mosse[0].Mossa&(CATTURA|PROMO)))
  1185.       {
  1186.          assert(PezzoAssTratto(t,PezzoM(t->mosse[0].Mossa))!=0);
  1187.          t->History[HINDEX(0,PezzoM(t->mosse[0].Mossa),AM(t->mosse[0].Mossa))]+=HISTORYFACTOR*t->Depth*t->Depth;
  1188.          if (t->History[HINDEX(0,PezzoM(t->mosse[0].Mossa),AM(t->mosse[0].Mossa))]>LIMITEHISTORY)
  1189.             t->History[HINDEX(0,PezzoM(t->mosse[0].Mossa),AM(t->mosse[0].Mossa))]=LIMITEHISTORY;
  1190.       }
  1191.  
  1192.       /* aggiorna le killer */
  1193.       if (!Scacco(t) && !(t->mosse[0].Mossa&(CATTURA|PROMO)))
  1194.       {
  1195.          if ((t->mosse[0].Mossa&~SCACCO)!=t->Killer[KINDEX(0,0)])
  1196.          {
  1197.             t->Killer[KINDEX(0,1)]=t->Killer[KINDEX(0,0)];
  1198.             t->Killer[KINDEX(0,0)]=(t->mosse[0].Mossa&~SCACCO); // salva senza il campo scacco
  1199.          }
  1200.       }
  1201.       t->LastScore = t->alpha; // aggiorna ultimo score per aspiration search
  1202.  
  1203.    }while(t!=Threads); // continua a ciclare se non è il thred master
  1204.    return NULL;
  1205. }
  1206.  
  1207. /* Stampa la pv, usa NOOUTPUT solo quando si lanciano molte epd */
  1208. static void StampaPV(int npv,bool rootintb,int16_t tbscore,int64_t msec,int64_t nnodi,int64_t tbhits,TScacchiera *scacchierainiziale)
  1209. {
  1210. #ifndef NOOUTPUT
  1211.    char strmossa[10];
  1212.    TSlotHash sh;
  1213.    printf("info multipv %d depth %d time %"PRId64" nodes %"PRId64" nps %"PRId64" tbhits %"PRId64" ",npv+1, Threads[0].Depth, msec,nnodi,(nnodi*1000/(msec+1)),tbhits);
  1214.    int16_t val = Threads[0].mosse[npv].Val;
  1215.    // correggi lo score se la posizione alla radice è sulla tablebase
  1216.    if (rootintb && (abs(val)<MATTOMIN)) val = tbscore;
  1217.    // converti lo score in caso di matto e converti lo score da quati di cp a cp
  1218.    if (abs(val)<MATTOMIN) printf("score cp %d pv ",val/FATTVAL);
  1219.    else printf("score mate %d pv ", val>0 ? (MATTO-val+1)/2 : (-MATTO-val)/2);
  1220.  
  1221.    MoveToStr(strmossa,Threads[0].mosse[npv].Mossa,Tratto(Threads));
  1222.    printf("%s ",strmossa);
  1223.    Muovi(Threads,Threads[0].mosse[npv].Mossa);
  1224.    if (!Rip3(Threads))
  1225.    {
  1226.       TTLoad(Threads[0].Scacchiera->Hash,&sh);
  1227.       // mantenere il controllo sulla mossa e non sul nodo visto che in quiescenza la pv può non avere mosse
  1228.       while (sh.Hash==Threads[0].Scacchiera->Hash && sh.NRicercaNT&PVNODE && sh.MossaPack)
  1229.       {
  1230.          TMossa mossahash = UnPack(Threads,sh.MossaPack);
  1231.          MoveToStr(strmossa,mossahash,Tratto(Threads));
  1232.          printf("%s ",strmossa);
  1233.          Muovi(Threads,mossahash);
  1234.          if (Rip3(Threads)) break;
  1235.          TTLoad(Threads[0].Scacchiera->Hash,&sh);
  1236.       }
  1237.    }
  1238.    Threads[0].Scacchiera=scacchierainiziale; // riporta scacchiera a scacchierainiziale visto che è stata modificata del Muovi
  1239.    printf("\n");
  1240.    fflush(stdout);
  1241. #endif
  1242. }
  1243.  
  1244. // Funzione di ricerca del motore lanciato da una posizione precedentemente caricata, e recupera i parametri di ricerca da Ric e Opz
  1245. static inline void RootSearch(int64_t msec,int64_t inc,int movestogo,int depthlimit,int mossegiocate)
  1246. {
  1247.    Ric.TerminaRicerca=false; // imposta all'inizio il termine della ricerca a false
  1248.   /* Cerca una mossa nel libro */
  1249.     if (Opz.OwnBook && Ric.TipoRicerca!=RICINFINITA) /* Se il libro è abilitato e la ricerca non è di ponder/analisi */
  1250.     {
  1251.         TMossa bestmove = CercaMossaLibro(Threads,Opz.BookFile,Opz.BookRandom); /* ATTENZIONE!!! La mossa restituita è utile solo se la si converte a stringa */
  1252.         if (bestmove) /* non è buona per essere eseguita con il Muovi */
  1253.      {
  1254.         while (Ric.TipoRicerca==PONDER && !Ric.TerminaRicerca) // se sono in ponder attendi un comando
  1255.         {
  1256.            char comando[16];
  1257.            fgets(comando,16,stdin);
  1258.            if (!strncmp(comando,"isready",7)) { printf("readyok\n"); fflush(stdout); }
  1259.            else if (!strncmp(comando,"ponderhit",9)) Ric.TipoRicerca=NORMALE; // passa da ponder a ricerca normale
  1260.            else if (!strncmp(comando,"stop",4)) Ric.TerminaRicerca=true;
  1261.         }
  1262.         char strmossa[10];
  1263.         MoveToStr(strmossa,bestmove,Tratto(Threads));
  1264.         printf("bestmove %s\n",strmossa);
  1265.         fflush(stdout);
  1266.         return;
  1267.      }
  1268.     }
  1269.   // Definisci volatile queste variabili perchè dovranno essere recuperate dopo un longjmp
  1270.   TScacchiera *volatile ScacchieraIniziale;
  1271.   volatile bool RootInTB;
  1272.   volatile int16_t TBScore;
  1273.   volatile int64_t TempoInizio;
  1274.  
  1275.     ScacchieraIniziale=Threads[0].Scacchiera;
  1276.     if (__builtin_setjmp(Threads[0].Ambiente)) // !!!usare gli intrisics perchè con mingw64 crasha
  1277.   {  // al ritorno da un longump e sono in MultiPV=1 stampa la pv individuata da una ricerca parziale
  1278.         if (Opz.MultiPV==1)
  1279.      {
  1280.         Threads[0].Scacchiera=ScacchieraIniziale;
  1281.         int64_t misurazione = TempoMSec();
  1282.         int64_t NNodi=0;
  1283.         int64_t TBHits=0;
  1284.         for (int i=0;i<Opz.Threads;i++) { NNodi+=Threads[i].NNodi; TBHits+=Threads[i].TBHits; }
  1285.         /* ATTENZIONE QUI!!! se ci si arriva senza aver ricercato almeno una mossa a depth 1
  1286.            la valutazione della mossa non sar? quella della ricerca ma VALCATTURA o VALQUIETA ecc.
  1287.         */
  1288.         StampaPV(0,RootInTB,TBScore,misurazione-TempoInizio,NNodi,TBHits,ScacchieraIniziale);
  1289.      }
  1290.      // salta a stampa bestmove e pondermove
  1291.      goto stampamosse;
  1292.   }
  1293.  
  1294.   /* Azzera QUI NNodi e TBHits per tutti i thread */
  1295.   for (int i=0;i<Opz.Threads;i++) Threads[i].NNodi=Threads[i].TBHits=0;
  1296.  
  1297.   /* Probe TB */
  1298.   TBScore=0;
  1299.   RootInTB=false;
  1300.   Ric.TBCardinality = (Opz.SyzygyProbeLimit>Ric.TBLargest ? Ric.TBLargest : Opz.SyzygyProbeLimit);
  1301.   if (PopCount(Tutti(Threads)) <= Ric.TBCardinality)
  1302.   {
  1303.      Threads[0].TBHits = Threads[0].pmosse-Threads[0].mosse;
  1304.      // If the current root position is in the tablebases then RootMoves
  1305.      // contains only moves that preserve the draw or win.
  1306.      RootInTB = root_probe(Threads,Threads[0].mosse,&Threads[0].pmosse,&TBScore);
  1307.      if (RootInTB) Ric.TBCardinality = 0; // Do not probe tablebases during the search
  1308.      else Threads[0].TBHits=0;
  1309.   }
  1310.  
  1311.     // Recupera la mossa dalla hash e portala davanti
  1312.   TSlotHash sh;
  1313.     TTLoad(Threads[0].Scacchiera->Hash,&sh);
  1314.     if (sh.Hash==Threads[0].Scacchiera->Hash && sh.MossaPack)
  1315.     {
  1316.      TMossa mossahash = UnPack(Threads,sh.MossaPack);
  1317.      TMossaVal *p;
  1318.      for (p=Threads[0].mosse;p<Threads[0].pmosse && p->Mossa!=mossahash;p++);
  1319.      if (p<Threads[0].pmosse) // solo se la mossa della hash st? tra quelle generate e filtrate dal tbprobe
  1320.      {
  1321.         for (;p>=&Threads[0].mosse[1];p--) *p=*(p-1);
  1322.         Threads[0].mosse[0].Mossa=mossahash;
  1323.      }
  1324.   }
  1325.  
  1326.   /* inizializza i vari threads copiando l'array partita e le mosse (farlo qui dopo il filtro della tablebase) */
  1327.    for (int t=1;t<Opz.Threads;t++) // copia posizione e mosse
  1328.    {
  1329.       memcpy(Threads[t].Partita,Threads[0].Partita,sizeof(TScacchiera)*(Threads[0].Scacchiera-Threads[0].Partita+1));
  1330.       Threads[t].Scacchiera=Threads[t].Partita+(Threads[0].Scacchiera-Threads[0].Partita);
  1331.       memcpy(Threads[t].mosse,Threads[0].mosse,sizeof(TMossaVal)*(Threads[0].pmosse-Threads[0].mosse));
  1332.       Threads[t].pmosse=Threads[t].mosse+(Threads[0].pmosse-Threads[0].mosse);
  1333.    }
  1334.  
  1335.    InizializzaKillerHistory(Threads);
  1336.    /* Imposta il tempo limite entro il quale ricercare la mossa da eseguire */
  1337.    int64_t misurazione;
  1338.     TempoInizio = TempoMSec();
  1339.    /* A seconda del time control sceglie la formula adeguata */
  1340.    int64_t msecpermossa;
  1341.    if (movestogo)
  1342.    {
  1343.       if (inc) msecpermossa = 2*msec/(movestogo+10)+inc; /* movestogo!=0 && inc!=0 */
  1344.       else msecpermossa = 2*msec/(movestogo+10); /* movestogo!=0 && inc==0 */
  1345.    }
  1346.    else
  1347.    {
  1348.       if (inc) msecpermossa = 4*msec/((mossegiocate>=60 ? 0 : 60-mossegiocate)+40)+inc; /* movestogo==0 && inc!=0 */
  1349.       else msecpermossa = 4*msec/((mossegiocate>=60 ? 0 : 60-mossegiocate)+60); /* movestogo==0 && inc==0 */
  1350.    }
  1351.    if (Opz.Ponder) msecpermossa+=msecpermossa/10; // aggiungi il 10% del tempo se in ponder
  1352.    msecpermossa = msecpermossa>((3*msec)/8) ? ((3*msec)/8) : msecpermossa; // caso possibile solo in caso di incremento
  1353.    if (Threads[0].pmosse==Threads[0].mosse) msecpermossa/=10; // se c'è solo una mossa riduci di 10 volte il tempo
  1354.   Ric.LimiteMSec = TempoInizio + (msecpermossa*28)/64;
  1355.   Ric.LimiteUltimoMSec = TempoInizio + msecpermossa*2; // msecpermossa*2 non sar? mai superiore a 3*msec/4 con icremento o msec/2 senza incremento
  1356.  
  1357.   /* Inizializza variabili per la ricerca */
  1358.   Ric.NRicerca += 0x04; /* essendo uint8_t dopo 64 ricerche parte da 0 */
  1359.   Threads[0].Depth=1;
  1360.   Ric.NNodiCheck = msecpermossa<1000 ? (msecpermossa+1)*100: 100000; // modifica la distanza tra un controllo del tempo e l'altro a seconda del tempo rimanente
  1361.    Ric.ControlloTempo=Ric.NNodiCheck;
  1362.    Threads[0].LastScore=0;
  1363.    Ric.MultiPVReale=Opz.MultiPV>(Threads[0].pmosse-Threads[0].mosse) ? (Threads[0].pmosse-Threads[0].mosse) : Opz.MultiPV;
  1364.    // Avvia i Threads
  1365.    for (int i=1;i<Opz.Threads;i++) pthread_create(&Threads[i].Thread,NULL,ThreadSearch,(void *)(&Threads[i]));
  1366.    /* Iterative Deepening */
  1367.    do {
  1368.       /* Lancia in ricerca anche il thread master */
  1369.       ThreadSearch(Threads);
  1370.  
  1371.         /* salva la mossa ricavata nella hash */
  1372.         sh.Hash=Threads[0].Scacchiera->Hash;
  1373.         sh.MossaPack = Pack(Threads[0].mosse[0].Mossa);
  1374.         sh.Val = Threads[0].alpha;
  1375.         sh.ValStatica = Threads[0].alpha;
  1376.         assert(Threads[0].Depth>=-128 && Threads[0].Depth<=127);
  1377.         sh.Depth=Threads[0].Depth;
  1378.         sh.NRicercaNT = Ric.NRicerca|PVNODE;
  1379.         TTStore(Threads[0].Scacchiera->Hash,&sh);
  1380.  
  1381.       /* se il livello non è il massimo aggiungi un tempo di attesa */
  1382.       if (Opz.Strength!=MAXSTRENGTH)
  1383.       {
  1384.          int64_t attesa=(600-6*Opz.Strength)*(Threads[0].Depth);
  1385.          int64_t tempoattuale=TempoMSec();
  1386.          if (tempoattuale+attesa>Ric.LimiteMSec) attesa=Ric.LimiteMSec-tempoattuale+10; // aggiungi 10 msec per essere sicuri di superare LimiteMSec
  1387.          attesa= attesa<0 ? 0:attesa;
  1388.          mySleep(attesa);
  1389.       }
  1390.  
  1391.         /* recupera il tempo trascorso e calcola il numero dei nodi recuperandoli tra i vari thread e stampa la o le pv */
  1392.         misurazione = TempoMSec();
  1393.         int64_t NNodi=0;
  1394.         int64_t TBHits=0;
  1395.         for (int i=0;i<Opz.Threads;i++) { NNodi+=Threads[i].NNodi; TBHits+=Threads[i].TBHits; }
  1396.       for (int npv = Ric.MultiPVReale-1;npv>=0;npv--)
  1397.          StampaPV(npv,RootInTB,TBScore,misurazione-TempoInizio,NNodi,TBHits,ScacchieraIniziale);
  1398.         Threads[0].Depth++;
  1399.     /* termina per raggiunto il tempo limite e la ricerca non è di ponder o la profondit? è oltre il limite */
  1400.     }while((misurazione<Ric.LimiteMSec || Ric.TipoRicerca!=NORMALE) && Threads[0].Depth<=depthlimit);
  1401.  
  1402.    /* se arrivo qui e sono in Ponder significa che la ricerca è terminata prima del previsto, devo attendere stop o ponderhit */
  1403.    while (Ric.TipoRicerca!=NORMALE && !Ric.TerminaRicerca)
  1404.    {
  1405.       char comando[16];
  1406.       fgets(comando,16,stdin);
  1407.       if (!strncmp(comando,"isready",7)) { printf("readyok\n"); fflush(stdout); }
  1408.       else if (!strncmp(comando,"ponderhit",9)) Ric.TipoRicerca=NORMALE; // passa da ponder a ricerca normale
  1409.       else if (!strncmp(comando,"stop",4)) Ric.TerminaRicerca=true;
  1410.    }
  1411.  
  1412.    stampamosse:
  1413.    Ric.TerminaRicerca=true; // serve per terminare i thread slave
  1414.    Threads[0].Scacchiera=ScacchieraIniziale; // se si arriva da un longjmp reimposta la posizione corretta
  1415.    for (int i=1;i<Opz.Threads;i++) pthread_join(Threads[i].Thread,NULL); /* attendi i threads: bisogna aspettarli tutti nel caso il numero cambiasse tra una ricerca e l'altra */
  1416. #ifndef NOOUTPUT
  1417.   // prendi la prima mossa dell'array (quella migliore) e stampala
  1418.    char strmossa[10];
  1419.    MoveToStr(strmossa,Threads[0].mosse[0].Mossa,Tratto(Threads));
  1420.    printf("bestmove %s",strmossa);
  1421.    Muovi(Threads,Threads[0].mosse[0].Mossa);
  1422.    TTLoad(Threads[0].Scacchiera->Hash,&sh);
  1423.    if (sh.Hash==Threads[0].Scacchiera->Hash && sh.MossaPack) // recupera dalla hash la seconda mossa della pv e usala come ponder move
  1424.    {
  1425.       MoveToStr(strmossa,UnPack(Threads,sh.MossaPack),Tratto(Threads));
  1426.       printf(" ponder %s",strmossa);
  1427.    }
  1428.    printf("\n");
  1429.    fflush(stdout);
  1430.    // ATTENZIONE!!! Non viene ripristinata la scacchierainiziale
  1431. #endif
  1432. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement