Don't tap the white tile - AutoHotkey Bot

Ich sehe gerade, dass ich hier noch nie etwas über Phrase Express und AutoHotkey geschrieben habe. Das Eine vorher, das Andere jetzt, sind eigentlich mein Rückgrat in meiner täglichen Arbeit. Das muss ich unbedingt als Jedi-Tricks verbloggen.

Doch kommen wir zur Überschrift.

Ich bin vor Kurzem auf dieses Video von CodeBullet ( Channel) gestoßen. In diesem erstellt er ein Python Bot für das Spiel “Don’t tap the white tile” oder “Piano Tiles” auf sehr unterhaltsame Weise. Ich kann euch eh den ganzen Kanal nur empfehlen.

Das hat mich auch inspiriert. Ich habe schon vor Monaten mal versucht mit Python Forza Horizon 2 auf der XBox zu steuern. Das klappte jedoch nicht so gut, da das Koppeln des PCs mit der XBox mehr schlecht als recht war. Also am besten ein Spielt auf dem PC steuern. Da ich aber kein Abklatsch machen wollte, habe ich mir vorgenommen, dies mit AutoHotkey zu realisieren.

Ich habe das Spiel online auf dieser Seite gefunden. Der Bot und die Zeiten und Koordinaten sind auf diese Version eingestellt. Das muss natürlich von Umgebung zu Umgebung angepasst werden.

Das Skript startet mit den üblichen Umgebungseinstellungen für AutoHotkey.

#SingleInstance, force
#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%

Der nächste Block ist die Umgebung für den Bot. Mit persistent wird der Bot am Laufen gehalten. Deswegen wird er auch sofort pausiert.

Dann folgt der Settimer Befehl mit dem ich die Unterroutine spalte1 jede 10 Milisekunden (laut AutoHotkey Dokumentation nur annähernd) aufrufe. Zu den Unterroutinen komme ich gleich.

Und ganz wichtig bei Skripten, die Eingaben und die Maus steuern immer! eine Möglichkeit einbauen um das Skript zu pausieren oder gar abzuschalten. Ich habe F1 als Pause/Play Taste und ESC als Abbruch des Skriptes. Im Video von CodeBullet kann man schön sehen, was passieren kann, wenn man das vergisst.

#persistent
pause
Settimer, spalte1, 10

F1::pause
esc::exitapp

Jetzt kommen die Subroutinen für jede Spalte des Pianos. Diese gibt es natürlich vier mal mit verschiedenen Koordinaten.
Nach der Sprungmarke spalte1 wird der Befehl PixelSearch verwendet. Mit diesem kann man einen Bereich definieren, in dem nach einer Farbe gesucht wird. In unserem Fall 0x111111 für Schwarz. Diese Suchen wir in einem Rechteck mit den Koordinaten links oben 590,630 und rechts unten 620,660. Dieses befindet sich in der zweiten Reihe von unten und umfasst etwa immer das mittlere Drittel einer Tile wie im Screenshot zu sehen ist.

Wenn in dem genannten Bereich die Farbe nicht vorkommt, dann gibt PixelSearch einen Fehler aus den ich mit ErrorLevel abfangen. D.h. wenn ein Fehler ausgegeben wird, dann ist das Suchfeld nicht Schwarz, also Sprung zur nächsten Spalte. Ansonsten fahre ich mit der Maus an die vorgegeben Koordinaten und klicke. Die Koordinaten sind immer in der Mitte der Tile und am untersten Ende.

spalte1:
    PixelSearch, , , 590, 620, 630, 660, 0x111111, 0, Fast
    if ErrorLevel
        goto spalte2
    else
        MouseClick, left, 600, 710
        ;Send a
    return

Diese Routine wiederholt sich jetzt viel mal für jede Spalte. Nur bei Spalte 4 ist anstelle des goto auch ein return, da keine weitere Spalte folgt.

Die Suchkoordinaten, wie auch mit dem Klick Position, habe ich durch sehr langes ausprobieren eingestellt. Das sind die Stellen, an denen man schrauben muss, um den Highscore nach oben zu kitzeln.

Wie Ihr auch sehen könnt, habe ich Send a auskommentiert. Ich dachte, zuerst kann ich einfach nur die Taste klicken lassen. An Anfang ist jedoch das Spiel so langsam, dass der Bot ein schwarzes Feld doppelt erkennt und deswegen doppelt drückt. Die Maus zu positionieren und dann zu klicken hilft den Bot zu bremsen. Das ist jedoch, im späteren Verlauf, der Grund warum der Bot zu langsam ist. Hier habe ich schon eine Idee mit einem Zähler oder Timer, der ab einem bestimmten Zeitpunkt von Maus auf Tastatur umspringt und somit schneller wird.

Mit dieser Methode jedoch erreiche ich immer Highscores über 400 Punkte. Mein bisheriger Rekord ist bei 509.

Den Rekord vom Python Skript vom CodeBullet werde ich jedoch nicht so schnell erreichen, da AutoHotkey insgesamt etwas langsamer bei der Bilderkennung ist. Auch schwankt die Performance des Skriptes immens. Aber ich bleibe dran und melde mich, wenn ich einen Schritt weitergekommen bin.

Warum ich weiter mache? Weil ich auf dieses Video gestoßen bin. Das ist scheinbar auch ein AutoHotkey Bot, der sage und schreibe 9 Stunden gelaufen ist und 176.573 Tiles geklickt hat. Also muss es eine bessere Lösung geben.

Falls ich Euch inspiriert habe oder Ihr sogar Lösungsvorschläge für mich habt, dann könnt Ihr mich gerne über Twitter oder per Mail kontaktieren.

Zum Schluß der Code. Einfach als *.ahk Datei abspeichern, per AutoHotkey ausführen und das Spiel auf der Webseite öffnen.

#SingleInstance, force
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
CoordMode, Pixel , Client
timevar := 10

#persistent
 pause
;  timevar -= 0.23
 Settimer, spalte1, %timevar%

F1::pause
esc::exitapp

 spalte1:
 PixelSearch, , , 590, 620, 630, 660, 0x111111, 0, Fast
 if ErrorLevel
 goto spalte2
 else
 MouseClick, left, 600, 710
;  Send a
 return

 spalte2:
 PixelSearch, , , 690, 620, 730, 660, 0x111111, 0, Fast
 if ErrorLevel
 goto spalte3
 else
 MouseClick, left, 700, 710
;  Send s
 return

 spalte3:
 PixelSearch, , , 790, 620, 830, 660, 0x111111, 0, Fast
 if ErrorLevel
 goto spalte4
 else
 MouseClick, left, 800, 710
;  Send d
 return

 spalte4:
 PixelSearch, , , 890, 620, 930, 660, 0x111111, 0, Fast
 if ErrorLevel
 return
 else
 MouseClick, left, 900, 710
;  Send f
 return