Zweiter Platz im russischen AI Cup 2018: CodeBall

Hallo allerseits!

Ich bin ein Student im dritten Jahr und habe gleich zu Beginn meines Studiums an der Universität etwas über den russischen Ai Cup und später den Mini Ai Cup , Wettbewerbe für künstliche Intelligenz, gelernt und begann, aktiv daran teilzunehmen, wobei ich gute Ergebnisse zeigte. Dieses Mal fiel RAIC direkt in die Sitzung, sodass mich nichts aufhalten konnte :) Und heute möchte ich Ihnen sagen, wie ich es geschafft habe, den zweiten Platz zu belegen.

Die Wettbewerbsregeln finden Sie auf der Website des Wettbewerbs sowie in diesem Artikel . Link zu meinem Profil: russianaicup.ru/profile/TonyK .

Einerseits war die Aufgabe in diesem Jahr den Aufgaben der vergangenen Jahre ähnlich, und es schien, dass die ideologische Lösung den vorherigen sehr ähnlich sein würde (Agar IO und Mad Cars); Nach ungefähr einer Woche wird es mir langweilig und ich werde es leid, daran teilzunehmen.

Andererseits habe ich verstanden, dass ich in früheren Wettbewerben mit Physik viel gelernt habe und jetzt kann ich diese Erfahrung anwenden, nicht auf den alten Rechen treten und am Ende ein besseres Ergebnis zeigen.

Für die Visualisierung habe ich beschlossen, genügend Projektionen auf verschiedenen Achsen zu haben oder in einem bestimmten Winkel anzuzeigen. Aber ich habe mich sehr geirrt, und wenn es nicht den in Local Runner integrierten Magic Visualizer gäbe, den die Organisatoren später hinzufügten, müsste ich mir 3D-Visualizer von den freundlichen Teilnehmern ausleihen, die die Beta-Testphase damit verbracht haben, sie zu schreiben und sie öffentlich zugänglich zu machen.

Diesmal war der Pseudocode des Simulators verfügbar, der die Möglichkeiten derer ausbalancierte, die wussten, wie man Physik umkehrt und einen coolen Bot schreibt, und derer, die die Physik nicht umkehren konnten, aber auch einen starken Bot schreiben konnten. Ich denke, das war eine gute Entscheidung der Organisatoren.

Als erstes habe ich den Simulatorcode aus der Dokumentation in C ++ neu geschrieben und dann die Zeit des Simulators auf meinem alten Computer und auf dem Server gemessen. Im zweiten Fall stellte sich heraus, dass es doppelt so schnell war, obwohl dies erwartet wurde. Ich dachte mir, wie oft und bis zu welcher Tiefe ich simulieren könnte. Es wurde sofort klar, dass man die ehrliche Simulation von 100 Mikrotiken vergessen musste (auf dem Server wurde ein Tick Physik in 100 „Mikrotiken“ unterteilt), und es wäre notwendig, Probleme mit Genauigkeit auf Umwegen zu lösen.

Aufgrund der Tatsache, dass die Shell so angeordnet war, dass die Aktionsanforderung für jeden Roboter bei jedem Tick separat aufgerufen wird, habe ich eine einfache Logik implementiert: In dem Moment, in dem der erste Roboter nach einer Aktion gefragt wird, findet das Programm Aktionen für alle Roboter, merkt sich und gibt die Aktion des ersten, und wenn die Aktion von den anderen Robotern verlangt wird, gibt sie zurück, woran sie sich erinnert.

Ich war ungeduldig, den Bot bald in die Schlacht zu schicken. Ich beschloss, zufällige Trajektorien zu generieren und die beste auszuwählen. Gleichzeitig wollte er, dass das generierte Set es ermöglicht, einige komplexe Aktionen auszuführen, z. B. von der rechten Seite um den Ball herumzugehen und dann zu schlagen.

Eine Flugbahn ist ein Aktionsplan. Anfänglich war die Flugbahn folgende:

  • Stellen Sie die Aktion in einem zufälligen Winkel ein.
  • Ändern Sie bei einem zufälligen Häkchen der Flugbahn den Winkel in einen anderen zufälligen.
  • Springe einmal in einen zufälligen Tick der Flugbahn.

Ein solcher Raum von Trajektorien war gut für die zufällige Suche mit der Anzahl von Simulationen geeignet, die ich (und wahrscheinlich jeder zu dieser Zeit) mit dem Rohsimulator aus der Dokumentation leisten konnte. Gute Flugbahnen wurden oft erraten, und da die beste Flugbahn des vorherigen Ticks erhalten blieb, stellte sich heraus, dass die Suche zeitlich gestreckt war.

Alle Objekte wurden in den Simulator gelegt: meine Roboter, die Roboter des Gegners und der Ball. Die Bewertung war die einfachste: die Summe der Entfernungen vom Ball zum feindlichen Tor an allen Punkten der Flugbahn und die großen Werte für das Tor für jemanden. Simulationstiefe 200 Ticks. Feinde werden mit ihrer letzten Geschwindigkeit vorhergesagt.



Ich habe sofort eine separate Aktion für den zweiten Roboter hinzugefügt sowie den Sprung erzwungen, wenn während des Fluges kein Kontakt mit dem Ball bestand, um nicht umsonst zu springen. Gleichzeitig hatten meine Roboter mehr als die Hälfte der Zeit und kannten die beste Flugbahn des anderen. Jetzt haben die ersten Tore für starke Gegner begonnen, die bereits einen Torhüter und eine kompliziertere Logik hatten.

Es stellte sich weiter heraus, dass ich nicht die Entfernung zu den feindlichen Toren berücksichtigte, sondern den Punkt zur Seite der Mitte des Feldes ( x und z ), aber dies hatte keinerlei Einfluss auf die Strategie. Es ist gut, dass es nach der Korrektur nicht schlimmer wurde. Dies passiert oft, wenn Sie einen Bot schreiben.

Dann fügte er den Torhüter hinzu, indem er die Punktzahl änderte: Er verhängte eine Strafe für den Ball in meiner Hälfte des Feldes und für das Tor für mich und schätzte auch die Entfernung vom Torhüter zu meinem Tor. Jetzt stand der Torhüter am Tor und schlug den Ball aus. Eine wichtige Optimierung war, dass, wenn sich der Ball nicht in meiner Hälfte des Feldes befindet, 90% der Zeit dem Angreifer und 10% des Torhüters gegeben werden, ansonsten 50%.

Die Bewertung der Flugbahnen der Roboter an jedem Punkt wurde mit 0,9 ^ Tiefe multipliziert. Ich habe diesen Koeffizienten empirisch abgeleitet, wie die gesamte Bewertung. Die Werte der Koeffizienten änderten sich lange Zeit nicht nach dem Prinzip "es funktioniert, okay".

Er begann die Spitzen zu gewinnen und stieg schnell in der Rangliste auf. Die Beta-Phase ist vorbei.

Lange Zeit hatte ich keine Ahnung von der Strategie, die Versionen waren bemerkenswert für kleinere Änderungen, Fehlerkorrekturen (es stellte sich heraus, dass ich die durchschnittliche Rückprallstärke als (MAX_HIT_E - MIN_HIT_E) / 2 ) und optimierten auch den Simulator. Eine wichtige Rolle spielte die Anzahl der Trajektorien, die ich pro Tick aussortieren konnte, daher konzentrierte ich mich auf die Optimierung. Nebenhöhlen und Quadratwurzeln entfernt. Es wurde eine unwahrscheinliche Geschwindigkeit von Null auf der Flugbahn vor oder nach dem Ändern des Winkels hinzugefügt. Leicht veränderte Wertung.

Die 16. Version blieb lange Zeit an der Spitze der Tabelle, aber eine Woche nach dem Ende des Beta-Tests begannen erwartungsgemäß viele zu gewinnen .

Ich habe versucht, die Flugbahn mit der Summe der engsten Entfernungen vom Feind zum Ball zu verfeinern, und ich habe ein sehr interessantes Verhalten festgestellt. Wenn meine Roboter nicht gewinnbringend treffen konnten, blockierten sie oft Feinde, brachen ihre Flugbahn und hinderten sie daran, zum Ball zu rennen. Manchmal stellte sich heraus, dass dies sehr erfolgreich und heimtückisch war.

Als nächstes habe ich die Genauigkeit beim Springen korrigiert. Wenn jemand auf den aktuellen Tick springt, machen wir zuerst zweimal 1 Mikrotik und dann die restlichen 98 Mikrotik. Ich habe auch versucht, den Genauigkeitsverlust mit einem heuristischen Koeffizienten zu kompensieren, wenn die maximale Geschwindigkeit bei einigen Mikrotik erreicht ist. Verbesserungen haben sehr geholfen und es gab genauere, vorberechnete Treffer.

Zu diesem Zeitpunkt begann ich, auf der Site unter den Debugging-Informationen die Anzahl der Iterationen anzuzeigen, die ich abgeschlossen habe. Es gab 250 von ihnen bei 200 Ticks, insgesamt hatte ich 50.000 Ticks Simulationen während der Zeit, die für meine Strategie pro Tick vorgesehen war.

Dann schaltete ich die Mutationstrajektorien ein. Dies hat die Strategie erheblich verbessert. In ungefähr der Hälfte aller Iterationen wurde nicht die neue Trajektorie verwendet, sondern die beste mit leicht veränderten Werten, die es ermöglichte, beispielsweise irgendwo auf ein lokales Maximum zu konvergieren. Es stellte sich damals als starke Strategie heraus, die ich bis zur ersten Runde verlassen wollte, obwohl es noch zwei Wochen dauerte. Aber nach ein paar Tagen hörte sie auf, die Spitze zu dominieren.

Ich habe einige Zeit damit verbracht, mich von der völligen Zufälligkeit zu lösen. Zum Beispiel habe ich mit einer ternären Suche versucht, den Winkel zu finden, in dem der Roboter beschleunigen muss, um den Ball zu treffen. Dies hat jedoch nicht immer funktioniert, und ich habe nicht herausgefunden, wie ich diese Idee weiterentwickeln kann.

Meine Roboter wussten nur einmal pro Flugbahn zu springen, aber als sie am Boden waren und springen wollten und dann den Ball in die Luft schlugen, wussten sie nicht, dass man beim Berühren des Balls ein zweites Mal springen und dadurch den Ball hart treffen kann nicht nur schieben.

Dies wurde behoben, und jetzt rollte der Simulator, als er bemerkte, dass jemand den Ball beim aktuellen Tick schlagen konnte, einen Tick zurück und zwang den Roboter, mit maximaler Kraft zu springen. Jetzt stand der Roboter auf dem Boden und wusste, dass er vom Boden abstoßen und nicht nur schieben, sondern den Ball mit einem zweiten Sprung treffen würde.

Ich verstand, dass, wenn Nitro und ein weiterer Roboter hinzugefügt wurden, alles aufgrund fehlender Iterationen verbogen werden würde. Auch an verschiedenen Orten hatte ich große Probleme mit der Genauigkeit, die ich nicht lösen konnte. Ich habe keine analytischen Lösungen oder intelligenten Managementmethoden gesehen .

Ich brauchte entweder eine völlig neue Strategie oder einen magischen Simulator, der Genauigkeit und Geschwindigkeit kombiniert und mir im Endstadium genügend Flugbahnen zur Verfügung stellt, um sie zu wiederholen. Ich habe mir (überraschenderweise) keine neue Strategie ausgedacht und angefangen, an einem Simulator zu arbeiten.

"Smart Simulator"


Als erstes wollte ich mich mit Genauigkeit befassen.

Ich habe 100 Mikrotiks gleichzeitig simuliert, obwohl bei einem dieser hundert Mikrotiks eine Kollision - oder ein anderes Ereignis - aufgetreten ist. Wenn Sie dies ignorieren, kollidieren Objekte später als in der Realität (immer auf der 100. Mikrotik) und springen daher anders. Gegen Ende der Flugbahn kann dieser kleine Fehler zu einer großen Ungenauigkeit führen. Zum Beispiel denken wir, dass der Ball das gegnerische Tor trifft, aber in Wirklichkeit wird er vom Pfosten in unseren springen.

Es ist leicht zu erkennen, dass in einer Situation, in der eine Kollision mit der i ten Mikrotik auftritt, anstatt alle 100 Mikrotiken zu zählen, es ausreicht, die ersten i - 1 Mikrotiken gleichzeitig zu zählen (tatsächlich wird der Physikschritt für eine bestimmte Zeit dt berücksichtigt, und jetzt wird dies sein t * (i - 1) , wobei t die Zeit ist, die einer Mikrotik entspricht). Jetzt müssen Sie 1 Mikrotik ( dt = t ) und die verbleibenden 100 - i Mikrotik simulieren. Wir erhalten genau das gleiche Ergebnis in nur drei Simulationen anstelle von hundert. Das einzige Problem ist, dass wir nicht wissen, auf welcher Mikrotik die Kollision auftreten wird.

Wenn wir uns auf einem festen Punkt der Simulation befinden, können wir in einer Simulation eine beliebige Anzahl von Mikrotiken von 1 bis 100 erstellen und prüfen, ob eine Kollision vorliegt oder nicht. In diesem Fall sieht das Bild folgendermaßen aus: Zuerst gibt es keine Berührung, aber ab einer bestimmten Anzahl von Mikrotiken und bis zu hundert gibt es eine Berührung. Außer in sehr seltenen Fällen, wenn zuerst kein Kontakt besteht, berührt ein Teil der Mikrotik und dann wieder keine Berührung.

Daher ist es möglich, die Mikrotik, bei der die Kollision aufgetreten ist, im schlimmsten Fall durch eine binäre Suche nach 10 Simulationen zu finden. Und wie bereits beschrieben, können Sie für drei Simulationen den Zustand der Welt durch 100 Mikrotik mit perfekter Genauigkeit ermitteln.

Tatsächlich gab es neben einer Kollision mehrere andere Arten von Ereignissen, und mehrere könnten in einem Tick aufgetreten sein, sodass sich nur das erste Ereignis in einer Dichotomie befand, das zweite Ereignis sich auf dem verbleibenden Suffix der Tick-Dichotomie befand und so weiter. Daher wurde ein Tick als Segmente mehrerer Mikrotik pro Simulation betrachtet, bis alle Ereignisse gezählt wurden.

So wurden die Probleme mit Genauigkeit gelöst. Aufgrund der Tatsache, dass die Simulation 5 Objekte enthielt und nach den endgültigen Regeln 7 hätte sein müssen, und alle stürzten häufig ab, wurden Dichotomien im Durchschnitt zu oft aufgerufen, und dies funktionierte unerschwinglich lange. Daher ging ich zur zweiten Stufe der Entwicklung des Simulators über - der Optimierung.

Wenn die Flugbahn eines der Roboter überwunden ist, bewegen sich natürlich alle anderen Objekte, gegen die dieser Roboter stößt, nicht jedes Mal gleich. Es ist klar, dass eine Neuberechnung ihrer Zustände mit einem Simulator - beispielsweise die Berechnung schwerer Kollisionen mit der Arena - nicht erforderlich ist.

Bevor Sie die Trajektorien für einen bestimmten Roboter aussortieren, reicht es aus, die verbleibenden Objekte zu jedem Zeitpunkt ehrlich zu simulieren und für die verbleibenden Objekte zu speichern und diese Zustände dann einfach aus dem Speicher zu nehmen. Wir nennen solche Objekte statisch, und ein Roboter, nach dem die Flugbahn sortiert ist, ist dynamisch.

Wenn plötzlich ein dynamisches Objekt ein statisches Objekt beeinflusst (eine Kollision hat), fügen wir dieses statische Objekt bis zum Ende der Simulation der aktuellen Trajektorie zu den dynamischen hinzu. Tatsächlich wird beim Speichern von Zuständen für statische Objekte ein Diagramm der gegenseitigen Einflüsse erstellt und dann verwendet, um statische Objekte korrekt auf dynamische Objekte zu übertragen. Zum Beispiel hat ein feindlicher Roboter den Ball getroffen, und wir haben einen Pfad generiert, auf dem wir den feindlichen Roboter niederschlagen, bevor er den Ball trifft. Jetzt fliegt der Ball weiter und während der Simulation, wenn der feindliche Roboter zu dynamischen Objekten hinzugefügt wird, muss beachtet werden, dass der Ball etwas später zu den dynamischen Objekten hinzugefügt werden sollte, an dem Punkt, an dem der feindliche Roboter den Ball schlagen würde, wenn wir ihn nicht stören würden . Im allgemeinen Fall erfolgt dies rekursiv gemäß dem Einflussgraphen.



Jetzt berechnet der Simulator nicht alle Objekte, sondern nur dynamische, und dies sind im Durchschnitt eineinhalb statt sieben Objekte, und lange Dichotomien werden viel seltener verwendet. Es stellte sich sehr schnell heraus und muss im Finale nicht mehr mit zusätzlichen Robotern leiden - cool!

Die 26. Version mit einem neuen Simulator und einer von 200 auf 100 reduzierten Simulationstiefe wurde in der ersten Runde zum Spielen geschickt. Aber es enthielt einige Fehler, und es gab keinen offensichtlichen Vorteil.

Das letzte Problem mit der Genauigkeit blieb bestehen: Bewegung entlang der Rundung der Arena. In diesem Fall ist es zur Erzielung einer absoluten Genauigkeit erforderlich, 100 Mikrotik ehrlich zu zählen. Die Lösung war überraschend einfach: Springen Sie immer von allen Oberflächen außer dem Boden. Keine Rundung - kein Problem.

Außerdem habe ich einige Zeit optimiert, entkräftet und bei Spielen mit intelligenteren Strategien neue Bewertungskonstanten gefunden. Es ist viel besser geworden, die Strategie ist in der Rangliste hoch gestiegen und die 37. Version hat die beste Zeit aller meiner Strategien in der Sandbox vor dem Finale erzielt.

Von diesem Zeitpunkt an mietete ich eine 32-Kern-Maschine in einem Cloud-Dienst, um meine Strategien gegeneinander auszuführen, und begann viel mit allem hintereinander zu experimentieren. Die Konstanten wurden geändert. Ich habe versucht, meine eigene Strategie zu verwenden, um die Aktionen des Feindes vorherzusagen, aber dies hat selbst in Spielen gegen meine Strategie nicht geholfen.

Durch Lösen der Gleichung lernte er, die letzte Aktion des Feindes zu berechnen und begann, sein weiteres Verhalten vorherzusagen. Unterstützung für Nitro hinzugefügt: Für die Aktion wird ein zufälliger Punkt auf der Oberfläche der Kugel ausgewählt. Viele kleinere Änderungen vorgenommen. Aber es gab keine großen Fortschritte. Zu Beginn der zweiten Runde gewannen mich stetig 4-5 Tops

Trotzdem verzweifelte ich nicht. Ich hatte zwei Verbesserungen, die ich vor dem Finale umsetzen wollte, und ich hoffte, dass sie die Strategie erheblich verbessern würden. Ich beschloss, sie nicht in Angriff zu nehmen, bis die Sandbox gemäß den endgültigen Regeln gestartet war, und stattdessen Zeit damit zu verbringen, das zu debuggen und zu optimieren, was bereits getan wurde, um die Wahrscheinlichkeit böser Fehler in der letzten Woche zu minimieren, wenn jede Minute zählt.

Die letzte Woche vor dem Finale begann.

Die erste Verbesserung, die ich gemacht habe, war diese. In Spielen entstehen im Allgemeinen die meisten meiner Probleme und jede andere Strategie, wenn der Gegner den Ball in Besitz nimmt. Er schlägt ihn irgendwie, geht im Allgemeinen vorbei - kontrolliert. In diesem Fall ist es unmöglich, die Flugbahn des Balls vorherzusagen und einige profitable Aktionen weiter zu planen. Es bleibt „was auch immer“ zu tun, bis der Gegner einen Fehler macht und die Kontrolle über den Ball auf meine Roboter überträgt. Und danach müssen Sie versuchen, keine solchen Aktionen auszuführen, die dazu führen könnten, dass der Ball wieder beim Feind ist.

Mit anderen Worten, zum Zeitpunkt der Planung der Flugbahn möchte ich die möglichen Positionen der Gegner berücksichtigen und versuchen, den Ball dort nicht zu treffen. Ich entschied mich für ein vierdimensionales Potentialfeld (die ersten drei Dimensionen sind die Koordinaten, die Seite der Würfel entspricht dem Durchmesser des Roboters und die vierte Dimension ist die Zeit), das ich ausfüllen werde, um zufällige feindliche Flugbahnen zu erzeugen.

Später, als ich die Flugbahn für meinen Roboter auswertete, berechnete ich die Summe aller Würfel, die den Ball zu den entsprechenden Zeitpunkten überquerten, und multiplizierte sie mit einem Koeffizienten, der alle anderen Werte bei der Wertung übersteigt. Das heißt, das potenzielle Feld wurde mit der höchsten Priorität nach dem Ziel berücksichtigt. Es erlaubte auch, Feinde nach den ersten 30 Ticks aus der Simulation zu entfernen (der Feind konnte während dieser Zeit am Boden alles tun, und solche entfernten ungenauen Vorhersagen störten nur), wenn sie nicht in der Luft waren (es schien, als wäre niemand drin Luft, um die Flugbahn auf komplexe Weise mit Nitro zu verändern).

Durch die Erzeugung zufälliger Flugbahnen für den Feind konnte die Mindestzeit ermittelt werden, die er zum Schlagen des Balls benötigte. Dieser Wert war nützlich, um das Problem mit den frühen Sprüngen meines Torhüters aus dem Tor zu lösen. Viele Tore wurden mir erzielt, weil mein Torhüter früh sprang und unkontrollierbar in der Luft wurde. Danach sagte der Feind leicht voraus, wie mein Torhüter fliegen würde, und änderte, wenn er konnte, die Flugbahn des Balls, bevor mein Torhüter ihn erreichte. Jetzt habe ich den Torwartsprung abgebrochen, wenn der Feind den Ball früher schlagen kann, als mein Torhüter vorhat.



Es stellte sich heraus, dass es ohne signifikanten Schaden an der Strategie möglich ist, die Flugbahn nicht für jeden Tick, sondern durch einen zu berechnen. Durch die Halbierung der Laufzeit habe ich dadurch die durchschnittliche Anzahl der Iterationen verdoppelt. Hier passiert etwas Magie. Es scheint, dass sich die durchschnittliche Anzahl der Iterationen nicht ändert, wenn wir die Trajektorien jedes zweiten Ticks zählen und die Anzahl der Iterationen verdoppeln. Tatsächlich zählt der Simulator jedoch zwei Ticks (200 Mikrotiks) pro Simulation anstelle von einem. Und die Trajektorien werden bereits 50 und nicht 100 tief sein. Deshalb wird sich die durchschnittliche Anzahl der Iterationen verdoppeln.

Blieb ein paar Tage vor dem Finale. Obwohl meine Strategie aufgrund der guten Ballkontrolle weniger Tore zu kassieren begann, begann ich nicht besser zu punkten. Deshalb musste ich sie bald mit einem Koeffizienten für das Tor eines Gegners motivieren. Je schneller ein Tor erzielt wird, desto größer ist das Verhältnis. Und dieser Koeffizient wächst sehr stark, um den Rest der Wertung zu übertreffen und keine Angst vor dem potenziellen Feld zu haben, wenn beispielsweise vor der Wertung noch 10 Ticks übrig sind.

Es wurde eine Berechnung hinzugefügt, wohin der Feind Nitro sendet. Dies wurde mit roher Gewalt mit einem bestimmten Schritt durchgeführt. Außerdem begann der Torhüter, die Reserven an Nitro aufzufüllen, als nichts mein Tor bedrohte.

Die zweite wesentliche Verbesserung war die Verwendung von Minimax. Wenn die Verwendung unterschiedlicher Aufprallkräfte für den Feind während der Konstruktion statischer Flugbahnen den Flug des Balls beeinflusst, wurden bei der Suche beide Optionen mit maximaler und minimaler Aufprallkraft des Feindes berücksichtigt und das Minimum der Schätzungen vorgenommen.

Im Finale hatte ich 7 Optionen für Flugbahnen, als der Roboter am Boden war:

  • 2 Ecken ohne Sprung;
  • 2 Ecken mit einem Sprung;
  • 2 Winkel mit Sprung- und Nitro-Codiergeschwindigkeit;
  • 2 Winkel mit einem Sprung und Nitro kompensieren die Schwerkraft;
  • 1 Ecke mit einem Sprung;
  • 1 Winkel mit Sprung- und Nitro-Codiergeschwindigkeit;
  • 1 Ecke mit einem Sprung und Nitro gleicht die Schwerkraft aus (wird aufgrund eines Fehlers nicht verwendet, der beim Schreiben eines Artikels bemerkt wird).

und zwei Optionen, wenn der Roboter in der Luft ist:

  • Nitro zu einem zufälligen Punkt auf der Oberfläche der Kugel und zufällige Aufprallkraft;
  • zufällige Aufprallkraft.

Einige Stunden vor dem Finale gab es einen Wettbewerb, aber meine Strategie war eindeutig besser. Es schien, als wäre bereits alles erledigt, ich hatte nicht länger als einen Tag geschlafen und nichts hing von mir ab. Es blieb zu beobachten. Zwei Stunden vor dem Finale schickte Andrei seinen frisch gebackenen Gral und gewann erfolgreich den ersten Platz. Die Geschichte seiner Teilnahme finden Sie hier: habr.com/de/post/440398 .

In der Pause zwischen den Phasen des Finales fügte ich ein potenzielles Feld hinzu, das den Ball unabhängig von allem anderen von meinem Tor wegdrückte, und dies schien mir, wie es mir schien, mit Andrei gleichzusetzen. Aber es war schon spät, denn ich habe in der ersten Halbzeit 7 Punkte verloren und selbst 3/3 Siege in der zweiten Halbzeit waren nicht genug.

RAIC ist ein schwieriger Wettbewerb und die Preise werden den Teilnehmern sehr, sehr schwer verliehen. Wenn ein Teilnehmer an der Spitze des Tisches steht, ist dies für ihn nicht nur Unterhaltung, sondern ein Kampf. Beim Schreiben einer starken Strategie sind viele kleine Dinge zu beachten. Jede getroffene Entscheidung kann das Ergebnis erheblich beeinflussen.

Der Quellcode für die Strategie wird hier verfügbar sein.

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


All Articles