340 kB - Ruhr-Universität Bochum

Werbung
Masterarbeit
Alpha-Beta-Pruning
Oliver Kock
Bochum, Februar 2009
Fakultät für Mathematik
Ruhr-Universität Bochum
Inhaltsverzeichnis
Kapitel I. Einleitung
4
Kapitel II. Grundlagen der Spieletheorie
II.1. Zwei-Personen-Nullsummenspiele mit perfekter
Information
II.2. Spielbäume
II.3. Auswertung eines Spielbaums
II.4. Prinzipieller Aufbau eines Computerprogramms
II.5. Der Bestimmtheitssatz von Zermelo
6
Kapitel III. Alpha-Beta-Pruning
III.1. Beschreibung eines Vorläufers
III.2. Alpha-Beta-Pruning: Beschreibung, Algorithmus und
Korrektheitsbeweis
III.3. Analyse des besten Falls
III.4. Analyse des schlechtesten Falls
III.5. Allgemeinere Ergebnisse
7
8
10
12
14
18
18
21
25
31
32
Kapitel IV. Spielabhängige und allgemeine Modifikationen des
Alpha-Beta-Prunings
IV.1. Vorsortierung der Züge
IV.2. Hash-Funktionen
IV.3. Endspieldatenbanken
IV.4. Suchfenstertechnik
IV.4.1. F-Verbesserung
IV.4.2. L-Verbesserung
IV.5. Nullfenster-Suchverfahren
IV.5.1. Negascout-Verfahren
IV.5.2. F-Verbesserung
IV.5.3. L-Verbesserung
IV.5.4. TL-Verbesserung
33
33
34
38
41
41
43
43
44
46
47
47
Literaturverzeichnis
49
3
KAPITEL I
Einleitung
Schach ist sicherlich eines der bekanntesten Brettspiele der Welt. Allein die Strategie der zwei Spieler ist für den Sieg ausschlaggebend. Es
gibt keine zufälligen Elemente. Auch können dem Gegner keine wichtigen Informationen vorenthalten werden, wie es bei den meisten Kartenspielen der Fall ist. Dort hält man im Allgemeinen Karten auf der Hand,
die der Spielpartner nicht einsehen kann. Schach oder allgemeiner eine
Klasse von Spielen, die ähnliche Eigenschaften wie Schach aufweisen,
bieten sich damit für die Erforschung künstlicher Intelligenz besonders
an.
Ziel dieser Arbeit wird es sein, für diese Klasse von Spielen einen
möglichst starken automatischen Spielpartner im Form eines Computerprogramms zu konstruieren. Die zentrale Frage, die es zu beantworten gilt, ist:
Welcher Spielzug ist in der aktuellen Situation optimal?
Ein mathematischer Ansatz zur Lösung besteht darin, alle denkbaren
Züge zu verfolgen, bis eine Endstellung erreicht ist. Dort lässt sich ablesen, welcher der beiden Spieler gewonnen hat. Durch vollständige Suche
wird so ein exaktes Ergebnis für die Optimalität eines Zuges berechnet.
Eine ausführliche Herleitung dieser grundlegenden Spielbaumsuche sowie Details zur Klasse der Spiele, auf die dieser Algorithmus anwendbar
ist, finden sich in Kapitel II. Als theoretische Grundlage dient der Bestimmtheitssatz von Zermelo, welcher in Abschnitt II.5 formuliert und
bewiesen wird.
Nun gibt es Spiele, die relativ komplex sind. Hier ist ein hoher Verzweigungsgrad des Spielbaumes gemeint, d.h. die Zahl möglicher Züge
pro Situation ist relativ hoch. Für komplexe Spiele kann diese simple Spielbaumsuche nicht vollständig durchgeführt werden, weil sie zu
lange dauern würde. In Kapitel III dieser Arbeit wird ein Algorithmus vorgestellt, der als Verbesserung der normalen Spielbaumsuche
interpretiert werden kann. Spielzüge, die nicht zu einem besseren Ergebnis führen können, werden direkt erkannt und brauchen nicht näher
untersucht werden. Dieser Algorithmus heißt Alpha-Beta-Pruning. Er
wird in Kapitel III ausführlich hergeleitet und es wird bewiesen, dass
das Ergebnis des Algorithmus korrekt ist. Außerdem erfolgt eine kurze
4
I. EINLEITUNG
5
Analyse der Laufzeit und es wird eine gewisse Optimalität gezeigt.
In der Praxis wird das Alpha-Beta-Pruning häufig mit Techniken
kombiniert, wie sie in der Informatik gebräuchlich sind. Die ersten Abschnitte des Kapitels IV dienen der Vorstellung dieser Techniken. Exemplarisch seien hier die beiden Stichworte Hash-Funktion und Endspieldatenbank genannt.
Abschließend werden in den Abschnitten IV.4 und IV.5 einige Modifikationen des Alpha-Beta-Prunings präsentiert, die kleinere Schwächen
beheben sollen. Sie können als optimierte Varianten des ursprünglichen
Algorithmus verstanden werden.
KAPITEL II
Grundlagen der Spieletheorie
Bei Spielen bestimmen mehrere Faktoren darüber, wer am Ende gewinnt. Im Wesentlichen lassen sich diese jedoch auf zwei verschiedene
Ursachen eingrenzen:
1. Zufall
2. Strategie
Bei Gesellschaftsspielen tritt der Zufall vor allem in Form eines
Würfels auf. Auch das Mischen von Spielkarten bewirkt einen zufälligen Einfluss auf das Spielergebnis. Als Beipiele für reine Glücksspiele
seien hier Lotto und Roulette genannt. Aber nur wenige Spiele hängen
einzig vom Zufall ab. Bei vielen Spielen ist über eine zufällige Komponente hinaus zusätzlich strategisches Geschick notwendig, um gewinnen
zu können. Etwa bei Skat, Kniffel oder Mensch ärgere dich nicht“ ist
”
dies der Fall. Schließlich gibt es noch solche Spiele, bei denen die Zufallskomponente gar keine Rolle spielt, z.B. Schach oder Go. Sie werden
kombinatorische Spiele genannt. Ihr Schwierigkeitsgrad besteht allein
aus einer großen Anzahl von möglichen Zügen. Bevor die Betrachtung
dieser kombinatorischen Spiele näher präzisiert wird, folgt zunächst eine formale Definition eines Spiels:
Definition II.0.1. Ein Spiel wird durch seine Spielregeln charakterisiert. Folgende Fragen müssen darin beantwortet werden:
• Wie viele Spieler sind zu dem Spiel zugelassen?
• Für jeden möglichen Spielstand:
– Wer ist am Zug?
– Welche Zugmöglichkeiten bestehen für den ziehenden Spieler?
– Auf Basis welcher Informationen hat er seine Entscheidung zu treffen?
• Für Spielstände, an denen das Spiel beendet ist: Wer hat wieviel gewonnen?
• Falls Zufall im Spiel ist: Wie wahrscheinlich sind die möglichen
Ergebnisse?
Falls ein Spieler während eines Spiels die Gelegenheit hat, im Rahmen
der Spielregeln zu handeln, so wird dieser Spielabschnitt als Spielzug
6
II.1. ZWEI-PERSONEN-NULLSUMMENSPIELE
7
bezeichnet.
Besonders bei der Betrachtung von kombinatorischen Spielen kommt
eine zentrale Frage auf:
Wie findet man einen optimalen Spielzug?
Hier gibt es schliesslich (mindestens) einen besten Zug, da zufällige
Einflüsse ausgeschlossen sind. Im Folgenden wird ein Teilbereich der
kombinatorischen Spiele definiert, in dem diese Frage durch einen Algorithmus beantwortet werden kann.
II.1. Zwei-Personen-Nullsummenspiele mit perfekter
Information
Definition II.1.1. Ein gegebenes Spiel heißt Zwei-Personen-Nullsummenspiel mit perfekter Information, falls folgende Kriterien erfüllt
sind:
• Das Spiel wird von zwei Personen gespielt.
• Der Gewinn des einen Spielers entspricht dem Verlust des anderen Spielers, d.h. Verlust wird als negativer Gewinn interpretiert und die Summe beider Gewinne beträgt Null.
• Sämtliche Informationen über den erreichten Spielstand liegen
beiden Spielern offen.
• Der Zufall ist ausgeschlossen.
• Jeder Spieler hat zu jedem Zeitpunkt nur endlich viele Zugmöglichkeiten.
• Das Spiel endet nach einer begrenzten Anzahl von Zügen.
Warum gerade diese Forderungen an zu untersuchende Spiele gestellt werden, wird in Abschnitt II.5 deutlich. Dort wird ausgeführt,
dass der Bestimmtheitssatz von Ernst Zermelo für Zwei-Personen-Nullsummenspiele mit perfekter Information gilt und welche Konsequenzen
diese Tatsache für die Suche nach einem optimalen Zug hat. Es wird
für das gesamte Kapitel II davon ausgegangen, dass ein Zwei-PersonenNullsummenspiel mit perfekter Information vorliegt, wenn von einem
Spiel gesprochen wird.
Bemerkung II.1.2. In Definition II.1.1 wird nicht explizit gefordert, dass die Spieler abwechselnd ziehen. Gleichzeitige Züge sind jedoch gemäß dem dritten Punkt der Definition ausgeschlossen, so dass
von einer abwechselnden Zugfolge ausgegangen werden kann.
Definition II.1.3. Eine Situation im Spiel, wie sie vor und nach
Spielzügen auftreten kann, heißt (Spiel-)Position. Sie enthält alle Angaben über den aktuellen Spielstand sowie die Angabe, welcher Spieler
gerade am Zug ist.
Eine Position, in der ein Spiel endet, heißt Endposition.
II.2. SPIELBÄUME
8
Ein Computerprogramm kann den Ausgang eines Spiels und speziell die damit verbundenen Gewinne nur in Endpositionen verlässlich
bewerten, da nur dort die Gewinne bzw. Verluste direkt ablesbar sind.
Zur Bewertung der Gewinnaussichten in anderen Situationen müssten
Schätzwerte herangezogen werden. Daraus ergibt sich direkt ein wesentlicher Unterschied zwischen einer menschlichen Strategie und einer
computergestützten Analyse:
• Computer können (zumindest theoretisch) jeden möglichen Zug
inklusive aller Antworten des Gegners betrachten. Kein Spielzug wird im Voraus ausgeschlossen, da erst am Ende des Spiels
ablesbar ist, ob eine Zugfolge von Erfolg gekrönt ist. Zumindest
wird erst nach einigen Doppelzügen ein verläßlicher Schätzwert
für die Gewinnaussichten erzielt.
• Menschen hingegen wiegen nur einige wenige Züge gegeneinander ab. Es entwickelt sich ein Gefühl dafür, welche Züge
erfolgsversprechend sind und schlechte Züge werden intuitiv
ausgeschlossen.
Die Details einer Computersuche werden im Laufe dieses Kapitels
entwickelt. Hier soll nur ein erster Eindruck der grundlegenden Strategie vermittelt werden.
II.2. Spielbäume
Zur grafischen Darstellung der Suche nach einem optimalen Zug eignen sich Bäume besonders gut. Sie definieren eine hierarchische Struktur auf einer Menge von Elementen. Ein bekanntes Beispiel eines Baums
ist ein Familien-Stammbaum.
Die folgenden Definitionen führen Bäume ein, wie sie als Veranschaulichung von Spielanalysen verwendet werden können.
Definition II.2.1. Ein Baum ist ein Paar (K, Rer ), wobei K eine
Menge von beliebigen Elementen ist, die Knoten genannt werden. Unter
allen Knoten gibt es einen ausgezeichneten Wurzelknoten (oder kurz
Wurzel ) w. Weiter wird auf der Menge K der Knoten eine zyklenfreie
Relation
Rer ⊂ K × K
definiert (genannt Elternrelation“), so dass für jeden Knoten
”
k ∈ K \ {w} genau ein Knoten ke 6= k existiert mit (ke , k) ∈ Rer .
Definition II.2.2. Es werden einige Bezeichnungen definiert:
• Falls (ke , k) ∈ Rer ist, heißt ke Elternknoten von k und k heißt
Kind (bzw. Kinderknoten) von ke .
• Knoten k, für die es kein k0 mit (k, k0 ) ∈ Rer gibt, heißen
Blätter des Baumes bzw. Blattknoten oder terminale Knoten.
II.2. SPIELBÄUME
9
Abbildung II.2.1. Beispiel eines Baums
Alle Knoten, die keine Blätter sind, heißen nicht-terminal oder
innere Knoten.
Da die Definition eines Baumes doch etwas technisch ist, wird zusätzlich eine einfache Charakterisierung von Bäumen angegeben.
Bemerkung II.2.3. Ein Baum kann rekursiv aufgebaut werden wie
folgt:
• Ein einzelner Knoten ist ein Baum. Dieser Knoten ist gleichzeitig Wurzel des Baums.
• Sei k ein Knoten und B1 , B2 , . . . , Bn Bäume mit jeweiligen
Wurzeln k1 , k2 , . . . , kn . Dann entsteht ein neuer Baum, indem
man k zum Elternknoten von k1 , k2 , . . . , kn macht. Im neuen
Baum ist k der ausgezeichnete Wurzelknoten und k1 , k2 , . . . , kn
seine Kinder.
In Abbildung II.2.1 ist ein typisches Beipiel eines Baums zu sehen.
Die Relation Rer gibt in diesem Fall die Hierarchie des Enthalten”
seins“ an. Ein Buch enthält seine Kapitel und die Kapitel enthalten
wiederum Abschnitte. Links ist eine typische Darstellung in einem Inhaltsverzeichnis und rechts eine Darstellung als Baumform zu sehen.
Definition II.2.4. Ein ungerichteter Graph ist ein Paar (V, E), wobei V eine Menge von Knoten und E ⊂ V × V eine Menge von Kanten
(d.h. Verbindungen zwischen Knoten) ist. Weiterhin muss (b, a) ∈ E
gelten, falls (a, b) ∈ E ist.
Die Forderung (a, b) ∈ E ⇒ (b, a) ∈ E bewirkt, dass in der Kantenmenge keine gerichteten Kanten auftreten können, d.h. die Knoten
II.3. AUSWERTUNG EINES SPIELBAUMS
10
a und b sollen so verbunden werden, dass keine explizite Richtung angegeben wird.
Da später (in Abschnitt III.5) der Begriff eines Pfades und speziell
die Pfadlänge benötigt wird, ist eine Verbindung zwischen Bäumen und
ungerichteten Graphen hilfreich:
Bemerkung II.2.5. Ein Baum B = (K, Rer ) mit Wurzel w entspricht einem ungerichteten Graphen G = (V, E) mit ausgezeichnetem
−1
ist. Die Umkehrrelation
Knoten w, wobei V := K und E := Rer ∪ Rer
−1
Rer
ist dabei definiert als
−1
Rer
:= {(b, a) : (a, b) ∈ Rer }.
G ist hierbei zyklenfrei, da Rer ebenfalls zyklenfrei ist.
Definition II.2.6. Gegeben sei ein ungerichteter Graph G = (V, E).
Ein Pfad P = (v1 , v2 , . . . , vn ) ist eine Folge von Knoten vi ∈ V,
i = 1, 2, . . . , n, für die gilt:
(vi , vi+1 ) ∈ E für alle i ∈ {1, 2, . . . , n − 1}
Weiterhin gelte vi 6= vj , falls i 6= j.
Die Länge des Pfades P = (v1 , v2 , . . . , vn ) ist gegeben durch die Anzahl
seiner Kanten, nämlich n − 1.
Aber nun zurück zum eigentlichen Thema, den Spielen. Spielabläufe
können in Baumform dargestellt werden:
Definition II.2.7. Ein Baum heißt Spielbaum, falls seine Knoten den Positionen des Spiels entsprechen. Ebenso entspricht die Relation Rer den Spielzügen. Genauer gilt für die Positionen p und p0
(p, p0 ) ∈ Rer , wenn es bei Spielposition p einen Spielzug gibt, der zu
Position p0 führt.
Mit anderen Worten: Um Spiele in Baumform darzustellen, Wird
die Ausgangsstellung als Wurzel des Baumes interpretiert. Allgemein
werden dann alle möglichen Positionen, die durch einen legalen Spielzug
erreicht werden können, als die Kinder des Ausgangsknotens definiert.
II.3. Auswertung eines Spielbaums
Nachdem die Darstellung des Problems durch Bäume gelöst ist,
wird näher auf die eigentliche Problemstellung eingegangen. Zur Auswertung eines Spielbaums stellt sich zunächst die Frage, wie man die
Güte von Spielpositionen in Zahlen messen kann. Prinzipiell wird ein
höherer Zahlwert eine bessere Position bedeuten. Doch bereits hier gibt
es zwei mögliche Varianten:
• Ansatz 1 : Es wird der Wert einer Position stets aus Sicht von
Spieler A bewertet. Hohe Werte bedeuten dann, dass Spieler
A einen Vorteil hat. Negative Werte sprechen für Spieler B.
II.3. AUSWERTUNG EINES SPIELBAUMS
11
Abbildung II.3.1. Situation innerhalb eines Baums
• Ansatz 2 : Der Wert einer Position wird aus Sicht desjenigen
Spielers ermittelt, der gerade am Zug ist. Wieder bedeuten
hohe Werte einen Vorteil für den jeweiligen Spieler.
Dieser Unterschied mag vielleicht nebensächlich erscheinen. Er hat jedoch große Auswirkungen auf die folgenden Überlegungen zur Auswertung eines Spielbaums. Später werden folgerichtig auch zwei verschiedene Versionen einer Spielbaumsuche entstehen.
Bereits klar ist, dass nur Endpositionen direkt ausgewertet werden
können. Schließlich kann man nur an ihnen direkt den Gewinner eines Spiels ablesen. Für andere Positionen bzw. nicht-terminale Knoten
im Spielbaum erfolgt eine rekursive Definition der Bewertungsfunktion
F (p).
Ansatz 1 :
Für Blätter des Spielbaums ist
Bewertungsfunktion möglich:

 ∞
−∞
F (p) =
 0
wie erwähnt eine direkte Definition der
bei Sieg für Spieler A
bei Sieg für Spieler B
bei Unentschieden
Für nicht-terminale Knoten sei Situation II.3.1 gegeben. Die Werte
der Positionen p1 , p2 , . . . , pd seien bekannt. Falls Spieler A in Position
p am Zug ist, wird er einen Spielzug derart wählen, dass der Wert der
Folgeposition pi möglichst hoch ist. Analog wird Spieler B einen Zug
wählen, so dass der Wert der Folgeposition möglichst niedrig ausfällt:
max{F (p1 ), . . . , F (pd )}, falls Spieler A am Zug ist
F (p) =
min{F (p1 ), . . . , F (pd )}, falls Spieler B am Zug ist
So ist die Bewertungsfunktion rekursiv für alle Knoten des Baumes
definiert. Bei diesem Ansatz wird stets derjenige Spieler, der an der
Wurzel des Baumes am Zug ist, Spieler A genannt. Somit muss der
Wert des Wurzelknotens stets maximiert werden.
Ansatz 2 :
Hier bezeichnet F (p) den Wert einer Position aus Sicht des Spielers,
II.4. PRINZIPIELLER AUFBAU EINES COMPUTERPROGRAMMS
12
der gerade am Zug ist. Der Wert aus Sicht des anderen Spielers ist
dann −F (p). Die Bewertungsfunktion für Blätter des Spielbaums lautet
somit

bei Sieg
 ∞
−∞ bei Niederlage
.
F (p) =
 0
bei Unentschieden
Für nicht-terminale Knoten sei wiederum Situation II.3.1 gegeben.
Die Werte der Positionen p1 , p2 , . . . , pd seien bekannt. Der bei Position
p ziehende Spieler wird einen Spielzug derart wählen, dass der Wert
der Folgeposition pi aus seiner Sicht (d.h. −F (pi )) möglichst hoch ist:
F (p) = max{−F (p1 ), . . . , −F (pd )}
Eine Fallunterscheidung ist also hier nicht notwendig.
Ziel einer Spielbaumsuche ist es nun, die Bewertung des Wurzelknotens zu finden. Sobald sie bekannt ist, kann der optimale Zug aus
den Bewertungen der Kinder des Wurzelknotens abgelesen werden.
II.4. Prinzipieller Aufbau eines Computerprogramms
Da die Definition der Bewertungsfunktion bereits rekursiv ist, bietet es sich an, auch die Implementierung eines Computerprogramms
rekursiv zu gestalten. Es werden entsprechende Java-Methoden angegeben:
Algorithmus II.4.1.
Diese Implementierung verfolgt Ansatz 1 aus Abschnitt II.3:
1
int valueMax(Position p){
2
if(endposition(p))
3
return f(p);
4
int m = - INF;
5
berechneMöglicheZüge(p);
6
while(zügeÜbrig()){
7
Position q = führeNächstenZugAus(p);
8
m = max(m,valueMin(q));
9
}
10
return m;
11
}
II.4. PRINZIPIELLER AUFBAU EINES COMPUTERPROGRAMMS
13
14
15
16
17
18
19
20
21
22
23
13
int valueMin(Position p){
if(endposition(p))
return f(p);
int m = INF;
berechneMöglicheZüge(p);
while(zügeÜbrig()){
Position q = führeNächstenZugAus(p);
m = min(m,valueMax(q));
}
return m;
}
Je nachdem, welcher Spieler am Zug ist, wird die jeweilige Methode
aufgerufen. Der erstmalige Aufruf am Wurzelknoten w erfolgt durch
valueMax(w);
Zu Beginn des Algorithmus (Zeile 2 bzw. 14) wird überprüft, ob man
sich an einer Endposition befindet. Falls ja, kann der Algorithmus einfach mit Rückgabe des exakten Wertes abgebrochen werden. Andernfalls muss berechnet werden, welche Spielzüge möglich sind (Anweisung 5 bzw. 17). Durch die Anweisungen 6-9 bzw. 18-21 wird erreicht,
dass die Werte aller Kinderknoten rekursiv berechnet werden und der
Optimalwert (d.h. das Maximum, falls Spieler A am Zug ist und das
Minimum, falls Spieler B am Zug ist) in Variable m gespeichert wird.
Bei Maximumsbildung (bzw. Minimumsbildung) wurde m vor Schleifenbeginn entsprechend mit −∞ (bzw. ∞) initialisiert. Anweisung 10
bzw. 22 gibt den optimalen Wert schließlich aus.
Falls Ansatz 2 benutzt wird, ist beim Entwurf des Algorithmus wie
schon bei der Definition der Bewertungsfunktion keine Fallunterscheidung, welcher Spieler das Zugrecht besitzt, notwendig:
1
2
3
4
5
6
7
8
9
10
11
Algorithmus II.4.2.
int value(Position p){
if(endposition(p))
return f(p);
int m = - INF;
berechneMöglicheZüge(p);
while(zügeÜbrig()){
Position q = führeNächstenZugAus(p);
m = max(m,-value(q));
}
return m;
}
II.5. DER BESTIMMTHEITSSATZ VON ZERMELO
14
Bemerkung II.4.3.
• Algorithmus II.4.1 wird Minimax-Suche genannt, da abwechselnd Minima und Maxima gebildet werden.
• Algorithmus II.4.2 wird entsprechend Negamax-Suche genannt.
• In der Praxis sind diese naiven Algorithmen praktisch unbrauchbar, da der Aufwand zu groß ist. In Kapitel III wird gezeigt, wie die Spielbaumsuche verbessert werden kann, indem
nicht mehr sämtliche Zweige des Baumes durchsucht, sondern
unwichtige Teile abgeschnitten“ werden.
”
• Zusätzlich verwendet man in der Praxis eine feste Suchtiefe oder auch einen Zeitmonitor. Dadurch müssen die Werte
an den Blättern zwar geschätzt werden und es wird nur eine
Näherung an die Bewertungsfunktion F berechnet, aber die
Laufzeit rückt in eine akzeptable Größenordnung.
In Abbildung II.4.1 ist ein Beispieldurchlauf der Minimax-Suche
II.4.1 zu sehen.
II.5. Der Bestimmtheitssatz von Zermelo
Am Ende dieses Kapitels steht der Begriff der Strategie im Mittelpunkt. Mit Hilfe des Strategiebegriffs lässt sich der Bestimmtheitssatz
von Zermelo präzise formulieren. Weiterhin wird in diesem Abschnitt
von einer Verwendung des Minimax-Ansatzes ausgegangen.
Definition II.5.1. Sei ein Spiel gegeben. Eine Strategie eines Spielers für dieses Spiel ist eine vollständige Handlungsanweisung, die für
jede denkbare Position einen Spielzug vorsieht.
Für theoretische Betrachtungen ist es möglich, sämtliche Entscheidungen, die während eines Spiels von Spielern getroffen werden müssen,
an den Anfang zu verschieben, indem beide Spieler ihre Strategie offenlegen. Dass in der Praxis das Offenlegen einer vollständigen Strategie
unmöglich oder zumindest schwierig ist, weil die enthaltenen Informationen sehr umfangreich sind, wird für folgende theoretischen Betrachtungen übersehen. Das Offenlegen der Strategie der beiden Spieler A
und B kann auf verschiedene Arten geschehen:
• Beide Spieler offenbaren ihre Strategie gleichzeitig.
• Spieler A offenbart seine Strategie, bevor Spieler B sich entscheiden muss.
• Spieler B offenbart seine Strategie, bevor Spieler A sich entscheiden muss.
Ein gleichzeitiges Offenlegen der Strategie entspricht dem normalen
Spiel. Es ist unerheblich, ob eine Entscheidung, die während des Spiels
gefällt wird, an den Anfang verlegt wird. Wichtig ist nur, dass diese
II.5. DER BESTIMMTHEITSSATZ VON ZERMELO
Abbildung II.4.1. Beispieldurchlauf der Minimax-Suche
15
II.5. DER BESTIMMTHEITSSATZ VON ZERMELO
16
Entscheidung in beiden Fällen am gleichen Informationsstand ausgerichtet ist.
In den beiden anderen Fällen hat jedoch einer der beiden Spieler
einen Vorteil. Er kennt die Strategie seines Gegners und kann gezielt
deren Schwächen ausnutzen.
Falls Spieler A seine Strategie zuerst offenlegen muss, wählt er
möglichst eine Strategie, bei der er unabhängig von den Erwiderungen durch Spieler B einen möglichst hohen Gewinn erhält. Spieler B
wird anschließend seine Strategie darauf ausrichten, den Gewinn von
Spieler A zu minimieren. Der Gewinn, den sich Spieler A trotzdem sichern kann, ist das Maximum dieser Minima und wird Maximin-Wert
genannt.
Falls umgekehrt Spieler B seine Strategie zuerst offenlegen muss,
wird er bestrebt sein, eine Strategie zu wählen, bei der Spieler A trotz
seiner Erwiderungen einen möglichst niedrigen Gewinn erhält. Spieler
A wird anschließend seine Strategie darauf ausrichten, seinen eigenen
Gewinn zu maximieren. Der Gewinn, den sich Spieler A so sichern kann,
ist das Minimum dieser Maxima und wird Minimax-Wert genannt.
Spieler A verfügt also über eine Strategie, die ihm mindestens den
Maximin-Wert als Gewinn sichert und Spieler B kann den Gewinn von
Spieler A auf den Minimax-Wert beschränken. Damit gilt
Maximin-Wert ≤ Minimax-Wert.
In dieser Situation setzt der Bestimmtheitssatz an:
Satz II.5.2. Gegeben sei ein Zwei-Personen-Nullsummenspiel mit
perfekter Information. Dann gilt
Maximin-Wert = Minimax-Wert.
Dieser übereinstimmende Wert wird auch Wert des Spiels genannt.
Der Beweis dieses Satzes erfolgt per vollständiger Induktion:
Induktionsvoraussetzung:
Für Spiele, die nicht länger als n Züge dauern, ist der Maximin-Wert
gleich dem Minimax-Wert.
Induktionsanfang:
Für n = 0 ist die Induktionsvorraussetzung sicherlich erfüllt. Ein solches Spiel besteht aus 0 Spielzügen und somit nur aus einer Vorschrift,
wer wieviel gewinnt.
II.5. DER BESTIMMTHEITSSATZ VON ZERMELO
17
Induktionsschritt:
Betrachte ein Spiel, dass maximal n + 1 Züge dauert. Aus Symmetriegründen kann davon ausgegangen werden, dass Spieler A den ersten
Zug macht. Jedes Endspiel“, dass sich an den ersten Zug anschließt,
”
besteht aus maximal n Zügen. Der Bestimmtheitssatz gilt damit für
diese Spiele. Weiterhin bezeichne v die größte Zahl unter den Werten
dieser Endspiele. Spieler A zieht optimalerweise zum Endspiel mit dem
Wert v. Damit ist der Maximin-Wert des gesamten Spiels v. Im Endspiel gilt nun Minimax-Wert = Maximin-Wert, so dass Spieler B sich so
verteidigen kann, wie er es in diesem einzelnen Endspiel könnte. Damit
ist auch der Minimax-Wert des Gesamtspiels v und der Bestimmtheitssatz gilt für das Spiel mit n + 1 Zügen.
Wenn man die Menge der betrachteten Spiele so einschränkt, dass
nur Sieg, Unentschieden und Niederlage möglich ist und die Höhe eines
Gewinns nicht variabel ist, so lautet eine alternative Formulierung des
Bestimmtheitssatzes:
Korollar II.5.3. Bei Schach oder vergleichbaren Spielen tritt stets
einer der drei folgenden Fälle ein:
• Weiß kann einen Sieg erzwingen, unabhängig von der Spielweise von Schwarz.
• Schwarz kann einen Sieg erzwingen, unabhängig von der Spielweise von Weiß.
• Beide Spieler können unabhängig voneinander ein Unentschieden erreichen.
Spätestens an dieser Stelle ist klar, dass ein Durchschauen des Gegners bei Spielen wie Schach unwichtig ist. Das optimale Vorgehen kann
völlig unabhängig vom Gegner geplant werden, zum Beispiel mit einem
Computerprogramm.
KAPITEL III
Alpha-Beta-Pruning
In diesem Abschnitt wird das Alpha-Beta-Pruning hergeleitet und
erklärt. Durch Verwendung dieses Algorithmus kann eine vollständige
Durchsuchung des Spielbaums, wie sie bei einer normalen Baumsuche
erforderlich ist, vermieden werden. Der Baum wird an Knoten, deren
Werte für die Untersuchung des Wurzelknotens unerheblich sind, be”
schnitten“ (engl.: to prune). Außerdem wird ein Korrektheitsbeweis
geführt sowie eine gewisse Optimalität gezeigt.
In Sätzen, deren Beweisen und bei Algorithmen wird nun im Allgemeinen die Negamax-Schreibweise benutzt, um Fallunterscheidungen
zu vermeiden. Beispiele hingegen sind in Minimax-Schreibweise anschaulicher.
III.1. Beschreibung eines Vorläufers
Zunächst wird ein Vorläufer des Alpha-Beta-Prunings vorgestellt.
Gegeben sei Situation III.1.1 in einem Spielbaum (Minimax-Schreibweise). Spieler B sei am Zug.
Abbildung III.1.1. Idee 1
Gesucht sei der Wert des Knotens p. Der Algorithmus habe für p1
bereits beispielhaft den Wert FA (p1 ) = 10 ermittelt und inspiziere nun
den zweiten Teilbaum (insbesondere p2 ).
18
III.1. BESCHREIBUNG EINES VORLÄUFERS
19
Wegen der Bildung des Minimums bei p gilt
FB (p) = min {FA (p1 ), FA (p2 )} ≤ FA (p1 ) = 10.
Falls nun FA (p21 ) ≥ 10 ist, so wird der Wert von p2 wegen der Maximumsbildung ebenfalls nicht kleiner als 10 sein. Der gesamte Teil
des Baumes, der statt des ?“ noch folgen könnte, braucht somit nicht
”
mehr betrachtet zu werden, da das Ergebnis FA (p) = 10 nicht mehr
beeinflusst werden kann.
Formell bedeutet dies die Einführung einer oberen Schranke β, so
dass der (noch zu bestimmende) Suchalgorithmus F 1(p, β) folgende
Bedingungen erfüllen muss:
(III.1.1)
F 1(p, β) = F (p), wenn F (p) < β
F 1(p, β) ≥ β,
wenn F (p) ≥ β
Im Worten: Es muss der exakte Wert ausgegeben werden, falls F (p)
kleiner als die Schranke β ist. Andernfalls soll am Rückgabewert erkennbar sein, dass das Ergebnis größer als die Schranke β war.
Bemerkung III.1.1. F 1(p, β) ist durch diese Bedingungen nicht
vollständig definiert. Allerdings gilt bei Forderung III.1.1 insbesondere
F 1(p, ∞) = F (p) für alle Positionen p, denn bei der Wahl β = ∞ tritt
immer der Fall 1 (d.h. F (p) < β) ein.
Nach Bemerkung III.1.1 sind verschiedene Realisierungen des Algorithmus denkbar. Als Beispiel dient die folgende rekursive Form einer
Java-Methode:
1
2
3
4
5
6
7
8
9
10
11
Algorithmus III.1.2.
int value(Position p , int beta){
if(endposition(p))
return f(p);
int m = - INF;
berechneMöglicheZüge(p);
while(zügeÜbrig() && m<beta){
Position q = führeNächstenZugAus(p);
m = max(m,-value(q,-m));
}
return m;
}
Die Unterschiede zur normalen Spielbaumsuche aus Kapitel II sind hier
blau markiert.
Im Folgenden wird bewiesen, dass Algorithmus III.1.2 die Bedingungen
III.1.1 einhält.
III.1. BESCHREIBUNG EINES VORLÄUFERS
20
Falls p eine Endposition ist (d = 0, d.h. keine möglichen Spielzüge),
produziert der Algorithmus III.1.2 als Ausgabe den exakten Wert f (p),
unabhängig von β. Denn es gilt
endposition(p) == true (Zeile 2),
so dass mit Ausgabe f (p) abgebrochen wird (Zeile 3).
Der Beweis, dass die Bedingungen III.1.1 für den Aufruf value(p,
beta) an allen anderen Knoten erfüllt sind, erfolgt per Induktion nach
der Baumhöhe. Der Induktionsanfang besteht aus den Endpositionen
und der Induktionsschritt setzt voraus, dass die Bedingungen für die
Folgepositionen bereits gelten. Aber nun wird zunächst eine Invarianzbedingung bewiesen, die im weiteren Verlauf des Beweises benötigt
wird:
(III.1.2)
Vor Beginn der i-ten Iteration der while-Schleife gilt
m = max{−F (p1 ), . . . , −F (pi−1 )}
Auch diese Invarianzbedingung wird durch vollständige Induktion bewiesen:
Induktionsanfang: i = 1
Es gilt die Initialisierung m=-INF, die vor Beginn der Schleife geschieht.
Außerdem ist max ∅ = −∞, so dass die Invarianzbedingung erfüllt ist.
Induktionsschritt: i → i + 1
1. Fall: F (pi ) < −m mit m = max{−F (p1 ), . . . , −F (pi−1 )}
Da die Bedingungen III.1.1 für pi gelten, gilt insbesondere
value(pi , −m) = F (pi ), wenn F (pi ) < −m. Während der i-ten Iteration der while-Schleife wird mneu = max(m, −value(pi , −m)) gesetzt.
Mit obiger Überlegung sowie der Induktionsvoraussetzung gilt damit
mneu = max{−F (p1 ), . . . , −F (pi−1 ), −F (pi )}.
2. Fall: F (pi ) ≥ −m mit m = max{−F (p1 ), . . . , −F (pi−1 )}
Auch in diesem Fall gelten die Bedingungen III.1.1 für pi , insbesondere
value(pi , −m) ≥ −m, wenn F (pi ) ≥ −m. Damit ist −value(pi , −m)
≤ m und die Zuweisung mneu = max(m, −value(pi , −m)) führt wegen
−value(pi , −m) ≤ m und der Induktionsvoraussetzung zu
mneu = m = max{−F (p1 ), . . . , −F (pi−1 ), −F (pi )}.
Nach dem Beweis der Invarianzbedingung kann nun die Korrektheit
des Algorithmus gezeigt werden:
Induktionsanfang: Sei p Endposition.
Falls p eine Endposition ist, gilt F (p) = f (p) und value(p, β) = f (p)
III.2. BESCHREIBUNG UND KORREKTHEITSBEWEIS
21
Abbildung III.1.2. Ausgangssituation
für alle β (siehe oben). Damit sind beide Bedingungen in III.1.1 erfüllt.
Induktionsschritt:
Falls p keine Endposition ist, gibt es d mögliche Züge (siehe Ausgangssituation). Seien also p1 , . . . , pd Folgepositionen von p, die die Bedingungen III.1.1 erfüllen.
1. Bedingung: value(p, β) = F (p) für F (p) < β
F (p) < β
⇒ max{−F (p1 ), . . . , −F (pd )} < β
⇒ max{−F (p1 ), . . . , −F (pi )} < β für alle i
Wegen der Invarianzbedingung III.1.2 gilt nach jeder Iteration der
while-Schleife m < β und der Algorithmus gibt
max{−F (p1 ), . . . , −F (pd )} = F (p)
aus.
2. Bedingung: value(p, β) ≥ β für F (p) ≥ β
F (p) ≥ β
⇒ max{−F (p1 ), . . . , −F (pd )} ≥ β
⇒ ∃i minimal mit max{−F (p1 ), . . . , −F (pi )} ≥ β
Wegen der Invarianzbedingung III.1.2 ist nach der i-ten Iteration der
while-Schleife erstmals m ≥ β und der Algorithmus bricht mit der Ausgabe m ≥ β ab.
III.2. Alpha-Beta-Pruning: Beschreibung, Algorithmus und
Korrektheitsbeweis
Zusätzlich zur Spielsituation, die zur Idee für Algorithmus III.1.2
geführt hat, wird eine weitere Situation analysiert. Sei ein Ausschnitt
aus einem Spielbaum gegeben, wie er in Abbildung III.2.1 zu sehen ist
und sei Spieler A am Zug.
Gesucht sei der Wert des Knotens p. Der Algorithmus habe für p1
bereits den Wert FB (p1 ) = 10 ermittelt und inspiziere nun den zweiten
Teilbaum. Es folgt eine zum vorigen Abschnitt ähnliche Überlegung.
III.2. BESCHREIBUNG UND KORREKTHEITSBEWEIS
22
Abbildung III.2.1. Idee 2
Wegen Maximumsbildung bei p gilt
FA (p) = max {FB (p1 ), FB (p2 )} ≥ FB (p1 ) = 10.
Falls nun FA (p21 ) ≤ 10 ist, so wird der Wert von p2 wegen Minimumsbildung ebenfalls kleiner als 10 sein. Der gesamte Teil des Baumes, der
statt des ?“ noch folgen könnte, braucht nicht mehr betrachtet zu wer”
den, da das Ergebnis FA (p) = 10 nicht mehr beeinflusst werden kann.
Dieses Vorgehen entspricht formal der Einführung einer unteren
Schranke α (zusätzlich zum bereits eingeführten β). Der noch näher
zu spezifizierende Algorithmus F 2(p, α, β) sollte folgende Bedingungen
erfüllen:
(III.2.1)
F 2(p, α, β) ≤ α,
wenn F (p) ≤ α
F 2(p, α, β) = F (p), wenn α < F (p) < β
F 2(p, α, β) ≥ β,
wenn F (p) ≥ β
In Worten: Innerhalb des Intervalls (α, β) wird der exakte Wert
F (p) zurückgeliefert. Falls F (p) nicht im Intervall (α, β) liegt, soll zumindest erkennbar sein, ob der exakte Wert kleiner als α oder größer
als β ist.
Bemerkung III.2.1. Es gilt eine zu III.1.1 analoge Bemerkung.
Insbesondere gilt F 2(p, −∞, ∞) = F (p) für alle Positionen p.
Auch hier sind verschiedene Realisierungen des Algorithmus denkbar.
Als Beispiel dient erneut eine rekursive Java-Methode:
III.2. BESCHREIBUNG UND KORREKTHEITSBEWEIS
1
2
3
4
5
6
7
8
9
10
11
23
Algorithmus III.2.2.
int value(Position p , int alpha, int beta){
if(endposition(p))
return f(p);
int m = alpha;
berechneMöglicheZüge(p);
while(zügeÜbrig() && m<beta){
Position q = führeNächstenZugAus(p);
m = max(m,-value(q,-beta,-m));
}
return m;
}
Die Unterschiede zur normalen Spielbaumsuche aus Kapitel II sind blau
markiert.
Korrektheitsbeweis:
Die Technik des Beweises ist vollkommen analog zu F1. Allerdings
lautet hier die passende Invarianzbedingung
(III.2.2)
m = max{α, −F (p1 ), . . . , −F (pi−1 )}.
Die zusätzliche Bedingung m < β darf oBdA vorausgesetzt werden.
Ansonsten würde die while-Schleife abgebrochen und das aktuelle m
ausgegeben. Es könnte keine Aussage für einen folgenden Durchlauf
getroffen werden. Die Fallunterscheidung im Induktionsschritt zum Beweis der Invarianzbedingung lautet damit:
1.Fall: F (pi ) ≤ β
2.Fall: −β < F (pi ) < −m
Die ausstehenden Beweisdetails können analog zu vorigem Kapitel ausgefüllt werden.
Bemerkung III.2.3. Das folgende Beispiel eines Alpha-BetaPruning-Durchlaufs verwendet eine auf der Minimax-Notation basierende Version des Algorithmus:
1
2
3
4
5
6
7
8
9
10
11
int valueMax(Position p , int alpha, int beta){
if(endposition(p))
return f(p);
int m = alpha;
berechneMöglicheZüge(p);
while(zügeÜbrig() && m<beta){
Position q = führeNächstenZugAus(p);
m = max(m,valueMin(q,alpha,beta));
}
return m;
}
III.2. BESCHREIBUNG UND KORREKTHEITSBEWEIS
Abbildung III.2.2. Beispiel für Alpha-Beta-Pruning
24
III.3. ANALYSE DES BESTEN FALLS
13
14
15
16
17
18
19
20
21
22
23
25
int valueMin(Position p , int alpha, int beta){
if(endposition(p))
return f(p);
int m = alpha;
berechneMöglicheZüge(p);
while(zügeÜbrig() && m>alpha){
Position q = führeNächstenZugAus(p);
m = min(m,valueMax(q,alpha,beta));
}
return m;
}
Bemerkung III.2.4. Zu Abbildung III.2.2:
• Für jeden Knoten gibt es einen zugehörigen Aufruf des AlphaBeta-Prunings. Die Beschriftungen der Knoten geben den
Rückgabewert an. Neben den Knoten ist zusätzlich das Intervall (α, β) beim Aufruf des Algorithmus angegeben. Hierbei ist
die für die Abbruchbedingung (Zeile 6 und 18 in Algorithmus
III.2.3) relevante Grenze fett gedruckt.
• Grundsätzlich wird der Spielbaum rekursiv in PostorderReihenfolge ausgewertet, d.h. lokal werden zunächst die Werte
der Kinderknoten bestimmt, um anschließend den Elternknoten berechnen zu können. Die in diesem Beispiel abgeschnittenen Knoten sind dabei grau eingefärbt.
• Bei Knoten, an denen neue Intervallgrenzen vorkommen, ist
durch farbige Pfeile markiert, woher sie stammen.
• Welche Bedingung das Abschneiden eines Knotens (auch
Cutoff“ genannt) verursacht hat, wird auch manchmal durch
”
die Begriffe α-Cutoff und β-Cutoff verdeutlicht. In diesem
Beispiel kommt sowohl ein α-Cutoff als auch ein β-Cutoff vor.
III.3. Analyse des besten Falls
Die Analyse des besten Falls beschäftigt sich mit der Frage, wieviele
Knoten des Spielbaums mindestens besucht werden müssen. Um diese
Frage zu beantworten, zunächst zwei Definitionen:
Definition III.3.1. Gegeben sei ein Spielbaum. Man ordnet den
Knoten des Baums nach folgendem Schema Koordinaten zu:
• Der Wurzelknoten des Baums ist eindeutig und benötigt keine
Koordinaten.
III.3. ANALYSE DES BESTEN FALLS
26
• Wenn (im Teilbaum unten) p die Koordinaten a1 . . . al hat,
dann ordnet man dem Knoten pi jeweils die Koordinaten a1 . . . al i
zu.
Abbildung III.3.1
Die folgende Definition beschäftigt sich mit kritischen Knoten. Später
wird sich zeigen, dass bei einer bestimmten Sortierung des Spielbaums
nur kritische Positionen vom Alpha-Beta-Pruning besucht werden.
Definition III.3.2. Gegeben sei ein Spielbaum. Eine Position a1 . . . al
im Spielbaum heißt kritisch, wenn mindestens eine der folgenden Bedingungen erfüllt ist:
• ai = 1 für alle ungeraden i (1 ≤ i ≤ l)
• aj = 1 für alle geraden j (1 ≤ j ≤ l)
Die Position des Wurzelknotens heißt immer kritisch.
Bemerkung III.3.3. Betrachte die Koordinaten eines Knotens im
Spielbaum:
• Alle ungeraden Koordinaten (a1 , a3 , a5 , . . . ) eines Knotens stehen für die Züge, die Spieler A bis zur aktuellen Position
gewählt hat.
• Analog stehen gerade Koordinaten (a2 , a4 , a6 , . . . ) für die Zugfolge von Spieler B.
Satz III.3.4. Gegeben sei ein Spielbaum, bei dem der Wurzelknoten
nicht den Wert −∞ oder ∞ hat. Weiter sei an jeder Position im Baum
der erste Spielzug optimal (für den Spieler, der jeweils am Zug ist), d.h.

falls a1 . . . al ein Blatt ist

 f (a1 . . . al ),
)
sonst
−F
(
a
.
.
.
a
1
1
l
F (a1 . . . al ) =
| {z }


erster Nachfolger
von a1 . . . al
Dann wertet der Algorithmus III.2.2 genau die kritischen Positionen
des Spielbaums aus.
Zum Beweis werden drei Typen von kritischen Positionen eingeführt.
Definition III.3.5. Eine kritische Position al heißt
• vom Typ 1, falls ai = 1 für alle i ∈ {1, . . . l} gilt.
III.3. ANALYSE DES BESTEN FALLS
27
• vom Typ 2, falls ai = 1 für i ∈ {1, . . . j − 1} gilt, aj 6= 1 sowie
l − j gerade ist.
• vom Typ 3, falls ai = 1 für i ∈ {1, . . . j − 1} gilt, aj 6= 1 sowie
l − j ungerade ist.
Die (kritische) Position des Wurzelknotens p hat den Typ 1, d.h.
beim anfänglichen Aufruf value(p, −∞, ∞) wird eine Typ 1-Position
untersucht. Laut Voraussetzung gilt zudem, dass der Wurzelknoten
nicht den Wert −∞ oder ∞ hat.
Typ 1-Positionen:
Eine Position p vom Typ 1 wird durch den Aufruf value(p, −∞, ∞)
ausgewertet. Sofern es Folgepositionen gibt, sind sie alle kritisch. p1 ist
vom Typ 1 und p2 , . . . , pd sind vom Typ 2.
p1 wird durch den Aufruf value(p1 , −∞, ∞) untersucht. Da der erste
Zug stets optimal sein soll, folgt F (p) = −F (p1 ). Somit gilt F (p) 6= ±∞
für alle Positionen vom Typ 1.
Die Positionen p2 , . . . , pd werden durch den Aufruf value(pi , −∞, F (p1 ))
untersucht, wobei max{−F (p2 ), −F (p3 ), . . . , −F (pd )} ≤ −F (p1 ) und
weiter F (p1 ) ≤ F (pi ) für alle i ∈ {2, . . . , d} gilt, da p1 als erste Folgeposition bereits optimal ist.
Typ 2-Positionen:
Eine Position p vom Typ 2 wird durch einen Aufruf value(p, −∞, β)
ausgewertet, wobei −∞ < β ≤ F (p) gilt. Bei den Aufrufen von Typen
1 und 3 ist diese Form nachgewiesen. Sofern es Folgepositionen gibt,
ist p1 vom Typ 3. p2 , . . . , pd sind keine kritischen Positionen.
Bei p1 gilt F (p) = −F (p1 ), da der erste Zug optimal ist. Für den zu p1
gehörigen Aufruf value(p1 , −β, ∞) gilt insbesondere
∞ > −β ≥ −F (p) = F (p1 ).
Bei den Aufrufen value(pi , −β, F (p1 )) für p2 , . . . , pd ist −β ≥ F (p1 ).
Damit ist die Bedingung m<beta ⇐⇒ F (p1 ) < −β (Zeile 6 in Algorithmus III.2.2) offensichtlich verletzt und der Algorithmus bricht ab,
ohne p2 , . . . , pd zu untersuchen.
Typ 3-Positionen:
Eine Position p vom Typ 3 wird durch einen Aufruf value(p, α, ∞)
ausgewertet, wobei ∞ > α ≥ F (p) gilt. Bei den Aufrufen von Typ 2
ist diese Form nachgewiesen. Sofern es Folgepositionen gibt, sind sie
alle vom Typ 2. Denn nach Definition von Typ 3 ist dort die letzte
Koordinate 1, da aj 6= 1 sowie l − j ungerade gilt. Zudem muss bei
kritischen Positionen jede zweite Koordinate 1 sein.
Die zugehörigen Aufrufe lauten value(pi , −∞, −α), i ∈ {1, . . . d} und
es gilt (wegen F (p) = max{−F (p1 ), . . . , −F (pd )})
−∞ < −α ≤ −F (p) ≤ F (pi ).
III.3. ANALYSE DES BESTEN FALLS
28
Abbildung III.3.2. Gegenbeispiel zur optimalen Sortierung
Aus den obigen Punkten folgt induktiv, dass nur kritische Positionen untersucht werden. Außerdem werden, vom Wurzelknoten ausgehend, alle kritischen Positionen besucht. Es folgt die Behauptung.
Bemerkung III.3.6. Warum es ein Vorteil ist, den ersten möglichen Zug als optimal anzunehmen, wurde nicht gezeigt. Intuitiv sollte
eine frühe Untersuchung des optimalen Zuges zwar zumindest nicht
schlecht sein. Jedoch gibt es durchaus Situationen, bei denen eine abweichende Sortierung bessere Laufzeiten des Alpha-Beta-Prunings liefert. Abbildung III.3.2 zeigt eine solche Situation. Im Spielbaum auf
der linken Seite ist von zwei möglichen Zügen jeweils der erste optimal.
Trotzdem braucht das Alpha-Beta-Pruning hier mehr Rechenschritte
als bei der Anordnung rechts.
Wie die Bemerkung zeigt, ist eine optimale Sortierung des Spielbaums nicht offensichtlich. Es ist aber trotzdem möglich, einen Vergleich mit beliebigen anderen Algorithmen zu treffen und eine gewisse
Optimalität des Alpha-Beta-Prunings zu zeigen:
Satz III.3.7. Gegeben sei ein beliebiger Spielbaum und ein beliebiger
Algorithmus, der den Wert des Wurzelknotens berechnet. Dieser Algorithmus habe keine Kenntnis von eventuell vorhandenen Abhängigkeiten zwischen den Werten der Blattknoten (bzw. Endpositionen). Dann
gibt es eine Permutation des Baumes (d.h. für alle Knoten des Baummes gibt es eine Umnummerierung der Kinderknoten), so dass jeder
Knoten, der vom Alpha-Beta-Pruning untersucht wird, auch vom gegebenen Algorithmus untersucht wird. Wenn der Wert des Wurzelknotens
III.3. ANALYSE DES BESTEN FALLS
29
weder ∞ noch −∞ ist, wertet das Alpha-Beta-Pruning genau diejenigen Knoten aus, deren Position bzgl. der Permutation kritisch sind.
Zum Beweis werden zunächst für die Werte aller Knoten p in Baum
bestmögliche Schranken gesucht (in NegaMax-Schreibweise):
(III.3.1)

falls p terminal und noch nicht besucht
 −∞,
f (p),
falls p terminal und bereits besucht
Funten (p) =
 max{−F (p ), . . . , −F (p )}
sonst
oben 1
oben d

falls p terminal und noch nicht besucht
 ∞,
f (p),
falls p terminal und bereits besucht
Foben (p) =
 max{−F
sonst
unten (p1 ), . . . , −Funten (pd )}
Die Schranken für Blattknoten ergeben sich zum genauen Wert,
falls der Knoten bereits vom gegebenen Algorithmus besucht worden
ist. Sonst ist −∞ untere und ∞ obere Schranke. Für nicht-terminale
Knoten erhält man Schranken analog zur Spielbaumsuche aus Kapitel
II rekursiv. Insbesondere gilt
Funten (p) ≤ Foben (p)
für alle Positionen p. Dies ist direkt per Induktion nach Baumhöhe einzusehen.
Da der Wert des Wurzelknotens vom gegebenen Algorithmus genau
berechnet wird, muss hierfür F (p) = Funten (p) = Foben (p) gelten.
Sei F (p) ∈
/ {−∞, ∞}.
Es wird nun explizit eine Permutation des Baumes konstruiert, so dass
das Alpha-Beta-Pruning genau die kritischen Positionen des Baumes
und der andere gegebene Algorithmus mindestens die kritischen Positionen untersucht. Kritische Positionen werden erneut in die drei verschiedenen Typen aus Definition III.3.5 eingeteilt.
Typ 1-Positionen:
An Positionen p vom Typ 1 gilt Foben (p) = Funten (p) = F (p) 6= ±∞. Sie
werden vom Alpha-Beta-Pruning durch den Aufruf value(p, −∞, ∞)
ausgewertet.
Falls p ein Blattknoten ist, muss er vom gegebenen Algorithmus untersucht werden, da Funten (p) 6= −∞ gilt. Falls p Kinderknoten hat,
bezeichne pj einen Knoten mit Funten (p) = −Foben (pj ) und pk einen
Knoten mit Foben (p) = −Funten (pk ). Unter Ausnutzung von III.3.1
erhält man Foben (pj ) = min{Foben (p1 ), . . . , Foben (pd )} bzw. Funten (pk )
= min{Funten (p1 ), . . . , Funten (pd )}. Damit gilt
Funten (pk ) ≤ Funten (pj ) ≤ Foben (pj ) = −F (p) = Funten (pk )
III.3. ANALYSE DES BESTEN FALLS
30
und weiter Funten (pj ) = Funten (pk ). Also kann j = k angenommen werden. Durch Permutation der Kinderknoten von p wird pj nun an die
erste Position gesetzt.
Alle Folgepositionen von p sind kritisch. Genauer ist nach der Permutation p1 vom Typ 1 und wird durch value(p1 , −∞, ∞) ausgewertet.
p2 , . . . , pd sind vom Typ 2 und werden durch den Aufruf
value(pi , −∞, F (p1 )), i ∈ {2, . . . , d} untersucht.
Da der erste Zug nach Konstruktion optimal ist, folgt F (p) = −F (p1 ).
Somit gilt
Foben (p) = Funten (p) = F (p) 6= ±∞
für alle Positionen vom Typ 1. Bei den Positionen p2 , . . . , pd gilt
max{−Funten (p2 ), . . . , −Funten (pd )} ≤ −Funten (p1 ) ≤ −F (p1 ) und weiter
Funten (pi ) ≥ F (p1 ) > −∞
für i ∈ {2, . . . , d}, da p1 bereits optimal ist.
Typ 2-Positionen:
An Positionen p vom Typ 2 gilt Funten (p) > −∞. Sie werden vom
Alpha-Beta-Pruning durch den Aufruf value(p, −∞, β) ausgewertet,
wobei −∞ < β ≤ Funten (p) gilt. Bei den Aufrufen von Typen 1 und 3
ist diese Form nachgewiesen.
Falls p ein Blattknoten ist, muss er vom gegebenen Algorithmus untersucht werden, da Funten (p) 6= −∞ gilt. Falls p Kinderknoten hat,
bezeichne pj denjenigen Knoten mit Funten (p) = −Foben (pj ). Durch
Permutation der Kinderknoten von p wird pj nun an die erste Position
gesetzt.
Nach Permutation ist p1 kritisch, vom Typ 3 und wird durch
value(p1 , −β, ∞) ausgewertet. Wegen Foben (p1 ) = −Funten (p) ≤ −β ist
der Rückgabewert ≤ β. Somit werden die anderen Positionen p2 , . . . , pd
vom Alpha-Beta-Pruning nicht untersucht. Im Übrigen sind sie nicht
kritisch.
Aus Funten (p) = −Foben (p1 ) folgt Foben (p1 ) < ∞. Für den zu p1 gehörigen Aufruf value(p1 , −β, ∞) gilt insbesondere
∞ > −β ≥ −Funten (p) = Foben (p1 ).
Typ 3-Positionen:
An Positionen p vom Typ 3 gilt Foben (p) < ∞. Sie werden vom AlphaBeta-Pruning durch den Aufruf value(p, α, ∞) ausgewertet, wobei
Foben (p) ≤ α < ∞ gilt. Bei den Aufrufen von Typ 2 ist diese Form
nachgewiesen.
Falls p ein Blattknoten ist, muss er vom gegebenen Algorithmus untersucht werden, da Foben (p) 6= ∞ gilt. Falls p Kinderknoten hat, sind alle
Knoten pi , i ∈ {1, . . . , d} kritisch und vom Typ 2. Sie werden durch
den Aufruf value(pi , −∞, −α) ausgewertet. Permutation der Kinderknoten von p ist hier nicht nötig.
III.4. ANALYSE DES SCHLECHTESTEN FALLS
31
Für diese Aufrufe gilt wegen Foben (p) = max{−Funten (p1 ), . . . , −F (pd )}:
−∞ < −α ≤ −Foben (p) ≤ Funten (pi )
Bisher wurden die Fälle F (p) = ∞ und F (p) = −∞ ausgelassen.
Hier führen analoge Argumente zum Ziel. Wenn F (p) = ∞ ist, behandelt man den Wurzelknoten als Knoten des Typs 2. Bei F (p) = −∞
hingegen ist eine Betrachtung erfolgreich, die den Wurzelknoten als
Knoten des Typs 3 behandelt.
Damit ist gezeigt, dass sämtliche Positionen, die vom Alpha-BetaPruning untersucht werden, auch vom anderen gegebenen Algorithmus untersucht werden müssen. Die Voraussetzung, dass der gegebene
Algorithmus keine Kenntnis von eventuellen Abhängigkeiten zwischen
den Blattknoten haben darf, führt zu einer schichtweisen Untersuchung
des Spielbaums. Unter der konstruierten Permutation kann das AlphaBeta-Pruning also nicht schlechter sein als der gegebene Algorithmus.
Bemerkung III.3.8. Eine Sortierung der Kinder eines Typ 3Knotens hat keinerlei Auswirkung auf die Laufzeit des Alpha-BetaPrunings. Dies wurde während des vorigen Beweises deutlich.
III.4. Analyse des schlechtesten Falls
Satz III.4.1. Gegeben sei ein beliebiger Spielbaum. Dann können
die Werte der Blätter so gewählt werden, dass sämtliche Knoten im
Baum vom Alpha-Beta-Pruning ausgewertet werden müssen.
Die Werte können derart an den Blättern angeordnet werden, dass
an jedem Knoten p beim Aufruf von value(p, α, β) die Beziehung
α < −F (p1 ) < −F (p2 ) < · · · < −F (pd ) < β
erfüllt ist. Damit ist zu jedem Zeitpunkt α < m < β und die Abbruchbedingung der while-Schleife in Algorithmus III.2.2 ist nie erfüllt. Es
folgt die Behauptung.
Von praktischer Bedeutung ist dieses Resultat jedoch kaum, da
bei Verwendung des Alpha-Beta-Prunings eine Vorsortierung der Züge
integriert werden sollte. Das grundlegende Ziel einer solchen Vorsortierung besteht darin, vielversprechende Züge relativ früh (durch das
Alpha-Beta-Pruning) untersuchen zu lassen. Damit steigt die Chance
auf Cutoffs. Der Abschnitt IV.1 befasst sich mit diesem Thema. Insbesondere wird dort beschrieben, wie man solche guten Züge im Voraus
III.5. ALLGEMEINERE ERGEBNISSE
32
erkennen kann.
III.5. Allgemeinere Ergebnisse
Aussagekräftiger als der worst case ist ein anderer Ansatz. Es werden gleichmäßige Spielbäume mit Höhe h und Grad d betrachtet, deren
Blättern zufällige Werte zugeordnet werden.
Definition III.5.1. Ein Spielbaum heißt gleichmäßig (mit Höhe h
und Grad d), falls die beiden folgenden Bedingungen erfüllt sind:
• Ein Pfad von der Wurzel des Baums zu einem beliebigen Blatt
hat Länge h.
• Nicht-terminale Knoten haben genau d Kinder.
Satz III.5.2. Gegeben sei ein gleichmäßiger Spielbaum mit Höhe h
und Grad d. Den Blättern seien zufällige Werte zugeordnet. Dann ist
die Anzahl der zu durchsuchenden Positionen proportional zu
(rd )h
wobei rd von d abhängig ist. Genauer ist rd proportional zu
d
.
ln d
Auf einen Beweis dieses Satzes wird verzichtet. Selbst eine Analyse
des schwächeren Algorithmus III.1.2 würde bereits den Rahmen dieser Arbeit sprengen. In An Analysis of Alpha-Beta-Pruning“ ist ein
”
entsprechender Beweis zu finden. (siehe [4], S. 311ff.)
KAPITEL IV
Spielabhängige und allgemeine Modifikationen des
Alpha-Beta-Prunings
Nachdem in den letzten Kapiteln die grundlegende Arbeitsweise
des Alpha-Beta-Prunings deutlich geworden ist, werden hier Techniken vorgestellt, die mit dem Alpha-Beta-Pruning kombiniert werden
können. Auf diese Weise lässt sich die Effizienz des Algorithmus weiter steigern. Denkbar sind beispielsweise spielabhängige Modifikationen
des Algorithmus wie Eröffnungs- und Endspieldatenbanken oder HashFunktionen. Bei solchen Optimierungen wird im Folgenden auf Schach
als wohl bekanntestes Zwei-Personen-Nullsummenspiel Bezug genommen. Ab Abschnitt IV.4 werden schließlich einige Modifikationen des
Alpha-Beta-Prunings vorgestellt, die nicht von speziellen Spielregeln
abhängen.
IV.1. Vorsortierung der Züge
Um möglichst viele Cutoffs im Spielbaum zu erreichen, ist es von
Vorteil, gute Züge“ im Rahmen des Alpha-Beta-Algorithmus möglichst
”
früh zu untersuchen. Ein guter Zug ist hier ein Zug, der zu einem
möglichst guten Ergebnis führt, d.h. einem möglichst hohen Wert der
Bewertungsfunktion. Dazu bietet es sich an, die Spielzüge zu sortieren,
bevor sie durch das Alpha-Beta-Pruning analysiert werden. Eine Sortierung jedoch kann nur dann optimal durchgeführt werden, wenn das
Spiel bekannt ist. Beim Schach beispielsweise gibt es hierzu verschiedene heuristische Kriterien:
• Wer schlägt wen?
Es wird überprüft, ob eine Figur eine andere schlägt. Falls ja,
werden die Werte der beiden beteiligten Figuren verglichen
und die verschiedenen Züge nach der Differenz sortiert. Üblich
sind Werte wie 1000, 9, 5, 3, 3 und 1 für die Figuren König, Dame, Turm, Läufer, Springer und Bauer. Der Wert des Königs
ist unverhältnismäßig hoch, weil sein Verlust nicht durch andere Figuren aufgewogen werden kann.
• Liegt ein Schlagabtausch vor?
Falls im letzten Zug eine eigene Figur geschlagen wurde, ist in
vielen Fällen ein Zurückschlagen sinnvoll.
33
IV.2. HASH-FUNKTIONEN
34
• Wurde diese Stellung schon einmal untersucht?
Wenn die Suchtiefe des Alpha-Beta-Prunings groß genug ist,
wurden viele Züge, die in der momentanen Situation möglich
sind, bereits (mit kleinerer Suchtiefe) bei der Untersuchung
für den vorhergehenden Zug analysiert und bewertet. Diese
Bewertung kann direkt zur Sortierung verwendet werden.
• Killer-Heuristik:
Man betrachtet ausschließlich die aktuelle Ebene des Baumes.
Nun geht man davon aus, dass Züge, die in den bereits untersuchten Teilbäumen ein gutes Ergebnis geliefert haben, auch
im aktuellen Teilbaum gut sein müssen. Dabei ist jedoch keineswegs klar, dass diese Züge überhaupt gültig sind.
• Nullzug-Ansatz:
Abgesehen vom Endspiel, für das es eine eigenständige Modifikation gibt (siehe Abschnitt IV.3), ist beim Schach das
Zugrecht von Vorteil. Wenn man nun zwei Züge direkt hintereinander ausführt und den Zug des Gegners streicht, sollte
sich eine signifikante Verbesserung der Situation ergeben. Falls
dies nicht der Fall ist, war vermutlich schon der erste der beiden Züge schlecht und wird für die Vorsortierung nach hinten
geschoben.
Der Begriff heuristisch bedeutet, dass diese Ansätze intuitiv sinnvoll
sind und sich in der Praxis als nützlich erwiesen haben. Ihre Effektivität ist jedoch nicht in jedem Spezialfall gesichert.
IV.2. Hash-Funktionen
Beim Schach können Stellungen auf verschiedene Weise entstehen.
Sei beispielsweise die Stellung aus Abbildung IV.2.1 gegeben (mit Weiß
am Zug).
Diese Position kann aus 13 verschiedenen Zugfolgen entstehen, genauer aus 4 Vierzügern und 9 Sechszügern. Theoretisch sind auch
Spielzüge mit 8 und mehr Zügen möglich, dies entspricht aber nicht einer realistischen Eröffnung. Um diese Stellung im Alpha-Beta-Pruning
nicht 13-mal auswerten zu müssen, können für eine Stellung errechnete Ergebnisse gespeichert werden. Eine solche Datenbank benötigt
allerdings viel Speicherplatz. Zudem muss eine wesentliche Bedingung
erfüllt sein:
Bewertungen müssen schnell abgerufen werden können.
Wenn das Wiederfinden einer Position zu lange dauert, könnte man
die Stellung letztlich schneller neu berechnen. Als Datenstruktur zur
Realisierung bieten sich Hashtabellen an. Eine solche Tabelle besteht
allgemein aus einem Index und den zugehörigen Daten. Sie kommen in
IV.2. HASH-FUNKTIONEN
35
Abbildung IV.2.1. Beispielsituation
vielen Bereichen der Informatik vor. In diesem speziellen Anwendungsbereich bestehen die gespeicherten Daten aus Positionsbewertungen.
Der Index (d.h. die Position in der Tabelle), an dem diese Daten gespeichert werden, berechnet sich aus der aktuellen Spielstellung mittels
einer Hash-Funktion.
Definition IV.2.1. Eine Hashfunktion ist eine Funktion, die einer
Eingabe beliebiger Länge eine Ausgabe kleinerer Länge zuordnet. Die
Menge der möglichen Ausgabewerte ist ebenfalls kleiner als die Menge
möglicher Eingabewerte.
Diese Definition ist sehr weit gefasst. Idealerweise erfüllt eine Hashfunktion noch weitere Bedingungen, die für Hashtabellen wichtig sind:
Bemerkung IV.2.2.
• Die Ausgabe der Hashfunktion sollte eine ganze Zahl in einem vorgegebenen Intervall sein (beispielsweise zwischen 0 und
232 − 1).
• Die Funktion ist weitgehend kollisionsfrei, d.h. zu zwei verschiedenen Spielpositionen generiert die Hashfunktion unterschiedliche Ausgaben.
So wird sichergestellt, dass die Größe der Hashtabelle beschränkt
ist. Außerdem werden zwei Stellungsbewertungen möglichst unter verschiedenen Indizes gespeichert. Es gibt etwa 1043 verschiedene
Schachstellungen (siehe [3], S. 175) Wenn der Index nun die Größe
232 (≈ 4 · 109 ) hat, liegt es auf der Hand, dass es keine Funktion geben
kann, die für jede Position einen eigenen Index generiert. Wenn zwei
IV.2. HASH-FUNKTIONEN
36
Stellungen derselbe Index zugewiesen werden muss, wird dieser Fall
Kollision genannt. Er ist zwar sehr selten, aber es gibt Lösungsstrategien:
• Kollisionen werden ignoriert. Es wird ausgenutzt, dass Kollisionen sehr selten sind. Der dadurch entstehende Fehler wird
vernachlässigt.
• Statt nur die Bewertung in der Tabelle zu speichern, können
zusätzlich die Daten der Position gespeichert werden. So kann
überprüft werden, ob es sich um die richtige Position handelt.
Zusätzlich ist es denkbar, bei Kollisionen am entsprechenden
Index mehrere Positionen in einer Liste zu verwalten.
Der Schnelligkeit wegen wird in der Praxis häufig die erste Variante
gewählt.
Um das Hashing möglichst effizient durchführen zu können, wird
die Berechnung der Indizes iterativ organisiert, d.h. bei jedem Spielzug
wird der Index der Folgeposition aus dem Index der Vorgängerposition
berechnet.
Genauer wird zu Beginn eines Spiels für jedes Paar (Figur, Feld) eine
binäre Zufallszahl aus dem Zahlenraum von 0 bis 232 − 1 erzeugt. Um
den Überblick in einem konkreten Beispiel zu wahren, beschränken sich
diese Zufallszahlen im Folgenden auf 16 Stellen:
Weißer König auf Feld a1:
Weißer König auf Feld a2:
Weißer König auf Feld a3:
...
Weißer Turm auf Feld d5:
...
Schwarzer König auf Feld c8:
...
Schwarzer Bauer auf Feld h7:
0111010110101110
1110111000100101
0001001101110100
1100100101011011
0110110011110001
1000111110010101
Für die konkrete Berechnung eines Indexes bietet sich die bitweise Addition XOR an. XOR steht hierbei für eXclusive OR“ . Diese
”
Verknüpfung zweier Wahrheitswerte ist genau dann wahr, wenn beide
Wahrheitswerte unterschiedlich sind. Dies entspricht einer Addition ohne Übertrag. Der Operator XOR wird auf binäre Zahlen angewendet,
indem er auf jede Stelle einzeln angewendet wird.
Der Hash-Index von Beispielsituation IV.2.2 berechnet sich demnach zu:
IV.2. HASH-FUNKTIONEN
37
Abbildung IV.2.2. Beispielsituation
Weißer König auf Feld a2:
Weißer Turm auf Feld d5:
Schwarzer König auf Feld c8:
1110111000100101
1100100101011011
0110110011110001
Ausgabe der Hashfunktion:
0100101110001111
Wenn nun Weiß am Zug ist und mit dem König von a2 nach a3 zieht,
ist die Berechnung des neuen Hashwertes denkbar einfach:
Bisheriger Wert:
Weißer König auf Feld a2:
Weißer König auf Feld a3:
0100101110001111
1110111000100101
0001001101110100
Ausgabe der Hashfunktion:
1011011011011110
Dies ist so einfach möglich, da XOR(a, a) = 0 für a ∈ {0, 1} gilt. In
diesem konkreten Beispiel bedeutet der iterative Ansatz keinen großen
Vorteil gegenüber einer kompletten Neuberechnung. In der Anfangsphase des Spiels jedoch, wenn noch bis zu 32 Figuren auf dem Spielfeld
sind, sieht das anders aus.
IV.3. ENDSPIELDATENBANKEN
38
IV.3. Endspieldatenbanken
Nun ist klar, wie man bereits berechnete Spielpositionen schnell
wiederfinden kann. Da liegt die Idee nahe, beste Züge für bestimmte Stellungen bereits vor dem eigentlichen Durchlauf des Alpha-BetaPrunings zu berechnen und in einer Datenbank zu speichern. So könnte
während des Alpha-Beta-Prunings einfach auf diese Datenbank zugegriffen und alle nötigen Berechnungen eingespart werden.
Falls das Spiel Tic Tac Toe betrachtet würde, könnten für alle Positionen sämtliche Bewertungsdaten gespeichert werden. Die Anzahl
möglicher Positionen beträgt 5478 (siehe [3], S. 170) und ist damit gering genug, um die Datenbank klein zu halten. Beim Schach sieht das
anders aus. Hier können aus Platzmangel nur ausgewählte Positionen
gespeichert werden, zum Beispiel Eröffnungen oder Endspiele.
Eröffnungsbibliotheken sind erfolgsversprechend, da in der Anfangsphase die Zahl möglicher Züge noch überschaubar ist. Am Beginn
dürfen schließlich nur Bauern und Springer ziehen. Um Eröffnungsbibliotheken zu erstellen, wird Expertenwissen benötigt. Ein Großmeister
weiß intuitiv, welche Eröffnungen sinnvoll sind. Daher werden Datenbanken oft generiert, indem Meisterpartien analysiert werden.
Mathematisch interessanter sind Endspieldatenbanken. Denn um
sie zu erzeugen, ist man nicht auf Expertenwissen angewiesen. Da in
Endspielen im Allgemeinen wenige Figuren auf dem Spielfeld sind, ist
auch die Zahl möglicher Stellungen stark eingeschränkt. Trotz dieser
Einschränkung ist mit einem enormen Platzaufwand zu rechnen. So
können bislang mit einem Platzaufwand von 1,3 TByte lediglich alle
Schachstellungen mit maximal 6 Figuren erfasst werden (siehe [3], Seite
171). Meist werden deshalb bestimmte Figurenkonstellationen vorgegeben (z.B. Weiß mit Turm und König gegen Schwarz mit König) und so
sukzessiv eine umfangreiche Datenbank angelegt. Dies ist jedoch nicht
zwingend erforderlich. Mit folgendem Algorithmus lässt sich eine solche
Endspieldatenbank erstellen:
Algorithmus IV.3.1.
Gegeben sei eine Konstellation von Schachfiguren.
Schritt 1: Erzeugen möglicher Stellungen
(1) Erstelle einen Index für alle Positionen, die mit der gegebenen
Figuren-Konstellation zulässig sind. Schließe dabei auch Positionen ein, die nur einen Teil der gegebenen Figuren benötigen.
IV.3. ENDSPIELDATENBANKEN
39
Schritt 2: Gewinnstellungen für Weiß
(1) Markiere alle Stellungen, bei denen Schwarz bereits matt gesetzt ist. Setze n = 1.
(2) Suche alle Stellungen, bei denen Weiß am Zug ist und mindestens ein möglicher Zug zu einer Stellung führt, die in Teilschritt (1) markiert worden ist. Weiß kann hier in einem Zug
matt setzen. Ergänze den Index an allen gefundenen Stellungen
um den zugehörigen Zug und den Hinweis Gewinnstellung für
”
Weiß“.
(3) Markiere alle Stellungen, bei denen Schwarz am Zug ist und
jeder mögliche Zug von Schwarz zu einer Gewinnstellung für
Weiß führt. Schwarz kann hier eine Niederlage nicht verhindern. Gehe zu Schritt 3, sobald keine Stellungen mehr markiert
wurden.
(4) Erhöhe n um 1. Suche alle Stellungen, bei denen Weiß am
Zug ist und mindestens ein möglicher Zug zu einer Stellung
führt, die in Teilschritt (3) markiert worden ist. Weiß kann
hier in n Zügen matt setzen. Ergänze den Index an allen gefundenen Stellungen um den zugehörigen Zug und den Hinweis
Gewinnstellung für Weiß“. Gehe zurück zu Teilschritt (3).
”
Schritt 3: Gewinnstellungen für Schwarz
(1) Markiere alle Stellungen, bei denen Weiß bereits matt gesetzt
ist. Setze n = 1.
(2) Suche alle Stellungen, bei denen Schwarz am Zug ist und mindestens ein möglicher Zug zu einer Stellung führt, die in Teilschritt (1) markiert worden ist. Schwarz kann hier in einem
Zug matt setzen. Ergänze den Index an allen gefundenen Stellungen um den zugehörigen Zug und den Hinweis Gewinn”
stellung für Schwarz“.
(3) Markiere alle Stellungen, bei denen Weiß am Zug ist und jeder
mögliche Zug von Weiß zu einer Gewinnstellung für Schwarz
führt. Weiß kann hier eine Niederlage nicht verhindern. Gehe
zu Schritt 4, sobald keine Stellungen mehr markiert wurden.
(4) Erhöhe n um 1. Suche alle Stellungen, bei denen Schwarz am
Zug ist und mindestens ein möglicher Zug zu einer Stellung
führt, die in Teilschritt (3) markiert worden ist. Schwarz kann
hier in n Zügen matt setzen. Ergänze den Index an allen gefundenen Stellungen um den zugehörigen Zug und den Hinweis
Gewinnstellung für Schwarz“. Gehe zurück zu Teilschritt (3).
”
IV.3. ENDSPIELDATENBANKEN
40
Schritt 4: Remisstellungen
(1) Stellungen, die weder einen Hinweis Gewinnstellung für Weiß“
”
noch Gewinnstellung für Schwarz“ haben, können als Remis”
stellungen behandelt werden.
Abbildung IV.3.1. Beispielsituation
Bemerkung IV.3.2.
• Die Zahl aller betrachteten Stellungen ist endlich. Daher kann
- genug Speicher vorausgesetzt - auch ohne Probleme ein entsprechender Index erstellt werden.
• Algorithmus IV.3.1 muss nach endlicher Zeit enden, da die
Zahl der betrachteten Stellungen endlich ist. Insbesondere kann
es nur endlich viele Gewinnstellungen für Weiß sowie Schwarz
geben.
• Ein Problem bei der Anwendung dieses Algorithmus stellt die
50-Züge-Regel des Schachs dar. Sie besagt, dass eine Partie
als Remis zu werten ist, falls von beiden Spielern mindestens
50 Züge gemacht worden sind, ohne dass ein Stein geschlagen
oder ein Bauer gezogen wurde. Dies kann zu einem Problem
werden, wenn Endspieldatenbanken diese Regel nicht berücksichtigen. Beispielsweise ist es Weiß in der Situation aus Abbildung IV.3.1 erst im 243. (Doppel-)Zug möglich, einen schwarzen Springer zu schlagen (siehe [2], S. 189).
IV.4. SUCHFENSTERTECHNIK
41
IV.4. Suchfenstertechnik
Bislang wurde das Alpha-Beta-Pruning immer mit einem Suchfenster (−∞, ∞) gestartet. Dieses Intervall enthält den optimalen Wert auf
jeden Fall.
Man könnte das Alpha-Beta-Pruning allerdings auch direkt mit einem eingeschränkten Suchfenster (α, β) mit α, β ∈ Z starten und hoffen, dass der optimale Wert der Position darin liegt. So steigt zwar
die Chance auf Cutoffs und damit die Chance auf eine Beschleunigung
der Suche. Aber falls der Wert nicht in dem vorgegebenen Fenster liegt,
muss der gesamte Baum mit anderem Suchfenster nochmals durchsucht
werden. Man spricht hier von einer Wiederholungssuche.
Bei einer solchen Wiederholungssuche können zwei Fälle eintreten.
Hier sei p der Knoten, an dem die Suche gestartet wird.
• Die erste Suche mit Intervall (α, β) liefert α. Dann ist der
Minimax-Wert F (p) ≤ α und die Suche muss mit Fenster
(−∞, α) wiederholt werden.
• Die erste Suche mit Intervall (α, β) liefert β. Dann ist der
Minimax-Wert F (p) ≥ β und die Suche muss mit Fenster
(β, ∞) wiederholt werden.
IV.4.1. F-Verbesserung.
Wenn der Minimax-Wert außerhalb des Suchfensters liegt, wird eine
Intervallgrenze vom Alpha-Beta-Pruning zurückgeliefert. Es wäre jedoch wünschenswert, eine bessere Abschätzung zu haben. Damit könnte das Suchfenster für eine Wiederholungssuche schon vor dem Start
eingegrenzt werden. Glücklicherweise kann eine solche Änderung beim
Alpha-Beta-Pruning auf einfache Art realisiert werden.
Zunächst wird an das normale“ Alpha-Beta-Pruning erinnert:
”
1
int value(Position p , int alpha, int beta){
2
if(endposition(p))
3
return f(p);
4
int m = alpha;
5
berechneMöglicheZüge(p);
6
while(zügeÜbrig() && m<beta){
7
Position q = führeNächstenZugAus(p);
8
m = max(m,-value(q,-beta,-m));
9
}
10
return m;
11
}
IV.4. SUCHFENSTERTECHNIK
42
Die Invarianzbedingung des Korrektheitsbeweises für das AlphaBeta-Pruning in Abschnitt III.2,
m = max{α, −F (p1 ), . . . , −F (pi−1 )},
zeigt bereits einen Ansatz auf, wie eine optimierte Schranke ausgegeben
werden kann. Ziel einer Änderung muss es sein, den Eingabeparameter
α nicht in die Maximumsbildung einzubeziehen. Falls das α aus der Maximumsbildung in Programmzeile 8 ausgeschlossen wäre, würden nicht
nur Werte innerhalb des Suchintervalls ausgegeben. Möglich wäre auch
die Ausgabe eines korrekten Maximums, das außerhalb des Intervalls
(α, β) liegt. Insbesondere darf ein Maximum dann kleiner als α sein.
Wäre es größer als β, läge ein Cutoff vor und weitere Betrachtungen
wären nicht notwendig.
Um Werte möglich zu machen, die kleiner als α sind, muss die
Initialisierung der Variable m in Zeile 4 zu
int m = - INF;
geändert werden. So ist α keine untere Schranke für den Ausgabewert
mehr. Nun müssen allerdings mehr Knoten durchsucht werden als vor
der Änderung, da in Zeile 8 für −m der Wert ∞ statt −α übergeben wird. Um dies zu korrigieren, wird auch dieser Übergabeparameter
geändert:
m = max(m,-value(q,-beta,-max(m,alpha)));
Damit sind die übergebenen Werte vor und nach der Änderung gleich.
Somit werden im Verlauf des Algorithmus auch genau dieselben Knoten besucht wie vorher.
Der so entstandene Algorithmus heißt F-Verbesserung des AlphaBeta-Prunings. Das F“ steht hier für failsoft.
”
Algorithmus IV.4.1.
Die F-Verbesserung des Alpha-Beta-Prunings:
1
int value(Position p , int alpha, int beta){
2
if(endposition(p))
3
return f(p);
4
int m = - INF;
5
berechneMöglicheZüge(p);
6
while(zügeÜbrig() && m<beta){
7
Position q = führeNächstenZugAus(p);
8
m = max(m,-value(q,-beta,-max(m,alpha)));
9
}
10
return m;
11
}
Falls allerdings das Suchfenster zu Beginn geschickt gewählt wird,
sind kaum Wiederholungssuchen nötig. Die F-Verbesserung hat so kaum
IV.5. NULLFENSTER-SUCHVERFAHREN
43
Möglichkeiten, ihre Vorteile auszuspielen. In Abschnitt IV.5 bei den
Nullfenster-Suchverfahren ändert sich dies. Das dort vorgestellte Verfahren basiert hauptsächlich auf Wiederholungssuchen.
IV.4.2. L-Verbesserung.
Beim Entwurf der Bewertungsfunktion wird oft darauf geachtet, dass
sie nur ganzzahlige Werte annehmen kann. In diesem Fall sind auch
alle berechneten Minimax-Werte ganze Zahlen. Falls zusätzlich nur der
bestmögliche Zug gefunden werden soll und die exakte Berechnung des
Minimax-Wertes vernachlässigt werden kann, gibt es eine weitere Verbesserung des Alpha-Beta-Prunings. Sie heißt L-Verbesserung (engl.
last move improvement).
Falls der Algorithmus an Knoten p aufgerufen wird und p genau d
Kinder hat, werden nur die ersten d − 1 Kinder auf bekannte Weise
vom Alpha-Beta-Pruning untersucht. Der dabei ermittelte vorläufige
Optimalwert sei m. Die Untersuchung des letzten Unterbaums von p
wird nun mit dem Intervall (m, m + 1) durchgeführt. Dieses Suchfenster kann keinen Minimax-Wert enthalten, da die Bewertungsfunktion
nur ganze Zahlen liefert. Falls der Wert m zurückgegeben wird, ist der
Wert des letzten Unterbaums (d.h. −F (pd )) nicht größer als m. Der
bisherige optimale Zug bleibt weiterhin optimal. Falls allerdings m + 1
zurückgegeben wird, gilt −F (pd ) ≥ m + 1 > m und der letzte Zug ist
besser als alle vorherigen (d.h. optimal).
Diese Verbesserung braucht keinen zusätzlichen Speicherplatz oder
zusätzliche Rechenzeit. Es wird lediglich ein Suchfenster verkleinert.
Dadurch steigen natürlich die Chancen auf einen Cutoff, was der wesentliche Vorteil der L-Verbesserung ist. Hier wird diese Technik nur
beim letzten Unterbaum angewendet. Im nächsten Abschnitt jedoch
wird die Verwendung solcher minimalen Suchfenster weiter ausgeweitet. Es entsteht eine neue Klasse von Spielbaumsuchverfahren.
IV.5. Nullfenster-Suchverfahren
Bereits bei der L-Verbesserung der Suchfenstertechnik IV.4.2 kamen minimale Suchfenster der Form (m, m+1) (für m ∈ Z) vor. Solche
Suchfenster, die keinen Minimax-Wert enthalten können, werden Nullfenster genannt. Bei Verwendung des Alpha-Beta-Prunings mit einem
Nullfenster kann lediglich geprüft werden, ob der Minimax-Wert ≤ m
oder ≥ m + 1 ist. Die genaue Größe des Minimax-Wertes kann nicht
ermittelt werden.
IV.5. NULLFENSTER-SUCHVERFAHREN
44
Aufrufe mit einem Nullfenster sind sehr effizient, da das Suchfenster
sehr klein ist. Allgemein wird bei Nullfenster-Suchverfahren der Wert
des linken Kinderknotens auf herkömmliche Weise bestimmt. Danach
wird für alle weiteren Kinder lediglich geprüft, ob dieser Wert noch
übertroffen werden kann. Falls nicht, ist man am Ziel. Falls er hingegen
noch verbessert werden kann, muss eine Wiederholungssuche erfolgen,
um den Wert des neuen“ optimalen Knotens zu bestimmen.
”
Bei Kombination mit einer entsprechenden Vorsortierung der Züge,
wie sie in Abschnitt IV.1 vorgestellt wurde, sind in der Praxis kaum
Wiederholungssuchen notwendig.
IV.5.1. Negascout-Verfahren.
Der wohl bekannteste Vertreter der Nullfenster-Suchverfahren ist das
Negascout-Verfahren.
Abbildung IV.5.1. Ausgangssituation
Sei im Baum die Ausgangssituation IV.5.1 gegeben. Die Basis für
das Negascout-Verfahren IV.5.1 bildet das normale“ Alpha-Beta-Pru”
ning III.2.2. Der Wert von p1 muss exakt berechnet werden. Hierfür
erfolgt ein Aufruf mit normalem Suchfenster. Sobald ein Wert für p1
berechnet wurde, wird er mittels eines Nullfenster-Aufrufs mit den Werten von p2 , . . . , pd verglichen. Sobald ein Knoten pi gefunden wird, der
einen besseren Wert als p1 hat, wird eine Wiederholungssuche mit einem normalen Suchfenster eingeleitet. Der so berechnete Wert kann
dann wiederum mit den Knoten pi+1 , . . . , pd mittels Nullfenster verglichen werden.
Zunächst wird der Algorithmus angegeben. Änderungen zum AlphaBeta-Pruning werden blau markiert. Danach folgen einige Erklärungen.
IV.5. NULLFENSTER-SUCHVERFAHREN
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
45
Algorithmus IV.5.1.
int value(Position p, int alpha, int beta){
if(endposition(p))
return f(p);
int lo m = alpha;
int hi m = beta;
int j = 1;
berechneMöglicheZüge(p);
while(zügeÜbrig() && lo m<beta){
Position q = führeNächstenZugAus(p);
int t = -value(q,-hi m,-lo m);
if(t>lo m && t<beta && j>1)
t = -value(q,-beta,-t);
lo m = max(lo m,t);
hi m = lo m + 1;
j++;
}
return lo m;
}
Die Variable j dient ausschließlich dem Zählen des Knotens, welcher momentan untersucht wird (Anweisungen 6 und 15). Beim ersten
Kind p1 ist schließlich ein anderes Vorgehen notwendig als bei p2 , . . . , pd .
Die Variable lo m ist gleichwertig zur Variable m des Alpha-BetaPrunings. Sie wurde umbenannt, da die Einführung einer neuen Variable hi m notwendig ist. Diese beiden Variablen bilden zusammen das
Suchfenster des Algorithmus. Dies dient dazu, durch eine einfache Zuweisung der Variable hi m ein Nullfenster zu erzeugen.
Erinnerung: Beim Alpha-Beta-Pruning ist das Suchfenster (m, β), wobei m mit α initialisiert wird.
Vor dem Betreten der while-Schleife ist der Algorithmus identisch
zum Alpha-Beta-Pruning. Es kommen lediglich die beiden Initialisierungen in den Zeilen 5 und 6 hinzu. Auch die Abbruchbedingung für
die while-Schleife ist gleich. Sie besagt weiterhin:
Breche ab, falls alle Züge untersucht sind oder ein Cutoff vorliegt.
Beim ersten Durchlauf der while-Schleife (j = 1) ist das Suchfenster (lo m, hi m) = (α, β) aktuell. Dies entspricht dem normalen
Alpha-Beta-Pruning. Die Wiederholungssuche in Zeile 12 wird nicht
ausgeführt, da die Bedingung j > 1 in Zeile 11 verletzt ist. Daher
entsprechen die Zeilen 10 und 13 ebenfalls dem normalen Alpha-BetaPruning.
IV.5. NULLFENSTER-SUCHVERFAHREN
46
Abschließend wird innerhalb der while-Schleife ein Nullfenster gewählt (Zeile 14) und der untersuchte Knoten aktualisiert (Zeile 15).
Für das Nullfenster ist zu beachten, dass lo m den aktuellen MinimaxWert enthält. Daher bildet (lo m, lo m + 1) das zugehörige Nullfenster.
Indem diese beiden Zuweisungen nach jedem Schleifendurchlauf aktualisiert werden, wird sichergestellt, dass sie stets die korrekten Werte
enthalten.
Ab dem zweiten Schleifendurchlauf kommen die Anweisungen 11
und 12 zur Geltung. Sie bilden zusammen mit Anweisung 10 das Herzstück des Algorithmus. Das Suchfenster (lo m, hi m) ist ein Nullfenster.
Falls bei diesem Intervall lo m als Ergebnis zurückgeliefert wird, war
der zugehörige Zug nicht besser als der bisherige Favorit. Dann kann
die Wiederholungssuche in Zeile 12 übersprungen werden (Bedingung
t>lo m in der if-Anweisung). Falls aber hi m zurückgeliefert wird, kann
noch geprüft werden, ob ein Cutoff möglich ist. Das wäre bei β ≥ t der
Fall. Somit muss der genaue Wert nur berechnet werden, wenn t < β
gilt.
Um den Negascout-Algorithmus zu optimieren, kann man nur bei
den Wiederholungssuchen ansetzen. Nullfenster-Suchen sind bereits optimal (für einen Beweis siehe [5]). In den folgenden Abschnitten werden
einige konkrete Verbesserungen vorgestellt.
IV.5.2. F-Verbesserung.
Bereits im Rahmen des Alpha-Beta-Prunings wurde eine F-Verbesserung vorgestellt. Sie entfaltet jedoch erst hier im Rahmen des Negascout-Verfahrens ihre volle Wirkung. Die grundlegende Idee der failsoftVerbesserung besteht darin, für den Minimax-Wert eine genauere Abschätzung als die jeweilige Intervallgrenze zu liefern. Insbesondere wird
auch bei Nullfenstersuchen eine genaue Abschätzung zurückgegeben.
Die ausführliche Herleitung der F-Verbesserung für das Alpha-BetaPruning aus Abschnitt IV.4.1 kann analog übernommen werden. Das
Ziel ist auch hier, die Übergabeparameter zu erhalten und α aus der
Maximumsbildung auszuschließen.
IV.5. NULLFENSTER-SUCHVERFAHREN
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
47
Algorithmus IV.5.2.
int value(Position p, int alpha, int beta){
if(endposition(p))
return f(p);
int lo m = - INF;
int hi m = beta;
int j = 1;
berechneMöglicheZüge(p);
while(zügeÜbrig() && lo m<beta){
Position q = führeNächstenZugAus(p);
int t = -value(q,-hi m,-max(lo m,alpha));
if(t>max(lo m,alpha) && t<beta && j>1)
t = -value(q,-beta,-t);
lo m = max(lo m,t);
hi m = max(lo m,alpha) + 1;
j++;
}
return lo m;
}
Änderungen im Vergleich zu Algorithmus IV.5.1 sind wiederum
blau markiert.
IV.5.3. L-Verbesserung.
Während des Negascout-Algorithmus werden alle Knoten p2 , . . . , pd mit
einem Nullfenster untersucht, insbesondere auch der Letzte. Daher ist
die L-Verbesserung für das Alpha-Beta-Pruning aus Abschnitt IV.4.2
im Wesentlichen bereits in der Ursprungsversion integriert. Es muss nur
zusätzlich sichergestellt werden, dass bei Untersuchung des Knotens pd
auch dann keine Wiederholungssuche stattfindet, wenn er allen vorigen
Knoten überlegen sein sollte.
IV.5.4. TL-Verbesserung.
Ein Spielbaum werde mit dem Negascout-Verfahren samt F-Verbesserung durchsucht und der Wert des Knotens p1 sei bereits bekannt. Nun
beginnt der Algorithmus mit Nullfenster-Untersuchungen der Knoten
p2 , . . . , pd . Sobald ein überlegener Knoten gefunden wird, liefert die FVerbesserung eine untere Schranke für den Wert des Knotens.
Mit dieser Schranke kann man das Suchfenster aktualisieren und die
Suche nach weiteren überlegenen Knoten mit einem Nullfenster fortsetzen, ohne eine direkte Wiederholungssuche zu starten. Wenn man
Glück hat, gibt es keine weiteren Knoten, die als Favorit in Frage kommen. In diesem Fall muss man den Wert des überlegenen Knotens nicht
genau ausrechnen, weil bereits feststeht, dass es der beste ist. Diese
IV.5. NULLFENSTER-SUCHVERFAHREN
48
Verbesserung kann demnach als verfeinerte L-Verbesserung angesehen
werden.
Bei dieser Strategie gibt es allerdings einen Schwachpunkt. Wenn
der Wert des ersten gefundenen überlegenen Knotens nicht direkt ausgerechnet wird, werden zwar die dazu nötigen Berechnungen gespart.
Aber die folgenden Knoten müssen dann mit einem ungünstigeren
Suchfenster untersucht werden, weil nur eine untere Schranke anstelle
des exakten Wertes verwendet werden kann. Und sobald eine Wiederholungssuche unabwendbar ist, bedeutet dies einen großen Mehraufwand.
Im Endeffekt ist es eine Spekulation, ob ein weiterer überlegener
Knoten existiert. Es ist nicht a priori klar, ob sich diese Erweiterung
des Negascout-Algorithmus positiv oder negativ auswirkt. Die einfache
L-Verbesserung hingegen bedeutet nie einen Nachteil.
Literaturverzeichnis
[1] Alfred V. Aho, John E. Hopcroft, Jeffrey D. Ullman, Data structures and algorithms, Addison-Wesley Publishing Company, 1987.
[2] Jörg Bewersdorff, Glück, Logik und Bluff, 4., durchgesehene und ergänzte Auflage, Friedr. Vieweg & Sohn Verlag, Wiesbaden, 2007.
[3] Lars Bremer, Von MIPS zu Grips: Wie Computer den Menschen bei Denkspielen
schlagen - oder nicht, c’t 18/2007 (2007), Heise Zeitschriften Verlag.
[4] Donald E. Knuth and Ronald W. Moore, An Analysis of Alpha-Beta-Pruning,
Artificial Intelligence 6 (1975), 293–326.
[5] Alexander Reinefeld, Spielbaum-Suchverfahren, Informatik-Fachberichte 200
(1989), Springer-Verlag.
[6] Wikipedia, Alpha-Beta-Pruning, http://de.wikipedia.org/wiki/Alpha-BetaPruning, abgerufen am 27.11.2008.
[7] Wikipedia, Endspieldatenbank, http://de.wikipedia.org/wiki/Endspieldatenbank,
abgerufen am 05.01.2009.
49
Eigenständigkeitserklärung
Hiermit versichere ich, dass ich diese Masterarbeit selbständig verfasst
und keine anderen als die angegebenen Quellen und Hilfsmittel verwendet sowie Zitate kenntlich gemacht habe.
Bochum, 19. Februar 2009
Herunterladen