Erste Schritte
Zuletzt aktualisiert: April 1, 2025Aufgabe
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:
- das Spiel
- die Bot-Bibliothek (eine .jar Datei), die für euch die Kommunikation mit dem Spiel übernimmt.
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:
- Starte das Spiel
- Wähle den Challenge-Modus
- Aktiviere den Haken neben
Bot aktivieren
. - 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:
- das Feld frei ist,
- es sich in der Baufläche befindet,
- ein benachbartes Feld bebaut ist, und
- man die Karte auf der Hand hat.
Neue Karten erhält man durch Nachziehen.
- Alle 20 Sekunden kann man kostenlos nachziehen, was die Hand auf 5 Karten nachfüllt.
- Zwischendurch, wenn man mit Rersourcen dafür zahlt, was alle Karten aus der Hand entfernt und durch 5 neue ersetzt.
- Zu Beginn jeder Runde (auffüllen wie beim kostenlosen 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.
- Gras: Dummy-Karte. Diese Karte ist nur als Lückenfüller zu gebrauchen.
- Wald: produziert Materialien. Die Menge steigt linear mit der Menge der direkt benachbarten Wald-Karten.
- Weizen: produziert Nahrung. Am meisten wird in Weizen-Gruppen der Größe 9 produziert.
- Bienenkasten: produziert Nahrung. Die Menge steigt mit der Menge an Wald- und Weizen-Karten in der Nähe.
- Mühle: produziert Nahrung. Die Windmühle muss in der Nähe von Weizen-Karten platziert werden. Je mehr Weizen-Karten in der Nähe, desto besser. Jede Weizen-Karte unterstützt maximal 2 Windmühlen. Direkt benachbarter Wald bremst den Wind.
- Haus: produziert eine konstante Menge an Geld.
- Doppelhaus: produziert Geld. Die größte Menge mit exakt 3 anderen Häusern als direkter Nachbar.
- Moai: produziert nichts. Moai-Karten verbessern Häuser in der Nähe. Der Effekt ist größer, wenn der Moai eine große Vielfalt an anderen Karten um sich hat.
- Marktplatz: Verkauft Materialien und Nahrung für Geld. Die Menge hängt von den in der Umgebung produzierten Ressourcen ab und der Preis von der Anzahl an Häusern in der Umgebung ab. Die Menge, die verkauft wird, kann eingestellt werden.
- Steine: produziert nichts. Ist eine Level-1 Stein-Karte und unterstützt einen Steinbruch.
- Hügel: produziert nichts. Ist eine Level-2 Stein-Karte und unterstützt zwei Steinbrüche.
- Berg: produziert nichts. Ist eine Level-3 Stein-Karte und unterstützt drei Steinbrüche.
- Steinbruch: produziert Materialien. Der Steinbruch baut Materialien von einer Stein-Karte ab. Je höher das Level dieser Karte, desto höher die Menge. Steinbrüche werden automatisch bestmöglich den Stein-Karten zugeordnet.
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 CubeCoordinate
s nicht komplett verstehen. Wir haben eine Klasse CubeCoordiante implementiert, die für dich einige Arbeit übernimmt.
Einige sehr nützliche Features:
this.getRing(int)
: gibt einen Java-Iterator zurück, der alle Karten auf einem Hexagon-Kreis umthis
, mit dem Radiusint
, enthält.this.getArea(int)
: gibt einen Java-Iterator zurück, der alle Karten auf einer Hexagon-Fläche umthis
, mit dem Radiusint
, enthält.- mit den Methoden
.add
,.sub
,.mul
,.div
,.neg
können normale Vektor-Operationen berechnet werden.
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.
BuildArea
getBuildArea()
- Gibt ein Objekt mit allen Informationen über die Baufläche zurück.Hand
getHand()
- Gibt ein Objekt mit allen Karten auf der Hand zurück.Map
getMap()
- Gibt ein Objekt mit allen platzierten Karten zurück.Metrics
getRedrawCosts()
- Gibt ein Objekt zurück, welches die aktuellen Kosten zum Nachziehen beinhaltet.double getRedrawTime()
- Zeit in Sekunden, bis das nächste Mal kostenlos nachgezogen werden kann.Metrics
getResources()
- Gibt ein Objekt zurück, welches deine aktuelle Menge an Ressourcen beinhaltet.Metrics
getResourcesRate()
- Gibt ein Objekt zurück, welches beinhaltet, wie viele Ressourcen du momentan pro Sekunde erhältst.Rewards
getRewards()
- Gibt ein Objekt zurück, welches alle Belohnung beinhaltet, die gerade eingesammelt werden können.int getRound()
- Aktuelle Runde. Beginnt mit 0. (UI fängt mit 1 an zu zählen.)double getRoundTime()
- Wie viel Zeit (in Sekunden) in der aktuellen Runde noch übrig ist.Metrics
getTargetResources()
- Gibt ein Objekt zurück, welches das aktuelle Ressourcenziel beinhaltet.
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.