TerraTactician Expandoria Logo

TerraTactician Expandoria

Erste Schritte

Zuletzt aktualisiert: April 1, 2025

Aufgabe

Die Aufgabe des diesjährigen AuD-Wettbewerbs lautet: Schreibe einen Bot für unser Spiel Terratactician-Expandoria (TTE), der im Challenge Mode mindestens bis Runde 5 kommt.

Ihr werdet dafür eine Java-Datei schreiben und auf der AuD-Seite abgeben.

Installation

Zum Erfüllen der Aufgabe benötigt ihr zwei Komponenten:

Installation des Spiels

Je nach Plattform gibt es verschiedene Möglichkeiten, das Spiel zu installieren. Am einfachsten ist es, das Spiel online zu spielen.
Willst du die volle Performance oder deinen Bot ohne UI / schnell testen, dann muss das Spiel installiert werden. (empfohlen)

Eine vollständige Installationsanleitung findest du hier.

Unsere offizielle Release-Seite kannst du auf Codeberg finden. Sollte Codeberg nicht erreichbar sein, kannst du das Spiel auch vom vccourses-Mirror herunterladen.

Installation der JavaBot-Bibliothek

Lade die letzte Version von tte-bot-full.jar von hier runter.

Weitere Informationen und andere Möglichkeiten findest du hier. Z. B. gibt es die Möglichkeit, eine build.gradle zu nutzen.

Den Bot aufsetzen

Um einen Bot zu schreiben, erstelle eine Java Datei MyBot.java. Eine Vorlage findest du hier. Kopiere diesen Code aus der Vorlage nach MyBot.java und passe Namen und Matrikelnummer an.

Deine Aufgabe ist es die Methode executeTurn zu implementieren. Du kannst weitere Klassen in der Datei hinzufügen, aber nicht weitere Java-Dateien erstellen.

Den Bot starten und Testen

Führe die beiden Befehle aus. Passe je die beiden Pfade zu den Dateien an, sodass sie auf die tte-bot-full.jar Datei bzw. deinen Bot zeigen.

# Bot kompilieren
javac -cp tte-bot-full.jar bots/MyBot.java

# Bot ausführen
java -jar tte-bot-full.jar -c bots/MyBot.class

Spiel mit Bot starten:

  1. Starte das Spiel
  2. Wähle den Challenge-Modus
  3. Aktiviere den Haken neben Bot aktivieren.
  4. Klicke auf Starten (Achtung: Der Bot muss vorher laufen.)

Wir werden deinen Bot mit dem seed XXX testen.

Wenn du den Bot ohne UI und schnell testen willst, dann nutze den folgenden Befehl:

terratactician-expandoria --challenge --bot --headless

(Wenn das Spiel nicht im Pfad ist, musst du eventuell terratactician-expandoria durch den Pfad zur executable ersetzen.)

Tips und Infos für den Bot

Spielprinzip

Eine ausführliche Anleitung des Spielmodus Challenge kannst du hier finden.

TerraTactician-Expandoria ist ein rundenbasiertes Strategiespiel. Das Ziel ist es, so lange wie möglich zu überleben. Dafür muss man die Ressourcenanforderungen erfüllen.
Wenn man zwei Runden in Folge die Anforderungen (Materialien, Nahrung, Geld) nicht erfüllt, hat man verloren. Runden sind je eine Minute lang.

Ressourcen kann man bekommen, indem man mit Karten ein Dorf baut. Eine Karte kann auf einem Feld platziert werden, wenn:

Neue Karten erhält man durch Nachziehen.

Ein weiterer Weg, Ressourcen zu bekommen, ist es, Belohnungen einzusammeln, welche alle 19 Sekunden auf der Karte erscheinen.

Karten können einige Sekunden nach dem Platzieren wieder eingesammelt werden.

Karten

Man erhält mehr Ressourcen, wenn man die Karten sinnvoll platziert.

Eine genaue Dokumentation kannst du hier finden.

Hier ist eine kurze Übersicht über alle Karten, mit Informationen.

Features der Bot Bibliothek

CubeCoordinates

Wie du vielleicht schon mitbekommen hast, besteht die Welt in TTE aus Hexagons und nutzt deswegen auch ein dafür passendes Koordinatensystem: die CubeCoordinates.
Eine ausführliche Anleitung kannst du hier finden.

Kurz gefasst: Eine Koordinate besteht aus 3 ganzen Zahlen, deren Summe 0 ergeben muss. CubeCoordinate können auch als Vektor zwischen zwei Koordinaten verwendet werden. (Wie „normale“ Koordinaten)

Zum Schreiben eines Bots musst du CubeCoordinates nicht komplett verstehen. Wir haben eine Klasse CubeCoordiante implementiert, die für dich einige Arbeit übernimmt.

Einige sehr nützliche Features:

Zug ausführen

Pro Sekunde wird dein Code in executeTurn einmal ausgeführt. Dein Bot hat dann je 40ms Zeit seinen nächsten Zug zu bestimmen (oder auszusetzen).
Nutze World um Informationen zu erhalten und Controller um deinen Zug zu setzen. Mit return wird dein Zug beendet. Rechnet dein Bot zu lange, wird der Zug automatisch ausgesetzt.

Eine genaue Dokumentation kannst du hier finden.

Einige Beispiele:

@Override
public void executeTurn(World world, Controller controller) {
    // Platziert das erste Tile in der Hand an (0,0,0) ohne zu prüfen, ob das eine
    // valide Koordinate ist oder die Hand überhaupt Karten beinhaltet.
    // Du kannst mit `world.getHand().len()` wie viele Karten auf der Hand sind.
    // Mit `world.getBuildArea().contains(coord)` und `world.getMap().at(coord)`
    // kannst du prüfen ob das Feld noch frei ist und auf der Baufläche liegt.
    controller.placeTile(world.getHand().get(0), new CubeCoordinate(0, 0, 0));

    // Folgender Aufruf ist equivalent.
    controller.selectSlot(0);
    controller.placeTile(new CubeCoordinate(0, 0, 0));

    // Es ist auch möglich eine Karte wie folgt zu plazieren, wenn sie in der Hand ist:
    // Du kannst Karten anhand ihres Typs plazieren
    controller.placeTile(TileType.Wheat, new CubeCoordinate(0, 0, 0));
    // Wenn du direkt beim Plazieren Daten angeben willst, 
    // kannst du auch eine Klasse angeben
    controller.placeTile(new MarketplaceTile().withFoodRatio(0.5), new CubeCoordinate(0, 0, 0));
    
    // Karten können wie folgt wieder eingesammlt werden
    CubeCoordinate coord = /* ... */ ;
    // prüfe ob das Einsammeln möglich ist
    if (world.getMap().at(coord).takeable()) {
        // Karte einsammeln
        controller.takeTile(coord);
    }
    
    // Belohnung einsammeln
    controller.collectReward(/* coord */);
    
    // Karten nachziehen
    controller.redraw();

    // Marktplatz konfigurieren
    controller.configureMarket(/* coord */, /* food [0.0-1.0] */, /* materials [0.0-1.0] */);
}

Nötige Informationen erhältst du aus: World.

Eine Idee für einen Bot

Du hast keine Idee, wie du an deinen Bot herangehen kannst?

Nutze getArea, um über die ganze Karte zu iterieren. Nutze dann getMap um zu prüfen, ob das Feld frei ist und einen Nachbar hat, also prinzipiell bespielbar ist. Wende eine Heuristik an, die für jede Karte auf deiner Hand bewertet, wie gut das aktuell betrachtete Feld ist.
Wähle dann die Option (Karte und Position), die den höchsten Wert hat.

Tipp für eine sehr einfache Heuristik: Teile die 14 Karten in sinnvolle Mengen ein und schaue wie viele Karten aus der Menge der aktuell betrachteten Karte in der Nachbarschaft sind.