Docs Anleitungen

Profi-Kochbuch

Der Vorsprung guter Spieler steckt größtenteils in Dutzenden kleiner Gewohnheiten. Diese Seite übersetzt gängige Profi-Techniken eine nach der anderen in SDK-Code – jeder Abschnitt lässt sich direkt in on_tick kopieren.

Konventionen: g ist das Game, home ist unsere Hauptbasis (g.my_buildings({"htow", "hkee", "hcas"})[0]), now = g.clock(). Details zur API findest du in der API-Referenz, vollständige lauffähige Beispiele unter Beispiel-Bots.

Wenn ein LLM eine bestimmte Technik einbauen soll, gib ihm das passende Rezept samt Code mit. Das wirkt viel besser als die Bitte, „professioneller zu spielen“.

I. Wirtschaft

1. Arbeiter nie untätig, 5 pro Mine

for w in g.idle_workers():                                   # nur untätige zuweisen (neue Befehle an beschäftigte unterbrechen das Sammeln)
    mine = g.nearest([m for m in g.gold_mines() if crew[m.addr] < 5], w)
    g.gather(w, mine) if mine else g.gather(w, g.trees(w.x, w.y, limit=1)[0])

Merk dir selbst, wie viele du jeder Mine zugewiesen hast (crew): Arbeiter in einer Goldmine sind nicht im Snapshot. Vollständiges Beispiel in hello_bot.py.

2. Nur 1 in die Warteschlange, kein gebundenes Gold

for b in g.my_buildings({"hbar"}):
    if not g.queue(b):                                       # erst den nächsten einreihen, wenn sie leer ist
        g.train(b, "hfoo")

3. Nie an der Nahrung hängen bleiben

stuck = any(p.blocked for _b, p in g.all_production("me"))  # eingereiht, aber nicht gestartet = nicht genug Nahrung
res = g.resources()
if stuck or res["food_cap"] - res["food_used"] <= 6:
    g.build_near(builder, "hhou", home.x, home.y)

blocked greift einen Schritt früher als „fast voll“: Verlierst du im Kampf einen Teil der Armee und stockt beim Nachbauen die Warteschlange, weißt du es sofort.

4. Bauabfolge + danach selbst zur Mine zurück (Shift-Rückkehr zur Mine)

spot = g.build_near(w, "hbar", home.x, home.y)
if spot:
    g.gather(w, mine, queue="after")                         # nach dem Bau zurück zur Mine, im nächsten Tick nicht erneut suchen

Ein Bauer baut mehrere Gebäude nacheinander: g.build_queue(w, [("hhou", x1, y1), ("hhou", x2, y2)]). Das Gold wird erst bei Baubeginn abgezogen.

5. Tier-up-Timing, Angriffs-/Rüstungs-Upgrades

if not g.queue(hall) and g.can_do(hall, "hkee") in (0, 220):   # das Hauptgebäude kann nur mit leerer Warteschlange ausbauen (sonst 185)
    g.upgrade(hall, "hkee")
p = g.production(hall)                                          # Tier-up-Fortschritt
if p and p.kind == "upgrade":
    print(f"Hauptgebäude braucht noch {p.remaining:.0f} Sekunden")
for sm in g.my_buildings({"hbla"}):
    if not g.queue(sm):
        ok = [u for u, v in zip(UPS, g.can_do_many([(sm, u) for u in UPS])) if v in (0, 220)]
        if ok:
            g.research(sm, ok[0])

6. Expansion: die nächste Mine nach Laufweg wählen

mines = [m for m in g.gold_mines() if g.dist(m, home) > 1500 and not taken(m)]
best = min(mines, key=lambda m: g.path_distance(home, m) or 1e9)   # Minen auf Inseln liefern None -> landen ganz hinten

II. Aufklärung und Informationen

7. Sehen, was der Gegner macht

for b, p in g.all_production("enemy"):          # was sichtbare gegnerische Gebäude trainieren / erforschen / aufwerten
    print(b.type, p.kind, p.queue, f"{p.progress:.0%}" if p.progress is not None else "hängt")

Kombiniert mit Events: ev.kind == "production.done" and ev.owner != g.me() – was der Gegner gerade fertiggestellt hat.

8. Merken, was du gesehen hast (Kriegsnebel)

for u, t, age in g.last_seen(max_age=60):       # Gegner, die in den letzten 60 Spielsekunden gesehen wurden (letzte Position und TP)
    ...
hero_seen = [r for r in g.last_seen() if r[0].is_hero]   # wo der gegnerische Held zuletzt war

Im Fair-Modus ist das deine einzige Informationsquelle über den Gegner – genau wie bei einem menschlichen Spieler.

9. Wo der Computergegner angreifen will (nur Computer-KI)

plan = g.enemy_ai_plan(some_enemy_soldier)      # wohin sein Computer-Captain unterwegs ist

Der Computer legt seinen Zielpunkt fest, bevor er losmarschiert – zieh deine Armee rechtzeitig dorthin zurück.

III. Creepen

10. Nachts creepen

if g.is_night():                                 # 18 ~ 6 Uhr: Creeps schlafen (du triffst zuerst, ohne umzingelt zu werden), alle sehen weniger weit
    ...
wait = g.seconds_until(18)                       # Spielsekunden bis zum Einbruch der Nacht (ein Tag hat 480 Sekunden)

11. Nur Lager angreifen, die du schaffst

from openwar3 import combat
mine = [g.stats(u) for u in army]
def ttk(target): return combat.time_to_kill(mine, g.stats(target), target_hp=target.hp) or 1e9
camp = [c for c in g.creeps() if g.dist(c, center) < 600]
ours = max(ttk(c) for c in camp)                                 # wie lange es dauert, dieses Lager zu räumen (grob)
theirs = g.time_to_kill(camp, weakest_of_mine) or 1e9            # wie lange sie brauchen, um unsere schwächste Einheit zu töten
if ours < theirs and g.reachable(center, camp[0]):
    g.attack_move(army, camp[0].x, camp[0].y)

Vollständiges Beispiel: _maybe_creep in micro_bot.py.

IV. Mikro

12. Fokusfeuer: das angreifen, was am schnellsten stirbt, nicht das Nächste

target = min(visible_enemies, key=lambda e: g.time_to_kill(fighters, e) or 1e9)
g.attack([u for u in fighters if (g.current_target(u) or target).handle != target.handle], target)

Befiehl nur den Einheiten, die es noch nicht angreifen (current_target), damit du die anderen nicht unterbrichst.

13. Verwundete zurückziehen

for u in army:
    if u.hp < u.hp_max * 0.35:
        g.move(u, *toward(home, u, 500))       # 500 Richtung Basis zurückziehen; dieselbe Einheit 3 Sekunden lang nicht erneut ziehen

Fokusfeuer erkennen: Trifft dieselbe Einheit in damage-Events kurz hintereinander Schaden aus mehreren Quellen, ist sie umzingelt.

14. Helden am Leben halten, keine EP verschenken

for h in g.my_heroes():
    if h.hp < h.hp_max * 0.4:
        g.move(h, home.x, home.y)
        g.use_item(h, slot_of(h, "phea"))       # Heiltrank: Platznummer über inventory(h) finden

15. Konter: die richtige Einheit auf das richtige Ziel

s = g.stats(u)
best = max(enemies, key=lambda e: s.dps_vs(g.stats(e)))   # Büchsenschützen auf Greifenreiter (Durchbohrend gegen leichte Rüstung ×2), Greifenreiter auf Fußsoldaten (Magie gegen schwere Rüstung ×2)

Die Kontertabelle stammt aus den Spieldaten: combat.damage_multiplier("pierce", "small") == 2.0.

16. Flanken und Wegführung: Türme umgehen

route = g.walk_path(army_center, target)        # Knickpunkte des kürzesten Bodenwegs
g.path(army, route, attack=True)                # nacheinander per Angriffsbewegung durch jeden Punkt

Um Türme zu umgehen, markierst du den Bereich um jeden Turm im Wegfindungsraster als unpassierbar und berechnest dann die Route:

grid = g.grid().copy()
for t in towers:
    grid.block_area(t.x, t.y, 800)             # Turmreichweite 700 + Puffer
route = grid.path((army_x, army_y), (target.x, target.y))

17. Die Befehle eines Ticks als ein Batch senden

with g.batch():
    g.attack(melee, target_a)
    g.attack(ranged, target_b)
    g.move(wounded, *home_xy)
    g.cast(hero, "thunderclap")

Dutzende Befehle warten nur einmal auf den Spiel-Thread (gemessen: 8 Bewegungen 68 ms → 6.5 ms).

18. Belagerung: Artillerie greift den Boden an

g.attack_ground(mortars, tower.x, tower.y)       # Mörsertrupps / Katapulte feuern auf eine Fläche (hinter Bäumen, unsichtbare Einheiten)

V. Helden

19. Skill-Reihenfolge

SKILLS = {"Hamg": ["AHwe", "AHbz", "AHwe", "AHbz", "AHwe", "AHmt"]}   # Wasserelementar, Blizzard … Stufe-6-Ultimate Massenteleportation
info = g.hero_info(h)
if info and info["skill_points"]:
    g.learn(h, SKILLS[h.type][learned_count])  # abgelehnt (Stufe zu niedrig fürs Ultimate)? auf die nächste Stufe warten

20. Wurde der Zauber wirklich gewirkt?

r = g.cast(h, "thunderbolt", target=enemy_hero)
# im nächsten Tick:
if g.cooldown(h, "AHtb"):                         # Abklingzeit läuft = wirklich gewirkt; angenommen ≠ gewirkt
    ...

21. Tränke kaufen, zurück in die Stadt

g.buy(shop, "phea")                               # der Held steht neben dem Laden
g.use_item(hero, slot, x=home.x, y=home.y)        # Stadtportal-Schriftrolle (Gegenstand auf einen Punkt benutzen)

VI. Nachbesprechung

  • Schreib die Entscheidungen jedes Ticks ins Log (print landet im Ausführungsfenster) und nutze g.say(einheit, "Rückzug"), um sie im Spiel zu sehen;
  • production.done-Events enthalten „wie viele Sekunden es gedauert hat“ – erstelle daraus deine eigene Bau-Timeline (in welcher Sekunde der erste Held kam, wann dein Tier-up fertig war) und vergleiche sie mit der von Top-Spielern;
  • Lass den Agent sich selbst auswerten: siehe den Spielbericht in Agent-Selbstiteration.