Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Contiene le funzioni che gestiscono le opzioni configurabili con la GUI, la comunicazione GUI-engine
- e la funzione di ricerca a partire da una posizione iniziale
- */
- /*
- 18/06/17 Pedone 1.7
- Novit? rispetto alla versione 1.6
- - corretto baco sulla null move
- - tuning
- - rivista valutazione pedoni passati
- - supporto allocazione hash tramite large pages
- - rivista gestione tempo alloca +10% in ponder
- - modificato LMP
- - countermove
- - riduzione per le catture cattive
- - modificata history
- - risolte le perdite per il tempo con la forza ridotta
- */
- /*
- DA FARE:
- ATTENZIONE!!!! In valutazione dove ci sono shift o divisioni su costanti (ad es mobilit?) può capitare che non venga moltiplicata
- la mobilit? per il bonus e poi divisa, ma che venga moltiplicata per una costante gi? divisa, quindi potrebbe perdere
- qualcosina in precisione ottenendo valori distanti di 1 cp dai valori corretti
- */
- /* COME USARE OPROFILE
- si compila con -g ma non -pg
- operf ./Pedone pgo
- opreport --symbols
- */
- /* Define per la compilazione abilitate e disabilitate tramite makefile*/
- //#define BMI
- //#define BIT32
- /* ATTENZIONE!!! In release definire NDEBUG */
- //#define NDEBUG
- #include <stdlib.h>
- #include <string.h>
- #include <sys/time.h>
- #include <stdio.h>
- #include <stdint.h>
- #include <inttypes.h>
- #include <pthread.h>
- #include <assert.h>
- #include <unistd.h>
- #include <setjmp.h>
- #ifdef BMI
- #include <immintrin.h>
- #endif
- #ifdef _WIN32
- #include <windows.h>
- #include <conio.h>
- #endif
- static void DefinizioneDati(){} // Serve solo per CodeBlocks
- /* Definizioni di Tipi, costanti e variabili globali */
- /* Dimensione di default della tabella delle trasposizioni */
- #define MBHASHDEFAULT 256
- /* profondit? limite raggiungibile in ricerca */
- #define DEFAULTMAXDEPTH 100
- /* Valutazione in ricerca massima che indica che non sono ancora stati individuati altri score */
- #define INFINITO 32701
- /* Valutazione del matto */
- #define MATTO 32700
- /* Distanza massima del matto, serve a distinguere gli score di matto dagli altri */
- #define MATTOMIN (MATTO-800)
- /* Definizioni per il tipo pezzo salvabile nelle mosse */
- #define PED 1
- #define CAV 2
- #define ALF 3
- #define TOR 4
- #define REG 5
- #define RE 6
- /* Gli score in valutazione e ricerca sono tutti in 1/4 di cp quindi per convertirli in cp si divide per FATTVAL */
- #define FATTVAL 4
- /* Genera gli scacchi da depth 0 fino a DEPTHSCACHI, in questo caso solo a depth 0 */
- #define DEPTHSCACCHI 0 /* 0 va meglio che -1 dai test */
- /* indici che indicano il codice hash che modifica la chiave principale a seconda del tipo di mossa */
- /* Indici Arrocco corto bianco, lungo bianco, corto nero, lungo nero */
- #define CHARROCCOCB 1024
- #define CHARROCCOCN 1025
- #define CHARROCCOLB 1026
- #define CHARROCCOLN 1027
- #define CHCOLONNEENPASSANT 1028
- #define CHTRATTON 1036
- typedef enum {false=0,true=1} bool;
- /* direzioni per accedere alla matrice Direzioni */
- /* DX destra SX sinistra SU sù GI giù DS diagonale su DG diagonale giù AS antidiagonale sù AG antidiagonale giù */
- #define DX 0
- #define SX 1
- #define SU 2
- #define GI 3
- #define DS 4
- #define DG 5
- #define AS 6
- #define AG 7
- /* Fasi della generazione mosse nella funzione di ricerca */
- /* ATTENZIONE ALLA NUMERAZIONE, LE KILLER DEVONO ESSERE IN SUCCESSIONE */
- typedef enum{HASH=0,GEN=1,CATTUREBUONE=2,KILLER10=3,KILLER11=4,COUNTERMOVE=5,KILLER20=6,KILLER21=7,GENALTRE=8,ALTREMOSSE=9} TOrdinamento;
- typedef uint64_t TBB; /* rappresenta le 64 case della scacchiera */
- typedef uint32_t TPos; /* da 0 a 63, rappresenta l'indice del bit nella bitboard */
- typedef uint32_t TMossa;/* 5 Flag + 3 Prom + 3 Catt + 6 A 6 Da + 3 Pezzo*/
- typedef uint16_t TMossaPack;
- /* Costanti per formare il tipo mossa */
- /* il risultato di RE|ARROCCO sar? il tipomossa arrocco
- PED|CATTURA|EP sar? un enpassant
- PED|PROMO|CATTURA sar? una promozione con cattura */
- #define SCACCO 0x02000000
- #define ARROCCO 0x01000000
- #define PROMO 0x00800000
- #define EP 0x00400000
- #define CATTURA 0x00200000
- /* Score minimo per le catture */
- #define VALCATTURE 0x40000000
- /* Score minimo per le quiete */
- #define VALQUIETE 0x20000000
- /* la catture cattive hanno score negativo */
- /* Score da assegnare all'arrocco per portarlo davanti alle altre quiete */
- #define VALARROCCO 0x10000000
- /* score di partenza per le promozioni minori (promozioni diverse da donna) */
- #define VALPROMOMINORI -2000000000
- // il limite history è minore di 4 volte rispetto a valarrocco, così sommando in ricerca le 3 history si rimane sempre sotto a VALARROCCO
- #define LIMITEHISTORY 67108864
- /* Definizione della struttura mossa/score composto dalla mossa e dalla valutazione di quella mossa */
- typedef struct
- {
- int32_t Val;
- TMossa Mossa;
- } TMossaVal;
- /* Per salvare le destinazioni di torre e alfiere */
- /* Servono per le Magic Bitboard, da notare che se si usano le istruzioni BMI i campi magic e shift scompaiono */
- typedef struct
- {
- const TBB Mask;
- #ifndef BMI
- const TBB Magic;
- const TBB Shift;
- #endif
- TBB *const Dest;
- }TMagic;
- /*
- tipo dati che verr? usato per aggiornare in maniera incrementare la valutazione materiale/piece sqare table
- e la generazione della chiave hash della posizione
- */
- typedef struct
- {
- uint64_t Hash;
- int16_t ValMg;
- int16_t ValEg;
- } THashVal;
- /* Definizione del tipo nodo in ricerca e dei valori associabili a questo tipo*/
- #define PVNODE 0x02
- #define CUTNODE 0x01
- #define ALLNODE 0x00
- /* maschera node type per individuare il tipo nodo */
- #define MASKNT 0x03
- /* maschera ricerca, per individuare il numero di ricerca per un certo valore salvato nella hash */
- #define MASKRIC 0xFC
- /* flag per salvare la mossa nella hash in formato packed */
- #define PACKSCACCO 0x8000
- #define PACKPROMO 0x4000
- #define PACKEP 0x2000
- #define PACKARROCCO 0x1000
- /*
- Definizione dello slot salvato nella hash trasposizioni, si può accedere tramite 2 valori a 64 bit
- o tramite i vari campi.
- */
- typedef union
- {
- uint64_t V[2];
- struct{ // !!! ATTENZIONE !!! NRic occupa solo 6 bit, per essere sicuri ne dovrebbe utilizzare almeno 7
- uint64_t Hash; // Chiave hash della posizione salvata
- int16_t Val; // score salvato: può essere esatto, un limite alto o un limite basso
- int16_t ValStatica; // valutazione statica per questa posizione
- TMossaPack MossaPack;// 6bit sorgente + 6bit destinazione + 4bit flag
- // bit flag 0123 bit 3 scacco bit 2 promo- se promo==1 bit 0 e 1 conterranno il pezzo promosso
- int8_t Depth;
- uint8_t NRicercaNT; // 6 bit N Ricerca + 2 bit Node Type
- };
- } TSlotHash;
- /* Definizione tipo per la hash dedicata alla posizione dei pedoni e dei 2 re */
- typedef union
- {
- uint64_t V[2]; /* Hash pedoni */
- struct{
- uint64_t Hash; // chiave hash della posizione dei pedoni e re
- int16_t ValMg; // valutazione calcolata per il mediogioco
- int16_t ValEg; // valutazione calcolata per il finale
- int16_t BonusRe[2]; // sicurezza dei re per entrambi i giocatori [1] chi ha il tratto [0] chi non muove
- };
- } TSlotHashPR;
- /* strutture per la scacchiera e la partita */
- /* definisci il colore che deve muovere */
- #define BIANCO 0
- #define NERO 8
- /* flag per indicare se una posizione è una ripetizione o meno */
- #define RIP3 0x01
- /* flag che indica se nella posizione corrente si è sotto scacco */
- #define SOTTOSCACCO 0x80
- /* Definizione struttura scacchiera*/
- typedef struct
- {
- TBB PT; /* Tutti i pezzi del lato tratto */
- TBB P0; /* Da P2 a P0 si possono ricavare tutti i pezzi, in particolar modo il tipo del pezzo */
- TBB P1;
- TBB P2;
- uint8_t ScaccoTrattoRip3; // S...T..R 1 bit scacco, 1 bit tratto 1 bit ripetizione
- uint8_t Arrocchi; /* ..rd..RD "r" "d" re e regina avversario e RE e REGINA tratto */
- uint8_t EnPassant; /* numero della colonna su cui effettuare la presa, =8 se non impostato */
- uint8_t Cont50Mosse; /* conta le mosse dall'ultima cattura o spinta di pedone */
- int16_t ValMg; /* valutazione materiale/tabelle pezzi della scacchiera nel mediogioco */
- int16_t ValEg; /* valutazione materiale/tabelle pezzi della scacchiera nel finale */
- uint64_t Hash; /* codice hash della scacchiera */
- uint64_t HashPR; /* codice hash pedoni e re */
- } TScacchiera;
- /* Struttura dei libri polyglot per leggere questo tipo di libri di aperture */
- typedef struct
- {
- uint64_t Hash; // codice hash della posizione
- uint16_t Mossa; // mossa salvata nel libro
- uint16_t Weight; // valutazione di questa mossa
- uint32_t Learn; // non usato in genere, ma servirebbe per il learning sul libro di aperture
- } TSlotBook;
- /* limite massimo di forza dell'engine (nel caso lo si volesse limitare in forza di gioco) */
- #define MAXSTRENGTH 100
- /* Opzioni che possono essere gestite dalla GUI per modificare varie funzionalit? */
- typedef struct
- {
- int Hash; //Dimensione in Mb della trasposition table
- bool Ponder; //Abilita o disabilita la possibilit? di pensare durante il turno avversario
- int DrawScore; //Score da assegnare alla parit? per spingere l'engine a evitare o cercare la patta
- bool OwnBook; //Abilita l'uso di un proprio libro (Polyglot)
- char BookFile[512]; //Nome del file del libro di aperture
- bool BookRandom; //Scegli casualmente la mossa, se a false sceglie sempre la mossa migliore
- int Strength; //Forza dell'engine MAXSTRENGTH è la forza massima 1 la minima
- int Threads; //Numero di thread da utilizzare per la ricerca parallela
- bool LargePages;
- // ci dovrebbe essere anche SyzygyPath, ma non è inclusa perchè non è necessario mantenere memorizzato il percorso
- int MultiPV; //Abilit? la modalit? di analisi con la stampa di varianti multiple
- bool Syzygy50MoveRule; //Abilita la regola delle 50 mosse per la tablebase o meno
- int SyzygyProbeLimit; //Limite di pezzi entro il quale fare il probe della tablebase
- } TOpzioni;
- // Definisci i tipi di ricerca con i quali può essere lanciato l'engine
- // NORMALE la ricerca termina dopo un certo lasso di tempo determinato all'avvio della ricerca
- // PONDER l'engine attende che l'avversario muova per terminare la ricerca o restare in ricerca per un certo lasso di tempo
- // RICINFINITA l'engine rimane in ricerca a tempo indeterminato finche non viene stoppato dalla GUI
- typedef enum {NORMALE,PONDER,RICINFINITA} TTipoRicerca;
- /*
- Struttura che salva le variabili relative alla ricerca
- */
- typedef struct
- {
- TTipoRicerca TipoRicerca; // tipo di ricerca da eseguire
- 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
- int64_t LimiteMSec,LimiteUltimoMSec; // limiti in msec da controllare in ricerca per non usare troppo tempo
- int64_t ControlloTempo; // numero di nodi oltre il quale effettuare un controllo del tempo
- int64_t NNodiCheck; // numero di nodi tra un controllo del tempo e un altro
- /* maschere per individuare l'indice al quale salvare le posizioni rispettivamente nella hash e nella hash dei pedoni/re*/
- uint64_t MASKHASH,MASKHASHPED;
- volatile TSlotHash *TT; // indirizzo al quale comincia la trasposition table
- volatile TSlotHashPR *TTPedoni; // indirizzo al quale comincia la hash dei pedoni/re
- int TBLargest,TBCardinality;// massimo numero di pezzi della tablebase e massimo numero di pezzi per il quale effetture il probe della tablebase
- int MultiPVReale; // numero di mosse da esaminare in multipv tenendo conto del numero complessivo di mosse
- // sotto windows servono per la lettura dell'input non bloccante
- #ifdef _WIN32
- int Pipe;
- HANDLE Handle;
- #endif
- uint8_t NRicerca; // numero progressivo di ricerca effettuato
- } TRicerca;
- /* numero massimo di mosse per una singola posizione (il numero è molto alto per evitare sforamenti)*/
- #define MAXMOSSE 256
- // Definisci la struttura dati per salvare le info di un singolo thread
- typedef struct
- {
- // è sufficiente 256 visto che con il limite delle 50 mosse e il caricamento della posizione non dovrebbero esserci
- // più di 100 posizioni + 128 in ricerca. Per sicurezza 256
- pthread_t Thread;
- jmp_buf Ambiente; // salvataggio ambiente per un longjump
- TScacchiera Partita[256]; // tutte le posizioni della partita a partire dalla primo azzeramento delle 50 mosse prima della posizione corrente
- TScacchiera *Scacchiera; // puntatore alla posizione corrente
- volatile int Depth; // depth in ricerca attualmente (volatile perchè deve venir letto da altri thread)
- int16_t alpha; // score alpha alla radice della ricerca
- int16_t LastScore; // ultimo score per l'aspiration window
- volatile int64_t NNodi; // Numero nodi ricercati, volatile perchè vengono usati in RootSearch quelli dei thread slave dal thread master
- volatile int64_t TBHits; // Numero hit della tablebase volatile per come sopra
- TMossaVal mosse[MAXMOSSE]; // contine tutte le mosse legali della posizione da unalizzare
- TMossaVal *pmosse; // puntatore all'ultima mossa dell'array mosse
- TMossa Killer[128*2]; // salva le killer moves aggiornate in ricerca
- int History[128*8*64]; // salva i punteggi per le mosse aggiornate in ricerca
- TMossa CounterMoves[2*8*64*64]; // salva le countermoves [lato][pezzo][da][a]
- } TStructThread;
- static void DichiarazioneVarGlobali() {} // Serve solo per CodeBlocks
- /* Dichiarazione di tutti i dati condivisi dai moduli del programma */
- /* numero massimo di thread supportati dalla ricerca parallela */
- #define MAXTHREADS 128
- /* array di threads */
- TStructThread Threads[MAXTHREADS];
- /* Posizione iniziale degli scacchi */
- char STARTPOS[]="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
- TRicerca Ric; //dati da passare per l'avvio della ricerca
- TOpzioni Opz; // opzioni dell'engine
- /* codici per aggiornamento della valutazione e della hash */
- /* numero massimo di chiavi hash differenti per generare le chiavi delle posizioni */
- #define DIMVETCODICIHASH 1037
- 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 */
- 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
- uint8_t Direzioni[64*64]; // si accede con [da<<6+a] e ritorna il numero di direzione, 8 se non sono allineate
- TBB DistanzaPedoni[64][7]; // [casa][distanza] genera una bitboard
- /* case nelle quali deve essere presente il pedone per catturare con enpassant */
- const TBB EnPassant[8] = {
- 0x0000000200000000ULL,0x0000000500000000ULL,0x0000000A00000000ULL,0x0000001400000000ULL,
- 0x0000002800000000ULL,0x0000005000000000ULL,0x000000A000000000ULL,0x0000004000000000ULL
- };
- /* come prima solo che i valori sono a traverse invertite per usarli nel muovi */
- const TBB EnPassantM[8] = {
- 0x0000000002000000ULL,0x0000000005000000ULL,0x000000000A000000ULL,0x0000000014000000ULL,
- 0x0000000028000000ULL,0x0000000050000000ULL,0x00000000A0000000ULL,0x0000000040000000ULL
- };
- /* bitboard con le destinazioni del cavallo */
- const TBB DestCavallo[64]= {0x0000000000020400ULL,0x0000000000050800ULL,0x00000000000a1100ULL,0x0000000000142200ULL,
- 0x0000000000284400ULL,0x0000000000508800ULL,0x0000000000a01000ULL,0x0000000000402000ULL,
- 0x0000000002040004ULL,0x0000000005080008ULL,0x000000000a110011ULL,0x0000000014220022ULL,
- 0x0000000028440044ULL,0x0000000050880088ULL,0x00000000a0100010ULL,0x0000000040200020ULL,
- 0x0000000204000402ULL,0x0000000508000805ULL,0x0000000a1100110aULL,0x0000001422002214ULL,
- 0x0000002844004428ULL,0x0000005088008850ULL,0x000000a0100010a0ULL,0x0000004020002040ULL,
- 0x0000020400040200ULL,0x0000050800080500ULL,0x00000a1100110a00ULL,0x0000142200221400ULL,
- 0x0000284400442800ULL,0x0000508800885000ULL,0x0000a0100010a000ULL,0x0000402000204000ULL,
- 0x0002040004020000ULL,0x0005080008050000ULL,0x000a1100110a0000ULL,0x0014220022140000ULL,
- 0x0028440044280000ULL,0x0050880088500000ULL,0x00a0100010a00000ULL,0x0040200020400000ULL,
- 0x0204000402000000ULL,0x0508000805000000ULL,0x0a1100110a000000ULL,0x1422002214000000ULL,
- 0x2844004428000000ULL,0x5088008850000000ULL,0xa0100010a0000000ULL,0x4020002040000000ULL,
- 0x0400040200000000ULL,0x0800080500000000ULL,0x1100110a00000000ULL,0x2200221400000000ULL,
- 0x4400442800000000ULL,0x8800885000000000ULL,0x100010a000000000ULL,0x2000204000000000ULL,
- 0x0004020000000000ULL,0x0008050000000000ULL,0x00110a0000000000ULL,0x0022140000000000ULL,
- 0x0044280000000000ULL,0x0088500000000000ULL,0x0010a00000000000ULL,0x0020400000000000ULL};
- /* bitboard con le destinazioni del re */
- const TBB DestRe[64] = {0x0000000000000302ULL,0x0000000000000705ULL,0x0000000000000e0aULL,0x0000000000001c14ULL,
- 0x0000000000003828ULL,0x0000000000007050ULL,0x000000000000e0a0ULL,0x000000000000c040ULL,
- 0x0000000000030203ULL,0x0000000000070507ULL,0x00000000000e0a0eULL,0x00000000001c141cULL,
- 0x0000000000382838ULL,0x0000000000705070ULL,0x0000000000e0a0e0ULL,0x0000000000c040c0ULL,
- 0x0000000003020300ULL,0x0000000007050700ULL,0x000000000e0a0e00ULL,0x000000001c141c00ULL,
- 0x0000000038283800ULL,0x0000000070507000ULL,0x00000000e0a0e000ULL,0x00000000c040c000ULL,
- 0x0000000302030000ULL,0x0000000705070000ULL,0x0000000e0a0e0000ULL,0x0000001c141c0000ULL,
- 0x0000003828380000ULL,0x0000007050700000ULL,0x000000e0a0e00000ULL,0x000000c040c00000ULL,
- 0x0000030203000000ULL,0x0000070507000000ULL,0x00000e0a0e000000ULL,0x00001c141c000000ULL,
- 0x0000382838000000ULL,0x0000705070000000ULL,0x0000e0a0e0000000ULL,0x0000c040c0000000ULL,
- 0x0003020300000000ULL,0x0007050700000000ULL,0x000e0a0e00000000ULL,0x001c141c00000000ULL,
- 0x0038283800000000ULL,0x0070507000000000ULL,0x00e0a0e000000000ULL,0x00c040c000000000ULL,
- 0x0302030000000000ULL,0x0705070000000000ULL,0x0e0a0e0000000000ULL,0x1c141c0000000000ULL,
- 0x3828380000000000ULL,0x7050700000000000ULL,0xe0a0e00000000000ULL,0xc040c00000000000ULL,
- 0x0203000000000000ULL,0x0507000000000000ULL,0x0a0e000000000000ULL,0x141c000000000000ULL,
- 0x2838000000000000ULL,0x5070000000000000ULL,0xa0e0000000000000ULL,0x40c0000000000000ULL};
- TBB DestMagic[5248+102400]; /* tutte le destinazioni di Alfiere e Torre */
- /* usa questo trucco per dimezzare la tabella successiva Magic visto che con le BMI magic e shift non sono utilizzati */
- #ifndef BMI
- #define MASCHERAMAGIC(mask,magic,shift,dest) {mask,magic,shift,dest}
- #else
- #define MASCHERAMAGIC(mask,magic,shift,dest) {mask,dest}
- #endif
- /* Magic[0] è riferito all'Alfiere, Magic[1] è riferito alla Torre */
- TMagic Magic[2][64] = {
- {
- MASCHERAMAGIC(0x0040201008040200ULL,0x89a1121896040240ULL,58,&DestMagic[ 0]),
- MASCHERAMAGIC(0x0000402010080400ULL,0x2004844802002010ULL,59,&DestMagic[ 64]),
- MASCHERAMAGIC(0x0000004020100a00ULL,0x2068080051921000ULL,59,&DestMagic[ 96]),
- MASCHERAMAGIC(0x0000000040221400ULL,0x62880a0220200808ULL,59,&DestMagic[ 128]),
- MASCHERAMAGIC(0x0000000002442800ULL,0x0004042004000000ULL,59,&DestMagic[ 160]),
- MASCHERAMAGIC(0x0000000204085000ULL,0x0100822020200011ULL,59,&DestMagic[ 192]),
- MASCHERAMAGIC(0x0000020408102000ULL,0xc00444222012000aULL,59,&DestMagic[ 224]),
- MASCHERAMAGIC(0x0002040810204000ULL,0x0028808801216001ULL,58,&DestMagic[ 256]),
- MASCHERAMAGIC(0x0020100804020000ULL,0x0400492088408100ULL,59,&DestMagic[ 320]),
- MASCHERAMAGIC(0x0040201008040000ULL,0x0201c401040c0084ULL,59,&DestMagic[ 352]),
- MASCHERAMAGIC(0x00004020100a0000ULL,0x00840800910a0010ULL,59,&DestMagic[ 384]),
- MASCHERAMAGIC(0x0000004022140000ULL,0x0000082080240060ULL,59,&DestMagic[ 416]),
- MASCHERAMAGIC(0x0000000244280000ULL,0x2000840504006000ULL,59,&DestMagic[ 448]),
- MASCHERAMAGIC(0x0000020408500000ULL,0x30010c4108405004ULL,59,&DestMagic[ 480]),
- MASCHERAMAGIC(0x0002040810200000ULL,0x1008005410080802ULL,59,&DestMagic[ 512]),
- MASCHERAMAGIC(0x0004081020400000ULL,0x8144042209100900ULL,59,&DestMagic[ 544]),
- MASCHERAMAGIC(0x0010080402000200ULL,0x0208081020014400ULL,59,&DestMagic[ 576]),
- MASCHERAMAGIC(0x0020100804000400ULL,0x004800201208ca00ULL,59,&DestMagic[ 608]),
- MASCHERAMAGIC(0x004020100a000a00ULL,0x0f18140408012008ULL,57,&DestMagic[ 640]),
- MASCHERAMAGIC(0x0000402214001400ULL,0x1004002802102001ULL,57,&DestMagic[ 768]),
- MASCHERAMAGIC(0x0000024428002800ULL,0x0841000820080811ULL,57,&DestMagic[ 896]),
- MASCHERAMAGIC(0x0002040850005000ULL,0x0040200200a42008ULL,57,&DestMagic[1024]),
- MASCHERAMAGIC(0x0004081020002000ULL,0x0000800054042000ULL,59,&DestMagic[1152]),
- MASCHERAMAGIC(0x0008102040004000ULL,0x88010400410c9000ULL,59,&DestMagic[1184]),
- MASCHERAMAGIC(0x0008040200020400ULL,0x0520040470104290ULL,59,&DestMagic[1216]),
- MASCHERAMAGIC(0x0010080400040800ULL,0x1004040051500081ULL,59,&DestMagic[1248]),
- MASCHERAMAGIC(0x0020100a000a1000ULL,0x2002081833080021ULL,57,&DestMagic[1280]),
- MASCHERAMAGIC(0x0040221400142200ULL,0x000400c00c010142ULL,55,&DestMagic[1408]),
- MASCHERAMAGIC(0x0002442800284400ULL,0x941408200c002000ULL,55,&DestMagic[1920]),
- MASCHERAMAGIC(0x0004085000500800ULL,0x0658810000806011ULL,57,&DestMagic[2432]),
- MASCHERAMAGIC(0x0008102000201000ULL,0x0188071040440a00ULL,59,&DestMagic[2560]),
- MASCHERAMAGIC(0x0010204000402000ULL,0x4800404002011c00ULL,59,&DestMagic[2592]),
- MASCHERAMAGIC(0x0004020002040800ULL,0x0104442040404200ULL,59,&DestMagic[2624]),
- MASCHERAMAGIC(0x0008040004081000ULL,0x0511080202091021ULL,59,&DestMagic[2656]),
- MASCHERAMAGIC(0x00100a000a102000ULL,0x0004022401120400ULL,57,&DestMagic[2688]),
- MASCHERAMAGIC(0x0022140014224000ULL,0x80c0040400080120ULL,55,&DestMagic[2816]),
- MASCHERAMAGIC(0x0044280028440200ULL,0x8040010040820802ULL,55,&DestMagic[3328]),
- MASCHERAMAGIC(0x0008500050080400ULL,0x0480810700020090ULL,57,&DestMagic[3840]),
- MASCHERAMAGIC(0x0010200020100800ULL,0x0102008e00040242ULL,59,&DestMagic[3968]),
- MASCHERAMAGIC(0x0020400040201000ULL,0x0809005202050100ULL,59,&DestMagic[4000]),
- MASCHERAMAGIC(0x0002000204081000ULL,0x8002024220104080ULL,59,&DestMagic[4032]),
- MASCHERAMAGIC(0x0004000408102000ULL,0x0431008804142000ULL,59,&DestMagic[4064]),
- MASCHERAMAGIC(0x000a000a10204000ULL,0x0019001802081400ULL,57,&DestMagic[4096]),
- MASCHERAMAGIC(0x0014001422400000ULL,0x0200014208040080ULL,57,&DestMagic[4224]),
- MASCHERAMAGIC(0x0028002844020000ULL,0x3308082008200100ULL,57,&DestMagic[4352]),
- MASCHERAMAGIC(0x0050005008040200ULL,0x041010500040c020ULL,57,&DestMagic[4480]),
- MASCHERAMAGIC(0x0020002010080400ULL,0x4012020c04210308ULL,59,&DestMagic[4608]),
- MASCHERAMAGIC(0x0040004020100800ULL,0x208220a202004080ULL,59,&DestMagic[4640]),
- MASCHERAMAGIC(0x0000020408102000ULL,0x0111040120082000ULL,59,&DestMagic[4672]),
- MASCHERAMAGIC(0x0000040810204000ULL,0x6803040141280a00ULL,59,&DestMagic[4704]),
- MASCHERAMAGIC(0x00000a1020400000ULL,0x2101004202410000ULL,59,&DestMagic[4736]),
- MASCHERAMAGIC(0x0000142240000000ULL,0x8200000041108022ULL,59,&DestMagic[4768]),
- MASCHERAMAGIC(0x0000284402000000ULL,0x0000021082088000ULL,59,&DestMagic[4800]),
- MASCHERAMAGIC(0x0000500804020000ULL,0x0002410204010040ULL,59,&DestMagic[4832]),
- MASCHERAMAGIC(0x0000201008040200ULL,0x0040100400809000ULL,59,&DestMagic[4864]),
- MASCHERAMAGIC(0x0000402010080400ULL,0x0822088220820214ULL,59,&DestMagic[4896]),
- MASCHERAMAGIC(0x0002040810204000ULL,0x0040808090012004ULL,58,&DestMagic[4928]),
- MASCHERAMAGIC(0x0004081020400000ULL,0x00910224040218c9ULL,59,&DestMagic[4992]),
- MASCHERAMAGIC(0x000a102040000000ULL,0x0402814422015008ULL,59,&DestMagic[5024]),
- MASCHERAMAGIC(0x0014224000000000ULL,0x0090014004842410ULL,59,&DestMagic[5056]),
- MASCHERAMAGIC(0x0028440200000000ULL,0x0001000042304105ULL,59,&DestMagic[5088]),
- MASCHERAMAGIC(0x0050080402000000ULL,0x0010008830412a00ULL,59,&DestMagic[5120]),
- MASCHERAMAGIC(0x0020100804020000ULL,0x2520081090008908ULL,59,&DestMagic[5152]),
- MASCHERAMAGIC(0x0040201008040200ULL,0x40102000a0a60140ULL,58,&DestMagic[5184])
- },
- {
- MASCHERAMAGIC(0x000101010101017eULL,0x0a8002c000108020ULL,52,&DestMagic[ 0+5248]),
- MASCHERAMAGIC(0x000202020202027cULL,0x06c00049b0002001ULL,53,&DestMagic[ 4096+5248]),
- MASCHERAMAGIC(0x000404040404047aULL,0x0100200010090040ULL,53,&DestMagic[ 6144+5248]),
- MASCHERAMAGIC(0x0008080808080876ULL,0x2480041000800801ULL,53,&DestMagic[ 8192+5248]),
- MASCHERAMAGIC(0x001010101010106eULL,0x0280028004000800ULL,53,&DestMagic[10240+5248]),
- MASCHERAMAGIC(0x002020202020205eULL,0x0900410008040022ULL,53,&DestMagic[12288+5248]),
- MASCHERAMAGIC(0x004040404040403eULL,0x0280020001001080ULL,53,&DestMagic[14336+5248]),
- MASCHERAMAGIC(0x008080808080807eULL,0x2880002041000080ULL,52,&DestMagic[16384+5248]),
- MASCHERAMAGIC(0x0001010101017e00ULL,0xa000800080400034ULL,53,&DestMagic[20480+5248]),
- MASCHERAMAGIC(0x0002020202027c00ULL,0x0004808020004000ULL,54,&DestMagic[22528+5248]),
- MASCHERAMAGIC(0x0004040404047a00ULL,0x2290802004801000ULL,54,&DestMagic[23552+5248]),
- MASCHERAMAGIC(0x0008080808087600ULL,0x0411000d00100020ULL,54,&DestMagic[24576+5248]),
- MASCHERAMAGIC(0x0010101010106e00ULL,0x0402800800040080ULL,54,&DestMagic[25600+5248]),
- MASCHERAMAGIC(0x0020202020205e00ULL,0x000b000401004208ULL,54,&DestMagic[26624+5248]),
- MASCHERAMAGIC(0x0040404040403e00ULL,0x2409000100040200ULL,54,&DestMagic[27648+5248]),
- MASCHERAMAGIC(0x0080808080807e00ULL,0x0001002100004082ULL,53,&DestMagic[28672+5248]),
- MASCHERAMAGIC(0x00010101017e0100ULL,0x0022878001e24000ULL,53,&DestMagic[30720+5248]),
- MASCHERAMAGIC(0x00020202027c0200ULL,0x1090810021004010ULL,54,&DestMagic[32768+5248]),
- MASCHERAMAGIC(0x00040404047a0400ULL,0x0801030040200012ULL,54,&DestMagic[33792+5248]),
- MASCHERAMAGIC(0x0008080808760800ULL,0x0500808008001000ULL,54,&DestMagic[34816+5248]),
- MASCHERAMAGIC(0x00101010106e1000ULL,0x0a08018014000880ULL,54,&DestMagic[35840+5248]),
- MASCHERAMAGIC(0x00202020205e2000ULL,0x8000808004000200ULL,54,&DestMagic[36864+5248]),
- MASCHERAMAGIC(0x00404040403e4000ULL,0x0201008080010200ULL,54,&DestMagic[37888+5248]),
- MASCHERAMAGIC(0x00808080807e8000ULL,0x0801020000441091ULL,53,&DestMagic[38912+5248]),
- MASCHERAMAGIC(0x000101017e010100ULL,0x0000800080204005ULL,53,&DestMagic[40960+5248]),
- MASCHERAMAGIC(0x000202027c020200ULL,0x1040200040100048ULL,54,&DestMagic[43008+5248]),
- MASCHERAMAGIC(0x000404047a040400ULL,0x0000120200402082ULL,54,&DestMagic[44032+5248]),
- MASCHERAMAGIC(0x0008080876080800ULL,0x0d14880480100080ULL,54,&DestMagic[45056+5248]),
- MASCHERAMAGIC(0x001010106e101000ULL,0x0012040280080080ULL,54,&DestMagic[46080+5248]),
- MASCHERAMAGIC(0x002020205e202000ULL,0x0100040080020080ULL,54,&DestMagic[47104+5248]),
- MASCHERAMAGIC(0x004040403e404000ULL,0x9020010080800200ULL,54,&DestMagic[48128+5248]),
- MASCHERAMAGIC(0x008080807e808000ULL,0x0813241200148449ULL,53,&DestMagic[49152+5248]),
- MASCHERAMAGIC(0x0001017e01010100ULL,0x0491604001800080ULL,53,&DestMagic[51200+5248]),
- MASCHERAMAGIC(0x0002027c02020200ULL,0x0100401000402001ULL,54,&DestMagic[53248+5248]),
- MASCHERAMAGIC(0x0004047a04040400ULL,0x4820010021001040ULL,54,&DestMagic[54272+5248]),
- MASCHERAMAGIC(0x0008087608080800ULL,0x0400402202000812ULL,54,&DestMagic[55296+5248]),
- MASCHERAMAGIC(0x0010106e10101000ULL,0x0209009005000802ULL,54,&DestMagic[56320+5248]),
- MASCHERAMAGIC(0x0020205e20202000ULL,0x0810800601800400ULL,54,&DestMagic[57344+5248]),
- MASCHERAMAGIC(0x0040403e40404000ULL,0x4301083214000150ULL,54,&DestMagic[58368+5248]),
- MASCHERAMAGIC(0x0080807e80808000ULL,0x204026458e001401ULL,53,&DestMagic[59392+5248]),
- MASCHERAMAGIC(0x00017e0101010100ULL,0x0040204000808000ULL,53,&DestMagic[61440+5248]),
- MASCHERAMAGIC(0x00027c0202020200ULL,0x8001008040010020ULL,54,&DestMagic[63488+5248]),
- MASCHERAMAGIC(0x00047a0404040400ULL,0x8410820820420010ULL,54,&DestMagic[64512+5248]),
- MASCHERAMAGIC(0x0008760808080800ULL,0x1003001000090020ULL,54,&DestMagic[65536+5248]),
- MASCHERAMAGIC(0x00106e1010101000ULL,0x0804040008008080ULL,54,&DestMagic[66560+5248]),
- MASCHERAMAGIC(0x00205e2020202000ULL,0x0012000810020004ULL,54,&DestMagic[67584+5248]),
- MASCHERAMAGIC(0x00403e4040404000ULL,0x1000100200040208ULL,54,&DestMagic[68608+5248]),
- MASCHERAMAGIC(0x00807e8080808000ULL,0x430000a044020001ULL,53,&DestMagic[69632+5248]),
- MASCHERAMAGIC(0x007e010101010100ULL,0x0280009023410300ULL,53,&DestMagic[71680+5248]),
- MASCHERAMAGIC(0x007c020202020200ULL,0x00e0100040002240ULL,54,&DestMagic[73728+5248]),
- MASCHERAMAGIC(0x007a040404040400ULL,0x0000200100401700ULL,54,&DestMagic[74752+5248]),
- MASCHERAMAGIC(0x0076080808080800ULL,0x2244100408008080ULL,54,&DestMagic[75776+5248]),
- MASCHERAMAGIC(0x006e101010101000ULL,0x0008000400801980ULL,54,&DestMagic[76800+5248]),
- MASCHERAMAGIC(0x005e202020202000ULL,0x0002000810040200ULL,54,&DestMagic[77824+5248]),
- MASCHERAMAGIC(0x003e404040404000ULL,0x8010100228810400ULL,54,&DestMagic[78848+5248]),
- MASCHERAMAGIC(0x007e808080808000ULL,0x2000009044210200ULL,53,&DestMagic[79872+5248]),
- MASCHERAMAGIC(0x7e01010101010100ULL,0x4080008040102101ULL,52,&DestMagic[81920+5248]),
- MASCHERAMAGIC(0x7c02020202020200ULL,0x0040002080411d01ULL,53,&DestMagic[86016+5248]),
- MASCHERAMAGIC(0x7a04040404040400ULL,0x2005524060000901ULL,53,&DestMagic[88064+5248]),
- MASCHERAMAGIC(0x7608080808080800ULL,0x0502001008400422ULL,53,&DestMagic[90112+5248]),
- MASCHERAMAGIC(0x6e10101010101000ULL,0x489a000810200402ULL,53,&DestMagic[92160+5248]),
- MASCHERAMAGIC(0x5e20202020202000ULL,0x0001004400080a13ULL,53,&DestMagic[94208+5248]),
- MASCHERAMAGIC(0x3e40404040404000ULL,0x4000011008020084ULL,53,&DestMagic[96256+5248]),
- MASCHERAMAGIC(0x7e80808080808000ULL,0x0026002114058042ULL,52,&DestMagic[98304+5248])
- }
- };
- /* costanti per la ricerca */
- // margine futility ricerca, margine futility quiescenza, margine razoring, fattore tra valori history e tabelle pezzi, margine internal iterative deepening, percentuale tempo per mossa
- #define FUTMARGIN 220
- #define FUTQMARGIN 360
- #define RAZORMARGIN 790
- #define IIDMARGIN 400
- #define LMPLIMIT 6
- #define HISTORYFACTOR 4
- static inline void *ThreadSearch(void *ptr);
- static inline void RootSearch(int64_t msec,int64_t inc,int movestogo,int depthlimit,int mossegiocate);
- static inline void CaricaHashVal(void);
- static inline void CaricaImbalances(void);
- static inline void InizializzaDati(void);
- static inline void InizializzaMotore(uint64_t *largepagesallocated);
- static inline int CaricaPosizione(TStructThread *t,char *fen, char *mosse);
- // COMMENTARE SE NON SI STA ESEGUENDO IL TEST EPD
- // definire solo per lanciare dei test con le epd, commentare per compilare l'engine
- //#define EPD
- #ifdef EPD
- TMossa MosseCalcolate[6];
- #endif
- #include "bonus.h"
- #include "scacchierahash.h"
- #include "genmosse.h"
- #include "muovi.h"
- #include "tbprobe.h"
- #include "valutazione.h"
- #include "ricerca.h"
- #include "libro.h"
- // togliere il commento qui sotto solo se si stanno usando funzioni di debug, mantenere commentato in release
- //#include "debug.h"
- #if defined(EPD)
- #include "tuning.h"
- #endif
- int main(int argc, char *argv[])
- {
- char comando[4096]; // variabile dove salvare i comandi ricevuti dalla GUI
- comando[0]=0;
- int mossegiocate=0; //mantiene il numero di mosse giocate caricate con il comando position
- uint64_t largepagesallocated=0; // numero di byte allocati con le large pages
- // Inizializza le variabili da utilizzare nella RootSearch e nella comunicazione engine-GUI
- Opz.Hash=MBHASHDEFAULT;
- Opz.Ponder=false;
- Opz.DrawScore = -20;
- Opz.OwnBook = false;
- strcpy(Opz.BookFile,"./book.bin");
- Opz.BookRandom = false;
- Opz.Strength=MAXSTRENGTH;
- Opz.Threads=1;
- Opz.MultiPV=1;
- Opz.LargePages=false;
- Opz.Syzygy50MoveRule=true;
- Opz.SyzygyProbeLimit=6;
- Ric.TTPedoni=0; // inizializza a 0 il puntatore, per richiedere l'allocazione
- Ric.TBLargest=0; //se non c'è la TB imposta a 0 questo limite
- #ifdef _WIN32
- // Solo sotto windows inizializza queste variabili per la lettura dell'input non bloccante
- DWORD bytes_left;
- Ric.Handle = GetStdHandle(STD_INPUT_HANDLE);
- Ric.Pipe = !GetConsoleMode(Ric.Handle, &bytes_left);
- #endif
- InizializzaDati(); /* inizializza le strutture dati del motore */
- //printf("Risultato: %d\n",LanciaAnalisi());
- //printf("Risultato: %d\n",LanciaAnalisi());
- //SommaInfoTuning(2);
- //CaricaValoriValutazione();
- //GeneraFileBonus();
- //TrovaMaggiori();
- //DividiFile(32);
- //IndicazioniTuning();
- //printf("Risultato: %d\n",LanciaTestProc(32));
- //TestValutazione();
- //return 0;
- // 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
- if (argc==2 && !strncmp(argv[1],"pgo",3)) // Se lanciato con parametro pgo
- {
- char fentest[10][90]={{"1qr3k1/p3bppp/4pn2/1B2n3/N7/P3P2P/1P2QPP1/2R1B2K w - -"},
- {"2br2k1/r5p1/4p3/5p2/8/pP3B2/1q2RPPP/Q3R1K1 b - - "},
- {"r5k1/5p2/7p/5qP1/1P1QR3/5P2/r4RK1/8 b - - "},
- {"r4rk1/1p2bppp/p3bn2/8/Pq1BP3/1BN1Q3/1PP3PP/R3K2R w KQ - "},
- {"r2qk2r/3nbpp1/2bBp2p/p3P3/1p6/8/PPPQBPPP/1NKR3R w kq - "},
- {"3r4/3r2bk/1p4pp/pN2n3/P6P/4Q1P1/1P2B1K1/8 b - h3"},
- {"6k1/1b2bp2/p3p2p/4P1p1/1pr5/4BP1P/PP2N1P1/3R2K1 b - - "},
- {"1rr3k1/1q3pp1/pnbQp2p/1p2P3/3B1P2/2PB4/P1P2RPP/R5K1 w - - "},
- {"2r2rk1/p3qp1p/2b1pp1Q/2b5/1n6/2N2NP1/1P2PPBP/R2R2K1 w - - "},
- {"8/p4k2/1p3r2/2pPnb2/2Pr3P/PPK3P1/4B1Q1/8 b - - "}};
- for (int i=0;i<10; i++)
- {
- InizializzaMotore(&largepagesallocated); // Azzera le varie strutture del motore
- mossegiocate=CaricaPosizione(Threads,&fentest[i][0],NULL); // carica una posizione
- Ric.TipoRicerca=NORMALE; // inizializza le variabili della ricerca
- Threads[0].pmosse=GeneraTutteLegali(Threads,Threads[0].mosse); // carica l'array delle mosse generando solo mosse legali
- RootSearch(4000000000,0,0,23,mossegiocate); // lancia la ricerca
- }
- strcpy(comando,"quit"); // permetti la terminazione completa senza usare l'exit
- }
- // Entra nel ciclo nel quale si attendono i comandi
- while(strncmp(comando,"quit",4)) //esci per Comando=quit
- {
- fgets(comando,4096,stdin);
- if (!strncmp(comando,"uci\n",4)) // invia le opzioni modificabili dalla GUI
- {
- printf("id name Pedone 1.7\nid author Fabio Gobbato\n");
- printf("option name Hash type spin default %d min 1 max 1048576\n",MBHASHDEFAULT);
- printf("option name Threads type spin default 1 min 1 max %d\n",MAXTHREADS);
- printf("option name Ponder type check default false\n");
- printf("option name OwnBook type check default false\n");
- printf("option name BookFile type string default %s\n",Opz.BookFile);
- printf("option name BookRandom type check default false\n");
- printf("option name DrawScore type spin default -5 min -500 max 500\n");
- printf("option name Strength type spin default %d min 1 max %d\n",MAXSTRENGTH,MAXSTRENGTH);
- printf("option name MultiPV type spin default 1 min 1 max %d\n",MAXMOSSE);
- printf("option name LargePages type check default false\n");
- printf("option name SyzygyPath type string default <empty>\n");
- printf("option name Syzygy50MoveRule type check default true\n");
- printf("option name SyzygyProbeLimit type spin default 6 min 0 max 6\n");
- printf("uciok\n");
- fflush(stdout);
- }
- else if (!strncmp(comando,"setoption name ",15)) /* Gestione parametri motore */
- {
- // recupera il nome dell'opzione da modificare ed il valore
- char *parametro,*strvalore;
- char *saveptr;
- parametro = strtok_r(&comando[15]," ",&saveptr);
- strtok_r(NULL," ",&saveptr); /* value */
- strvalore=strtok_r(NULL,"\n",&saveptr); /* la parte finale di setoption termina con \n */
- if (!strvalore) continue; // se non c'è valore prosegui
- // Individua quale opzione modificare
- if (!strcmp(parametro,"Hash")) Opz.Hash = atoi(strvalore);
- else if (!strcmp(parametro,"Threads")) Opz.Threads = atoi(strvalore);
- else if (!strcmp(parametro,"Ponder")) Opz.Ponder = !strcmp(strvalore,"true") ? true : false;
- else if (!strcmp(parametro,"OwnBook")) Opz.OwnBook = !strcmp(strvalore,"true") ? true : false;
- else if (!strcmp(parametro,"BookFile")) strcpy(Opz.BookFile,strvalore);
- else if (!strcmp(parametro,"BookRandom")) Opz.BookRandom = !strcmp(strvalore,"true") ? true : false;
- else if (!strcmp(parametro,"DrawScore")) Opz.DrawScore = atoi(strvalore)*FATTVAL; // converti da cp a 1/FATTVAL cp
- else if (!strcmp(parametro,"Strength")) Opz.Strength = atoi(strvalore);
- else if (!strcmp(parametro,"MultiPV")) Opz.MultiPV = atoi(strvalore);
- else if (!strcmp(parametro,"LargePages")) Opz.LargePages = !strcmp(strvalore,"true") ? true : false;
- else if (!strcmp(parametro,"SyzygyPath")) Ric.TBLargest=initsyzygy(strvalore);
- else if (!strcmp(parametro,"Syzygy50MoveRule")) Opz.Syzygy50MoveRule = !strcmp(strvalore,"true") ? true : false;
- else if (!strcmp(parametro,"SyzygyProbeLimit")) Opz.SyzygyProbeLimit=atoi(strvalore);
- } /* Comandi per la ricerca */
- else if (!strncmp(comando,"ucinewgame",10)) InizializzaMotore(&largepagesallocated); // inizio di una nuova partita, inizializza alcune parti dell'engine
- else if (!strncmp(comando,"isready",7)) { printf("readyok\n"); fflush(stdout); } // se la GUI interroga l'engine se è pronto rispondere
- else if (!strncmp(comando,"position",8)) // se viene inviata la stringa con la posizione
- {
- if (!Ric.TTPedoni) InizializzaMotore(&largepagesallocated); /* se non c'è stato ucinewgame inizializza il motore */
- char *fen=STARTPOS;
- char *moves=strstr(&comando[18],"moves"); // &Comando[18] è il minimo (position startpos )
- char *saveptr;
- if (moves) {*(moves-1)='\0'; moves+=6;}
- if (!strncmp(strtok_r(&comando[9]," ",&saveptr),"fen",3)) fen=&comando[13];
- // Dopo il parsing della stringa del comando carica la posizione nel formato interno dell'engine
- mossegiocate=CaricaPosizione(Threads,fen,moves);
- }
- else if (!strncmp(comando,"go",2)) // avvia la ricerca per la posizione passata tramite position
- {
- if (!Ric.TTPedoni) // se la TT non è stata inizializzata fallo ora
- {
- InizializzaMotore(&largepagesallocated); /* se non c'è stato position inizializza il motore */
- mossegiocate=CaricaPosizione(Threads,STARTPOS,0);
- }
- int64_t msec=4000000000;// impostare a questo valore nel caso di un "go depth N"
- int64_t inc=0;
- int movestogo=0;
- int depthlimit=DEFAULTMAXDEPTH;
- Threads[0].pmosse=Threads[0].mosse;
- Ric.TipoRicerca=NORMALE;
- char *saveptr;
- // fai il parsing del comando individuando le varie informazioni
- for (char *stringa=strtok_r(comando," ",&saveptr);stringa;stringa=strtok_r(NULL," ",&saveptr))
- {
- if (!strncmp(stringa,"ponder",6)) Ric.TipoRicerca=PONDER;
- else if (!strncmp(stringa,"wtime",5) && !Tratto(Threads)) msec = atoi(strtok_r(NULL," ",&saveptr));
- else if (!strncmp(stringa,"btime",5) && Tratto(Threads)) msec = atoi(strtok_r(NULL," ",&saveptr));
- else if (!strncmp(stringa,"winc",4) && !Tratto(Threads)) inc = atoi(strtok_r(NULL," ",&saveptr));
- else if (!strncmp(stringa,"binc",4) && Tratto(Threads)) inc = atoi(strtok_r(NULL," ",&saveptr));
- else if (!strncmp(stringa,"movestogo",9)) movestogo = atoi(strtok_r(NULL," ",&saveptr));
- else if (!strncmp(stringa,"depth",5)) depthlimit = atoi(strtok_r(NULL," ",&saveptr));
- else if (!strncmp(stringa,"movetime",8)) {msec = atoi(strtok_r(NULL," ",&saveptr)); movestogo=1; }
- else if (!strncmp(stringa,"infinite",8)) Ric.TipoRicerca=RICINFINITA;
- else if (!strncmp(stringa,"searchmoves",11)) // passa le mosse da ricercare
- {
- for (stringa=strtok_r(NULL," ",&saveptr);stringa;stringa=strtok_r(NULL," ",&saveptr))
- {
- Threads[0].pmosse->Mossa=StrToMove(Threads,stringa);
- DaScacco(Threads,&Threads[0].pmosse->Mossa);
- Threads[0].pmosse++;
- }
- }
- } /* se non sono state passate delle mosse precise da ricercare Genera tutte le mosse legali*/
- if (Threads[0].pmosse==Threads[0].mosse) Threads[0].pmosse = GeneraTutteLegali(Threads,Threads[0].mosse);
- /* per ovviare ad una follia di Arena di avviare la ricerca anche su posizioni di matto */
- if (Threads[0].pmosse==Threads[0].mosse) { printf("bestmove 0000\n"); fflush(stdout); }
- else RootSearch(msec,inc,movestogo,depthlimit,mossegiocate); // Avvia la ricerca alla radice
- }
- }
- // All'uscita dell'engine liberare la trasposition table
- if (Ric.TTPedoni)
- {
- if (largepagesallocated)
- #ifdef _WIN32
- VirtualFree((void *)Ric.TTPedoni,0,MEM_RELEASE);
- #else
- munmap((void *)Ric.TTPedoni,largepagesallocated);
- #endif // _WIN32
- else free((void *)Ric.TTPedoni);
- }
- return 0;
- }
- static inline void CaricaHashVal(void)
- {
- /* carica valutazioni per i pezzi da usare per aggiornare incrementalmente la valutazione materiale/tabelle pezzi */
- for (int j=1;j<7;j++) // pezzi da 1 a 6
- {
- for (int i=0;i<64;i++) // case da 0 a 63
- {
- HashVal[((j+8)<<6)+i].ValMg = Val.ValorePosizione[j-1][0][i]; // carica il bianco
- HashVal[((j+8)<<6)+i].ValEg = Val.ValorePosizione[j-1][1][i]; // carica il bianco
- HashVal[(j<<6)+i].ValMg = Val.ValorePosizione[j-1][0][i]; // carica il nero
- HashVal[(j<<6)+i].ValEg = Val.ValorePosizione[j-1][1][i]; // carica il nero
- }
- }
- }
- static inline void CaricaImbalances(void)
- { // Calcola gli squilibri
- // per ognuna delle varie configurazioni di pezzi carica dei bonus appropriati che verranno usati in valutazione
- for (int pb=0;pb<9;pb++) // da 0 a 8 pedoni bianchi
- for (int pn=0;pn<9;pn++) // da 0 a 8 pedoni neri
- for (int cb=0;cb<3;cb++) // da 0 a 2 cavalli bianchi
- for (int cn=0;cn<3;cn++) // da 0 a 2 cavalli neri
- for (int acb=0;acb<2;acb++) // da 0 a 1 alfiere campo chiaro bianco
- for (int acn=0;acn<2;acn++) // da 0 a 1 alfiere campo chiaro nero
- for (int asb=0;asb<2;asb++) // da 0 a 1 alfiere campo scuro bianco
- for (int asn=0;asn<2;asn++) // da 0 a 1 alfiere campo scuro nero
- for (int tb=0;tb<3;tb++) // da 0 a 2 torri bianche
- for (int tn=0;tn<3;tn++) // da 0 a 2 torri nere
- for (int db=0;db<2;db++) // da 0 a 1 donna bianca
- for (int dn=0;dn<2;dn++) // da 0 a 1 donna nera
- { // ATTENZIONE!! Il punteggio è riferito al bianco (chi ha il tratto)
- int16_t *corrente=&Imbalances[pb][pn][cb][cn][acb][acn][asb][asn][tb][tn][db][dn];
- *corrente=0; // inizializza a 0 la configurazione corrente per caricarne nelle prossime istruzioni il valore
- // Coppia alfieri
- if (acb==1 && asb==1) *corrente+=Val.COPPIAALFIERI;
- if (acn==1 && asn==1) *corrente-=Val.COPPIAALFIERI;
- // Alfieri di colore opposto
- 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;
- // Regina cavallo + pedoni
- if (db==1 && cb==1 && (acb+asb+tb)==0 && pb!=0) *corrente+=Val.REGINACAVALLO;
- if (dn==1 && cn==1 && (acn+asn+tn)==0 && pn!=0) *corrente-=Val.REGINACAVALLO;
- // Torre alfiere + pedoni
- if (tb==1 && (acb+asb)==1 && (db+cb)==0 && pb!=0) *corrente+=Val.TORREALFIERE;
- if (tn==1 && (acn+asn)==1 && (dn+cn)==0 && pn!=0) *corrente-=Val.TORREALFIERE;
- // Re contro 2 cavalli
- if (cb==2 && (pb+pn+cn+acb+acn+asb+asn+tb+tn+db+dn)==0) *corrente-=2*Val.ValStatico[CAV];
- if (cn==2 && (pb+pn+cb+acb+acn+asb+asn+tb+tn+db+dn)==0) *corrente+=2*Val.ValStatico[CAV];
- // Torre contro minore
- if (tb==1 && (cn+acn+asn)==1 && (pb+pn+cb+acb+asb+tn+db+dn)==0) *corrente-=Val.ValStatico[TOR]-Val.ValStatico[CAV];
- if (tn==1 && (cb+acb+asb)==1 && (pb+pn+cn+acn+asn+tb+db+dn)==0) *corrente+=Val.ValStatico[TOR]-Val.ValStatico[CAV];
- // 2 Minori contro 1 minore
- if ((cb+acb+asb)==2 && (cn+acn+asn)==1 && (pb+pn+tb+tn+db+dn)==0) *corrente-=Val.ValStatico[CAV];
- if ((cn+acn+asn)==2 && (cb+acb+asb)==1 && (pb+pn+tb+tn+db+dn)==0) *corrente+=Val.ValStatico[CAV];
- // Torre e minore contro torre
- if (tb==1 && (cb+acb+asb)==1 && tn==1 && (pb+pn+cn+acn+asn+db+dn)==0) *corrente-=Val.ValStatico[CAV];
- if (tn==1 && (cn+acn+asn)==1 && tb==1 && (pb+pn+cb+acb+asb+db+dn)==0) *corrente+=Val.ValStatico[CAV];
- // Regina contro 2 minori
- if ((pb+cb+acb+asb+tb+pn+tn+dn)==0 && db==1 && (cn+acn+asn)==2) *corrente-=Val.ValStatico[CAV];
- if ((pn+cn+acn+asn+tn+pb+tb+db)==0 && dn==1 && (cb+acb+asb)==2) *corrente+=Val.ValStatico[CAV];
- // Regina e 1 minore contro regina
- if ((pb+tb+pn+tn+cn+asn+acn)==0 && db==1 && (acb+asb+cb)==1 && dn==1) *corrente-=Val.ValStatico[CAV];
- if ((pn+tn+pb+tb+cb+asb+acb)==0 && dn==1 && (acn+asn+cn)==1 && db==1) *corrente+=Val.ValStatico[CAV];
- // Regina contro torre e minore
- 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];
- 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];
- // 2 torri contro torre e minore
- if ((pb+pn+cb+acb+asb+db+dn)==0 && tb==2 && tn==1 && (cn+acn+asn)==1) *corrente-=Val.ValStatico[TOR]-Val.ValStatico[CAV];
- if ((pn+pb+cn+acn+asn+dn+db)==0 && tn==2 && tb==1 && (cb+acb+asb)==1) *corrente+=Val.ValStatico[TOR]-Val.ValStatico[CAV];
- // 2 cavalli contro un pedone
- if (pb+cn+acb+acn+asb+asn+tb+tn+db+dn==0 && pn==1 && cb==2) *corrente-=2*Val.ValStatico[CAV];
- if (pn+cb+acn+acb+asn+asb+tn+tb+dn+db==0 && pb==1 && cn==2) *corrente+=2*Val.ValStatico[CAV];
- // 1 lato senza pedoni e l'altro con pedoni con vantaggio inferiore o uguale a un alfiere
- if ((pb==0 && pn!=0) || (pb!=0 && pn==0))
- {
- // calcola la valutazione materiale e abbassala
- int valutazione = pb*Val.ValStatico[PED]+cb*Val.ValStatico[CAV]+(acb+asb)*Val.ValStatico[ALF]+tb*Val.ValStatico[TOR]+db*Val.ValStatico[REG]
- -pn*Val.ValStatico[PED]-cn*Val.ValStatico[CAV]-(acn+asn)*Val.ValStatico[ALF]-tn*Val.ValStatico[TOR]-dn*Val.ValStatico[REG];
- if (pb==0 && valutazione>0 && valutazione<=Val.ValStatico[ALF]) *corrente-=valutazione/2;
- if (pn==0 && valutazione<0 && valutazione>=-Val.ValStatico[ALF]) *corrente-=valutazione/2; // ATTENZIONE!!! In entrambi i casi va sottratto
- }
- }
- }
- static inline void InizializzaDati(void)
- {
- // a partire da questi numeri casuali s0 e s1 genera tutte le chiavi hash per aggiornare incrementalmente la chiave della posizione
- uint64_t s0=0x0154db043d0efc3bULL,s1=0x67efe05134828892ULL;
- for (int i=0;i<DIMVETCODICIHASH;i++) /* Inizializza i codici per generale l'hash della scacchiera */
- {
- uint64_t tmp = s0;
- s0 = s1;
- tmp ^= tmp << 23;
- tmp ^= tmp >> 17;
- tmp ^= s1 ^ (s1 >> 26);
- HashVal[i].Hash = tmp+s1;
- s1 = tmp;
- }
- CaricaHashVal();
- // Inizializza i database delle mosse di alfiere e torre
- for (int pos=0;pos<64;pos++)
- {
- for (int pezzo=0;pezzo<2;pezzo++)
- {
- int nbit = PopCount(Magic[pezzo][pos].Mask);
- for (TBB index=0;index<(1ULL<<nbit);index++)
- {
- // converte l'indice index di nbit in BB occupazione
- assert(pezzo>=0 && pezzo<2 && pos>=0 && pos<64);
- TBB occupazione = 0ULL, mask = Magic[pezzo][pos].Mask;
- #ifdef BMI
- occupazione = pdep(index,mask);
- #else
- for(TBB k = 1; k < 1ULL<<nbit; k<<=1)
- {
- if(index & k) occupazione |= ExtractLSB(mask);
- mask=ClearLSB(mask);
- }
- #endif // BMI
- // genera la BB con le destinazioni del pezzo
- TBB destinazioni;
- if (pezzo)
- { // genera le destinazioni di torre a partire da pos e occupazione
- TBB pezzisu=(0x0101010101010101ULL<<pos)&(occupazione|0xFF00000000000000ULL); // pezzi sopra il pezzo che muove o fine scacchiera
- TBB pezzigi=(0x8080808080808080ULL>>(63-pos))&(occupazione|0x00000000000000FFULL);
- TBB pezzidx=(0x00000000000000FFULL<<pos)&(occupazione|0x8080808080808080ULL);
- TBB pezzisx=(0xFF00000000000000ULL>>(63-pos))&(occupazione|0x0101010101010101ULL);
- destinazioni = (((0x8080808080808080ULL>>(63-Pos(pezzisu)))&(0x0101010101010101ULL<<PosInv(pezzigi))) |
- ((0xFF00000000000000ULL>>(63-Pos(pezzidx)))&(0x00000000000000FFULL<<PosInv(pezzisx))))^(1ULL<<pos);
- }
- else
- { // genera le destinazioni di alfiere a partire da pos e occupazione
- TBB pezzisu=(0x8040201008040201ULL<<pos)&(occupazione|0xFF80808080808080ULL);
- TBB pezzigi=(0x8040201008040201ULL>>(63-pos))&(occupazione|0x01010101010101FFULL);
- TBB pezzisx=(0x8102040810204081ULL<<pos)&(occupazione|0xFF01010101010101ULL);
- TBB pezzidx=(0x8102040810204081ULL>>(63-pos))&(occupazione|0x80808080808080FFULL);
- destinazioni = (((0x8040201008040201ULL>>(63-Pos(pezzisu)))&(0x8040201008040201ULL<<PosInv(pezzigi))) |
- ((0x8102040810204081ULL>>(63-Pos(pezzisx)))&(0x8102040810204081ULL<<PosInv(pezzidx))))^(1ULL<<pos);
- }
- #ifdef BMI
- TBB indice = pext(occupazione,Magic[pezzo][pos].Mask);
- Magic[pezzo][pos].Dest[indice] = destinazioni;
- #else
- Magic[pezzo][pos].Dest[(occupazione*Magic[pezzo][pos].Magic)>>Magic[pezzo][pos].Shift]= destinazioni;
- #endif
- }
- }
- }
- // Inizializza Raggi, Direzioni e DistanzaPedoni
- for (int i=0;i<64;i++)
- {
- for (int j=0;j<64;j++)
- {
- TBB dest=1ULL<<j;
- Raggi[(i<<6)+j]=0;
- Direzioni[(i<<6)+j]=8;
- if (DirDs(i)&dest) {Raggi[(i<<6)+j] = DirDs(i)^DirDs(j); Direzioni[(i<<6)+j]=DS;}
- else if (DirDg(i)&dest) {Raggi[(i<<6)+j] = DirDg(i)^DirDg(j); Direzioni[(i<<6)+j]=DG;}
- else if (DirAs(i)&dest) {Raggi[(i<<6)+j] = DirAs(i)^DirAs(j); Direzioni[(i<<6)+j]=AS;}
- else if (DirAg(i)&dest) {Raggi[(i<<6)+j] = DirAg(i)^DirAg(j); Direzioni[(i<<6)+j]=AG;}
- else if (DirDx(i)&dest) {Raggi[(i<<6)+j] = DirDx(i)^DirDx(j); Direzioni[(i<<6)+j]=DX;}
- else if (DirSx(i)&dest) {Raggi[(i<<6)+j] = DirSx(i)^DirSx(j); Direzioni[(i<<6)+j]=SX;}
- else if (DirSu(i)&dest) {Raggi[(i<<6)+j] = DirSu(i)^DirSu(j); Direzioni[(i<<6)+j]=SU;}
- else if (DirGi(i)&dest) {Raggi[(i<<6)+j] = DirGi(i)^DirGi(j); Direzioni[(i<<6)+j]=GI;}
- }
- for (int j=0;j<7;j++)
- {
- DistanzaPedoni[i][j]=0;
- for (int k=0;k<63;k++) if (Distanza(i,k)==(j+1)) DistanzaPedoni[i][j]|=(1ULL<<k);
- }
- }
- CaricaImbalances();
- }
- // proporzione tra tt e hash pedoni
- #define PROPHASHPED 16
- // Inizializza le strutture dati dell'engine che vanno azzerate ad inizio partita
- static inline void InizializzaMotore(uint64_t *largepagesallocated)
- {
- /* inizializza le killer per i vari thread */
- for (int j=0;j<Opz.Threads;j++)
- {
- for (int i=0;i<=(128-1);i++) Threads[j].Killer[KINDEX(i,0)]=Threads[j].Killer[KINDEX(i,1)]=0;
- for (TMossa *p=&Threads[j].CounterMoves[0];p<=&Threads[j].CounterMoves[2*8*64*64-1];p++) *p=0;
- }
- /* Inizializza la tabella hash per la ricerca */
- Ric.NRicerca = 0; // azzera il numero progressivo della ricerca
- 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
- uint64_t nslothashped=nslothash/PROPHASHPED; // la tabella hash dei pedoni/re è uguale alla dimensione della trasposition table /16
- Ric.MASKHASH=nslothash-1; // Definisci le maschere e le dimensioni delle hash
- Ric.MASKHASHPED=nslothashped-1;
- uint64_t bytedaallocare=nslothash*sizeof(TSlotHash)+nslothashped*sizeof(TSlotHashPR);
- /* fai la richiesta per hash e per hash pedoni insieme caricando l'indirizzo su TTPedoni*/
- if (Ric.TTPedoni)
- {
- if (*largepagesallocated)
- #ifdef _WIN32
- VirtualFree((void *)Ric.TTPedoni,0,MEM_RELEASE);
- #else
- munmap((void *)Ric.TTPedoni,*largepagesallocated);
- #endif // _WIN32
- else free((void *)Ric.TTPedoni);
- Ric.TTPedoni=0;
- *largepagesallocated=0;
- }
- if (Opz.LargePages)
- {
- #ifdef _WIN32
- TOKEN_PRIVILEGES tp;
- HANDLE hToken;
- OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
- LookupPrivilegeValue(NULL, "SeLockMemoryPrivilege", &tp.Privileges[0].Luid);
- tp.PrivilegeCount = 1;
- tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
- Ric.TTPedoni = VirtualAlloc(NULL, bytedaallocare, MEM_LARGE_PAGES | MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
- #else
- Ric.TTPedoni = (TSlotHashPR *) mmap(NULL, bytedaallocare, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE | MAP_HUGETLB, -1, 0);
- if (Ric.TTPedoni == MAP_FAILED) Ric.TTPedoni = 0;
- #endif // _WIN32
- if (Ric.TTPedoni)
- {
- *largepagesallocated=bytedaallocare;
- #ifndef EPD
- printf("Allocated large pages\n");
- #endif
- }
- }
- if (!Ric.TTPedoni) Ric.TTPedoni = (TSlotHashPR *) malloc(bytedaallocare); //alloca entrambe le hash
- // se l'allocazione non va a buon fine dimezzare la dimensione e riallocare finchè non viene allocata o si arriva a 0
- while (!Ric.TTPedoni && Opz.Hash>=1)
- {
- Opz.Hash>>=1; // dimezza la dimensione per la hash
- 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
- nslothashped=nslothash/PROPHASHPED; // la tabella hash dei pedoni/re è uguale alla dimensione della trasposition table /16
- Ric.MASKHASH=nslothash-1; // Definisci le maschere e le dimensioni delle hash
- Ric.MASKHASHPED=nslothashped-1;
- bytedaallocare=nslothash*sizeof(TSlotHash)+nslothashped*sizeof(TSlotHashPR);
- Ric.TTPedoni = (TSlotHashPR *) malloc(bytedaallocare); //alloca entrambe le hash
- }
- // se non si è riusciti ad allocare nemmmeno 1Mb di hash termina l'engine
- if (!Ric.TTPedoni) { printf("Hash allocation error\n"); exit(EXIT_FAILURE); }
- Ric.TT = (TSlotHash *) &Ric.TTPedoni[nslothashped]; //calcola l'indirizzo della trasposition table
- /* azzera entrambe le hash */
- for (uint64_t i=0;i<nslothashped;i++) { Ric.TTPedoni[i].V[0] = 0; Ric.TTPedoni[i].V[1] = 0; }
- for (uint64_t i=0;i<nslothash;i++) { Ric.TT[i].V[0] = 0; Ric.TT[i].V[1] = 0; }
- }
- /*
- Carica la posizione nella struttura dati interna dell'engine a partire da una stringa fen iniziale e da una stringa di mosse
- Restituisce il numero di MOSSE (non semimosse) giocate
- ATTENZIONE!!!!! Non controlla se gli arrocchi e enpassant possano effettivamente essere eseguiti:
- potrebbe essere che siano su i flag di arrocco, ma che manchino le torri od il re non è in posizione.
- mosse viene modificato da strtok_r
- */
- static inline int CaricaPosizione(TStructThread *t,char *fen, char *mosse)
- {
- char strfen[128];
- strcpy(strfen,fen); // copia la stringa fen per non dover alterare quella principale
- /* Inizializza la scacchiera */
- t->Scacchiera=t->Partita;
- t->Scacchiera->P0 = t->Scacchiera->P1 = t->Scacchiera->P2 = t->Scacchiera->PT = 0;
- t->Scacchiera->EnPassant=8;
- t->Scacchiera->ScaccoTrattoRip3=0; /* non sotto scacco 0 ripetizioni tratto BIANCO */
- t->Scacchiera->Hash=0; /*inizializza la scacchierahash per caricare i pezzi */
- t->Scacchiera->HashPR=0;
- t->Scacchiera->ValMg=0; /* inizializza la valutazione */
- t->Scacchiera->ValEg=0;
- t->Scacchiera->Arrocchi=0;
- t->Scacchiera->Cont50Mosse=0;
- char *saveptr=0;
- strtok_r(strfen," ",&saveptr);
- char *strtratto=strtok_r(NULL," ",&saveptr); // ricava stringa tratto
- char *strarrocchi=strtok_r(NULL," ",&saveptr); // arrocchi
- char *strep=strtok_r(NULL," ",&saveptr); // enpassant
- char *strcont50=strtok_r(NULL," ",&saveptr); // contatore 50 mosse
- /* carica la posizione dei pezzi nella scacchiera, con il bianco come se avesse il tratto */
- uint8_t latopezzo=BIANCO;
- uint8_t pezzo=PED;
- uint8_t latotratto=BIANCO;
- TPos posfen=0;
- for (char *p=strfen;*p;p++)
- {
- if (*p>='1' && *p<='8') posfen += *p - '0';
- else if (*p=='/') continue;
- else
- {
- // Individua il pezzo
- TPos pos = PosAvv(posfen);
- if (*p=='p') { pezzo = PED; latopezzo = NERO; }
- else if (*p=='n') { pezzo = CAV; latopezzo = NERO; }
- else if (*p=='b') { pezzo = ALF; latopezzo = NERO; }
- else if (*p=='r') { pezzo = TOR; latopezzo = NERO; }
- else if (*p=='q') { pezzo = REG; latopezzo = NERO; }
- else if (*p=='k') { pezzo = RE; latopezzo = NERO; }
- else if (*p=='P') { pezzo = PED; latopezzo = BIANCO; }
- else if (*p=='N') { pezzo = CAV; latopezzo = BIANCO; }
- else if (*p=='B') { pezzo = ALF; latopezzo = BIANCO; }
- else if (*p=='R') { pezzo = TOR; latopezzo = BIANCO; }
- else if (*p=='Q') { pezzo = REG; latopezzo = BIANCO; }
- else if (*p=='K') { pezzo = RE; latopezzo = BIANCO; }
- // Carica il pezzo nella struttura scacchiera
- t->Scacchiera->P0|=((uint64_t)pezzo&1)<<pos;
- t->Scacchiera->P1|=((uint64_t)(pezzo>>1)&1)<<pos;
- t->Scacchiera->P2|=((uint64_t)pezzo>>2)<<pos;
- if (latopezzo==BIANCO) { t->Scacchiera->PT |= 1ULL<<pos; pezzo|=NERO; }
- t->Scacchiera->Hash ^= HashVal[(pezzo<<6)+PosAss(pos,latopezzo)].Hash;
- if ((pezzo&0x07)==PED || (pezzo&0x07)==RE) t->Scacchiera->HashPR ^= HashVal[(pezzo<<6)+PosAss(pos,latopezzo)].Hash;
- t->Scacchiera->ValMg += (latopezzo==BIANCO ? 1: -1)*HashVal[(pezzo<<6)+PosAss(pos,latopezzo)].ValMg;
- t->Scacchiera->ValEg += (latopezzo==BIANCO ? 1: -1)*HashVal[(pezzo<<6)+PosAss(pos,latopezzo)].ValEg;
- posfen++;
- }
- }
- /* leggi il tratto */
- if (*strtratto=='w') latotratto=BIANCO;
- else if (*strtratto=='b') latotratto=NERO;
- if (*strarrocchi!='-') /* leggi gli arrocchi */
- {
- for (char *p=strarrocchi;*p;p++)
- {
- if (*p=='K') { t->Scacchiera->Arrocchi|=0x02; t->Scacchiera->Hash ^= HashVal[CHARROCCOCB].Hash; }
- else if (*p=='Q') { t->Scacchiera->Arrocchi|=0x01; t->Scacchiera->Hash ^= HashVal[CHARROCCOLB].Hash; }
- else if (*p=='k') { t->Scacchiera->Arrocchi|=0x20; t->Scacchiera->Hash ^= HashVal[CHARROCCOCN].Hash; }
- else if (*p=='q') { t->Scacchiera->Arrocchi|=0x10; t->Scacchiera->Hash ^= HashVal[CHARROCCOLN].Hash; }
- }
- }
- if (*strep!='-' && (Pedoni(t)&(latotratto==BIANCO ? t->Scacchiera->PT&EnPassant[*strep - 'a']: (t->Scacchiera->PT^Tutti(t))&EnPassantM[*strep - 'a'])))
- { /* carica l'enpassant solo se ci sono pedoni avversari che possono eseguirlo (così rileva correttamente le ripetizioni)*/
- t->Scacchiera->EnPassant= *strep - 'a';
- t->Scacchiera->Hash ^= HashVal[CHCOLONNEENPASSANT+t->Scacchiera->EnPassant].Hash;
- }
- if (strcont50) t->Scacchiera->Cont50Mosse=atoi(strcont50); /* leggi contatore 50 mosse se presente */
- if (latotratto==NERO) CambiaTratto(t); /* gira la scacchiera se il tratto è del nero */
- /* carica le mosse */
- int mossegiocate=0;
- if (mosse)
- { // 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
- for (char *strmossa=strtok_r(mosse," ",&saveptr); strmossa; strmossa = strtok_r(NULL," ",&saveptr))
- {
- mossegiocate++;
- TMossa mossa = StrToMove(t,strmossa);
- Muovi(t,mossa); /* ATTENZIONE!! Non viene caricato correttamente lo scacco al re perchè non è necessario in questa fase*/
- if (t->Scacchiera->Cont50Mosse==0)
- { /* se viene azzerato il contatore delle 50 mosse le posizioni precedenti non sono interessanti per ricercare le ripetizioni*/
- t->Partita[0]=*t->Scacchiera;
- t->Scacchiera=t->Partita;
- }
- }
- }
- mossegiocate>>=1; /* ricava il numero di mosse e non di semimosse */
- /* solo alla fine carica sotto scacco */
- if (ScaccoRe(t)) t->Scacchiera->ScaccoTrattoRip3|=SOTTOSCACCO; /* imposta il campo scacco */
- return mossegiocate;
- }
- static inline void InizializzaKillerHistory(TStructThread *t)
- {
- for (int i=0;i<126;i++) // shifta killer di 2 visto che le ricerche vengono lanciate sempre a 2 semimosse di distanza
- {
- t->Killer[KINDEX(i,0)]=t->Killer[KINDEX(i+2,0)];
- t->Killer[KINDEX(i,1)]=t->Killer[KINDEX(i+2,1)];
- }
- t->Killer[KINDEX(126,0)]=t->Killer[KINDEX(126,1)]=0;
- t->Killer[KINDEX(127,0)]=t->Killer[KINDEX(127,1)]=0;
- for (int *p=&t->History[0];p<=&t->History[128*8*64-1];p++) *p=0; //Azzera History
- }
- /* La differenza di profondit? rispetto al thread master da assegnare ai thread slave, si cicla ogni 16 thread */
- const int DepthThrd[16]={0,1,1,2,0,2,0,3,1,2,3,4,0,1,3,4};
- // Funzione che viene lanciata avviando i vari threads
- static inline void *ThreadSearch(void *ptr)
- {
- TStructThread *t=(TStructThread *) ptr;
- if (t!=Threads) // se non è il thread master lascia che ogni thread si inizializzi i suoi dati
- {
- if (__builtin_setjmp(t->Ambiente)) return NULL; // salva l'ambiente per un longump !!!usare gli intrisics perchè con mingw64 crasha
- InizializzaKillerHistory(t);
- t->LastScore=0;
- }
- do{
- // Se non è il thread master ricava la profondit? alla quale ricercare usando gli stessi valori ogni 16 threads
- if (t!=Threads)
- {
- t->Depth=Threads[0].Depth+DepthThrd[(t-Threads)&0xF]; // cicla ogni 16
- if (t->Depth>DEFAULTMAXDEPTH) t->Depth=DEFAULTMAXDEPTH;
- }
- int16_t beta;
- // solo in una ricerca con MultiPV=1 carica i valori per l'aspiration window
- if (Ric.MultiPVReale==1 && t->Depth>=8 && abs(t->LastScore)<MATTOMIN) { t->alpha = t->LastScore-120; beta = t->LastScore+120; }
- else { t->alpha = -INFINITO; beta = INFINITO; }
- nuova_aspiration:
- for (TMossaVal *p=t->mosse;p<t->pmosse;p++) /* esegui tutte le mosse */
- {
- 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)];
- int riduzione=0,estensione=0;
- EstensioniRiduzioni(PVNODE,nonridurre,p->Mossa,0,t->Depth,p-t->mosse,&estensione,&riduzione);
- Muovi(t,p->Mossa);
- int nuovadepth=t->Depth-1+estensione;
- // se il numero di mossa è minore a MultiPV usa la finestra aperta
- if (p<&t->mosse[Ric.MultiPVReale]) p->Val = -Search(t,PVNODE,1,nuovadepth,-beta,-t->alpha,true,-INFINITO,p->Mossa);
- else
- { // altrimenti usa la null window
- p->Val = -Search(t,CUTNODE,1,nuovadepth-riduzione,-t->alpha-1,-t->alpha,true,-INFINITO,p->Mossa);
- if (riduzione && nuovadepth>0 && p->Val>t->alpha) p->Val = -Search(t,CUTNODE,1,nuovadepth,-t->alpha-1,-t->alpha,true,-INFINITO,p->Mossa);
- if (p->Val>t->alpha) p->Val = -Search(t,PVNODE,1,nuovadepth,-beta,-t->alpha,true,-INFINITO,p->Mossa);
- }
- t->Scacchiera--;
- if (Ric.MultiPVReale==1)
- { /* ripeti se limiti fuori dall'aspiration window (usa l'aspiration window solo per MultiPV=1) */
- if (p==t->mosse && (p->Val<=t->alpha || p->Val>=beta)) { t->alpha = -INFINITO; beta = INFINITO; goto nuova_aspiration; }
- if (p!=t->mosse && p->Val>=beta) { t->alpha = -INFINITO; beta = INFINITO; goto nuova_aspiration; }
- }
- if (p->Val>t->alpha) // se la valutazione è la migliore incontrata fin'ora
- {
- TMossaVal mossa=*p;
- TMossaVal *inizio=t->mosse;
- for (;inizio<p && mossa.Val<=inizio->Val;inizio++); /* cerca la prima mossa con val inferiore (necessaria per supportare la MultiPV)*/
- for (TMossaVal *j=p;j>inizio;j--) *j=*(j-1); /* riordina le mosse mettendo questa in testa */
- *inizio=mossa;
- if (p>=&t->mosse[Ric.MultiPVReale-1]) t->alpha = t->mosse[Ric.MultiPVReale-1].Val;
- }
- }
- /* aggiorna la history */
- if (t->Depth>3 && !(t->mosse[0].Mossa&(CATTURA|PROMO)))
- {
- assert(PezzoAssTratto(t,PezzoM(t->mosse[0].Mossa))!=0);
- t->History[HINDEX(0,PezzoM(t->mosse[0].Mossa),AM(t->mosse[0].Mossa))]+=HISTORYFACTOR*t->Depth*t->Depth;
- if (t->History[HINDEX(0,PezzoM(t->mosse[0].Mossa),AM(t->mosse[0].Mossa))]>LIMITEHISTORY)
- t->History[HINDEX(0,PezzoM(t->mosse[0].Mossa),AM(t->mosse[0].Mossa))]=LIMITEHISTORY;
- }
- /* aggiorna le killer */
- if (!Scacco(t) && !(t->mosse[0].Mossa&(CATTURA|PROMO)))
- {
- if ((t->mosse[0].Mossa&~SCACCO)!=t->Killer[KINDEX(0,0)])
- {
- t->Killer[KINDEX(0,1)]=t->Killer[KINDEX(0,0)];
- t->Killer[KINDEX(0,0)]=(t->mosse[0].Mossa&~SCACCO); // salva senza il campo scacco
- }
- }
- t->LastScore = t->alpha; // aggiorna ultimo score per aspiration search
- }while(t!=Threads); // continua a ciclare se non è il thred master
- return NULL;
- }
- /* Stampa la pv, usa NOOUTPUT solo quando si lanciano molte epd */
- static void StampaPV(int npv,bool rootintb,int16_t tbscore,int64_t msec,int64_t nnodi,int64_t tbhits,TScacchiera *scacchierainiziale)
- {
- #ifndef NOOUTPUT
- char strmossa[10];
- TSlotHash sh;
- 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);
- int16_t val = Threads[0].mosse[npv].Val;
- // correggi lo score se la posizione alla radice è sulla tablebase
- if (rootintb && (abs(val)<MATTOMIN)) val = tbscore;
- // converti lo score in caso di matto e converti lo score da quati di cp a cp
- if (abs(val)<MATTOMIN) printf("score cp %d pv ",val/FATTVAL);
- else printf("score mate %d pv ", val>0 ? (MATTO-val+1)/2 : (-MATTO-val)/2);
- MoveToStr(strmossa,Threads[0].mosse[npv].Mossa,Tratto(Threads));
- printf("%s ",strmossa);
- Muovi(Threads,Threads[0].mosse[npv].Mossa);
- if (!Rip3(Threads))
- {
- TTLoad(Threads[0].Scacchiera->Hash,&sh);
- // mantenere il controllo sulla mossa e non sul nodo visto che in quiescenza la pv può non avere mosse
- while (sh.Hash==Threads[0].Scacchiera->Hash && sh.NRicercaNT&PVNODE && sh.MossaPack)
- {
- TMossa mossahash = UnPack(Threads,sh.MossaPack);
- MoveToStr(strmossa,mossahash,Tratto(Threads));
- printf("%s ",strmossa);
- Muovi(Threads,mossahash);
- if (Rip3(Threads)) break;
- TTLoad(Threads[0].Scacchiera->Hash,&sh);
- }
- }
- Threads[0].Scacchiera=scacchierainiziale; // riporta scacchiera a scacchierainiziale visto che è stata modificata del Muovi
- printf("\n");
- fflush(stdout);
- #endif
- }
- // Funzione di ricerca del motore lanciato da una posizione precedentemente caricata, e recupera i parametri di ricerca da Ric e Opz
- static inline void RootSearch(int64_t msec,int64_t inc,int movestogo,int depthlimit,int mossegiocate)
- {
- Ric.TerminaRicerca=false; // imposta all'inizio il termine della ricerca a false
- /* Cerca una mossa nel libro */
- if (Opz.OwnBook && Ric.TipoRicerca!=RICINFINITA) /* Se il libro è abilitato e la ricerca non è di ponder/analisi */
- {
- TMossa bestmove = CercaMossaLibro(Threads,Opz.BookFile,Opz.BookRandom); /* ATTENZIONE!!! La mossa restituita è utile solo se la si converte a stringa */
- if (bestmove) /* non è buona per essere eseguita con il Muovi */
- {
- while (Ric.TipoRicerca==PONDER && !Ric.TerminaRicerca) // se sono in ponder attendi un comando
- {
- char comando[16];
- fgets(comando,16,stdin);
- if (!strncmp(comando,"isready",7)) { printf("readyok\n"); fflush(stdout); }
- else if (!strncmp(comando,"ponderhit",9)) Ric.TipoRicerca=NORMALE; // passa da ponder a ricerca normale
- else if (!strncmp(comando,"stop",4)) Ric.TerminaRicerca=true;
- }
- char strmossa[10];
- MoveToStr(strmossa,bestmove,Tratto(Threads));
- printf("bestmove %s\n",strmossa);
- fflush(stdout);
- return;
- }
- }
- // Definisci volatile queste variabili perchè dovranno essere recuperate dopo un longjmp
- TScacchiera *volatile ScacchieraIniziale;
- volatile bool RootInTB;
- volatile int16_t TBScore;
- volatile int64_t TempoInizio;
- ScacchieraIniziale=Threads[0].Scacchiera;
- if (__builtin_setjmp(Threads[0].Ambiente)) // !!!usare gli intrisics perchè con mingw64 crasha
- { // al ritorno da un longump e sono in MultiPV=1 stampa la pv individuata da una ricerca parziale
- if (Opz.MultiPV==1)
- {
- Threads[0].Scacchiera=ScacchieraIniziale;
- int64_t misurazione = TempoMSec();
- int64_t NNodi=0;
- int64_t TBHits=0;
- for (int i=0;i<Opz.Threads;i++) { NNodi+=Threads[i].NNodi; TBHits+=Threads[i].TBHits; }
- /* ATTENZIONE QUI!!! se ci si arriva senza aver ricercato almeno una mossa a depth 1
- la valutazione della mossa non sar? quella della ricerca ma VALCATTURA o VALQUIETA ecc.
- */
- StampaPV(0,RootInTB,TBScore,misurazione-TempoInizio,NNodi,TBHits,ScacchieraIniziale);
- }
- // salta a stampa bestmove e pondermove
- goto stampamosse;
- }
- /* Azzera QUI NNodi e TBHits per tutti i thread */
- for (int i=0;i<Opz.Threads;i++) Threads[i].NNodi=Threads[i].TBHits=0;
- /* Probe TB */
- TBScore=0;
- RootInTB=false;
- Ric.TBCardinality = (Opz.SyzygyProbeLimit>Ric.TBLargest ? Ric.TBLargest : Opz.SyzygyProbeLimit);
- if (PopCount(Tutti(Threads)) <= Ric.TBCardinality)
- {
- Threads[0].TBHits = Threads[0].pmosse-Threads[0].mosse;
- // If the current root position is in the tablebases then RootMoves
- // contains only moves that preserve the draw or win.
- RootInTB = root_probe(Threads,Threads[0].mosse,&Threads[0].pmosse,&TBScore);
- if (RootInTB) Ric.TBCardinality = 0; // Do not probe tablebases during the search
- else Threads[0].TBHits=0;
- }
- // Recupera la mossa dalla hash e portala davanti
- TSlotHash sh;
- TTLoad(Threads[0].Scacchiera->Hash,&sh);
- if (sh.Hash==Threads[0].Scacchiera->Hash && sh.MossaPack)
- {
- TMossa mossahash = UnPack(Threads,sh.MossaPack);
- TMossaVal *p;
- for (p=Threads[0].mosse;p<Threads[0].pmosse && p->Mossa!=mossahash;p++);
- if (p<Threads[0].pmosse) // solo se la mossa della hash st? tra quelle generate e filtrate dal tbprobe
- {
- for (;p>=&Threads[0].mosse[1];p--) *p=*(p-1);
- Threads[0].mosse[0].Mossa=mossahash;
- }
- }
- /* inizializza i vari threads copiando l'array partita e le mosse (farlo qui dopo il filtro della tablebase) */
- for (int t=1;t<Opz.Threads;t++) // copia posizione e mosse
- {
- memcpy(Threads[t].Partita,Threads[0].Partita,sizeof(TScacchiera)*(Threads[0].Scacchiera-Threads[0].Partita+1));
- Threads[t].Scacchiera=Threads[t].Partita+(Threads[0].Scacchiera-Threads[0].Partita);
- memcpy(Threads[t].mosse,Threads[0].mosse,sizeof(TMossaVal)*(Threads[0].pmosse-Threads[0].mosse));
- Threads[t].pmosse=Threads[t].mosse+(Threads[0].pmosse-Threads[0].mosse);
- }
- InizializzaKillerHistory(Threads);
- /* Imposta il tempo limite entro il quale ricercare la mossa da eseguire */
- int64_t misurazione;
- TempoInizio = TempoMSec();
- /* A seconda del time control sceglie la formula adeguata */
- int64_t msecpermossa;
- if (movestogo)
- {
- if (inc) msecpermossa = 2*msec/(movestogo+10)+inc; /* movestogo!=0 && inc!=0 */
- else msecpermossa = 2*msec/(movestogo+10); /* movestogo!=0 && inc==0 */
- }
- else
- {
- if (inc) msecpermossa = 4*msec/((mossegiocate>=60 ? 0 : 60-mossegiocate)+40)+inc; /* movestogo==0 && inc!=0 */
- else msecpermossa = 4*msec/((mossegiocate>=60 ? 0 : 60-mossegiocate)+60); /* movestogo==0 && inc==0 */
- }
- if (Opz.Ponder) msecpermossa+=msecpermossa/10; // aggiungi il 10% del tempo se in ponder
- msecpermossa = msecpermossa>((3*msec)/8) ? ((3*msec)/8) : msecpermossa; // caso possibile solo in caso di incremento
- if (Threads[0].pmosse==Threads[0].mosse) msecpermossa/=10; // se c'è solo una mossa riduci di 10 volte il tempo
- Ric.LimiteMSec = TempoInizio + (msecpermossa*28)/64;
- Ric.LimiteUltimoMSec = TempoInizio + msecpermossa*2; // msecpermossa*2 non sar? mai superiore a 3*msec/4 con icremento o msec/2 senza incremento
- /* Inizializza variabili per la ricerca */
- Ric.NRicerca += 0x04; /* essendo uint8_t dopo 64 ricerche parte da 0 */
- Threads[0].Depth=1;
- Ric.NNodiCheck = msecpermossa<1000 ? (msecpermossa+1)*100: 100000; // modifica la distanza tra un controllo del tempo e l'altro a seconda del tempo rimanente
- Ric.ControlloTempo=Ric.NNodiCheck;
- Threads[0].LastScore=0;
- Ric.MultiPVReale=Opz.MultiPV>(Threads[0].pmosse-Threads[0].mosse) ? (Threads[0].pmosse-Threads[0].mosse) : Opz.MultiPV;
- // Avvia i Threads
- for (int i=1;i<Opz.Threads;i++) pthread_create(&Threads[i].Thread,NULL,ThreadSearch,(void *)(&Threads[i]));
- /* Iterative Deepening */
- do {
- /* Lancia in ricerca anche il thread master */
- ThreadSearch(Threads);
- /* salva la mossa ricavata nella hash */
- sh.Hash=Threads[0].Scacchiera->Hash;
- sh.MossaPack = Pack(Threads[0].mosse[0].Mossa);
- sh.Val = Threads[0].alpha;
- sh.ValStatica = Threads[0].alpha;
- assert(Threads[0].Depth>=-128 && Threads[0].Depth<=127);
- sh.Depth=Threads[0].Depth;
- sh.NRicercaNT = Ric.NRicerca|PVNODE;
- TTStore(Threads[0].Scacchiera->Hash,&sh);
- /* se il livello non è il massimo aggiungi un tempo di attesa */
- if (Opz.Strength!=MAXSTRENGTH)
- {
- int64_t attesa=(600-6*Opz.Strength)*(Threads[0].Depth);
- int64_t tempoattuale=TempoMSec();
- if (tempoattuale+attesa>Ric.LimiteMSec) attesa=Ric.LimiteMSec-tempoattuale+10; // aggiungi 10 msec per essere sicuri di superare LimiteMSec
- attesa= attesa<0 ? 0:attesa;
- mySleep(attesa);
- }
- /* recupera il tempo trascorso e calcola il numero dei nodi recuperandoli tra i vari thread e stampa la o le pv */
- misurazione = TempoMSec();
- int64_t NNodi=0;
- int64_t TBHits=0;
- for (int i=0;i<Opz.Threads;i++) { NNodi+=Threads[i].NNodi; TBHits+=Threads[i].TBHits; }
- for (int npv = Ric.MultiPVReale-1;npv>=0;npv--)
- StampaPV(npv,RootInTB,TBScore,misurazione-TempoInizio,NNodi,TBHits,ScacchieraIniziale);
- Threads[0].Depth++;
- /* termina per raggiunto il tempo limite e la ricerca non è di ponder o la profondit? è oltre il limite */
- }while((misurazione<Ric.LimiteMSec || Ric.TipoRicerca!=NORMALE) && Threads[0].Depth<=depthlimit);
- /* se arrivo qui e sono in Ponder significa che la ricerca è terminata prima del previsto, devo attendere stop o ponderhit */
- while (Ric.TipoRicerca!=NORMALE && !Ric.TerminaRicerca)
- {
- char comando[16];
- fgets(comando,16,stdin);
- if (!strncmp(comando,"isready",7)) { printf("readyok\n"); fflush(stdout); }
- else if (!strncmp(comando,"ponderhit",9)) Ric.TipoRicerca=NORMALE; // passa da ponder a ricerca normale
- else if (!strncmp(comando,"stop",4)) Ric.TerminaRicerca=true;
- }
- stampamosse:
- Ric.TerminaRicerca=true; // serve per terminare i thread slave
- Threads[0].Scacchiera=ScacchieraIniziale; // se si arriva da un longjmp reimposta la posizione corretta
- 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 */
- #ifndef NOOUTPUT
- // prendi la prima mossa dell'array (quella migliore) e stampala
- char strmossa[10];
- MoveToStr(strmossa,Threads[0].mosse[0].Mossa,Tratto(Threads));
- printf("bestmove %s",strmossa);
- Muovi(Threads,Threads[0].mosse[0].Mossa);
- TTLoad(Threads[0].Scacchiera->Hash,&sh);
- if (sh.Hash==Threads[0].Scacchiera->Hash && sh.MossaPack) // recupera dalla hash la seconda mossa della pv e usala come ponder move
- {
- MoveToStr(strmossa,UnPack(Threads,sh.MossaPack),Tratto(Threads));
- printf(" ponder %s",strmossa);
- }
- printf("\n");
- fflush(stdout);
- // ATTENZIONE!!! Non viene ripristinata la scacchierainiziale
- #endif
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement