Ci scusiamo per la risposta tardiva ( 4 anni !)
NegaScout è un algoritmo molto semplice. Per capire dovremmo rivedere l' approfondimento iterativo .
L'approfondimento iterativo è una tecnica per un motore di scacchi per cercare la profondità i, quindi i + 1, quindi i + 2 ecc. Questo è un esempio di programmazione dinamica. Durante ogni iterazione abbiamo la migliore idea di quale sarebbe la mossa migliore. La maggior parte dei motori di scacchi manterrebbe questa mossa in una tabella di hashing.
Immagina di essere ora all'iterazione i + 1 e abbiamo la mossa migliore dall'ultima iterazione i. Ora abbiamo 5 nodi da cercare, dovremmo farlo?
Se assumiamo di aver svolto un buon lavoro durante l'ultima iterazione, la mossa migliore dall'ultima iterazione (che otteniamo dalla tabella hash) dovrebbe essere anche la mossa migliore per l'attuale iterazione.
Se la nostra ipotesi è corretta, dovremmo essere in grado di risparmiare tempo cercando ogni mossa diversa dalla mossa migliore (le quattro mosse non nella tabella hash) con a null window
. Una finestra nulla è simile a:
score := -pvs(child, depth-1, -α-1, -α, -color)
Nota -α-1
e -α
. Sono i valori alfa e beta che daremo alla prossima ricorsione. Poiché la larghezza della finestra è solo 1, la ricerca fallirà sempre:
- Se fallisce sotto α, la mossa è peggiore di quella che già abbiamo, quindi possiamo ignorarla
- Se fallisce sopra β, la mossa è troppo buona per essere giocata, quindi possiamo ignorarla
- Altrimenti, dobbiamo fare una nuova ricerca correttamente
Certo, cercheremo comunque la mossa migliore (quella che otteniamo dalla tabella hash) con una finestra alfa e beta appropriata. Dobbiamo farlo perché dobbiamo conoscere esattamente il valore del nodo, non possiamo semplicemente ignorarlo.
Tutto ciò che ho detto è implementato nel seguente pseudocodice. Lo pseudocodice specifica child is not first child
ma questo è un modo per verificare se la mossa è anche la mossa migliore nella precedente iterazione. La tabella hash è l'implementazione più comune.
# Negasort is also termed Principal Variation Search - hence - pvs
function pvs(node, depth, α, β, color)
if node is a terminal node or depth = 0
return color x the heuristic value of node
for each child of node
if child is not the first child
# search with a null window
score := -pvs(child, depth - 1, -α - 1, -α, -color)
# if it failed high, do a full re-search
if α < score < β
score := -pvs(child, depth - 1, -β, -score, -color)
else
score := -pvs(child, depth - 1, -β, -α, -color)
α := max(α, score)
# beta cut-off
if α >= β
break
return α