Begreper & referanser
Alle nøkkelbegrepene, formlene og referansene fra Motstandersøk: minimax og alfa-beta, samlet på én side. Bruk denne som oppslag når du leser, øver flashcards eller tar quiz.
Begreper
Sentrale begreper fra kapittelet med korte definisjoner.
Et spill der summen av spillernes nytte er den samme i alle sluttilstander, så det én spiller vinner, taper den andre (zero-sum game).
Treet der roten er starttilstanden, kantene er lovlige trekk og bladene er terminaltilstander med nytte (game tree).
Ett trekk av én spiller. To halvtrekk er én runde der begge har trukket én gang (ply).
Funksjonen som gir tallverdien av terminaltilstanden for spilleren , for eksempel for seier og for tap (utility function).
Nytten MAX får fra en node når begge spiller optimalt derfra: nytten i et blad, den største barneverdien i en MAX-node og den minste i en MIN-node (minimax value).
Minimax-søk som holder to grenser, α og β, langs stien og kutter barn som ikke kan endre valget høyere opp. Rotverdien og trekket blir de samme som med minimax (alpha–beta pruning).
Grensen α er den beste verdien MAX allerede har sikret et sted langs stien fra roten, og den starter på . En MIN-node kutter når (alpha).
Grensen β er den beste verdien MIN allerede har sikret langs stien, og den starter på . En MAX-node kutter når (beta).
Rekkefølgen søket prøver trekkene i. Kommer det beste trekket først, kutter alfa-beta mest og evaluerer omtrent blader (move ordering).
En hashtabell med verdiene til stillinger som allerede er evaluert, slik at en stilling som nås via en annen trekkrekkefølge, ikke regnes ut på nytt (transposition table).
Et raskt anslag på nytten fra en stilling som ikke er terminal, ofte en vektet sum av egenskaper ved stillingen (evaluation function).
Testen som avgjør om søket skal stoppe i en node og bruke Eval i stedet for å søke videre, typisk ved en fast dybde eller i en terminaltilstand (cutoff test).
Et søk med fast dybde ser ikke et uunngåelig tap som ligger rett bak dybdegrensen, og kan velge trekk som bare skyver tapet ut av syne (horizon effect).
Et ekstra søk fra urolige stillinger, der et slag eller en trussel henger i lufta, til stillingen er rolig nok til at evalueringsfunksjonen er til å stole på (quiescence search).
Å droppe trekk som ser dårlige ut, uten å søke dem, for eksempel ved å bare søke de beste trekkene i hver node. Det sparer tid, men kan kutte det beste trekket (forward pruning).
Formler
Hver formel: hva den heter, hvordan den ser ut, og hva symbolene betyr.
Minimax-verdien
Regnes nedenfra og opp: blader har nytten sin, MAX-noder tar det største barnet og MIN-noder det minste. En vanlig feil er å ta det største bladet i hele treet, som om MIN hjalp MAX.
Kuttregelen i alfa-beta
Brukes i hver node etter at et barn har returnert: oppdater , sjekk kuttet, og oppdater så α i en MAX-node eller β i en MIN-node. Det kuttes også ved likhet; å bare kutte ved streng ulikhet er den vanligste feilen.
Tidsbruken til alfa-beta
Sammenlign med for minimax. Med perfekt ordning er den effektive forgreningsfaktoren , så søket rekker omtrent dobbelt så dypt på samme tid. Tallet for tilfeldig ordning er et omtrentlig anslag.
Lineær evalueringsfunksjon
Brukes i nodene der søket stopper. Hver egenskap teller noe ved stillingen, og vekten sier hvor mye det betyr. Formen antar at egenskapene virker hver for seg, noe som ofte ikke stemmer.
Minimax med cutoff
Som minimax, men søket stopper når cutoff-testen slår til (fast dybde eller terminaltilstand) og bruker Eval der. Dybden øker med 1 per halvtrekk.
Kodesnutter
Kodesnutter fra kapittelet, vist literal.
Alfa-beta med ett justerbart blad
blad_F = 3 # @param -10..10 # Roten A er MAX. B og C er MIN-noder, og bladene leses fra venstre mot høyre.barn = {"A": ["B", "C"], "B": ["D", "E"], "C": ["F", "G", "H"]}blad = {"D": 3, "E": 7, "F": blad_F, "G": 8, "H": 6}er_max = {"A": True, "B": False, "C": False}evaluert, kuttet = [], [] def alfabeta(node, alfa, beta): if node in blad: evaluert.append(node) return blad[node], None v, valgt = (float("-inf") if er_max[node] else float("inf")), None for i, b in enumerate(barn[node]): w, _ = alfabeta(b, alfa, beta) if (er_max[node] and w > v) or (not er_max[node] and w < v): v, valgt = w, b if (er_max[node] and v >= beta) or (not er_max[node] and v <= alfa): kuttet.extend(barn[node][i + 1:]) # kutt også ved likhet break if er_max[node]: alfa = max(alfa, v) else: beta = min(beta, v) return v, valgt verdi, trekk = alfabeta("A", float("-inf"), float("inf"))print(f"Minimax-verdi i roten: {verdi}")print(f"Valgt trekk: {trekk}")print(f"Blader evaluert med alfa-beta: {len(evaluert)} av {len(blad)}")print(f"Kuttede noder: {', '.join(kuttet) if kuttet else 'ingen'}")Prøv: sett blad_F fra 3 til 4, og se at linja Kuttede noder: går fra G, H til ingen, mens Minimax-verdi i roten: først endrer seg ved 4.
Trekkordning og antall blader
import random b = 3 # @param 2..5d = 4 # @param 2..6random.seed(4)blader = [random.randint(0, 99) for _ in range(b ** d)]nivaa = [blader] # eksakte minimax-verdier nivå for nivå, MAX på partall dybdefor k in range(d - 1, -1, -1): nivaa.insert(0, [(max if k % 2 == 0 else min)(nivaa[0][i * b:(i + 1) * b]) for i in range(b ** k)]) def alfabeta(k, i, alfa, beta, orden, teller): if k == d: teller[0] += 1 return blader[i] barn = [i * b + j for j in range(b)] if orden == "perfekt": # beste trekk først, slik de eksakte verdiene sier barn.sort(key=lambda x: nivaa[k + 1][x], reverse=(k % 2 == 0)) elif orden == "tilfeldig": random.shuffle(barn) for x in barn: w = alfabeta(k + 1, x, alfa, beta, orden, teller) alfa, beta = (max(alfa, w), beta) if k % 2 == 0 else (alfa, min(beta, w)) if alfa >= beta: # kutt, også ved likhet break return alfa if k % 2 == 0 else beta tilfeldig, perfekt = [0], [0]alfabeta(0, 0, -1, 100, "tilfeldig", tilfeldig)alfabeta(0, 0, -1, 100, "perfekt", perfekt)print(f"Blader uten beskjæring: {b ** d}")print(f"Blader, tilfeldig ordning: {tilfeldig[0]}")print(f"Blader, perfekt ordning: {perfekt[0]}")print(f"Teoretisk b^(d/2): {b ** (d / 2):.0f}")Prøv: sett b til 5 og d til 6, og se at linja Blader, perfekt ordning: blir 249, nær to ganger Teoretisk b^(d/2):, mens tilfeldig ordning trenger nesten ti ganger så mange.
Pseudokode
Pseudokode som forklarer fremgangsmåten steg for steg.
Alfa-beta i pseudokode
alfabeta(node, alfa, beta): hvis node er terminal: returner nytte(node) hvis cutoff(node): returner eval(node) hvis MAX trekker i node: v = -uendelig for barn i barna(node): # venstre mot høyre v = max(v, alfabeta(barn, alfa, beta)) hvis v >= beta: returner v # kutt: MIN over vil aldri slippe hit alfa = max(alfa, v) ellers: v = +uendelig for barn i barna(node): v = min(v, alfabeta(barn, alfa, beta)) hvis v <= alfa: returner v # kutt: MAX over har noe minst like godt beta = min(beta, v) returner v # start: alfabeta(rot, -uendelig, +uendelig)Samme rekursjon som minimax, men med to grenser som sendes nedover. Kuttet skjer også ved likhet, og verdien som returneres etter et kutt, er en grense.
Læringsmål
Hva du skal kunne etter å ha lest kapittelet.
- 01Formaliser et tospillers nullsumspill med starttilstand, trekk, terminaltest og nyttefunksjon
- 02Regn ut minimax-verdien til hver indre node i et spilltre og finn trekket MAX velger
- 03Spor alfa-beta-beskjæring og oppgi de øverste ikke-besøkte nodene med begrunnelse for hvert kutt
- 04Forklar hvorfor trekkordning avgjør hvor mye alfa-beta kutter, og regn med
- 05Forklar evalueringsfunksjoner, cutoff, horisonteffekten og rosøk
- 06Bruk nyttevektorer til å regne ut verdier i spill med flere enn to spillere