I motori di scacchi memorizzano tutte le posizioni precedentemente analizzate tra le mosse


17

Sto iniziando a giocare con i motori di scacchi. Noto che i migliori motori di scacchi possono impiegare diversi minuti per muoversi. Mi chiedo perché. Prima di ogni mossa il motore esamina a fondo tutte le mosse legali future. Tuttavia, sembra quindi ripetere questo esercizio per la mossa successiva. Dato che la mossa precedente era già inclusa nell'albero delle mosse esaminate, non è inefficiente? O ho frainteso?

[Modifica: suppongo che il motivo per cui le analisi degli spostamenti non sono memorizzate nella cache sia dovuto ad alcune limitazioni di memoria del computer che rendono più veloce il riavvio dell'analisi]

Risposte:


20

La programmazione dei motori per gli scacchi è un territorio molto complicato, quindi ti indicherò il Wiki sulla programmazione degli scacchi , che contiene molte ottime informazioni su questo argomento.

sfondo

I calcoli degli scacchi (e molte altre cose simili) sono generalmente modellati e pensati come "alberi di gioco" o " alberi di decisione ". In generale, questo albero è un grafico diretto, con un nodo in alto (la posizione corrente), che porta a un nodo per ogni possibile spostamento, ognuno dei quali porta a più nodi per ogni possibile spostamento successivo e così via.

Nella loro forma più semplice, a forza bruta, i motori di scacchi generano tutte le posizioni su questo albero fino a un limite di profondità ("piega"), valutando ogni posizione risultante sulla base di alcuni criteri complessi 1 . Quindi gioca la mossa che sembra portare al miglior risultato. Al giorno d'oggi, sono state sviluppate molte tecniche davvero complicate per limitare il numero di posizioni che il motore deve guardare, ma le ignorerò ai fini di questa risposta, perché non cambiano il vero problema in mano.

Tangente matematica

Il motivo fondamentale per cui i motori impiegano generalmente lo stesso tempo per considerare ogni mossa è che la dimensione dell'albero decisionale aumenta esponenzialmente con la profondità ( k).

Considera la posizione iniziale. La parte superiore dell'albero ( k=0) è un nodo. Ci sono venti possibili prime mosse per il Bianco, quindi ci sono venti nodi in profondità k=1. Quindi, il Nero ha anche venti mosse disponibili per ciascuna delle opzioni del Bianco: quindi k=2, ci sono 20 * 20 = 400possibili posizioni! E peggiora solo quando i giocatori sviluppano i loro pezzi!

Ad esempio, facciamo finta che ci siano sempre venti mosse possibili per ciascun giocatore in un dato momento 2 . Comandi al computer di guardare avanti cinque mosse per ogni giocatore (dieci strati). Diamo un'occhiata alle dimensioni dell'albero della forza bruta ad ogni livello. Per divertimento, esamineremo anche il numero totale di posizioni nella struttura (dall'alto al livello indicato).

Ply |    Positions   |  Total Tree Size
----------------------------------------
 0  | 1              | 1
 1  | 20             | 21
 2  | 400            | 421
 3  | 8000           | 8421
 4  | 160000         | 168421
 5  | 3200000        | 3368421
 6  | 64000000       | 67368421
 7  | 1280000000     | 1347368421
 8  | 25600000000    | 26947368421
 9  | 512000000000   | 538947368421
10  | 10240000000000 | 10778947368421

Il risultato di ogni livello che è esponenzialmente più grande del livello precedente è che la dimensione dell'intero albero è dominata dal livello inferiore . Considera l'esempio sopra: solo l'ultimo livello contiene dieci trilioni di nodi. L'intero resto dell'albero contiene solo cinquecento miliardi. Il decimo strato contiene circa il 95% dei nodi nell'intero albero (questo è vero per ogni livello). In pratica, ciò significa che tutto il tempo di ricerca viene impiegato per valutare l '"ultima" mossa.

Risposta

Quindi, come si collega alla tua domanda? Bene, diciamo che il computer è impostato su dieci strati, come sopra, e inoltre "ricorda" i risultati delle sue valutazioni. Calcola una mossa, la gioca e poi fai una mossa. Ora sono state fatte due mosse, quindi elimina tutte le posizioni dalla memoria relative alle mosse che non sono avvenute e viene lasciato con un albero che scende le otto mosse rimanenti che ha già calcolato: 26.947.368.421 posizioni!

Tutto ok! Quindi dobbiamo solo calcolare gli ultimi due strati! Utilizzando la nostra stima di 20 mosse per ogni profondità, il numero totale di mosse che dobbiamo calcolare qui è ancora superiore a dieci trilioni. Le posizioni che abbiamo già calcolato rappresentano solo il 2,5% delle possibilità! Quindi, anche memorizzando nella cache i risultati dell'ultima mossa, il meglio che possiamo sperare è un aumento della velocità del 2,5%! In sostanza, questo è il motivo per cui anche se il tuo programma memorizza nella cache i risultati precedenti, di solito non vedi una significativa accelerazione tra le mosse (tranne i casi in cui il computer trova un compagno forzato o qualcosa del genere, ovviamente!).


Dichiarazione di non responsabilità

C'è molta complessità in questa domanda, motivo per cui mi sono legato al wiki di programmazione all'inizio e ho solo tentato di spiegare la risposta in termini matematici generali. In realtà, i programmi fanno generalmente parte di cache dell'albero di trasloco in trasloco, e ci sono altri motivi per cui questo è sufficiente di per sé - alcuni motivi semplici (ad esempio, una certa linea potrebbe guardare bene fuori per otto mosse, ma finisce con un back -rank mate on move nine!) e molti altri molto complicati (generalmente legati a vari metodi di potatura intelligenti). Quindi il computer deve continuare a guardare più avanti nel tentativo di evitare di fare cattive ipotesi basate sulla profondità di taglio della mossa precedente.


1 Non entrerò nelle funzioni euristiche qui, perché questa è la sua area incredibilmente complessa, ma spesso ci sono alcuni guadagni che possono essere raggiunti anche qui tramite schemi di memorizzazione della posizione.

2 Un fattore di ramificazione medio di 20 è probabilmente troppo basso .


Molto interessante, questo spiega perché la mia RAM quasi crolla quando ho analizzato a fondo il mio motore (un mistero che mi aveva sbalordito da un po 'di tempo).
Pablo S. Ocal,

Grazie! Molto interessante. Ho trovato affascinante la discussione sulla wiki del motore di scacchi.
Dom

3

Un tipico motore di scacchi memorizzerà alcune delle posizioni e i relativi punteggi alfa-beta in una tabella di trasposizione che può essere consultata durante le ricerche successive. Questa tabella non viene consultata direttamente per scegliere la mossa successiva, ma rende la ricerca di quella mossa più efficiente in due modi.

  1. Una posizione verrà probabilmente trovata più volte in un albero di ricerca, essendo raggiunta da una trasposizione o permutazione di una sequenza di mosse. Poiché la tabella può essere consultata, è possibile che una tale posizione debba essere valutata solo poche volte (per diverse profondità di ricerca fisse) anziché dozzine di volte in quanto la posizione viene visitata e rivista.

  2. Una tecnica standard per le ricerche alfa-beta consiste nell'utilizzare l' approfondimento iterativo , sondando ripetutamente l'albero a una profondità di ricerca maggiore fino a raggiungere la profondità terminale. I punteggi di valutazione calcolati nelle iterazioni precedenti vengono utilizzati per ordinare le mosse ricercate nelle iterazioni successive. Alpha-beta è noto per avere prestazioni migliori (ad esempio potare di più dell'albero di ricerca) se vengono cercate mosse valide prima di mosse sbagliate.


3

Esempio che evidenzia la memoria del motore:

Considera le posizioni in cui vengono scoperte profonde novità teoriche, in particolare il gioco Caruana vs Topalov giocato quest'anno. Quando lasci che il motore analizzi la posizione dopo la mossa 12 per un periodo di tempo più o meno breve (diciamo 10-15 minuti) puoi controllare le mosse suggerite e vedere che il TN ( 13.Re2!) non appare tra di loro. Presentare la mossa da soli, tornare indietro di una mossa e lasciare che il motore analizzi nuovamente la stessa posizione per più o meno lo stesso tempo. Sorprendentemente, dopo qualche pensiero, ora il motore considera il TN tra le migliori mosse e lo approva.

EDIT: la risposta originale (mantenuta sotto) è sbagliata, tuttavia, fornisce un utile esempio della memoria del motore, che è stata citata in alto.

Per quanto ne so, non lo fanno, cioè iniziano la ricerca dell'albero quasi da zero ad ogni mossa.

Tuttavia, devono avere un qualche tipo di funzione che attualizza i valori per ogni spostamento e questa funzione ha sicuramente una memoria a breve termine. Alcuni esempi sono posizioni in cui vengono scoperte profonde novità teoriche, in particolare il gioco Caruana vs Topalov giocato quest'anno. Quando lasci che il motore analizzi la posizione dopo la mossa 12 per un periodo di tempo più o meno breve (diciamo 10-15 minuti) puoi controllare le mosse suggerite e vedere che il TN ( 13.Re2!) non appare tra di loro. Presentare la mossa da soli, tornare indietro di una mossa e lasciare che il motore analizzi nuovamente la stessa posizione per più o meno lo stesso tempo. Sorprendentemente, dopo qualche pensiero, ora il motore considera il TN tra le migliori mosse e lo approva.

Non sono un esperto di software di scacchi, ma questo succede. Questo può essere almeno parzialmente spiegato se (come detto) la funzione che valuta i movimenti per la posizione ha un po 'di memoria.


2
No. I motori non avviano la ricerca dell'albero da zero. Fare riferimento alla mia risposta.
SmallChess,

Scusate ma trovo che la vostra risposta sia un po 'fuorviante
BlueTrin

1
Ho provato a renderlo più chiaro. Come detto, la risposta è sbagliata, tuttavia l'esempio vale ed è una buona cosa da controllare (per noi romantici, ci dà alcune speranze che nonostante i computer siano molto più forti degli umani, a volte intuizione, esperienza e duro lavoro possono "battere" il loro originale).
Pablo S. Ocal,

@pablo, il tuo esempio va bene. C'è memoria perché la prima volta che si esegue la ricerca, il motore memorizza le valutazioni di posizione in una tabella. Quando cerchi di nuovo la stessa posizione, il motore sarà in grado di effettuare ricerche molto più velocemente. Pertanto ti darà un risultato diverso.
SmallChess

L'ultima modifica è stata per @BlueTrin, che ha pensato che fosse fuorviante.
Pablo S. Ocal,

2

Henry Keiter ti ha già dato una risposta generale, ti darò una risposta più tecnica. Si tratta di tabella di trasposizione, profondità di ricerca e cutoff. La discussione qui è MOLTO più tecnica di altre risposte, ma sarà utile per chiunque voglia imparare la programmazione degli scacchi.

È un malinteso comune che se una posizione fosse valutata in precedenza, il punteggio di valutazione potrebbe essere riutilizzato fintanto che c'è memoria sufficiente per memorizzare le mosse. La programmazione degli scacchi è più complicata di così. Anche con una memoria infinita, dovresti cercare nuovamente le posizioni. Per ogni mossa, viene assegnato un punteggio di valutazione con la sua profondità e il suo limite. Ad esempio, se il motore memorizza una mossa per errore, la voce della tabella avrebbe un limite inferiore. Ciò significa che, se stai cercando una posizione, dovrai comunque verificare se è possibile utilizzare il punteggio di valutazione precedente.

A parte questo, ogni valutazione ha una profondità collegata ad essa. In un framework di approfondimento iterativo, man mano che aumenti la profondità di ogni iterazione, dovresti comunque cercare le posizioni che hai già cercato nella precedente iterazione.

La risposta breve alla tua domanda è che un motore memorizza tutte le precedenti posizioni analizzate (purché memoria sufficiente), ma quei risultati memorizzati non possono essere riutilizzati facilmente come si potrebbe pensare . In una fase di apertura in cui vi sono meno ripetizioni, i risultati memorizzati sono più utili per l'ordinamento delle mosse e una dozzina di euristiche di riduzione delle mosse. Ad esempio, si potrebbe presumere che la mossa migliore dall'ultima profondità sia la mossa migliore nella profondità corrente, quindi ordiniamo gli elenchi di mosse e cerchiamo la mossa migliore prima di qualsiasi altra mossa. Si spera che avremmo un taglio iniziale molto alto.

Non abbiamo memoria infinita per la memorizzazione delle posizioni. Dovremmo definire un algoritmo di hashing. L'algoritmo di hashing Zobrist ci offre una distribuzione pseudo-casuale, ma prima o poi dovremmo comunque sostituire alcune voci esistenti.


0

Ogni motore ha il proprio schema di gestione del tempo. Alcuni motori e GUI ti consentono di impostare il ritmo con cui il motore giocherà. I motori calcolano / valutano / minimax sempre quanto possono dare i vincoli imposti dalle subroutine di gestione del tempo o dalle impostazioni dell'utente. Se un motore pensa a lungo, è probabile che il controllo del tempo per il gioco sia lento o che l'utente lo abbia impostato per giocare lentamente.

Le posizioni e le valutazioni calcolate dal motore sono memorizzate in una tabella hash. L'utente può impostare la dimensione dell'hash disponibile nelle impostazioni della maggior parte dei motori UCI. Il motore stesso utilizza una certa quantità di RAM e, se si imposta una dimensione della tabella di hash troppo elevata, il computer inizierà a memorizzare l'hash sul disco rigido sotto forma di RAM virtuale. L'accesso alla memoria del disco rigido è più lento della RAM e di solito è possibile ascoltare il rumore del disco rigido. Molti utenti impostano la dimensione della tabella hash in modo che si adatti alla RAM disponibile.

Una grande parte di qualsiasi tabella di hash diventa inutile dopo che il motore e il suo avversario hanno fatto le loro mosse poiché le altre posizioni considerate non sono più rilevanti. Il motore riutilizzerà le valutazioni memorizzate nell'hash, ma alcune delle valutazioni si dimostrano errate a causa degli effetti dell'orizzonte una volta che il motore avanza più in profondità sulla stessa linea, quindi spesso deve riordinare le sue mosse candidate.

Poiché la quantità di hash è limitata, un motore deve anche decidere quali informazioni eliminare dall'hash quando aggiunge nuove informazioni. Il motore non sa in anticipo quali mosse verranno giocate, quindi potrebbe inavvertitamente eliminare le informazioni che sarebbero state utili in quanto aggiunge nuovi dati.

I motori in generale non esaminano tutte le mosse legali a una certa profondità. Eliminano determinati rami dell'albero dalla considerazione in base alla potatura in avanti e all'indietro. Inoltre, se una posizione del nodo foglia ha acquisizioni o controlli ancora da effettuare, il motore continuerà lungo quella linea fino a raggiungere una posizione silenziosa (quiescente). L'albero reale è probabilmente abbastanza profondo in alcuni punti, mentre altre linee potrebbero essere state troncate dopo un piccolo numero di mosse.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.