Russischer AI Cup 2018, Geschichte 9 Plätze

Also


Mein Name ist, wie letztes Jahr, Andrei Rybalka, nur dieses Mal bin ich 33. Und da ich unter den Top Ten war, habe ich beschlossen, meinen Ansatz, wieder einen Spielbot für den russischen AI Cup 2018 zu schreiben, zu teilen.


Diesmal war die Aufgabe Fußball. Die Aufgabe selbst erinnerte etwas an RAIC 2014, als es Hockey war, aber die Lösung war völlig anders.


Diesmal war die Welt dreidimensional und diese Dreidimensionalität wurde vollständig genutzt. Das Spiel selbst erinnerte am meisten an die Rocket League .


Ich werde den einleitenden Teil nicht langweilen, es ist einfacher zu zeigen, wie es aussah. Sie können die Spiele auf der Website oder im Video ansehen:



Damit unser Leben nicht zu süß erscheint, haben die Entwickler neben dem Nichtdeterminismus der Spielwelt auch den Spiel-Tick in 100 Subwoofer aufgeteilt, was den genauen Teilnehmern zunächst die genaue Simulation ein Ende setzte, und noch mehr für mich, einen Bot in langsamem Java zu schreiben.


Außerdem muss ich sagen, dass die Meisterschaft in Runden unterteilt ist, was wahrscheinlich korrekter wäre, wenn man Runden nennt.


Kurz zum Turniersystem


Für den Anfang sind 2 Wochen für die Entwicklung angegeben. Dann vergeht die erste Runde. Die 300 besten davon gehen noch weiter.


Nach der Runde ändern sich die Spielregeln (insbesondere wird Nitro zum Spiel hinzugefügt) und es werden weitere 2 Wochen gegeben, wonach die zweite Runde vergeht.


Dann sind die Regeln wieder kompliziert (der dritte Spieler wird hinzugefügt), eine weitere Woche wird gegeben und wir spielen das Finale.


Dies ist jedoch nicht das Ende. Nach dem Finale gibt es eine weitere Woche, an deren Ende der Sandkasten einfach stoppt, und die 6 besten darin, mit Ausnahme der Gewinner des Finales, werden ebenfalls vergeben. Der grundlegende Unterschied zwischen dem Sandbox-Finale und dem Meisterschaftsfinale besteht darin, dass in der Sandbox Spiele in einem zufälligen Format erstellt werden und nicht nur im Format der aktuellen Runde.


Beteiligungsgeschichten


Der technische Teil wird niedriger sein. Für wen die Geschichte uninteressant ist, können Sie nach unten scrollen, bis sie gut wird.


Erste Runde


Er begann, wie die meisten, mit einer Woche Beta. Verbrachte viel Zeit, jeden Abend 4+ Stunden.
Bevor Sie die erste Version ausfüllen, wurden mehrere Iterationen durchgeführt
Wir codieren, bis wir anfangen, die vorherige Version zu schlagen - wir sammeln - wir betrachten die aktuelle Version der vorherigen - wir wiederholen .


Ich hatte es mit der ersten Füllung nicht eilig und es passierte einige Tage vor der Runde. Und da mein Bot bis jetzt mit niemandem gespielt hat, hatte ich keine Ahnung, in welcher Art von Welt ich mich befand und welche Positionen in der Rangliste ich beanspruchen konnte. Als ich sah, dass ich bereits mehr als 100 Spiele hintereinander ohne eine einzige Niederlage gewonnen hatte, beruhigte ich mich.


Im Allgemeinen war die erste Niederlage, die ich hatte, anscheinend zeitlich auf dem 12. Platz, und das erste verlorene Spiel in Folge war bereits in den Top 10.


Kurz gesagt, ich erkannte, dass ich Chancen habe, in die zweite Runde zu kommen, in der die Top 300 gehen.
Deshalb habe ich die Position darin nicht verfolgt und nichts anderes für die Runde überflutet, sondern einfach weitergearbeitet.


Zu dieser Zeit sah ich, dass es noch viel Raum für Verbesserungen gab, ohne Nitro anzuschließen (was nach der ersten Runde erschien), also konzentrierte ich mich auf den Hauptteil der Strategie und erkannte, dass es vor der zweiten Runde mehr als 2 Wochen oder länger dauern würde und ich Zeit hätte, das Nitro zu befestigen.


Zweite Runde


In der ersten Woche habe ich aktiv programmiert, aber immer noch kein Nitro angeschlossen. Ich wollte das in der zweiten Woche machen. Aber alles verlief anders, denn am Ende der ersten Woche hatte ich eine Lungenentzündung. Ich konnte nicht programmieren, also habe ich einfach hochgeladen, was es war, und es kann gesagt werden, dass die aktive Teilnahme an der Meisterschaft für mich an diesem Ort beendet war.


In den nächsten 3 Wochen vor dem Ende der Meisterschaft arbeitete ich an einer Strategie in Höhe von vielleicht 20 Stunden.


Infolgedessen wusste mein Bot in der zweiten Runde im Prinzip nicht, dass es Nitro im Spiel gibt, belegte aber irgendwie immer noch den 16. Platz.


Finale


Im Finale wurde ein dritter Spieler hinzugefügt.


Ich schrieb in langsamem Java und nicht in C ++, da 7 von 8 Personen in der Bewertung höher sind als ich, und davor fiel mein Bot oft in eine Auszeit, so dass es mit dem Aufkommen des dritten Spielers in 100% der Spiele zu fallen begann. Glücklicherweise werden Spiele in der Sandbox in einem zufälligen Format erstellt, so dass ich automatisch
verlor nur jedes dritte Spiel und flog daher nicht zu viel runter. Es scheint auf den 18. Platz gefallen zu sein.


Abgesehen von der Programmierung, der Bearbeitung der Koeffizienten in der Bewertungsfunktion und der Durchführung der Tests setzte ich mich am Abend vor dem Finale zum ersten Mal nach Ausbruch der Krankheit an den Bot. Er fügte ein sehr einfaches Nitro hinzu, das streng nach oben gerichtet war, damit zwei Angreifer an derselben Stelle nicht mehr rennen und dort miteinander kollidieren und alles, was er für ein 3x3-Spiel konnte, von der Rendering-Tiefe bis zur Simulationsgenauigkeit reduzieren konnten Nur der Bot starb nicht durch Timeout.
In dieser Form spielte es das Finale.


In der Pause zwischen den Hälften des Finales setzte ich mich wieder in den Bot und verbrachte ein paar Stunden 10. Zum größten Teil betrafen die Änderungen die dynamische Auswahl von Koeffizienten, die frühzeitige Unterbrechung der Genetik usw. Im Allgemeinen suchte ich nach einem Gleichgewicht zwischen Genauigkeit und Fehlberechnungstiefe und -geschwindigkeit.
Neben dem Kampf gegen die Geschwindigkeit nahm er noch einige Änderungen vor:


  • Schickte einen entfernten Angreifer (relativ zum Ball) zu einem Punkt in der Mitte zwischen dem Ball und dem gegnerischen Tor
  • Ich habe Nitro ein wenig repariert (die Beschreibung wird im technischen Teil sein). Es war immer noch sehr einfach, aber es wurde viel effizienter.

Insgesamt, nachdem ich die Tests durchgeführt und die Punktzahl 395: 254 gegenüber der vorherigen Version gesehen hatte, beruhigte ich mich. Damit konnte ich im Finale den 9. Platz belegen.


Sandbox Finale


Ich tat weiter weh und arbeitete die meiste Zeit der Woche nicht am Bot. Am Tag vor dem Ende habe ich gesehen, dass mehrere Leute neue Versionen hochgeladen haben, die oft gegen mich gewinnen und Sandkästen aus Preisen werfen können. Also habe ich noch ein paar Stunden verbracht.


Die einzige große Änderung ist, dass ich vor drei Wochen meinen Zweig in Git ausgegraben habe, in dem ich die Bewegung des Feindes mit meinem vereinfachten Algorithmus simuliert habe. Zu dieser Zeit funktionierte es schlecht, aber ich erinnerte mich daran, führte Tests durch, sah
das übertrifft die vorherige Version fast verdoppelt und überflutet. Insgesamt war ich zum Zeitpunkt des Stopps auf dem 10. Platz in der Gesamttabelle, was dem 4. Platz im Finale des Sandkastens entspricht.


Wie das alles funktioniert (technischer Teil)


Ich entschuldige mich im Voraus für den Fall, dass die Terminologie ungenau ist. Außerdem schreibe ich aus dem Speicher, sodass ich die endgültige Version möglicherweise nicht beschreiben werde.


Genetische Algorithmen stehen also im Mittelpunkt. Das Chromosom besteht aus mehreren Genen:


  • Bruchzahl im Bereich -PI..PI, die die Bewegungsrichtung angibt
  • Eine Ganzzahl im Bereich 0..10, die die Anzahl der Wiederholungen dieser Aktion angibt
  • Bruchzahl von 0 bis 1. Wenn der Wert über einem bestimmten Schwellenwert liegt, machen Sie einen Sprung

Der Genotyp kann eine andere Anzahl von Chromosomen enthalten, jedoch so, dass die Gesamtzahl der Aktionen (einschließlich Wiederholungen) 40 beträgt.


Zunächst erstelle ich mehrere Dutzend zufällige Genotypen. Zu ihnen füge ich hinzu:


  • Die Flugbahn direkt am Ball
  • Direkte Flugbahnen in alle Richtungen, nur 10 Stück mit einem Versatz von 36 Grad
  • Ein Genotyp, der einfach nichts tut (ohne ihn läuft der Bot immer irgendwo, auch wenn er bereits am optimalen Punkt steht)
  • Bester Genotyp vom vorherigen Tick

Dann wird alles simuliert und durch die Auswertungsfunktion geführt. N beste Genotypen "überleben" und werden M-mal mit Mutationen kloniert. Bei der Mutation ändert sich jedes Gen in einem bestimmten Bereich mit einer Wahrscheinlichkeit von 10%. Nun, dies wird seit mehreren Generationen wiederholt.
Es gibt keine Kreuzung, in diesem Problem sehe ich keinen Sinn darin.


Insgesamt betrug die maximal mögliche Anzahl von Flugbahnen pro Tick pro Fußballspieler etwa 800, in den meisten Fällen jedoch viel weniger, weil In einigen Fällen (zum Beispiel, wenn wir in naher Zukunft definitiv nicht in der Lage sind, den Ball zu berühren) wurde die Bewegung der Spieler durch einfache Heuristiken ersetzt. Außerdem hingen N, M und die Anzahl der Generationen von der Situation auf dem Feld ab. Zunächst aus der Entfernung zum Ball. Außerdem wird die Fehleinschätzung vorzeitig (jedoch nicht früher als in der 5. Generation) unterbrochen, wenn eine Flugbahn mit einer akzeptablen Schätzung gefunden wird.


Makro


Der Torhüter rennt zum Punkt vor der Tormitte. Meine Tests haben gezeigt, dass es für mich am besten ist, vor dem Tor zu stehen und nicht darin, wie die meisten Spieler oben.


Die Position des Punktes weicht von der Mitte ab und hängt von mehreren Faktoren ab: der Position und Richtung des Ballfluges, dem Punkt, an dem der Ball mein Ziel getroffen hat, wenn ein Tor geplant ist, dem Ort des nächsten angreifenden Gegners usw.


Wenn der Ball auf der Seite des Gegners liegt und in Richtung seines Ziels fliegt, können wir uns für Nitro entscheiden.


Wenn mein Torhüter den Ball früher als mein Angreifer treffen kann (plus ein paar weitere Bedingungen), ignoriert der Angreifer den Ball und rennt zu einem Punkt in der Mitte zwischen dem Ball und dem gegnerischen Tor. Ich ging viele Optionen durch, wo genau er laufen sollte. In meinem Fall hat dieser am besten funktioniert.


Wenn der Ball zu weit ist, läuft der Angreifer in einer geraden Linie zum nächsten Kontaktpunkt des Balls mit dem Boden, an dem er den Ball abfangen kann (wenn wir keine Zeit für den ersten Kontaktpunkt haben - überprüfen Sie den nächsten usw.).


Andernfalls (wenn der Ball erreicht ist) rennt der Angreifer dorthin, wo die Bewertungsfunktion es ihm sagt. Ja, und wenn Nitro in der Nähe liegt und wir es abholen können, wählen wir es aus.


In einem 3x3-Spiel zielt der zweite Angreifer eher auf den Ball und mit weniger Vorwärtslauf, wobei er einen Pass vom Torhüter erwartet. Wenn es aber noch läuft, wird ein anderer Punkt gewählt - näher an der Mittellinie.


Außerdem simulierte jeder Tick einmal den Ball 100 Ticks vorwärts mit 100 Mikrotik (mit Caching).


Diese Flugbahn wurde an vielen Stellen verwendet. Z.B:


  • Um die Berührungspunkte des Balls mit dem Boden zu bestimmen
  • Um herauszufinden, ob der Ball mein Tor bedroht und ob der Torhüter in den Simulationsmodus geschaltet werden muss

Die gleiche exakte Flugbahn wurde bei der Simulation der Flugbahnen der Spieler verwendet, um den Ball nicht jedes Mal zu zählen. Aber nur bis zur ersten Kollision des Balles mit einem Fußballspieler.


Übrigens war das Schreiben von Footballist faul, die Worte Spieler, Roboter waren der Strategie vorbehalten,
Also hieß meine Wrapper-Klasse einfach Dude :)


Simulation


In den meisten Fällen ging es mit einer Mikrotik, aber in einigen Situationen wechselte es mit einer großen Anzahl von Mikrotiken in den genauen Modus (am Anfang waren es 100, dann wurde es in einem 2x2-Spiel auf 50 reduziert, da Tests zeigten, dass der Unterschied in den Ergebnissen innerhalb der Fehlergrenze lag, und auf 10 in 3x3, weil sonst in Timeouts geflogen).


Im genauen Modus habe ich entweder zum Zeitpunkt des Abprallens gewechselt oder war so nah am Ball, dass eine Kollision beim nächsten Tick möglich ist. Darüber hinaus gab es auch eine Menge kleiner Krücken, Hacks, Optimierungen, die ich selbst nicht verstehen werde.


Zum Beispiel wurde der fliegende Ball immer noch mit 1 Mikrotik simuliert, aber wenn ich nach dem nächsten Mikrotik sah, dass es zu einer Kollision kam, rollte er zurück zur vorherigen Position und simulierte sie erneut mit größerer Genauigkeit.


Außerdem gab ich vor, andere Spieler zu sein (sowohl meine eigenen als auch andere), wenn sie in der Luft waren (und daher ihre Flugbahn leichter vorherzusagen ist) oder nahe am Ball waren. Für Gegner verwendete die endgültige Version eine vereinfachte Version meiner eigenen Entscheidungsstrategie, die alle 5 Ticks gestartet wurde (häufiger erlaubte sie keine Geschwindigkeit).


Bei der Simulation jedes Charakters berechnete ich mich selbst, den Ball und andere Fußballspieler 40 Ticks voraus (mein Limit für die Anzahl der Aktionen im Genotyp) und simulierte dann die gleiche Anzahl von Ticks nur für einen Ball.


Nitro


Einfach bis unanständig.


In der endgültigen Version ist Nitro immer eingeschaltet, wenn dies der Fall ist, wenn der Spieler in der Luft ist und wenn er den Ball in den letzten Zecken nicht getroffen hat.


Am Anfang habe ich Nitro immer direkt nach oben gerichtet, aber dann habe ich versucht zu experimentieren und die Option, genau in die Mitte des Balls zu gehen, hat am besten funktioniert. Ich habe auch Optionen ausprobiert, damit die Richtung des Nitros von der Genetik gewählt wurde.


Es hat viel schlimmer funktioniert. Möglicherweise aufgrund mangelnder Suchtiefe.


Bewertungsfunktion


Die Summe der Bewertungen für jeden Tick mit einer Dämpfung von 2% pro Tick.


Das größte Gewicht hatte natürlich ein Ziel. Mehrere Dinge beeinflussten sein Gewicht:


  • Die Entfernung vom Ball zum gegnerischen Torhüter zum Zeitpunkt des Tores (je weiter desto besser)
  • Y-Koordinate des Balls (weil es am oberen Ende des Tores viel schwieriger ist, ihn zu treffen)
  • Die Geschwindigkeit des Balls entlang der Z-Achse (die auf das feindliche Ziel gerichtet ist)

Wenn ich angegriffen werde, ist alles genau gleich, nur mit dem entgegengesetzten Vorzeichen.


Für den Angreifer hing die Gesamtpunktzahl außerdem ab von:


  • Entfernungen vom Spieler zum Ball (so dass er zum Ball rennt, auch wenn er ihn nicht schlagen kann)
  • Strafe für den Sprung (nur zu springen, wenn es so viele Punkte bringt, dass sie diese Strafe überschreiten)
  • Entfernungen beim nächsten Tick der Simulation vom Ball zum Gegner
  • Y-Ballkoordinaten (je höher sie sind, desto geringer ist die Chance, dass der Feind sie abfängt)
  • Kosinus des Winkels zwischen der Richtung des Balls und der Mitte des feindlichen Tores
  • Flagge, wenn ich den Ball berührt habe
  • Flagge, ob der Feind den Ball berührt hat
  • Bonus für die Auswahl von Nitro

Es gab auch einen kleinen Bonus für das Schlagen eines feindlichen Spielers. Obwohl es tatsächlich passiert ist, aber selten.


Für Torhüter:


  • Bonus für die Entfernung zum Ball, Ballgeschwindigkeit in Z, Ballposition in Y.
  • Strafe für den Sprung
  • Strafe für das Finden des Balls im Bereich vor meinem Tor
  • Die Entfernung zu den Feinden und zu meinen Angreifern wurde berücksichtigt (damit der Ball von den Feinden wegfliegt, aber wenn möglich näher zu meinen Angreifern fliegt)
  • Und noch ein paar Kleinigkeiten.

Maschinelles Lernen


Es war nur ein wenig in einem der Zweige des Git als Experiment. Aber es scheint mir trotzdem erwähnenswert zu sein. Ich habe es nicht geschafft, mich daran zu erinnern (und ich bin mir nicht sicher, was Sinn machte).


Im Allgemeinen habe ich versucht, mit seiner Hilfe vorherzusagen, ob der Feind den Ball basierend auf den Positionen und Geschwindigkeiten des Feindes und des Balls abfangen kann. Ich hatte vor, dies in der Bewertungsfunktion zu verwenden. Bestrafen Sie Trajektorien, die abgefangen werden können.


Aber ich verstand sofort, dass ich mir nicht nur ein neuronales Netzwerk leisten konnte, sondern überhaupt nichts Ernstes, da dies 80 Mal pro Flugbahn durchgeführt werden müsste. Nun, selbst wenn es 40 oder 20 ist, wenn nicht jeder Tick gezählt wird, aber ich hatte überhaupt keine Zeitreserven, also habe ich diese Optionen nicht einmal in Betracht gezogen.


Folgendes habe ich getan:


Ich habe mehrere Spiele mit einem modifizierten Bot ausgeführt, in denen ich bei der Suche nach einer Flugbahn Daten über mich und den Ball sowie eine Flagge gespeichert habe, ob eine Flugbahn gefunden wurde, in der ich den Ball abfange.


Ich habe alle Koordinaten in Bezug auf den Fußballspieler berücksichtigt. Das heißt, Ich hatte es immer in der Koordinate [0,0,0], also habe ich nur 10 Felder behalten: die relative Position des Balls, den Geschwindigkeitsvektor des Balls, den Geschwindigkeitsvektor des Fußballspielers, das binäre Abfangflag. Ich habe den Datensatz nur für den zentralen Teil des Feldes gespeichert, weil Ich erkannte, dass einfache Algorithmen noch nicht ziehen und Boards berücksichtigen.


Dann habe ich diesen Datensatz DecisionTreeClassifier mit max_depth = 7 gefüttert. Der trainierte Baum ergab, soweit ich mich erinnere, eine Genauigkeit in der Größenordnung von 90%.


Als nächstes exportierte ich den Baum in eine Reihe von ifs (was DecisionTree im Wesentlichen ist).


Es sah ungefähr so ​​aus:


public static boolean predict(double dude_vel_x, double dude_vel_y, double dude_vel_z, double ball_rel_pos_x, double ball_rel_pos_y, double ball_rel_pos_z, double ball_vel_x, double ball_vel_y, double ball_vel_z) { if (ball_vel_z <= 6.4765448570251465) { if (dude_vel_y <= -6.087389945983887) { if (ball_vel_z <= -20.188323974609375) { if (dude_vel_x <= 13.032730102539062) { if (ball_rel_pos_y <= -1.1829500198364258) { return ball_vel_y <= 18.906089782714844; } else { return false; } } else { return true; } } else { // ............................ 

Zu diesem Zeitpunkt führte ich die Tests durch, stellte keine Verbesserung fest und verschob den Prozess auf einen späteren Zeitpunkt, der aufgrund meiner Abenteuer nie eintraf.


Schroedinbag


Irgendwann nach der ersten Runde habe ich dieses seltene Tier in meinem Haus gefangen.


Wer nicht weiß, dass dies ein solcher Fehler ist, den sie nur durch Lesen des Codes finden, und nachdem er ihn gefunden hat, fragt sich der Entwickler, wie das Programm überhaupt funktionieren könnte. Und in meinem Fall blieb sie auch in den Top 10.


Im Allgemeinen bestand der Fehler darin, dass ein Konstruktor in der Kopierfunktion des Gens aufgerufen wurde, in dem ein optionales Argument weggelassen wurde, das den Wert dieses Gens enthielt. In Abwesenheit dieses Arguments wurde der Wert zufällig ausgewählt. Beim Versuch, ein Gen anstelle einer Kopie zu kopieren, erstellte er daher eine neue zufällige Instanz.


Tatsächlich hatte ich anstelle der Genetik eine zufällige Suche, da jeder Tick einfach mehrere hundert zufällige Pfade erzeugte und den besten auswählte.


Nach der Korrektur (bestehend aus dem Hinzufügen von 2 Zeichen zum Code) wurde das Spiel ungefähr dreimal besser.


Rituelles Tanzen


Irgendwann bemerkte ich, dass Spieler manchmal ohne Grund abprallen und trotz der Strafe weit vom Ball entfernt sind.


Die Erklärung stellte sich als so heraus, dass ich den Moment des Sprunges mit einer Genauigkeit von 100 Mikrotik zählte. Und manchmal stellte sich heraus, dass gerade zum Zeitpunkt des Sprunges eine Kollision des Balls mit der Langhantel auftrat. Und abhängig von der Genauigkeit der Berechnung genau in diesem Tick führte die vorgeschlagene Flugbahn entweder zu einem Ziel oder nicht.


Grob gesagt fliegt der Ball zum gegnerischen Tor und trifft den Pfosten. Mein Fußballspieler, der am anderen Ende des Feldes läuft, simuliert eine Flugbahn ohne Sprung (mit 1 Mikrotik) und sieht, dass der Ball das Tor nicht trifft.


Dann kommt eine andere Flugbahn herein, mit einem Sprung genau in dem Moment, in dem der Ball die Latte trifft. Und da ich einen Tick mit einem Sprung von 100 Mikrotik nicht nur für einen Fußballspieler, sondern auch für einen Ball zähle, unterscheidet sich der berechnete Sprungwinkel des Balls von dem Winkel, der auf dem Weg mit 1 Mikrotik erhalten wird, und es kann vorkommen, dass der Ball in dieser genaueren Flugbahn hineinfällt das Tor.


Und deshalb wird diese Flugbahn ausgewählt und der Bot springt.


Im Allgemeinen haben die Spieler durch einen rituellen Tanz mit Hüpfen ein Ziel benannt :)


Killer-Feature


Sie ist nicht


Testen


Ich fuhr endlose Spiele in 8 Threads (4 auf jedem Computer und Laptop). Ich habe die Anzahl der Spiele so gewählt, dass sie statistisch signifikant ist.


Mit einer deutlichen Verbesserung der Strategie konnten insgesamt insgesamt ein halbes Tausend Ziele erreicht werden,
mit kleineren Korrekturen, für die Nacht verlassen und dann ging die Rechnung in die Tausende.


Genetische Selektion von Konstanten


Ich habe es vor der ersten Runde versucht. Es gab nichts aus dem Grund, dass Sie für die Genetik ein Turnier aus einer großen Anzahl von Spielen spielen müssen.


Ich habe versucht, Spiele mit 100.000 Zecken zu spielen, aber das war nicht genug. Mit einem kleinen Unterschied in der Stärke (und normalerweise ist dies bei der Auswahl von Konstanten genau der Fall) hängt der Gewinner pro 100.000 Ticks zu stark vom Fall ab. Sie müssen viel mehr spielen, um sich des Gewinners sicher zu sein. Und ich konnte es mir nicht leisten, die Auswahl für einen Tag oder länger zu verlassen, also lehnte ich dieses Unternehmen ab.


Abschließend


Traditionell danke an die Organisatoren. Die Aufgabe war interessant. Es ist schade, dass ich nur fast die Hälfte der Meisterschaft verpassen musste und wirklich nichts für Nitro oder drei Spieler getan habe.


Infolgedessen habe ich bis zum Ende im Sandkasten beobachtet, wie meine Strategie im 2x2-Modus ohne Nitro mit einer Punktzahl von 13: 2 gegen jeden Mr.Smile gewinnt, der im Finale den 3. Platz belegte und nach einigen Spielen gegen ihn das gleiche 12: 2 verliert im 3x3 Modus mit Nitro :)


Und natürlich das Video von meinem proprietären Visualizer:



Nur Sie müssen sich wahrscheinlich in zukünftigen Meisterschaften von diesem Visualizer verabschieden.
Mit jedem Mal bin ich mehr und mehr davon überzeugt, dass wenn Sie sich für normale Plätze bewerben, die einzige Möglichkeit darin besteht, in ...



... nun, du verstehst, worum es geht.


Jedes Mal müde, sich auf der Langsamkeit von Java auszuruhen und die Stärke der Strategie zu reduzieren, um die zugewiesene Zeit einzuhalten.


Ich hoffe, jemand hat für sich etwas Interessantes oder Nützliches in meinem Werk mit einer Note von autobiografischem Charakter gefunden :)

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


All Articles