Dagaz: Episoden (Teil 1)

Wir haben Ihre mentalen Filter erschüttert und das Ergebnis war eine Antwort. Die Methode hat funktioniert, es wird immer effektiv sein. Alles, was getan werden muss, ist, die zusätzliche Last der Vorurteile loszuwerden ...

Raymond Jones " Geräuschpegel "

Dagaz erschien nicht von Grund auf neu. Ich habe Brettspiele und Puzzles schon immer gemocht und programmiere so viel ich mich erinnern kann, aber der Gedanke an eine bestimmte „universelle“ Engine hätte mir einfach nicht in den Sinn kommen können. Ich war dieser Idee skeptisch gegenüber. Bis ich Zillions sah. Leider entwickelte sich das Produkt zu diesem Zeitpunkt nicht mehr, der Quellcode war nicht verfügbar, und das Programm funktionierte tatsächlich nur unter Windows. Nach einiger Zeit entschied ich mich für ein offenes Projekt.

Wie ich bereits sagte, hatte ich keine Quellcodes, aber ich habe Zillions ein wenig berührt und seine Hauptidee verstanden - die maximale Wiederverwendung von Anwendungscode, die es ermöglicht, dieselben Konstruktionen in verschiedenen zu verwenden, was völlig unterschiedlich zu sein scheint Fälle. Es ging um den richtigen Einsatz. Und ich habe einen Plan gemacht .

Kontrolleure


Diese wichtige, aber äußerst unterschätzte Spielefamilie legte den Grundstein für das Projekt. Alle "Dame" -Spiele sind einander ähnlich und unterscheiden sich nur in Details. In Bezug auf das Spieldesign verbinden sie alle drei Hauptideen:

  • Durch Scheck
  • Priorität nehmen
  • Zusammengesetzte Bewegung

Der erste Absatz wirft keine besonderen Fragen auf, aber wenn sich die Entwicklung auf Schachspiele konzentriert, kann dies eine Überraschung sein. Nicht in allen Spielen findet die Erfassung auf demselben Feld statt, auf dem das Stück den Zug abgeschlossen hat. Bei Priority Moves sind die Dinge etwas interessanter. In Checkern können Sie mit dieser Regel ein komplexes Kombinationsspiel erstellen, das den Feind in Fallen lockt, die nach dem Prinzip "Weniger geben - mehr aufheben" funktionieren.


Natürlich wurde der Mechanismus der Prioritätsbewegungen in Zillions implementiert (und von dort nach Dagaz migriert). Ohne sie könnten fast alle Dame-Spiele (die sicherlich im "Gentleman-Set" der Brettspiele enthalten sind, die für die Implementierung obligatorisch sind) einfach nicht richtig funktionieren. Es geht nur um die Details. Mal sehen, wie dieser Mechanismus implementiert wurde:

In Millionen
(move-priorities jump-type normal-type) ... (define checker-shift ( $1 (verify empty?) ;        add ;   )) (define checker-jump ( $1 (verify enemy?) ;         capture ;   ( capture  -   ) $1 (verify empty?) ;           add ;   )) ... (piece (name Man) (image White "images/stapeldammen/white.bmp" Red "images/stapeldammen/red.bmp") (moves (move-type jump-type) (checker-jump nw) (checker-jump ne) (checker-jump sw) (checker-jump se) (move-type normal-type) (checker-shift nw) (checker-shift ne) ) ) 

Dies ist eine fast vollständige Beschreibung des einfachsten Dame-Spiels. Das Konzept der Bewegungsmodi ( Bewegungstyp ) wird im ZRF eingeführt , und die Konstruktion der Bewegungsprioritäten erlaubt es uns zu sagen, dass bei Bewegungen mit höherer Priorität (Takes) eine geringere Priorität (ruhige Bewegungen) nicht berücksichtigt werden sollte. Prioritätsstufen können bestimmt werden und mehr als zwei, in dieser Hinsicht ist das Design ziemlich universell, aber bei der Arbeit an Spielen in Dagaz bin ich auf einige Einschränkungen dieses Mechanismus gestoßen.


In diesem von Solomon Golomb erfundenen Spiel gibt es neben Dame auch Schachfiguren. Die Schwierigkeit liegt in der Tatsache, dass das Nehmen, obwohl es für die Kontrolleure eine Priorität bleibt, für Schachfiguren keine solche ist (andernfalls wäre es zu einfach, sie zu fangen und zu essen). Eine naive Priorisierung mit dem Schlüsselwort Verschiebungsprioritäten funktioniert in diesem Spiel nicht.

Wenn Schachfiguren nicht in den Prioritätszügen enthalten sind und die Möglichkeit besteht, sowohl eine Schachfigur als auch eine Schachfigur zu nehmen, können wir keine Schachfigur spielen, da eine Scheckaufnahme Priorität hat. Wenn Schachzüge als gleichrangig angesehen werden, sind wir verpflichtet, bei jeder sich bietenden Gelegenheit Schachfiguren zu nehmen. Beide widersprechen den Spielregeln.

In Millionen ist dieses Problem praktisch nicht gelöst. Und das war der Hauptgrund, warum ich über die Einführung eines JavaScript-Erweiterungsmechanismus in Dagaz nachgedacht habe. Die Idee an sich ist recht einfach: Da einige Spielmechaniken im ZRF ziemlich schwer auszudrücken sind, warum nicht die Nachbearbeitungsphase der Züge einführen? In diesem Fall durchsucht das Erweiterungsmodul die gesamte Liste der generierten Züge in seiner Gesamtheit und kann Entscheidungen über die Ablehnung bestimmter Züge treffen. So sieht es für Shashmat aus :

Einfacher und kompakter Code
 var CheckInvariants = Dagaz.Model.CheckInvariants; Dagaz.Model.CheckInvariants = function(board) { var design = Dagaz.Model.design; var types = []; types.push(design.getPieceType("Bishop")); types.push(design.getPieceType("Camel")); var isPriority = false; _.each(board.moves, function(move) { if (isCapturing(board, move)) { if (_.indexOf(types, getType(board, move)) < 0) isPriority = true; } }); if (isPriority) { _.each(board.moves, function(move) { if (!isCapturing(board, move)) { move.failed = true; } }); } CheckInvariants(board); } 

In Zukunft entwickelte und blühte die Idee der Erweiterungen mit einer prächtigen Farbe. Ich habe einen praktischen und leistungsstarken Mechanismus zum Codieren vieler Spiele, deren Implementierung auf reinem ZRF äußerst problematisch wäre. Bedeutet dies jedoch, dass die Priorisierung im ZRF-Stil veraltet ist? Natürlich nicht! Erstens ist das Schreiben einer Zeile in ZRF einfacher als fünfzig in JavaScript, aber was noch wichtiger ist, „harte“ Prioritäten im ZRF-Stil funktionieren so, dass Bewegungen mit niedriger Priorität nicht einmal generiert werden! Dies ist wichtig für die Leistung. Das Generieren von Umzügen in Dagaz ist eine sehr teure Operation.

Ein weiteres Spiel mit herausfordernden Prioritäten

Dablot ist ein Spiel, das den italienischen Entwürfen etwas ähnelt, aber älter ist. Neben gewöhnlichen Figuren gibt es darin „Fürsten“ und „Könige“, und jüngere Figuren haben nicht das Recht, Älteste zu schlagen. Das ist aber nicht die Schwierigkeit. Für Könige (und in einigen Varianten des Spiels auch für Prinzen) ist die Erfassung optional! Hier tritt das gleiche Problem auf wie bei Shashmat . Wenn wir den König zur Priorität erklären, werden wir die Spielregeln grob verletzen, andernfalls können wir den König nicht mit der Möglichkeit eines alternativen Kampfes mit einer einfachen Figur schlagen. Nur die Dagaz-Erweiterungsmaschine löst dieses Problem.

Bei "Italian Drafts" ist übrigens nicht alles so einfach. In vielen Arten von Entwürfen gibt es eine Regel, die besagt, dass der Spieler verpflichtet ist, die maximale Anzahl von Stücken zu nehmen. Das heißt, er kann nicht einfach die Kette der Eroberungen unterbrechen, sondern muss den Weg wählen, auf dem er mehr Stücke nehmen wird! Aus den Gründen, die ich unten diskutieren werde, konnte diese Regel nicht in einer universellen Form in Zillions implementiert werden, und die Entwickler waren gezwungen, sie fest zu codieren. In italienischen Entwürfen klingt die "Regel der Mehrheit" noch komplizierter: "Sie müssen die maximal mögliche Anzahl der Entwürfe des Gegners schlagen, und bei gleichen Kampfoptionen müssen Sie die maximale Anzahl der Damen schlagen."

Zusammengesetzte Bewegungen sind die zweite wichtige Komponente von Dame-Spielen. So wichtig, dass ich den Test für die korrekte Erfassung in den " Turkish Drafts " bis jetzt regelmäßig durchführe. Ein paar Mal, als ich das Modell bei den nächsten Änderungen kaputt machte, hat es wirklich geholfen.

Bewegungen - zusammengesetzt und teilweise
Mal sehen, wie zusammengesetzte Bewegungen in ZRF implementiert werden
 (define checker-shift ( $1 (verify empty?) (if (in-zone? promotion) (add King) else add ) )) (define checker-jump ( $1 (verify enemy?) capture $1 (verify empty?) (if (in-zone? promotion) (add King) else (add-partial jump-type) ) )) (define king-shift ( $1 (verify empty?) add )) (define king-jump ( $1 (verify enemy?) capture $1 (verify empty?) (add-partial jump-type) )) 

So einfach ist das. Der Befehl zum Hinzufügen eines Teils besagt, dass der Zug fortgesetzt werden kann (mit demselben Teil ist dies wichtig), wenn noch Züge mit dem angegebenen Modus vorhanden sind. Mit anderen Worten: "Die Figur muss weiter nehmen, solange es eine solche Gelegenheit gibt." Alles scheint in Ordnung zu sein, aber es gibt eine Einschränkung. Zillions sieht jede solche Einstellung als separate „Teilbewegung“. Mal sehen, wozu das führen kann.


In diesem Spiel wird die Anzahl der von einem Stück ausgeführten "Schritte" durch das Symbol bestimmt, auf dem es steht. Jetzt bewegt sich Weiß und Damyo geht (ein Stück, das mit einer roten Perle markiert ist). In Zillions kann sie nach Abschluss von zwei Teilzügen leicht in die obere linke Ecke gehen, von wo aus sie den letzten verbleibenden Zug nicht mehr ausführen kann (Sie können nicht zurückgehen). Es ist ebenfalls verboten, die gegnerische Figur im zweiten Teilzug zu nehmen. In Zillions gibt es keine Möglichkeit, die Abfolge von Zügen zu verbieten, die zu einer Sackgasse führen.

Bei Dagaz ist das anders! Eine Folge von Teilbewegungen wird immer zu einer vollständigen zusammengesetzten Bewegung zusammengesetzt. Ein Zug, der nicht abgeschlossen werden kann, wird einfach nicht passieren! Dies ist ein ressourcenintensiverer Ansatz, weshalb das Erstellen einer Verschiebungsliste in Dagaz eine sehr teure Operation ist. Aber seine Vorteile sind bedeutend. Zum Beispiel empfängt der Bot die gesamte zusammengesetzte Bewegung in ihrer Gesamtheit und sollte nicht nach vorne schauen und die verbleibenden Teilbewegungen ausführen.

Noch wichtiger ist, dass dieser Ansatz die Möglichkeit bietet, die gesamte Liste der bedingt akzeptablen Bewegungen zu berücksichtigen, komplexere Überprüfungen durchzuführen und einige Bewegungen abhängig von der Anwesenheit anderer zu verbieten. Zum Beispiel wird die oben erwähnte "Mehrheitsregel" in Dagaz ganz einfach implementiert. Darüber hinaus auch für die "Italian Checkers". Die Entwickler von Zillions "lösten" das Problem, das sie für Checkers-Spiele kannten, indem sie die Option " Maximum Captures " fest codierten. Es gibt jedoch eine große Anzahl von Spielen mit anderen komplexen Checks, von denen sie zu diesem Zeitpunkt keine Ahnung hatten!

Bei der Arbeit an neuen Spielen wurde auch das Konzept eines zusammengesetzten Zuges entwickelt. Fanorona und Pasang schlugen eine interessante Spielmechanik vor, bei der der Spieler, der den Zug ausführt, eine Gruppe von vom Brett entfernten Teilen auswählen sollte:


Fanorona ist auch eines dieser seltenen Spiele, bei denen ein Spieler das Recht hat, die Kette der Eroberungen zu unterbrechen. Die erste Erfassung ist obligatorisch, die anschließende innerhalb desselben Zuges - nach Ermessen des Spielers. In Dagaz wird diese Option ( teilweise bestanden ) implementiert, indem die Figur an Ort und Stelle verschoben wird. Missclick kann hier sein, und dies ist anscheinend nicht sehr praktisch, aber mit der Einführung des Sitzungsmanagers können fehlerhafte Bewegungen jetzt zurückgesetzt werden.

Eine Weiterentwicklung des Themas waren die "Schieß" -Züge. Ich habe sie zuerst in Hanga Roa und Ko Shogi gemacht , aber wie sich später herausstellte, habe ich es falsch gemacht! Die fehlerhafte Implementierung funktionierte nicht unter der Kontrolle von Bots (und da ich für beide Spiele immer noch keine Bots habe, ist es nicht verwunderlich, dass ich nichts bemerkt habe). Viel später, als ich Amazons machte , gelang es mir, das Problem zu lokalisieren und zu beheben. Diese Idee erreichte ihren Höhepunkt in einem Spiel, das 1957 von einem unserer Landsleute erfunden wurde.


Es gibt ein weiteres Problem im Zusammenhang mit der Implementierung von Composite Moves in Dagaz. Tatsache ist, dass die Liste der zulässigen Züge aus einem bestimmten Spielzustand sofort erstellt wird - das Ganze. In Zillions mit seinen Teilzügen ist dies nicht sehr kritisch, aber in Dagaz wird die Phase der Generierung des Zuges niemals abgeschlossen sein, wenn das Stück die Möglichkeit erhält, „an Ort und Stelle zu kreisen“ (es ist offensichtlich, dass es unmöglich ist, dieses Problem mit Erweiterungen zu beheben, da es einfach ist, mit ihnen umzugehen erreicht nicht). Hier ist eines der Spiele, für die dies wichtig ist:


Hier werden die Teile nicht vom Brett entfernt und das gleiche Teil kann viele Male hintereinander gesprungen werden. Die naheliegende Lösung besteht darin, den Besuch desselben Feldes zweimal pro Runde zu verbieten, aber ich musste mich gründlich mit dem Kernel befassen, um eine solche Prüfung durchzuführen. Dies war ein bisschen wie die Implementierung der Option „ Aufgeschobene Erfassung “, aber da ich viel früher russische Entwürfe erstellt habe, gab es viel weniger Probleme damit.

Leider gibt es Spiele, in denen auch solche Prüfungen nicht speichern
Die Regeln der Stapeldammen (dies ist eine Art „ Säulen “) besagen ausdrücklich, dass dasselbe Stück mehrmals pro Spielzug geschlagen werden kann. Das Stück, das den Zug ausführt, kehrt mehrmals an dieselbe Position zurück und setzt den Kampf fort, während es sich im Feind befindet In den Spalten befinden sich Zahlen. Zusammengesetzte Bewegungen von Dagaz können dieses Problem nicht bewältigen. Die Logik des Pole Drafts-Kampfes ist für den Kernel zu kompliziert und erreicht die Erweiterungen nicht, da die Erzeugung der Schleife geloopt wird. Natürlich gibt es einen Ausweg:


Es gibt keine Teilzüge in Dagaz, aber wir können sie emulieren, indem wir den nächsten Zug des Gegners überspringen (der gleiche Ansatz wird in Abziehbildern verwendet ). Und genau diese Logik lässt sich leicht durch die Erweiterung implementieren. Wir verbieten einfach alle Züge unter bestimmten Bedingungen und die Option Pass-Turn = Forced generiert automatisch einen leeren Zug. Hier ist ein weiteres Spiel mit ähnlicher Emulation.


Das künstliche Teilen von zusammengesetzten Zügen in Teilbewegungen ist für KI-Bots nicht sehr gut, aber manchmal gibt es einfach keinen anderen Ausweg.

Im Allgemeinen bewegt und entwickelt sich das Konzept der Verbindung. In jüngerer Zeit musste ich eine weitere neue Option ( vollständig teilweise ) für ein altägyptisches Spiel vornehmen.


Neben der automatischen Vervollständigung der Bewegung von Figuren entlang der Pfeile bietet es auch andere interessante technische Lösungen. Aber darüber ein andermal.

Source: https://habr.com/ru/post/de459456/


All Articles