# Fair mode

> A client injected into the game can read the whole map. Fair mode limits your bot to what's within its vision, just like a human player and just like the Arena rules.

Source: https://war3ai.com/en/docs/fair-mode/

This project's observation capability comes from the fact that the client holds the state of every player: the snapshot contains every unit on the map, including enemies in the fog. That's handy for debugging, but unfair in a match.

**Fair mode** makes the SDK filter everything by your vision:

```bash
python tools/play.py --bot my_bot.py --fair
python -m openwar3 run my_bot.py --inst 5 --fair
```

```python
from openwar3 import Game, run
g = Game(inst=5, fair=True)            # use Game directly
run(MyBot, inst=5, fair=True)          # or hand it to the runner
```

## What gets filtered

| Content | In fair mode |
|---|---|
| Units | All of yours + the enemy and neutral units you can see right now |
| Items on the ground | Only those within your units' vision (day and night vision are computed separately from the data tables) |
| Production table | Only buildings you can see (you can't see what your opponent is training) |
| Events | Your own; visible ones (or ones that were visible within the last second); damage dealt by your side |

## Where vision comes from

- Every unit in the snapshot carries a **visibility mask**: bit p = player p can see it right now (only players 0–11 with units on the field count; your own units are always visible to you). `u.visible_to(g.me())` reads it directly, with zero wait.
- For any point, `g.visible(x, y)` asks the engine (visible / fog / black mask) through the fast lane, at about one frame per call. When a tick needs to check many units, use `u.visible_to()` from the snapshot instead of calling `g.visible()` one unit at a time.

## Remembering enemies: `last_seen`

A human player remembers "I just saw a pack of Raiders over there." The SDK remembers for you too: every time the snapshot refreshes, it records the enemy and creep units you can currently see (last position, HP, time); it removes them once it sees them die, and clears everything between games.

```python
for u, t, age in g.last_seen(max_age=60):         # enemies seen within the last 60 game seconds
    print(u.type, u.x, u.y, f"{age:.0f}s ago")

heroes = [r for r in g.last_seen() if r[0].is_hero]   # where the enemy heroes were last seen
camps  = g.last_seen(owner="creep")                   # creeps you've seen
```

In fair mode, this is your only source of information about your opponent, just like for a human player. Normal mode also records by vision, so the same code works in both.

## Commanding as a specific player

```bash
python tools/play.py --bot my_bot.py --player 1 --attach
```

`--player N` (or `Game(player=N)`) makes the bot command as player N, and it can only command player N's units. To have two AIs fight, open two such channels in the same game.

> **In local mode, fairness is a convention, not a security boundary**
>
> On your own machine, nothing can stop a program from reading the whole map. `--fair` is a constraint you place on yourself; real matches are guaranteed by the [Arena](https://war3ai.com/en/arena/)'s referee process: bots never touch shared memory, only receive observations that the referee has filtered by vision, can only submit actions, and every action is checked for unit ownership first.

## Why turn it on now

- The Arena will use exactly these rules. Write for fair mode now, and you won't have to change a line later;
- Without full-map information, you find out how good your bot really is (the reference brain currently relies heavily on full-map information, such as the computer captain's target point, which makes this a good test);
- Scouting, memory and judgment written under fair mode are the AI capabilities that actually matter.
