# Dein erster Bot

> Starte mit einem minimalen Bot aus 10 Zeilen, ergänze Bauern, Nahrung, Truppen, Helden und Angriffe und lerne zum Schluss, Quittungen zu lesen.

Quelle: https://war3ai.com/de/docs/first-bot/

Ein Bot ist eine Klasse, die von `openwar3.Bot` erbt. Du überschreibst nur die Hooks, die du brauchst; `g` (`Game`) ist fürs „Sehen“ und „Handeln“ zuständig.

## Der minimale Bot

```python title="my_bot.py"
from openwar3 import Bot

class MyBot(Bot):
    def on_start(self, g):          # einmal nach Partiebeginn aufgerufen
        g.message("Da bin ich")

    def on_tick(self, g):           # etwa 5-mal pro Sekunde
        for w in g.idle_workers():
            g.gather(w, g.nearest(g.gold_mines(), w))
```

```bash
python tools/play.py --bot my_bot.py
```

Untätige Bauern gehen zur nächsten Goldmine. Die vier Hooks:

| Hook | Wann er aufgerufen wird |
|---|---|
| `on_start(g)` | Einmal nach Partiebeginn, vor dem ersten Tick |
| `on_tick(g)` | In jedem Tick (standardmäßig 5-mal pro Sekunde). Dauert ein Tick zu lange, verschiebt sich der nächste automatisch, statt dass sich Ticks aufstauen |
| `on_event(g, ev)` | Vor jedem `on_tick`; übergibt dir alle Events seit dem letzten Tick, eines nach dem anderen |
| `on_end(g, reason)` | Einmal, wenn die Partie endet (Spielprozess beendet / keine eigenen Einheiten mehr / manuell gestoppt) |

> **Tipp**
>
> Eine Exception in `on_tick` bricht nicht die ganze Partie ab: Der Runner gibt den Stacktrace aus und macht im nächsten Tick weiter; erst nach **20 Fehlern in Folge** hält er an.

## Wirtschaft ergänzen: Bauern und Nahrung

```python
from openwar3 import Bot

class Economy(Bot):
    def on_tick(self, g):
        res = g.resources()                       # nicht lesbar = None, nicht 0
        halls = g.my_buildings({"htow", "hkee", "hcas"})
        if res is None or not halls:
            return
        home = halls[0]

        # 1. Untätige Bauern sammeln Gold
        for w in g.idle_workers():
            mine = g.nearest(g.gold_mines(), w)
            if mine:
                g.gather(w, mine)

        # 2. Bauern trainieren: nur 1 in die Warteschlange (eine volle Warteschlange bindet Gold)
        if len(g.my_workers()) < 15 and not g.queue(home):
            g.train(home, "hpea")

        # 3. Nahrung fast voll: einen Bauern suchen, der gerade nicht baut, und beim Hauptgebäude einen Bauernhof bauen
        if res["food_cap"] - res["food_used"] <= 6:
            builder = next((w for w in g.my_workers() if not g.is_constructing(w)), None)
            if builder:
                g.build_near(builder, "hhou", home.x, home.y)
```

Drei Muster, auf die es ankommt:

- **Nur trainieren, wenn `g.queue(home)` leer ist.** Gibst du jeden Tick einen Trainingsbefehl, füllst du die 7 Plätze der Warteschlange und bindest dein Gold (gemessen: 4 Bauern in der Warteschlange des Hauptgebäudes, 300 Gold gebunden – die Eröffnung wird deutlich langsamer).
- **`build_near` statt fester Koordinaten.** Es sucht von nah nach fern einen freien Platz und verfolgt das Ergebnis über mehrere Ticks; reicht das Geld nicht, tut es nichts. Feste Koordinaten liegen womöglich genau in einem Wald.
- **Keinen Bauern nehmen, der gerade baut.** Ein Bauernhof der Menschen braucht 35 Sekunden; wird der Arbeiter unterwegs abgezogen, steht die Baustelle still.

Eine vollständige Version, die mit allen vier Völkern läuft, ist `brains/examples/hello_bot.py`: 5 Arbeiter pro Mine, bei voller Mine Holz fällen, stillstehende Baustellen weiterbauen.

## Kaserne, Held und Angriff ergänzen

```python
from openwar3 import Bot

WAVE = 8

class Rush(Bot):
    def on_start(self, g):
        self.attacking = False

    def on_tick(self, g):
        halls = g.my_buildings({"htow", "hkee", "hcas"})
        if not halls:
            return
        home = halls[0]

        # Held: Altar vorhanden, aber kein Held -> zuerst wiederbeleben, sonst trainieren (Helden sind einzigartig; einen toten neu trainieren wird abgelehnt)
        altars = g.my_buildings({"halt"})
        if altars and not g.my_heroes():
            if not g.revive(altars[0]):
                g.train(altars[0], "Hpal")
        for h in g.my_heroes():
            info = g.hero_info(h)
            if info and info["skill_points"]:
                g.learn(h, "AHhb")                # Heiliges Licht

        # Die Kaserne produziert ständig Fußsoldaten (nur 1 in der Warteschlange)
        for b in g.my_buildings({"hbar"}):
            if not g.queue(b):
                g.train(b, "hfoo")

        # Bei voller Welle angreifen; nach schweren Verlusten zurück zur Basis
        army = g.my_army()
        if len(army) >= WAVE:
            self.attacking = True
        elif len(army) < WAVE // 2:
            self.attacking = False
        if self.attacking:
            target = g.nearest([e for e in g.enemies() if g.is_building(e)], home)
            if target:
                idle = [u for u in army if not g.order_of(u)]      # nur untätigen Einheiten Befehle geben
                g.attack_move(idle, target.x, target.y)
```

Die vollständige Version findest du in `brains/examples/rush_bot.py` (erbt von `hello_bot` und baut Kaserne / Altar, falls sie fehlen).

## Quittungen verstehen

Jeder Befehl liefert eine Quittung. `if r:` heißt „die Engine hat angenommen“; wenn nicht, steht in `r.reason` der Grund:

```python
r = g.train(barracks, "hfoo")
if not r:
    print(r.reason)        # rejected（人口不够）  (= nicht genug Nahrung)
    print(r.verdict)       # 3
```

Häufige Grundcodes: `3` nicht genug Nahrung, `8` nicht genug Gold, `9` nicht genug Holz, `32` Warteschlange voll, `183` Voraussetzung fehlt, `221` nicht vorhanden / im Bau / Held existiert bereits, `1001` Ziel nicht sichtbar. Die vollständige Tabelle findest du unter [Quittungen und Grundcodes](https://war3ai.com/de/docs/reason-codes/).

> **Angenommen ≠ erledigt**
>
> Die Quittung sagt nur, dass „die Engine diesen Befehl angenommen hat“. Auch einen Bauplatz im Wald nimmt die Engine sofort an, der Arbeiter scheitert erst, wenn er dort ankommt; Zauber können unterbrochen werden. Die Wirkung siehst du in Snapshot und Events: Zum Bauen `build_near` verwenden (es verfolgt, ob die Baustelle erscheint), bei Zaubern prüfen, ob `g.cooldown()` eine Abklingzeit zeigt.

## Nächste Schritte

  - [Mentales Modell](https://war3ai.com/de/docs/concepts/): Snapshot, Befehl, Event, Tick, Batch – warum es so gebaut ist.
  - [Profi-Kochbuch](https://war3ai.com/de/docs/cookbook/): 21 Rezepte: gesättigtes Sammeln, nie an der Nahrung hängen, Fokusfeuer, Verwundete zurückziehen, nachts creepen …
