Metadata-Version: 2.4
Name: unswbc
Version: 0.3.5
Summary: Write a bot for UNSW Battlecode, play matches on your machine, watch the replays
Author-email: UNSW CPMSoc <hi@battlecode.au>
License-Expression: MIT
Project-URL: Homepage, https://battlecode.au
Project-URL: Documentation, https://game.battlecode.au/docs/quickstart
Project-URL: Source, https://github.com/unswcpmsoc/battlecode
Keywords: battlecode,unsw,cpmsoc,contest,bot
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Education
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Games/Entertainment :: Turn Based Strategy
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: wasmtime>=25
Dynamic: license-file

# UNSW Battlecode

`unswbc` is the toolkit for UNSW CPMSoc's Battlecode competition. It creates a bot
project, builds it with the compiler already on your machine, and plays two bots
against each other on a map, writing a replay you can watch.

## Install

`unswbc` is a Python package. Install [uv](https://docs.astral.sh/uv/) first.

**macOS and Linux**

```sh
curl -LsSf https://astral.sh/uv/install.sh | sh
```

**Windows**, in PowerShell

```powershell
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
```

Open a new shell so `uv` is on your PATH. Then install the toolkit:

```sh
uv tool install unswbc
```

That puts `unswbc` on your PATH. Upgrade with `uv tool upgrade unswbc`, and pin
a version with `uv tool install unswbc==0.3.1`.

### Without uv

Possible, but not recommended. You need **Python 3.11 or newer** already
installed, and you manage the environment yourself:

```sh
python3 -m venv ~/.unswbc && ~/.unswbc/bin/pip install unswbc
```

`unswbc` then lives at `~/.unswbc/bin/unswbc`. Put that directory on your PATH
to run it by name. Plain `pip install --user unswbc` is not an option: most
Linux distributions and Homebrew refuse it.

The same wheel runs on macOS, Linux and Windows. It carries the game engine,
every contest map and the VS Code replay viewer, so there is nothing else to
download. It runs your bots with the tools already on your machine, so for C or
C++ bots you still need a compiler.

## Your first bot

```sh
unswbc init python mybot
unswbc run maps/arena.map mybot mybot
```

`init` writes a working bot and a helper library into `mybot/`, and adds missing
contest maps to a shared `maps/` folder beside it. Existing maps are never
overwritten, even with `init --force`. `run` takes a map and exactly two bots, builds both and plays
them, then writes a `.replay` file. Name the same project twice to play it
against itself.

Leave the language out and `init` asks for it, so `unswbc init mybot` works too.

After upgrading the toolkit, run `unswbc maps` to add newly bundled maps to
`maps/` without creating a bot. You can choose another folder with
`unswbc maps path/to/maps`. When initializing a bot in the current directory,
the shared map folder is `../maps/`; use `unswbc maps ../maps` to update it.

```sh
unswbc                 # the commands, and what this machine is missing
unswbc --build         # the same, but compile a test program too
unswbc run <map> a b   # two different bots
unswbc run <map> a b --no-replay
unswbc init python     # writes into the current directory
unswbc log             # the errors this machine has hit
unswbc help <command>
```

### Submitting

Make an API key on your team page, give it to `unswbc` once, then upload from the
command line. The zip holds `bot.toml` and the files `project.include` names, laid
out the way the judge wants:

```sh
unswbc auth set bc_...            # keeps it in ~/.unswbc/keys.json, one key per server
unswbc auth status                # which server, which key, which team
unswbc submit mybot               # upload the project in mybot/
unswbc submit mybot -n v12 -d "wider search"
unswbc auth clear                 # forget the key for this server
```

The version is named after the folder and the date unless `-n` says otherwise.
`UNSWBC_KEY` overrides the stored key, for CI.

### When something breaks

Every error `unswbc` prints is also appended to `~/.unswbc/log`. `unswbc log`
shows it. Quote it when you ask for help.

A bot is an ordinary process: `unswbc` writes the board to its stdin each turn and
reads the move back from stdout. Anything that can read and write text can play.

| variable | effect |
| -------- | ------ |
| `UNSWBC_PYTHON` | the interpreter to run `.py` bots with |
| `CC`, `CXX` | the compilers to build `.c` and `.cpp` bots with |
| `UNSWBC_SERVER` | the contest server, default `https://game.battlecode.au` |
| `UNSWBC_KEY` | the API key to submit with; beats the stored one |
| `UNSWBC_NO_VSCODE` | do not set up the replay viewer |
| `NO_COLOR` | plain output; colour is off anyway when the output is piped |

## In the judge

The judge runs bots inside a WebAssembly sandbox, so the same code behaves the
same on every machine, and it measures work in **CPU points** rather than
seconds: each WebAssembly instruction has a fixed price, so a slow judge day
cannot cost you a turn.

| limit | value |
| ----- | ----- |
| points per dragon per turn | 100 million |
| memory per dragon | 48 MB |
| time per turn | 1 s of CPU, 10 s wall; a backstop that only ever catches a bot that found a way around the meter |

A turn over its budget gives no reply, and a dragon that gives no reply dies
that turn, so leave yourself a margin. A dragon's first turn is no exception:
the interpreter and NumPy are already loaded, but your own imports and setup
count, so spread heavy precomputation over turns or do it lazily. Prices, in points: most instructions 1,
loads and stores 2, division 3, calls 4 to 6, memory growth 50, bulk copies and
fills 10 plus 1 per 8 bytes, and 2 for everything else, which includes 128-bit
SIMD. Writing output costs 2.5 million
per write plus 4,000 per byte, so keep logging light.

Rough costs to plan around: parsing a round in the Python helper is ~10 million
points, a full-map flood fill on 32x32 is ~19 million in Python and ~0.3 million
in C++. C and C++ are compiled with `-O2 -msimd128` against the C standard
library and libc++, with the zip's own directory on the include path; there are
no other libraries, so vendor any you need as source. Vector code is priced
like scalar code and runs as real SIMD, so it is worth writing. Python runs on
CPython 3.13 with the standard library and NumPy 2.5, nothing else, so vendor
any pure-Python code you need.

Output is sent when you flush, and a flush is one write. The helpers flush
once, at the end of the turn, and reading your next turn flushes too, so leave
it that way: a bot that flushes after every line pays 2.5 million points a
line. In C++ that means no `std::unitbuf`, no `cin.tie(nullptr)` unless you
flush at `ENDTURN` yourself, and `std::clog` rather than `std::cerr` for debug
output. To C and C++ the judge's stdout looks like a terminal (`isatty` is
true), so C stdio is line buffered: with `sync_with_stdio(false)` every line
that ends in `\n` goes out as its own write, at 2.5 million points each.
Python is unaffected, since the helper's stdout is fully buffered. A wait that
nothing can end, such as taking a lock twice on your only thread, ends the
turn over budget at once.

Matches are reproducible: randomness comes from a generator seeded per dragon
and match, and the clock advances with the points you spend, so `time.sleep`
costs no real time and timing your own search measures points.

## Watching replays

The VS Code extension opens any `.replay` file as an interactive board with a game
log, per-team statistics and charts. `unswbc` ships it and installs it when
`unswbc init` creates a project, so there is nothing to download. To redo that
at any point:

```sh
unswbc vscode
```

Replays also open at [game.battlecode.au](https://game.battlecode.au), which uses
the same renderer.
