# Your First Bot

> Start with a 10-line minimal Bot, then add training peasants, building for food, producing an army, heroes and attacking — and finally learn to read receipts.

Source: https://war3ai.com/en/docs/first-bot/

A Bot is a class that subclasses `openwar3.Bot`. You only override the hooks you need; `g` (`Game`) handles "observing" and "acting".

## The minimal Bot

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

class MyBot(Bot):
    def on_start(self, g):          # called once after the game starts
        g.message("I'm here")

    def on_tick(self, g):           # about 5 times per second
        for w in g.idle_workers():
            g.gather(w, g.nearest(g.gold_mines(), w))
```

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

Idle peasants head to the nearest gold mine. The four hooks:

| Hook | When it's called |
|---|---|
| `on_start(g)` | Once after the game starts, before the first tick |
| `on_tick(g)` | Every tick (5 times per second by default). If a tick runs over, the next one is pushed back automatically — they never pile up |
| `on_event(g, ev)` | Before each `on_tick`; hands you every event since the last tick, one by one |
| `on_end(g, reason)` | Once when the game ends (the game process is gone / we have no units left / stopped manually) |

> **Tip**
>
> An exception in `on_tick` doesn't end the game: the runner prints the stack trace and continues with the next tick; it only stops after **20 consecutive ticks with errors**.

## Adding an economy: training peasants, building for food

```python
from openwar3 import Bot

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

        # 1. Idle peasants go mine gold
        for w in g.idle_workers():
            mine = g.nearest(g.gold_mines(), w)
            if mine:
                g.gather(w, mine)

        # 2. Train peasants: only 1 in the queue at a time (a full queue locks gold up in it)
        if len(g.my_workers()) < 15 and not g.queue(home):
            g.train(home, "hpea")

        # 3. Food almost capped: find a peasant who isn't building and build a Farm near the hall
        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)
```

Three things worth noting:

- **Only train when `g.queue(home)` is empty.** Issuing a train order every tick fills the 7-slot queue and locks up your gold (measured: the hall queued 4 peasants with 300 gold locked in the queue, and the opening was much slower).
- **`build_near` instead of hard-coded coordinates.** It searches outward from near to far for a spot that fits and tracks the result across ticks; it does nothing when you can't afford it. Hard-coded coordinates may well land right in a forest.
- **Don't pick peasants who are already building.** A Human Farm takes 35 seconds to build; if you send the worker away partway through, construction stops.

The complete version that works for all four races is `brains/examples/hello_bot.py`: 5 per mine, extra workers chop trees once the mine is full, and it resumes stalled construction.

## Adding Barracks, a hero and attacks

```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]

        # Hero: have an altar but no hero -> revive first, train only if revive fails (heroes are unique; training again after death is rejected)
        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")                # Holy Light

        # Barracks keep producing Footmen (only 1 in the queue at a time)
        for b in g.my_buildings({"hbar"}):
            if not g.queue(b):
                g.train(b, "hfoo")

        # Attack once a wave is ready; go home after heavy losses
        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)]      # only order idle units
                g.attack_move(idle, target.x, target.y)
```

For the full version, see `brains/examples/rush_bot.py` (it subclasses `hello_bot` and builds the Barracks / altar if missing).

## Reading receipts

Every command returns a receipt. `if r:` means "the engine accepted it"; when it wasn't accepted, `r.reason` says why:

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

Common reason codes: `3` not enough food, `8` not enough gold, `9` not enough lumber, `32` queue full, `183` missing prerequisite, `221` no such item / under construction / you already have this hero, `1001` target not visible. For the full table, see [Receipts and reason codes](https://war3ai.com/en/docs/reason-codes/).

> **Accepted ≠ done**
>
> A receipt only tells you "the engine accepted this command". The engine also accepts a build spot inside a forest on the spot, and the worker only fails once it gets there; spells can be interrupted. To see the actual effect, look at snapshots and events: for buildings use `build_near` (it tracks whether the foundation appears), and for spells check whether `g.cooldown()` shows a cooldown.

## Next steps

  - [Mental Model](https://war3ai.com/en/docs/concepts/): Snapshots, commands, events, ticks, batches — why it's designed this way.
  - [Pro Playbook Cookbook](https://war3ai.com/en/docs/cookbook/): 21 recipes: saturated mining, never food blocked, focus fire, pulling back wounded units, night creeping…
