Bots
scmjs bot builds a BWAPI 4.4.0 bot, the C++ AI modules
of the bot tournaments, into one .scmbot file, and plays it.
Building a bot#
You can play against a built bot at scmjs.dev/play: Options → Community bots → Add a bot from a file…, then choose it for a computer slot. Building needs Docker: the toolchain is a Docker image, a few GB, downloaded the first time.
Run the commands in your bot's folder:
scmjs bot init # scmbot.json, read from the bot's Visual Studio project
scmjs bot build # out/<key>.scmbot
With no bot yet, scmjs bot new writes one to start from, which mines, trains workers and
builds supply. A build needs a licence file for the bot (LICENSE, with any licence you
choose), since it goes into every build and is shown with the bot.
scmjs bot update fetches the newest toolchain, the one the play page expects. The
toolchain's guide, with what it does for code written for Visual Studio and the fields of
scmbot.json, is at github.com/scm-js/scmbot.
Playing a bot#
scmjs bot run out/mybot.scmbot "(2)Jungle Duel.scx" plays the bot against the game's own
computers with no page open. The game is the play page's engine, and the bot sits in the
player's seat. It needs your copy of StarCraft and the
engine.
UAlbertaBot on (2)Jungle Duel.scx 128 × 128, jungle · bot zerg vs computer zerg · seed 1794078640 · Remastered files
Loaded the AI Module: bot
oracle: BWAPI 4.4.0.0 RELEASE is now live using "bot".
oracle: Enabled Flag UserInput
frame 2000 P1 bot Z 152/0 4/9 | P2 computer Z 252/0 9/9
frame 4000 P1 bot Z 88/0 9/9 | P2 computer Z 56/0 0/17
✔ the bot won at frame 5194 · 39 KB of orders · 0.21 ms a frame game, 0.32 bot · 4.5 s
| Option | What it does |
|---|---|
--race |
The bot's race |
--opponents zerg,terran |
The computers' races, one computer each |
--seed |
Fixes the game: the same seed, bot and map give the same game |
--frames |
Stops a game nobody has won, at 24 frames a second: 50,000 is about 35 minutes of play |
--every |
The frames between progress lines; 0 for none |
--data folder |
Keeps the files the bot writes between games (its bwapi-data/write), as the play page does |
--json |
Everything as data |
The bot's own text is printed as it comes. The command exits with 1 when the bot printed errors, and with 2 when the game could not start.
A ladder for bots#
scmjs bot ladder plays bots against each other and against the game's own computer,
every pairing on every map, and keeps every game's replay. Name the bots, computer for
the game's computer, and the maps:
scmjs bot ladder out/mybot.scmbot:p ../rival/out/rival.scmbot computer --maps "(2)Jungle Duel.scx" "(4)Crossing.scx" --races tzp
A race after a colon is the race that side always plays: mybot.scmbot:p, computer:t. A
side without one plays each race of --races in turn (z, t, p, and r for random,
which the game draws from the seed); computer alone is then one computer for each of
those races. Two bots play each other twice on each map, once each as the lobby's first
player, and a bot plays each computer once. --games 3 plays each of those games three
times, with the seeds 1, 2 and 3, or --seeds 4,9 names the seeds. The same seed, bots
and map give the same game, so a ladder run again after you change your bot shows what the
change did.
A line comes as each game ends, then the standing:

scmjs bot ladder with UAlbertaBot, the BWAPI example bot and the Zerg computer on two
maps made by map generate.
| Column | Means |
|---|---|
| Elo | Every side starts at 1500 and moves by up to 32 points a game; a game stopped at the frame limit counts as a draw. Games are counted in the order they were scheduled, so the same ladder gives the same ratings however the games ran |
| Length | The average game |
| ms a frame | The time the bot took to think, on average per frame |
| Longest | The bot's slowest frame; usually the first, where most bots read the map |
| > 55 ms | The frames over the 55 milliseconds the bot tournaments allow |
The time is counted, not enforced. The bot runs in WebAssembly beside a game that is itself translated code, so it is slower here than in the real game. With three sides or more, a head-to-head table follows, with each row's wins and losses against each column.
Everything goes in a folder of its own, ladder-<date>-<time> where you ran the command,
or the folder --out names:
- a replay of each game, named by the two sides in lobby order, the map, the races and the
seed (
mybot-vs-computer-t_jungle-duel_PvT_seed1.rep), so a loss opens withscmjs replay watchorscmjs replay open; ladder.json, the whole result as data (--jsonprints the same);bwapi-data/, what each bot wrote to itsbwapi-data/writefolder, which it reads again before its next game, as in the tournaments. Nothing is kept from a game in which the bot failed.--data folderkeeps these files somewhere that outlasts one ladder.
How ladder games are played#
A game between two bots is two copies of the game, one bot in each, kept in step on your computer. Every frame, both bots' orders go to both copies, so a slow bot slows the game as it would in a tournament, and the two copies are checked against each other as they go. A game against the computer is one copy.
A frame of a replay holds only so many orders, so two bots share that room: orders past a bot's half wait for the next frame, as they would in the real game with its turn full, and the replay plays back as the game that was played. A map from the original StarCraft (before Brood War) is played converted to Brood War, so that its replay plays back too.
--frames stops a game nobody has won (50,000 by default, about 35 minutes of play).
--parallel 4 plays four games at once, which suits a computer with the cores and memory:
a game takes about 1.5 GB for each bot in it. With games running side by side, a bot's
files from one game are not always there for the next.
A bot that fails has left the game, and the other side wins. A bot fails when it throws,
runs out of memory, or takes longer than --timeout seconds over one frame: 60 by
default, and at least five minutes for its first frame, where it reads the map. The
command exits with 1 when a game could not be played or a bot failed, so a script can tell
a broken bot from a losing one.