gambit
Eine Schach-Engine in Scala 3. Zuggenerierung, Stellungsbewertung und Suche - ein komplettes Gehirn zum Schachspielen, gebaut mit scala-cli.
Eine Schach-Engine in Scala 3. Drei schwierige Dinge auf einmal: fehlerfreie Zuggenerierung, sinnvolle Stellungsbewertung und eine Suche, die in vernünftiger Zeit einen guten Zug wählt. Ein vollständiges Gehirn zum Spielen.
Einführung
Eine Schach-Engine sieht nur aus wie ein Projekt. Es sind drei Subsysteme, von denen jedes das Ganze auf seine eigene Weise ruinieren kann, und erst zusammen ergeben sie etwas, das sinnvoll spielt. Bei gambit geht es darum, diese drei Teile so gut aufeinander abzustimmen, dass das Ergebnis anfängt, einem echten Gegner zu ähneln, und nicht einem Zufallszuggenerator.
Scala 3 bietet hier eine ausdrucksstarke Sprache, um das Brett, die Züge und den Baum der Varianten zu modellieren. Aber die echte Herausforderung ist nicht syntaktisch, sondern algorithmisch: ein fehlerfreier Generator, eine faire Bewertung und eine Suche, die nicht endlos rechnet.
Drei Probleme, die zusammenpassen müssen
Ein Zuggenerator, der einen illegalen Zug pro Million Stellungen durchlässt, bringt die Engine dazu, etwas Unmögliches zu spielen. Eine Bewertung, die die Figuren falsch gewichtet, führt sie mit Überzeugung in eine Niederlage. Eine Suche ohne Beschneidung denkt stundenlang über einen Zug nach, der in einer Sekunde fallen sollte.
alle legalen Züge in jeder Stellung, einschließlich Rochade, En passant und Umwandlung.
eine Zahl, die ausdrückt, wer besser steht, während die Partie noch läuft.
Alpha-Beta, das Äste verwirft, die sich nicht zu berechnen lohnen.
Keines dieser drei lässt sich abtun. Eine Engine, die in einem davon schwach ist, verliert, und zwar aus einem konkreten, benennbaren Grund, nicht aus allgemeiner Schwäche.
Alpha-Beta, die Kunst des Nichtrechnens
Die naive Suche prüft jede mögliche Fortsetzung, und davon gibt es schon wenige Züge tief Milliarden. Die Alpha-Beta-Beschneidung bemerkt, dass, wenn eine Antwort des Gegners eine Variante bereits widerlegt, der Rest seiner Antworten nicht berechnet werden muss. Bei guter Zugordnung schneidet das den Raum so stark, dass die Engine in derselben Zeit tiefer reicht.
Zu durchsuchende Knoten bei gleicher Tiefe (orientierend, Tsd.)
Das ist keine kleine Optimierung, sondern der Unterschied zwischen einer Engine, die drei Züge vorausschaut, und einer, die sechs sieht. Im Schach schlägt sich diese Tiefe direkt in Spielstärke nieder.
Perft, der Beweis der Generatorkorrektheit
Die Korrektheit des Zuggenerators wird mit dem sogenannten Perft überprüft: Sie zählen alle bis zu einer gegebenen Tiefe erreichbaren Stellungen und vergleichen sie mit Zahlen, die die ganze Schachgemeinschaft auswendig kennt. Stimmt Ihre Zahl nicht, haben Sie irgendwo einen Bug, und man sieht genau, bei welcher Tiefe die Abweichung beginnt.
Perft aus der Startstellung
| Tiefe | Anzahl der Stellungen |
|---|---|
| 1 | 20 |
| 2 | 400 |
| 3 | 8902 |
| 4 | 197281 |
| 5 | 4865609 |
Das Ergebnis ist eine vollständige Engine, die eine Stellung nimmt und einen Zug zurückgibt: Der Generator legt alle legalen Fortsetzungen aus, die Bewertung sagt, welche in eine bessere Richtung führt, und Alpha-Beta sucht so tief, wie es die Zeit erlaubt. Drei Subsysteme, die einzeln nur Teile sind, ergeben zusammen einen Gegner, der spielen kann.
Perft ist das Musterbeispiel eines Tests, der wirklich fehlschlagen kann. Er prüft nicht, dass etwas funktioniert, er vergleicht Ihre Zahl mit einer im Voraus bekannten Zahl, also wirft jeder Bug im Generator das Ergebnis sofort daneben.
Weitere Projekte
Weitere Projekte aus derselben Kategorie - sehen Sie, wie wir ähnliche Herausforderungen angehen.
Haben Sie ein ähnliches Projekt?
Melden Sie sich - ein Angebot ist kostenlos und kommt innerhalb einer Stunde.



