Dies ist die 14-tägige Herausforderung Nr. 3. Thema: Genetische Algorithmen
Diese Herausforderung ist ein bisschen experimentell. Wir wollten herausfinden, was wir mit genetischen Algorithmen herausfordern können. Es mag nicht alles optimal sein, aber wir haben unser Bestes gegeben, um es zugänglich zu machen. Wenn dies klappt, wer weiß, was wir in Zukunft sehen könnten? Vielleicht ein genetischer King of the Hill?
Die Spezifikation ist ziemlich lang! Wir haben versucht, die Spezifikation in "The Basics" zu unterteilen - das absolute Minimum, das Sie benötigen, um mit dem Framework zu spielen und eine Antwort zu senden - und "The Gory Details" - die vollständige Spezifikation mit allen Details zum Controller, auf deren Grundlage Sie arbeiten könnte deine eigene schreiben.
Wenn Sie irgendwelche Fragen haben, können Sie gerne mit uns chatten!
Du bist ein Forscher in der Verhaltenspsychologie. Es ist Freitagabend und Sie und Ihre Kollegen beschließen, Spaß zu haben und Ihre Laborratten für ein kleines Rattenrennen zu verwenden. Nennen wir sie tatsächlich Exemplare , bevor wir uns zu emotional an sie binden .
Sie haben eine kleine Rennstrecke für die Exemplare eingerichtet, und um es interessanter zu machen, haben Sie ein paar Mauern und Fallen und Teleporter über die Strecke gelegt. Jetzt sind deine Exemplare immer noch Ratten ... sie haben keine Ahnung, was eine Falle oder ein Teleporter ist. Sie sehen nur einige Dinge in verschiedenen Farben. Sie haben auch keinerlei Gedächtnis - alles, was sie tun können, ist Entscheidungen auf der Grundlage ihrer aktuellen Umgebung zu treffen. Ich vermute, dass die natürliche Selektion die Exemplare heraussucht, die wissen, wie man einer Falle aus dem Weg geht, die es nicht wissen (dieses Rennen wird eine Weile dauern ...). Lasst die Spiele beginnen! †
† 84.465 Exemplare wurden bei dieser Herausforderung verletzt.
Die Grundlagen
Dies ist ein Einzelspieler-Spiel (Sie und Ihre Kollegen wollten die Bevölkerung nicht verwechseln, also baute jeder seine eigene Rennstrecke). Die Rennstrecke ist ein rechteckiges Gitter, 15 Zellen hoch und 50 Zellen breit. Sie beginnen mit 15 Proben in zufälligen (nicht unbedingt unterschiedlichen) Zellen am linken Rand (wobei x = 0 ). Ihre Proben sollten versuchen, das Ziel zu erreichen, bei dem es sich um eine beliebige Zelle bei x ≥ 49 und 0 ≤ y ≤ 14 handelt (die Proben können die Spur nach rechts überschreiten). Jedes Mal, wenn dies passiert, bekommst du einen Punkt. Sie starten das Spiel auch mit 1 Punkt. Sie sollten versuchen, Ihre Punkte nach 10.000 Runden zu maximieren .
Mehrere Proben können dieselbe Zelle belegen und interagieren nicht.
Jedes Exemplar sieht in jeder Runde ein 5x5-Raster seiner Umgebung (mit sich selbst in der Mitte). Jede Zelle dieses Gitters enthält eine Farbe -1
für 15
. -1
Stellt Zellen dar, die außerhalb der Grenzen liegen. Ihre Probe stirbt, wenn sie sich außerhalb der Grenzen bewegt. Die anderen Farben repräsentieren leere Zellen, Fallen, Wände und Teleporter. Aber Ihr Exemplar weiß nicht, welche Farbe was darstellt, und Sie auch nicht. Es gibt jedoch einige Einschränkungen:
- 8 Farben stehen für leere Zellen.
- 4 Farben repräsentieren einen Teleporter. Ein Teleporter sendet die Probe an eine bestimmte Zelle in seiner 9x9-Nachbarschaft. Dieser Versatz ist für alle Teleporter der gleichen Farbe gleich.
- 2 Farben repräsentieren Wände. Sich in eine Wand zu bewegen ist dasselbe wie still zu stehen.
- 2 Farben repräsentieren eine Falle. Eine Falle zeigt an, dass eine der 9 Zellen in ihrer unmittelbaren Nachbarschaft tödlich ist (nicht unbedingt die Falle selbst). Dieser Versatz ist für alle Überfüllungen derselben Farbe gleich.
Nun zu dieser natürlichen Selektion ... jedes Exemplar hat ein Genom, das eine Zahl mit 100 Bits ist. Neue Exemplare werden durch Kreuzung zweier vorhandener Exemplare und anschließende leichte Mutation des Genoms erzeugt. Je erfolgreicher ein Exemplar ist, desto größer ist seine Reproduktionswahrscheinlichkeit.
Hier ist also Ihre Aufgabe: Sie schreiben eine einzelne Funktion, die als Eingabe das 5x5-Farbraster erhält, das eine Probe sieht, sowie ihr Genom. Ihre Funktion gibt eine Bewegung (Δx, Δy) für die Probe zurück, wobei Δx und Δy jeweils eine von sind {-1, 0, 1}
. Sie dürfen keine Daten zwischen Funktionsaufrufen beibehalten. Dies beinhaltet die Verwendung eigener Zufallszahlengeneratoren. Ihre Funktion wird mit einem gesetzten RNG ausgestattet, das Sie nach Belieben verwenden können.
Die Bewertung Ihres Beitrags ist das geometrische Mittel der Punktzahl auf 50 zufälligen Tracks. Wir haben festgestellt, dass diese Punktzahl einiges an Varianz aufweist. Daher sind diese Ergebnisse vorläufig . Sobald diese Herausforderung endet, wird eine Frist bekannt gegeben. Am Ende der Frist werden 100 Boards nach dem Zufallsprinzip ausgewählt und alle Einsendungen werden auf diesen 100 Boards neu bewertet. Fühlen Sie sich frei, eine geschätzte Punktzahl in Ihre Antwort einzutragen, aber wir werden jede Einreichung selbst bewerten, um sicherzustellen, dass niemand betrügt.
Wir haben Steuerungsprogramme in einer Handvoll Sprachen bereitgestellt. Derzeit können Sie Ihren Beitrag in Python (2 oder 3), Ruby , C ++ , C # oder Java schreiben . Der Controller generiert die Bretter, führt das Spiel aus und stellt einen Rahmen für den genetischen Algorithmus bereit. Sie müssen lediglich die Bewegungsfunktion bereitstellen.
Warten Sie, was genau mache ich mit dem Genom?
Die Herausforderung besteht darin, das herauszufinden!
Da die Exemplare kein Gedächtnis haben, ist alles, was Sie in einer bestimmten Runde haben, ein 5x5-Raster von Farben, die Ihnen nichts bedeuten. Sie müssen also das Genom verwenden, um das Ziel zu erreichen. Die allgemeine Idee ist, dass Sie Teile des Genoms verwenden, um Informationen über die Farben oder das Rasterlayout zu speichern, und Ihr Bot seine Entscheidungen auf der Grundlage der zusätzlichen Informationen, die im Genom gespeichert sind.
Natürlich können Sie dort nichts manuell speichern. Die dort gespeicherten Informationen sind also zunächst völlig zufällig. Der genetische Algorithmus wird jedoch bald diejenigen Exemplare auswählen, deren Genom die richtigen Informationen enthält, während diejenigen, die die falschen Informationen enthalten, getötet werden. Ihr Ziel ist es, eine Zuordnung von den Genombits und Ihrem Blickfeld zu einer Bewegung zu finden, mit der Sie schnell einen Weg zum Ziel finden und die sich konsequent zu einer Gewinnstrategie entwickelt.
Dies sollten genügend Informationen sein, um Ihnen den Einstieg zu erleichtern. Wenn Sie möchten, können Sie den nächsten Abschnitt überspringen und den Controller Ihrer Wahl aus der Liste der Controller unten auswählen (die auch Informationen zur Verwendung dieses bestimmten Controllers enthält).
Lesen Sie weiter, wenn Sie alle wollen ...
Die blutigen Details
Diese Spezifikation ist vollständig. Alle Controller müssen diese Regeln implementieren.
Jede Zufälligkeit verwendet eine gleichmäßige Verteilung, sofern nicht anders angegeben.
Track-Generierung:
- Die Spur ist ein rechteckiges Gitter, X = 53 Zellen breit und Y = 15 Zellen hoch. Zellen mit x ≥ 49 sind Zielzellen (wobei x auf Null basiert).
- Jede Zelle hat eine einzige Farbe und kann tödlich sein oder auch nicht - Zellen sind nicht tödlich, es sei denn, einer der folgenden Zelltypen gibt dies an.
- Es gibt 16 verschiedene Zellenfarben, die von
0
bis beschriftet sind15
und deren Bedeutung sich von Spiel zu Spiel ändert. Stellt außerdem-1
Zellen dar, die außerhalb der Grenzen liegen - diese sind tödlich . - Wähle 8 zufällige Farben . Dies sind leere Zellen (die keine Auswirkung haben).
- Wähle 4 weitere zufällige Farben . Das sind Teleporter. Wählen Sie für zwei dieser Farben einen Versatz ungleich Null in der Nachbarschaft 9x9 (von (-4, -4) bis (4,4) mit Ausnahme von (0,0)). Invertieren Sie für die beiden anderen Farben diese Offsets. Wenn ein Exemplar auf einen Teleporter tritt, wird es sofort um diesen Versatz bewegt.
- Wähle 2 weitere zufällige Farben . Das sind Fallen. Wählen Sie für jede dieser Farben einen Versatz im 3x3-Bereich (von (-1, -1) bis (1,1)). Eine Falle zeigt an, dass die Zelle an diesem Versatz tödlich ist . Hinweis: Die Falle selbst ist nicht unbedingt tödlich.
- Die 2 verbleibenden Farben sind Wände, die die Bewegung behindern. Der Versuch, auf eine Wandzelle zu gelangen, führt dazu, dass die Bewegung stillsteht. Wandzellen selbst sind tödlich .
- Wählen Sie für jede Nicht-Ziel-Zelle des Rasters eine zufällige Farbe. Wählen Sie für jede Zielzelle eine zufällige leere Farbe.
- Bestimmen Sie für jede Zelle am linken Rand der Spur, ob das Ziel innerhalb von 100 Runden erreicht werden kann (gemäß den folgenden Regeln für die Reihenfolge der Runden). Wenn ja, ist diese Zelle eine zulässige Startzelle . Wenn weniger als 10 Startzellen vorhanden sind, verwerfen Sie die Spur und generieren Sie eine neue.
- Erstellen Sie 15 Exemplare mit einem zufälligen Genom und einem Alter von 0 Jahren . Legen Sie jede Probe auf eine zufällige Startzelle.
Turn Reihenfolge:
- Die folgenden Schritte werden der Reihe nach für jede Probe ausgeführt. Die Proben interagieren nicht oder sehen sich nicht und können dieselbe Zelle einnehmen.
- Wenn die Probe 100 Jahre alt ist , stirbt sie. Andernfalls erhöhen Sie das Alter um 1.
- Die Probe erhält ihr Sichtfeld - ein 5x5-Farbraster, das auf der Probe zentriert ist - und gibt eine Bewegung in ihrer 3x3-Nachbarschaft zurück. Bei Bewegungen außerhalb dieses Bereichs wird der Controller beendet.
- Wenn die Zielzelle eine Wand ist, wird der Zug in (0,0) geändert.
- Wenn die Zielzelle ein Teleporter ist, wird die Probe um den Versatz des Teleporters bewegt. Hinweis: Dieser Schritt wird nur einmal und nicht iterativ ausgeführt.
- Wenn die derzeit von der Probe besetzte Zelle (möglicherweise nach Verwendung eines Teleporters) tödlich ist, stirbt die Probe. Dies ist das einzige Mal, dass Proben sterben (abgesehen von Schritt 1.1. Oben). Insbesondere eine neue Probe, die auf einer tödlichen Zelle erscheint, stirbt nicht sofort ab, sondern hat die Chance, die gefährliche Zelle zuerst zu verlassen.
- Wenn die Probe eine Zielzelle belegt, erzielen Sie einen Punkt, verschieben Sie die Probe in eine zufällige Startzelle und setzen Sie ihr Alter auf 0 zurück.
- Wenn sich weniger als zwei Exemplare auf dem Brett befinden, endet das Spiel.
- Erstellen Sie 10 neue Exemplare mit dem Alter von 0 Jahren . Jedes Genom wird (einzeln) durch die folgenden Zuchtregeln bestimmt. Legen Sie jede Probe auf eine zufällige Startzelle.
Zucht:
Wenn ein neues Exemplar erstellt wird, wählen Sie nach dem Zufallsprinzip zwei verschiedene Eltern mit einer Tendenz zu Exemplaren, die weiter nach rechts vorgerückt sind. Die Wahrscheinlichkeit, dass eine Probe ausgewählt wird, ist proportional zu ihrem aktuellen Fitness-Score . Der Fitness-Score eines Exemplars beträgt
1 + x + 50 * Häufigkeit, mit der das Ziel erreicht wurde
Dabei ist x der auf 0 basierende horizontale Index. Exemplare, die im selben Zug erstellt wurden, können nicht als Eltern ausgewählt werden.
Wählen Sie aus den beiden Elternteilen einen zufälligen aus, dem Sie das erste Genomstück entnehmen möchten.
- Wechseln Sie jetzt, während Sie durch das Genom gehen, mit einer Wahrscheinlichkeit von 0,05 die Eltern und nehmen Sie dem resultierenden Elternteil weitere Teile ab.
- Mutieren Sie das vollständig zusammengesetzte Genom: Drehen Sie es für jedes Bit mit einer Wahrscheinlichkeit von 0,01 um .
Wertung:
- Ein Spiel dauert 10.000 Runden.
- Die Spieler beginnen das Spiel mit 1 Punkt (um die Verwendung des geometrischen Mittels zu ermöglichen).
- Jedes Mal, wenn eine Probe das Ziel erreicht, erhält der Spieler einen Punkt.
- Derzeit wird die Einreichung jedes Spielers für 50 Spiele mit jeweils einer anderen zufälligen Spur ausgeführt.
- Der obige Ansatz führt zu mehr Varianz als wünschenswert ist. Sobald diese Herausforderung endet, wird eine Frist bekannt gegeben. Am Ende der Frist werden 100 Boards nach dem Zufallsprinzip ausgewählt und alle Einsendungen werden auf diesen 100 Boards neu bewertet.
- Die Gesamtpunktzahl eines Spielers ist das geometrische Mittel der Punktzahlen dieser einzelnen Spiele.
Die Controller
Sie können einen der folgenden Controller auswählen (da sie funktional gleichwertig sind). Wir haben alle getestet, aber wenn Sie einen Fehler entdecken, den Code oder die Leistung verbessern oder eine Funktion wie eine grafische Ausgabe hinzufügen möchten, senden Sie uns bitte ein Problem oder senden Sie eine Pull-Anfrage auf GitHub! Gerne können Sie auch einen neuen Controller in einer anderen Sprache hinzufügen!
Klicken Sie auf den Namen der Sprache für jeden Controller, um das richtige Verzeichnis auf GitHub aufzurufen, das eine README.md
mit genauen Verwendungsanweisungen enthält .
Wenn Sie nicht mit Git und / oder GitHub vertraut sind, können Sie das gesamte Repository als ZIP von der Startseite herunterladen (siehe Schaltfläche in der Seitenleiste).
Python
- Am gründlichsten getestet. Dies ist unsere Referenzimplementierung.
- Funktioniert sowohl mit Python 2.6+ als auch mit Python 3.2+!
- Es ist sehr langsam. Wir empfehlen, es mit PyPy auszuführen, um eine erhebliche Beschleunigung zu erzielen.
- Unterstützt die grafische Ausgabe mit
pygame
odertkinter
.
Rubin
- Getestet mit Ruby 2.0.0. Sollte mit neueren Versionen funktionieren.
- Es ist auch ziemlich langsam, aber Ruby kann nützlich sein, um eine Idee für eine Einreichung zu erstellen.
C ++
- Benötigt C ++ 11.
- Unterstützt optional Multithreading.
- Mit Abstand der schnellste Controller im Haufen.
C #
- Verwendet LINQ, daher ist .NET 3.5 erforderlich.
- Eher langsam.
Java
- Nicht besonders langsam. Nicht besonders schnell.
Vorläufige Rangliste
Alle Ergebnisse sind vorläufig. Sollte dennoch etwas falsch oder veraltet sein, lassen Sie es mich bitte wissen. Unser Beispielbeitrag ist zum Vergleich aufgeführt, jedoch nicht in Konkurrenz.
Score | # Games | User | Language | Bot
===================================================================================
2914.13 | 2000 | kuroi neko | C++ | Hard Believers
1817.05097| 1000 | TheBestOne | Java | Running Star
1009.72 | 2000 | kuroi neko | C++ | Blind faith
782.18 | 2000 | MT0 | C++ | Cautious Specimens
428.38 | | user2487951 | Python | NeighborsOfNeighbors
145.35 | 2000 | Wouter ibens | C++ | Triple Score
133.2 | | Anton | C++ | StarPlayer
122.92 | | Dominik Müller | Python | SkyWalker
89.90 | | aschmack | C++ | LookAheadPlayer
74.7 | | bitpwner | C++ | ColorFarSeeker
70.98 | 2000 | Ceribia | C++ | WallGuesser
50.35 | | feersum | C++ | Run-Bonus Player
35.85 | | Zgarb | C++ | Pathfinder
(34.45) | 5000 | Martin Büttner | <all> | ColorScorePlayer
9.77 | | DenDenDo | C++ | SlowAndSteady
3.7 | | flawr | Java | IAmARobotPlayer
1.9 | | trichoplax | Python | Bishop
1.04 | 2000 | fluffy | C++ | Gray-Color Lookahead
Credits
Diese Herausforderung war eine enorme gemeinsame Anstrengung:
- Nathan Merril: Hat Python- und Java-Controller geschrieben. Verwandelte das Herausforderungskonzept von einem King-of-the-Hill in ein Rat Race.
- Trichoplax: Spieltest. Arbeitete auf Python-Controller.
- feersum: Schrieb C ++ Controller.
- VisualMelon: Schrieb C # -Controller.
- Martin Büttner: Konzept. Schrieb Ruby-Controller. Spieltesting. Arbeitete auf Python-Controller.
- T Abraham: Spieltesting. Python getestet und C # - und C ++ - Controller getestet.
Alle oben genannten Benutzer (und wahrscheinlich ein paar weitere, die ich vergessen habe) haben zum Gesamtdesign der Herausforderung beigetragen.
C ++ Controller Update
Wenn Sie C ++ mit Visual Studio und Multithreading verwenden, sollten Sie das neueste Update erhalten, da ein Fehler beim Seeding des Zufallszahlengenerators aufgetreten ist, durch den doppelte Boards erstellt werden können.
'In particular, a new specimen which spawns on a lethal cell will not die immediately, but has a chance to move off the dangerous cell first.'