Archive for Jun. 2015

HearthstoneCalc – Injecting

Der Werdegang von HearthstoneCalc hat einen eigenen Post verdient, in welchem dann weitere Ansätze (Monte Carlo Tree Search) vorgestellt werden. In diesem Blogeintrag geht es allerdings um das Injecten und Daten abrufen aus Hearthstone. Denn ohne Daten aus dem Spiel müssen wir HearthstoneCalc garnicht mehr weiterentwickeln.

Uns wird es zum Glück leicht gemacht. Hearthstone ist mit der Engine Unity3D geschrieben. Für Blizzard hat das den großen Vorteil, das Spiel einfach auf mobile Geräte (Tables und Smartphones, Android und iOS) portieren zu können. Für uns hat es den großen Vorteil, dass Unity .NET (genauer gesagt: Mono) verwendet. Und da die Binaries noch nicht einmal obfuscated vorliegen, haben wir ein relativ einfaches Spiel.

Der für Unity relevante Code wird in der Assembly-CSharp.dll gespeichert. Die Anzahl der Klassen überschreitet alles, was ich bisher gesehen habe. Dementsprechend fällt es am Anfang schwer, uns zurecht zu finden. Auch muss man sich zunächst an die Unity-Eigenarten gewöhnen: Jedes Objekt ist eine Entity, die wiederrum mehrere Unterentities haben kann. Oftmals haben Klassen Unterklassen, enthalten viel zu viel Renderlogik oder scheinen nie erzeugt zu werden.

GameStateDiagDaher gilt zu klären: Welche Daten müssen wir alle Abrufen? Die Daten aus dem Spiel müssen in die Strukturen von HearthstoneCalc gebracht werden. Die wichtigste und größte Struktur ist hierbei die GameState-Klasse (Links). Sie enthält das Spielfeld mit den Monstern, die Karten des Spielers und die Infos über die jeweiligen Helden. Natürlich haben die Helden weitere Unterklassen, wie z.B. die ausgerüstete Waffe oder die gesetzen Geheimnisse. Auch Monster sind inzwischen komplexer geworden, denn sie können verschiedene Buffs besitzen und auf andere umliegende Minions Einfluss ausüben.

Die Klassen aus Hearthstone können wir nicht einfach übernehmen, denn sie enthalten viel zu viele Informationen. Diese Klassen sind nicht dafür ausgelegt, Millionen möglicher Boardzustände zu speichern. Zu diesem Problem werde ich nächsten Post über HearthstoneCalc noch mehr sagen.

Der große Vorteil von Mono ist natürlich, dass wir realtiv einfach .NET Code ausführen können. .NET Code in einem Programm ausführen? Klingt doch sehr nach CLR-Hosting!? Leider ist das nicht so einfach, denn die Unity-Klassen mögen es nicht, wenn sie außerhalb von mscorlib.dll Thread aufgrufen werden. Versucht man eine Unity-Funktion direkt aufzurufen, so erhält man folgende Fehlermeldung zu gesicht:

Weiterlesen

6 people like this post.

HearthstoneCalc - Einstieg und Abstaktion

In diesem Post werde ich etwas über mein aktuelles Freizeitprojekt “HearthstoneCalc” berichten. Ich werde fortsetzende Posts über das Tool danach richten, wie interessiert Ihr Leser an den Artikeln seid. Schauen wir mal ;)

Ich interessiere mich schon länger für Spiele KIs und bin der Überzeugung, dass Computer bei der Planung von Spielzügen weit effektiver sind als ein menschliches Gehirn. Dabei geht es nicht um die Kreativität die ein menschlicher Spieler an den Tag legt, sondern die reine rationale Beurteilung der Spielsituation. Schachcomputer sind inzwischen ungeschlagen, weil sie einfach Unmengen an Situationen vorraussehen und bewerten können. Seid einiger Zeit fasziniert mich das Spiel “Hearthstone“, ein Rundenbasiertes Kartenspiel ähnlich Magic oder Yu-Gi-Oh. Man kann Diener oder Zauber spielen, die eigenen Heldenfähigkeiten nutzen oder mit Waffen die Kontrolle über das Board behalten. Der Spielverlauf wird später nochmal genauer erklärt, jetzt geht es erstmal um das Programm “HearthstoneCalc”.

Ziel des Programms ist es, alle möglichen Züge zu eruieren und den besten auszuwählen. Dabei sollte das Programm den aktuellen Spielstatus auslesen, die Berechnungen durchführen und den Spielzug selbstständig ausführen. Im Gegensatz zu Spielen mit perfekten Informationen wie Schach oder Vier-Gewinnt haben wir bei Hearthstone drei große Probleme:

  1. Die gegnerischen Karten sind unbekannt. Zwar werden von den Spielern meist ähnliche und als effektiv geltende Decks gespielt, allerdings varieren auch hier die Karten. Die Karten des Gegners die er auf der Hand hat sind verdeckt und bieten daher keine perfekten Informationen über zukünftige Spielzüge
  2. Hearthstone braucht keinen Skill, sondern nur Glück“. An diesem Zitat ist leider viel wahres dran. Viele Zauber wirken auf alle Einheiten verteilt und viel Schaden (z.B. von explodierenden Bomben) ist variabel. Glück gehört einfach zum Spiel dazu, daher kann man den Ausgang eines Zuges nicht effektiv berechnen. Man muss mit Wahrscheinlichkeiten rechnen, und davon nicht wenige. Später gibt es ein Beispiel, wie komplex ein solcher Zug sein kann.
  3. Manche Decks verfolgen eine spezielle Strategie und sammeln daher Karten, um einen großen Zug zu machen. Solch eine “Strategie” bringt man dem Computer schlecht bei, vorallem da er nebenher darauf achten muss, nicht gegen den Gegner zu verlieren.

Ihr merkt, das Projekt wird komplex. Und ein solches Projekt fängt man am besten an, indem man abstrahiert und vereinfacht. Ein solch einfaches Modell kann dann später erweitert werden. Effektiv heißt das auf die beiden oberen Punkte bezogen: Wir schauen zunächst nur den aktuellen Zug unseres Spielers an und lassen die mögliche gegnerische Reaktion außer Acht. Zudem berechnen wir nur die Züge ohne Wahrscheinlichkeiten bzw Rechnen mit dem schlimmsten Ausgang für uns.

Weiterlesen

7 people like this post.