Wie ich aufhörte Angst zu haben und einen Spielbot schrieb

Oder die gute alte dynamische Programmierung ohne diese Ihrer neuronalen Netze.

Vor anderthalb Jahren nahm ich zufĂ€llig an einem Unternehmenswettbewerb (zum Zwecke der Unterhaltung) teil, um einen Bot fĂŒr das Spiel Lode Runner zu schreiben. Vor 20 Jahren habe ich alle Probleme der dynamischen Programmierung im entsprechenden Kurs fleißig gelöst, aber so ziemlich alles vergessen und keine Erfahrung in der Programmierung von Game Bots. Ich musste mich daran erinnern, dass wenig Zeit zur VerfĂŒgung stand, um unterwegs zu experimentieren und selbstĂ€ndig auf den Rechen zu treten. Aber plötzlich hat alles sehr gut geklappt, also habe ich beschlossen, das Material irgendwie zu systematisieren und den Leser nicht mit Matan zu ertrĂ€nken.

Bild
Spielbildschirm vom Codenjoy-Projektserver

ZunĂ€chst werden wir die Spielregeln ein wenig beschreiben : Der Spieler bewegt sich horizontal entlang des Bodens oder durch Rohre, weiß, wie man Treppen hoch und runter klettert, fĂ€llt, wenn sich kein Boden unter ihm befindet. Er kann auch links oder rechts von sich selbst ein Loch schneiden, aber nicht jede OberflĂ€che kann durchgeschnitten werden - bedingt ist ein „Holzboden“ möglich und Beton - nicht.

Monster rennen dem Spieler hinterher, fallen in die geschnittenen Löcher und sterben darin. Vor allem aber muss der Spieler Gold sammeln, fĂŒr das erste gesammelte Gold erhĂ€lt er 1 Gewinnpunkt, fĂŒr das N-te erhĂ€lt er N Punkte. Nach dem Tod bleibt der Gesamtgewinn, aber fĂŒr das erste Gold geben sie wieder 1 Punkt. Dies deutet darauf hin, dass die Hauptsache darin besteht, so lange wie möglich am Leben zu bleiben und Gold zu sammeln, ist irgendwie zweitrangig.

Da es Orte auf der Karte gibt, an denen der Spieler nicht aus sich herauskommen kann, wurde ein freier Selbstmord in das Spiel eingefĂŒhrt, der den Spieler zufĂ€llig irgendwohin brachte, aber tatsĂ€chlich das ganze Spiel brach - Selbstmord hat das Wachstum des gefundenen Goldwerts nicht unterbrochen. Wir werden diese Funktion jedoch nicht missbrauchen.

Alle Beispiele aus dem Spiel werden in einer vereinfachten Anzeige angezeigt, die in den Programmprotokollen verwendet wurde:

Bild

Ein bisschen Theorie


Um den Bot mithilfe einer Art Mathematik zu implementieren, mĂŒssen wir eine objektive Funktion festlegen, die die Leistungen des Bots beschreibt, und Aktionen finden, die ihn maximieren. Zum Beispiel erhalten wir fĂŒr das Sammeln von Gold +100, fĂŒr den Tod -100500, sodass keine Sammlung von Gold den möglichen Tod tötet.

Eine separate Frage, und worauf genau bestimmen wir die Zielfunktion, d.h. Wie ist der Stand des Spiels? Im einfachsten Fall reichen die Koordinaten des Spielers aus, aber bei uns ist alles viel komplizierter:

  • Spielerkoordinaten
  • die Koordinaten aller von allen Spielern durchbohrten Löcher
  • die Koordinaten des gesamten Goldes auf der Karte (oder die Koordinaten des kĂŒrzlich verzehrten Goldes)
  • Koordinaten aller anderen Spieler

Es sieht beĂ€ngstigend aus. Vereinfachen wir daher die Aufgabe ein wenig und bis wir uns an das Gold erinnern, das wir essen (wir werden spĂ€ter darauf zurĂŒckkommen), werden wir uns auch nicht an die Koordinaten anderer Spieler und Monster erinnern.

Der aktuelle Stand des Spiels ist also:

  • Spielerkoordinaten
  • Koordinaten aller Gruben

Spieleraktionen Àndern den Status auf verstÀndliche Weise:

  • Bewegungsbefehle Ă€ndern eine der entsprechenden Koordinaten
  • Das Grubenteam fĂŒgt eine neue Grube hinzu
  • Wenn ein Spieler ohne UnterstĂŒtzung fĂ€llt, wird die vertikale Koordinate verringert
  • Die UntĂ€tigkeit des Spielers, der auf der UnterstĂŒtzung steht, Ă€ndert nichts am Zustand

Jetzt mĂŒssen wir verstehen, wie die Funktion selbst maximiert werden kann. Eine der ehrwĂŒrdigen klassischen Methoden zur Berechnung des Spiels, das N vorantreibt, ist die dynamische Programmierung. Es ist unmöglich, auf Formeln zu verzichten, daher werde ich sie in vereinfachter Form geben. Sie mĂŒssen zuerst viel Notation einfĂŒhren.

Der Einfachheit halber behalten wir den Zeitbericht von der aktuellen Bewegung bei, d. H. Die aktuelle Bewegung ist t = 0.
Wir bezeichnen den Stand des Spiels im Laufe von t durchxt.
Viele bezeichnet alle gĂŒltigen Aktionen des Bots (in einem bestimmten Zustand, aber der Einfachheit halber schreiben wir den Zustandsindex nicht) durch Wir bezeichnen eine bestimmte Aktion auf dem Kurs t (wir lassen den Index weg).
Bedingungxt Unter dem Einfluss geht in den Zustand xat+1.

Gewinnen Sie, wenn Aktion a aktiviert istxt wir bezeichnen es als P(xt,xat+1). Bei der Berechnung nehmen wir an, dass wenn wir Gold gegessen haben, es gleich G = 100 ist, wenn sie gestorben sind, dann D = -100500, sonst 0.

SeiF(xt)Dies ist die Auszahlungsfunktion fĂŒr das optimale Spiel eines Bots, der sich zum Zeitpunkt t im Zustand x befindet. Dann mĂŒssen wir nur noch eine Aktion finden, die maximiertF(x0).

Jetzt schreiben wir die erste Formel, die sehr wichtig und gleichzeitig fast richtig ist:

F(x0)=maxa∈AF(xa1)+P(x0,xa1)



Oder fĂŒr einen beliebigen Zeitpunkt

F(xt)=maxa∈AF(xat+1)+P(xt,xat+1)



Es sieht ziemlich ungeschickt aus, aber die Bedeutung ist einfach - die optimale Lösung fĂŒr den aktuellen Zug besteht aus der optimalen Lösung fĂŒr den nĂ€chsten Zug und dem Gewinn im aktuellen Zug. Dies ist Bellmans schief formuliertes OptimalitĂ€tsprinzip. Wir wissen nichts ĂŒber die optimalen Werte in Schritt 1, aber wenn wir sie kennen wĂŒrden, wĂŒrden wir eine Aktion finden, die die Funktion maximiert, indem wir einfach alle Aktionen des Bots durchlaufen. Das Schöne an wiederkehrenden Beziehungen ist, dass wir sie finden könnenF(x1), wendet das OptimalitĂ€tsprinzip darauf an und drĂŒckt es in genau der gleichen Formel durch F(x2). Wir können die Auszahlungsfunktion auch bei jedem Schritt leicht ausdrĂŒcken.

Es scheint, dass das Problem gelöst ist, aber hier stehen wir vor dem Problem, dass wir, wenn wir bei jedem Schritt 6 Spieleraktionen sortieren mĂŒssten, beim N-Rekursionsschritt 6 ^ N Optionen sortieren mĂŒssten, was fĂŒr N = 8 bereits eine ziemlich anstĂ€ndige Zahl ~ 1,6 ist Millionen FĂ€lle. Auf der anderen Seite haben wir Gigahertz-Mikroprozessoren, die nichts zu tun haben, und es scheint, dass sie die Aufgabe vollstĂ€ndig bewĂ€ltigen werden, und wir werden die Suchtiefe mit genau 8 ZĂŒgen auf sie beschrĂ€nken.

Unser Planungshorizont betrĂ€gt also 8 ZĂŒge, aber wo erhalten wir die Werte?F(x9)? Und hier kommen wir nur auf die Idee, dass wir in der Lage sind, die Aussichten der Position irgendwie zu analysieren und ihr einen Wert zuzuweisen, der auf ihren höchsten Überlegungen basiert. LassenF(x9)=S(x9)wo S(x)Dies ist eine Funktion der Strategie. In der einfachsten Version ist es nur eine Matrix, aus der wir den Wert gemĂ€ĂŸ den geometrischen Koordinaten des Bots auswĂ€hlen. Wir können sagen, dass die ersten 8 ZĂŒge eine Taktik waren, und dann beginnt die Strategie. TatsĂ€chlich schrĂ€nkt uns niemand bei der Auswahl einer Strategie ein, und wir werden uns spĂ€ter damit befassen. Um jedoch nicht wie eine Eule aus einer Anekdote ĂŒber Hasen und Igel zu werden, gehen wir zur Taktik ĂŒber.

Allgemeines Schema


Also haben wir uns fĂŒr den Algorithmus entschieden. Bei jedem Schritt lösen wir das Optimierungsproblem, finden die optimale Aktion fĂŒr den Schritt, schließen sie ab und fahren mit dem nĂ€chsten Schritt fort.

Es ist notwendig, bei jedem Schritt ein neues Problem zu lösen, denn mit jedem Spielverlauf Àndert sich die Aufgabe ein wenig, neues Gold erscheint, jemand isst jemanden, die Spieler bewegen sich ...
Aber denken Sie nicht, dass unser genialer Algorithmus fĂŒr alles sorgen kann. Nachdem Sie das Optimierungsproblem gelöst haben, mĂŒssen Sie auf jeden Fall einen Handler hinzufĂŒgen, der nach unangenehmen Situationen sucht:

  • Stehender Bot fĂŒr lange Zeit an Ort und Stelle
  • Kontinuierliches Gehen von links nach rechts
  • Mangel an Einkommen zu lange

All dies kann eine radikale Änderung der Strategie, Selbstmord oder eine andere Aktion außerhalb des Rahmens des Optimierungsalgorithmus erfordern. Die Art dieser Situationen kann unterschiedlich sein. Manchmal fĂŒhren die WidersprĂŒche zwischen Strategie und Taktik dazu, dass der Bot an einem Punkt einfriert, den er fĂŒr strategisch wichtig hĂ€lt, was von alten Botanikern namens Buridanov Donkey entdeckt wurde.

Bild

Ihre Gegner können Ihren kurzen Weg zum begehrten Gold einfrieren und sperren - wir werden uns spĂ€ter darum kĂŒmmern.

Der Kampf gegen den Aufschub


Betrachten Sie den einfachen Fall, in dem sich ein Gold rechts vom Bot befindet und sich in einem Radius von 8 keine Goldzellen mehr befinden. Welchen Schritt wird der Bot nach unserer Formel unternehmen? In der Tat - absolut keine. Zum Beispiel liefern alle diese Lösungen auch fĂŒr drei ZĂŒge genau das gleiche Ergebnis:

  • Schritt nach links - Schritt nach rechts - Schritt nach rechts
  • Schritt nach rechts - UntĂ€tigkeit - UntĂ€tigkeit
  • UntĂ€tigkeit - UntĂ€tigkeit - Schritt nach rechts

Alle drei Optionen ergeben einen Gewinn von 100, der Bot kann die Option mit UntĂ€tigkeit auswĂ€hlen, im nĂ€chsten Schritt das gleiche Problem erneut lösen, die UntĂ€tigkeit erneut auswĂ€hlen ... und fĂŒr immer stillstehen. Wir mĂŒssen die Formel zur Berechnung der Gewinne Ă€ndern, um den Bot zu stimulieren, so frĂŒh wie möglich zu handeln:

F(x0)=maxa∈AF(xa1)∗E+P(x0,xa1)



Wir haben den zukĂŒnftigen Gewinn im nĂ€chsten Schritt mit dem „Inflationskoeffizienten“ E multipliziert, der kleiner als 1 gewĂ€hlt werden muss. Wir können sicher mit Werten von 0,95 oder 0,9 experimentieren. Aber wĂ€hlen Sie es nicht zu klein, zum Beispiel mit einem Wert von E = 0,5, das Gold, das im 8. Zug gegessen wird, bringt nur 0,39 Punkte.

Und so haben wir das Prinzip "Verschieben Sie nicht bis morgen, was Sie heute essen können" wiederentdeckt.

Sicherheit


Gold zu sammeln ist sicherlich gut, aber Sie mĂŒssen immer noch ĂŒber Sicherheit nachdenken. Wir haben zwei Aufgaben:

  • Bringe dem Bot bei, Löcher zu graben, wenn sich das Monster in einer geeigneten Position befindet
  • Bringe dem Bot bei, vor Monstern davonzulaufen

Wir sagen dem Bot jedoch nicht, was er tun soll, sondern legen den Wert der Gewinnfunktion fest und der Optimierungsalgorithmus wĂ€hlt die entsprechenden Schritte aus. Ein separates Problem ist, dass wir nicht genau berechnen, wo sich ein Monster in einer bestimmten Bewegung befinden kann. Der Einfachheit halber nehmen wir daher an, dass die Monster an Ort und Stelle sind, und wir mĂŒssen uns ihnen einfach nicht nĂ€hern.

Wenn sie sich uns nĂ€hern, wird der Bot selbst vor ihnen davonlaufen, weil er dafĂŒr bestraft wird, dass er ihnen zu nahe ist (eine Art Selbstisolation). Und so fĂŒhren wir zwei Regeln ein:

  • Wenn wir in einem Abstand d und d <= 3 zum Monster kommen, wird uns eine Geldstrafe von 100.500 * (4-d) / 4 auferlegt
  • Wenn das Monster nahe genug gekommen ist, mit uns auf der gleichen Linie ist und es ein Loch zwischen uns gibt, dann bekommen wir etwas Gewinn P.

Das Konzept "nĂ€herte sich dem Monster in einer Entfernung d" werden wir etwas spĂ€ter eröffnen, aber jetzt wollen wir zur Strategie ĂŒbergehen.

Wir gehen um die Grafiken herum


Mathematisch gesehen ist das Problem der optimalen Goldumgehung ein seit langem gelöstes Problem eines reisenden VerkĂ€ufers, dessen Lösung kein VergnĂŒgen ist. Bevor Sie solche Probleme lösen, mĂŒssen Sie sich eine einfache Frage ĂŒberlegen - aber wie finden Sie den Abstand zwischen zwei Punkten im Spiel? Oder in einer etwas nĂŒtzlicheren Form: Finden Sie fĂŒr ein bestimmtes Gold und fĂŒr jeden Punkt auf der Karte die Mindestanzahl von ZĂŒgen, fĂŒr die der Spieler den Punkt aus Gold erreicht. FĂŒr einige Zeit werden wir vergessen, Löcher zu graben und in sie zu springen, wir werden nur natĂŒrliche Bewegungen pro 1 Zelle lassen. Nur wir werden in die entgegengesetzte Richtung gehen - von Gold und ĂŒber die Karte.



Im ersten Schritt wĂ€hlen wir alle Zellen aus, aus denen wir in einem Zug Gold gewinnen können, und weisen sie 1 zu. Im zweiten Schritt wĂ€hlen wir alle Zellen, aus denen wir in einem Schritt in diejenigen fallen, aus und weisen sie 2 zu. Das Bild zeigt den Fall fĂŒr 3 Schritte. Versuchen wir nun, alles formal in einer fĂŒr die Programmierung geeigneten Form aufzuschreiben.

Wir brauchen:

  • Der zweidimensionale numerische Array-Abstand [x, y], in dem das Ergebnis gespeichert wird. FĂŒr Goldkoordinaten enthĂ€lt es zunĂ€chst 0 fĂŒr die verbleibenden Punkte -1.
  • Das oldBorder-Array, in dem wir die Punkte speichern, von denen aus wir uns bewegen, hat zunĂ€chst einen Punkt mit Goldkoordinaten
  • Array newBorder, in dem die im aktuellen Schritt gefundenen Punkte gespeichert werden

  1. FĂŒr jeden Punkt p von oldBorder finden wir alle Punkte p_a, von denen aus wir p in einem Schritt erreichen können (genauer gesagt, wir machen einfach alle möglichen Schritte von p in die entgegengesetzte Richtung, z. B. ohne UnterstĂŒtzung nach oben fliegen) und Entfernung [p_a] = - 1
  2. Wir platzieren jeden solchen Punkt p_a im Array newBorder, in der Entfernung [p_a] schreiben wir die Iterationsnummer
  3. Nachdem alle Punkte abgeschlossen sind:
  4. Tauschen Sie die Arrays von oldBorder und newBorder aus. Danach löschen wir newBorder
  5. Wenn oldBorder leer ist, beenden Sie den Algorithmus, andernfalls fahren Sie mit Schritt 1 fort.

Gleiches im Pseudocode:

iter=1;
newBorder.clear();
distance.fill(-1);
distance[gold]=0;
oldBorder.push(gold);

while(oldBorder.isNotEmpty()) {
  for (p: oldBorder){
    for (p_a: backMove(p)) {
      if (distance[p_a]==-1) {
         newBorder.push(p_a);
         distance[p_a]=iter;
      }
    }
  }
  Swap(newBorder, oldBorder);
  newBorder.clear();
  iter++;
}

Am Ausgang des Algorithmus haben wir eine Entfernungskarte mit dem Wert der Entfernung von jedem Punkt des gesamten Feldes des Spiels zu Gold. FĂŒr Punkte, von denen aus Gold nicht erreichbar ist, betrĂ€gt der Abstandswert -1. Mathematiker nennen einen solchen Spaziergang um das Spielfeld (der ein Diagramm mit Scheitelpunkten an Punkten im Feld und Kanten bildet, die die in einem Zug zugĂ€nglichen Scheitelpunkte verbinden) „Gehen Sie das Diagramm in der Breite“. Wenn wir eine Rekursion anstelle von zwei Rahmenarrays implementieren wĂŒrden, wĂŒrde dies als "Umgehen des Graphen in der Tiefe" bezeichnet. Da die Tiefe jedoch sehr groß sein kann (mehrere hundert), empfehle ich Ihnen, beim Durchlaufen von Graphen rekursive Algorithmen zu vermeiden.

Der eigentliche Algorithmus wird etwas komplizierter sein, da ein Loch gegraben und hineingesprungen wird. Es stellt sich heraus, dass wir in 4 ZĂŒgen eine Zelle seitwĂ€rts und zwei nach unten bewegen (da wir uns in die entgegengesetzte Richtung und dann nach oben bewegen), aber eine leichte Modifikation des Algorithmus löst das Problem.

Ich ergĂ€nzte das Bild mit Zahlen, einschließlich der BerĂŒcksichtigung, ein Loch zu graben und hinein zu springen:



Woran erinnert uns das?



Der Geruch von Gold! Und unser Bot wird sich fĂŒr diesen Geruch entscheiden, wie Rocky fĂŒr KĂ€se (aber gleichzeitig verliert er nicht sein Gehirn und weicht Monstern aus und grĂ€bt sogar Löcher fĂŒr sie). Machen wir ihn zu einer einfachen gierigen Strategie:

  1. FĂŒr jedes Gold erstellen wir eine Entfernungskarte und ermitteln die Entfernung zum Spieler.
  2. WÀhlen Sie das Gold, das dem Spieler am nÀchsten liegt, und nehmen Sie seine Karte, um die Strategie zu berechnen
  3. Geben Sie fĂŒr jede Zelle der Karte mit d den Abstand zu Gold und dann den strategischen Wert an

    S(x)={0 d<0,GsEsd d≄0 

Wo GsDies ist ein imaginĂ€rer Wert von Gold. Es ist wĂŒnschenswert, dass es um ein Vielfaches unter dem gegenwĂ€rtigen Wert liegt EsDies ist ein Inflationskoeffizient <1, denn je weiter das imaginĂ€re Gold entfernt ist, desto billiger ist es. Das VerhĂ€ltnis der Koeffizienten E undEsstellt ein ungelöstes Problem des Jahrtausends dar und lĂ€sst Raum fĂŒr KreativitĂ€t.

Denken Sie nicht, dass unser Bot immer zum nÀchsten Gold lÀuft. Nehmen wir an, wir haben links ein Gold in einem Abstand von 5 Zellen und dann eine Leere und rechts zwei Gold in einem Abstand von 6 und 7. Da echtes Gold wertvoller ist als gedacht, geht der Bot nach rechts.

Bevor wir zu interessanteren Strategien ĂŒbergehen, werden wir eine weitere Verbesserung vornehmen. Im Spiel zieht die Schwerkraft den Spieler nach unten und er kann nur die Treppe hinaufgehen. Das höhere Gold sollte also höher bewertet werden. Wenn die Höhe von der obersten Zeile nach unten angegeben wird, können Sie den Wert von Gold (mit vertikaler y-Koordinate) mit multiplizierenEhy. FĂŒr den KoeffizientenEh Der neue Begriff „vertikale Inflationsrate“ wurde geprĂ€gt, zumindest wird er von Ökonomen nicht verwendet und spiegelt das Wesentliche gut wider.

Strategien komplizieren


Wenn ein Gold aussortiert ist, mĂŒssen Sie mit all dem Gold etwas anfangen, und ich möchte keine schwere Mathematik anziehen. Es gibt eine sehr elegante, einfache und falsche (im engeren Sinne) Lösung: Wenn ein Gold ein „Wertfeld“ um sich herum erzeugt, fĂŒgen wir einfach alle Wertefelder aus allen Zellen mit Gold zu einer Matrix hinzu und verwenden es als Strategie. Ja, dies ist keine optimale Lösung, aber mehrere Goldeinheiten in mittlerer Entfernung können wertvoller sein als eine nahe Einheit.

Eine neue Lösung schafft jedoch neue Probleme - eine neue Wertematrix kann lokale Maxima enthalten, in deren NĂ€he kein Gold vorhanden ist. Da unser Bot in sie eindringen kann und nicht ausgehen möchte, mĂŒssen wir einen Handler hinzufĂŒgen, der ĂŒberprĂŒft, ob der Bot das lokale Maximum der Strategie erreicht und gemĂ€ĂŸ den Ergebnissen des Umzugs an Ort und Stelle bleibt. Und jetzt haben wir ein Werkzeug zur BekĂ€mpfung von Einfrierungen - brechen Sie diese Strategie mit N ZĂŒgen ab und kehren Sie vorĂŒbergehend zur Strategie des nĂ€chsten Goldes zurĂŒck.

Es ist ziemlich lustig zu sehen, wie ein festsitzender Bot seine Strategie Àndert und kontinuierlich nach unten geht und das nÀchste Gold frisst. In den unteren Etagen der Karte kommt der Bot zur Besinnung und versucht aufzusteigen. Eine Art Dr. Jekyll und Mr. Hyde.

Strategie widerspricht Taktik


Hier kommt unser Bot unter dem Boden zu Gold:



Es fÀllt bereits in den Optimierungsalgorithmus, es bleibt 3 Schritte nach rechts zu machen, ein Loch rechts zu schneiden und hinein zu springen, und dann wird die Schwerkraft alles von selbst tun. Etwas wie das:



Aber der Bot friert ein. Das Debuggen zeigte, dass es keinen Fehler gab: Der Bot entschied, dass die optimale Strategie darin bestand, einen Zug abzuwarten und dann den angegebenen Weg zu gehen und beim letzten analysierten Schritt Gold zu nehmen. Im ersten Fall erhĂ€lt es einen Gewinn aus dem empfangenen Gold und einen Gewinn aus imaginĂ€rem Gold (bei der letzten analysierten Iteration befindet es sich nur in der Zelle, in der sich das Gold befand) und im zweiten Fall - nur aus echtem Gold (obwohl eine Runde frĂŒher), aber den Gewinn Es gibt keine Strategie mehr, weil der Platz unter dem Gold faul und nicht vielversprechend ist. Nun, im nĂ€chsten Zug beschließt er erneut, eine Pause einzulegen. Wir haben solche Probleme bereits gelöst.

Ich musste die Strategie Ă€ndern - da wir das gesamte Gold, das in der Phase der Analyse gegessen wurde, auswendig lernten und die Wertkarten des verzehrten Goldes von der Gesamtmatrix des strategischen Werts subtrahierten, berĂŒcksichtigte die Strategie das Erreichen der Taktik (es war möglich, den Wert anders zu berechnen - Matrizen nur fĂŒr hinzuzufĂŒgen ganzes Gold, aber es ist rechnerisch komplizierter, weil es viel mehr Gold auf der Karte gibt, als wir in 8 ZĂŒgen essen können).

Aber das hat unsere Qual nicht beendet. Angenommen, die Matrix des strategischen Werts hat ein lokales Maximum und der Bot nĂ€hert sich ihm fĂŒr 7 ZĂŒge. Wird der Bot dorthin gehen, um einzufrieren? Nein, denn fĂŒr jede Route, auf der der Bot in 8 ZĂŒgen das lokale Maximum erreicht, ist der Gewinn der gleiche. Guter alter Aufschub. Der Grund dafĂŒr ist, dass der strategische Gewinn nicht von dem Moment abhĂ€ngt, in dem wir uns in der Zelle befinden. Das erste, was mir in den Sinn kommt, ist, den Bot fĂŒr einen einfachen zu bestrafen, aber dies hilft in keiner Weise, wenn man sinnlos nach links / rechts geht. Es ist notwendig, die Grundursache zu behandeln - um den strategischen Gewinn in jeder Runde (als Differenz zwischen dem strategischen Wert des neuen und des aktuellen Zustands) zu berĂŒcksichtigen und ihn im Laufe der Zeit um einen Faktor zu reduzieren.
Jene. FĂŒgen Sie einen zusĂ€tzlichen Begriff in den Ausdruck fĂŒr das Gewinnen ein:

pnew(x0,xa1)=p(x0,xa1)+(S(xa1)–S(x0)).



Der Wert der Zielfunktion fĂŒr letztere wird im Allgemeinen als Null angenommen: F(x9)=0. Da der Gewinn bei jeder Bewegung durch Multiplikation mit einem Koeffizienten abgeschrieben wird, gewinnt unser Bot schneller an strategischem Gewinn und beseitigt das beobachtete Problem.

Ungetestete Strategie


Ich habe diese Strategie in der Praxis nicht getestet, aber sie sieht vielversprechend aus.

  1. Da wir alle AbstĂ€nde zwischen den Goldpunkten und die AbstĂ€nde zwischen dem Gold und dem Spieler kennen, können wir die Spieler-N-Kette von Goldzellen (wobei N klein ist, zum Beispiel 5 oder 6) mit der kĂŒrzesten LĂ€nge finden. Schon die einfachste Suche nach Zeit reicht aus.
  2. WĂ€hlen Sie das erste Gold in dieser Kette aus und verwenden Sie das Wertefeld als Strategiematrix.

In diesem Fall ist es wĂŒnschenswert, die Kosten fĂŒr reales und das imaginĂ€re Gold nahe zu bringen, damit der Bot nicht in den Keller zum nĂ€chsten Gold stĂŒrzt.

Letzte Verbesserungen


Nachdem wir gelernt haben, uns auf der Karte zu „ausbreiten“, machen wir eine Ă€hnliche „Ausbreitung“ von jedem Monster fĂŒr mehrere ZĂŒge und finden alle Zellen, in denen das Monster landen kann, zusammen mit der Anzahl der ZĂŒge, fĂŒr die es es machen wird. Dadurch kann der Spieler völlig sicher durch das Rohr ĂŒber den Kopf des Monsters kriechen.

Und im letzten Moment - bei der Berechnung der Strategie und des imaginĂ€ren Wertes von Gold haben wir die Position der anderen Spieler nicht berĂŒcksichtigt, sondern sie bei der Analyse der Karte einfach „gelöscht“. Es stellt sich heraus, dass einzelne hĂ€ngende Schalen den Zugang zu ganzen Regionen blockieren können. Daher wurde ein zusĂ€tzlicher Handler hinzugefĂŒgt, um gefrorene Gegner zu verfolgen und sie wĂ€hrend der Analyse durch Betonblöcke zu ersetzen.

Implementierungsfunktionen


Da der Hauptalgorithmus rekursiv ist, mĂŒssen wir in der Lage sein, Statusobjekte schnell zu Ă€ndern und sie zur weiteren Änderung auf ihre ursprĂŒnglichen zurĂŒckzusetzen. Ich habe Java verwendet, eine Sprache mit Garbage Collection. Das Ausprobieren von Millionen von Änderungen im Zusammenhang mit dem Erstellen kurzlebiger Objekte kann in einer Spielrunde zu mehreren Garbage Collections fĂŒhren, was in Bezug auf die Geschwindigkeit fatal sein kann. Daher muss man bei den verwendeten Datenstrukturen Ă€ußerst vorsichtig sein, ich habe nur Arrays und Listen verwendet. Oder nutzen Sie das Valgala-Projekt auf eigene Gefahr und Gefahr :)

Quellcode und Spieleserver


Den Quellcode finden Sie hier auf dem Github . Beurteilen Sie nicht streng, es wurde viel in Eile getan. Der Codenjoy- Spieleserver bietet die Infrastruktur zum Starten von Bots und zum Überwachen des Spiels. Zum Zeitpunkt der Erstellung war die Revision relevant, Revision 1.0.26 wurde verwendet.

Sie können den Server mit der folgenden Zeile starten:

call mvn -DMAVEN_OPTS=-Xmx1024m -Dmaven.test.skip=true clean jetty:run-war -Dcontext=another-context -Ploderunner

Das Projekt selbst ist Ă€ußerst neugierig und bietet Spiele fĂŒr jeden Geschmack.

Fazit


Wenn Sie dies alles ohne vorbereitende Vorbereitung bis zum Ende gelesen und alles verstanden haben, dann sind Sie ein seltener Kerl.

All Articles