Login
crystal-robots
Login

crystal-robots is a programming game. You write a small program that drives a robot, and it battles other people's robots on a square battlefield. You can play it in your browser now.

What it's for

The game is the way in. You write robots in Crystal, a programming language whose syntax is simple to read, much like Ruby's. Then you follow that same code all the way down: from the text you typed, through each step a compiler takes (the program that turns code a person writes into instructions a machine runs), to the instructions themselves. That path, from learning a language to understanding its compiler, is the point.

The compiler here is kept small enough to read in an afternoon. Its ideas still apply to much larger compilers, so what you learn carries over to them.

Jason Kridner started crystal-robots for a personal reason too: to depend on programming tools that can be read and changed all the way through, down to the language itself, rather than on tools that can only be used as given.

What it's made of

How it's shaped

A robot passes through two stages inside crystal-robots. The front end reads the code and works out what it means. A back end then runs it.

The same code serves three places to play:

What success looks like

The Status page says where the work stands today.

  1. Play in a browser. A new player writes a robot, sees it checked, and watches it fight, with nothing to install. Done: the public site, with a manual and guided challenges.
  2. Play on the project's own server. The game runs as the repository's web app. Saved robots live in its wiki, and a tournament (many robots playing round after round down to one champion) can be shared by its link. Done: the app page, serving check-in 66bc8fd2b2.
  3. See how the code is read. A player can watch the parser's passes and see the WebAssembly their robot became. Done: the site's workbench page shows the passes, and its front page shows the WebAssembly.
  4. Follow how it was built. A tutorial rebuilds the project one change at a time, each with its code. Done: the project blog, merged in check-in 048d0ace53.
  5. Down to a real processor. The compiler also emits instructions for RISC-V, a real processor design used in many small chips, and draws a robot's parsed structure as a diagram (with Graphviz's dot format). Not yet: src/compiler/riscv_emitter.cr and src/compiler/dot_emitter.cr are empty placeholders.

The virtues behind it

crystal-robots is one of several projects built with OCX, a shared set of tools with which people and AI agents build and run these projects together. Like each of them, it follows OCX's four virtues:

Installation

shards build            # produces bin/crystal-robots
bin/crystal-robots -h

Crystal 1.14 or newer. Running the emitted WebAssembly (the specs and, later, battles) needs the wasmer runtime; see Development below.

Usage

bin/crystal-robots is one binary with several faces:

bin/crystal-robots -t examples/counter.cr           # print the parser derivation, one line per pass
bin/crystal-robots -i -l 5000 examples/counter.cr   # run robots in the interpreter, 5000 steps each
bin/crystal-robots -m 3 -l 100000 --seed 7 examples/counter.cr examples/rabbit.cr   # three seeded matches
bin/crystal-robots -c examples/sniper.cr -o sniper.wasm # compile a robot to WebAssembly (imports env.scan, env.cannon, ...)
bin/crystal-robots -c examples/sniper.cr --ticks -o sniper.wasm # also import env.tick(n) and charge CROBOTS cycles
GATEWAY_INTERFACE=CGI/1.1 bin/crystal-robots        # serve the web app (Fossil does this for you)

The easiest way to play is the public site. The compiler is built into the web page. You can provide sources for the various robots and watch them battle it out.

There are a lot of other methods to battle your crystal-robots and each peels back a layer to teach you more about full-stack programming.

Fossil server for contributors

The web app is a Fossil CGI extension: Fossil serves the repository, the docs and the app, and supplies the login. The app replies in Markdown, so it appears inside the repository's own skin.

shards build
scripts/install_extroot.sh /path/to/extroot      # symlinks extroot/crystal-robots -> bin/crystal-robots
fossil server crystal-robots.fossil --extroot /path/to/extroot --port 8080

Then browse to http://localhost:8080/ext/crystal-robots/: pick example robots or paste your own, run a seeded match, watch the replay at a chosen pace (cycles per second, 300 by default, roughly the original curses display), step through its frames drawn in Pikchr with each robot's trail, or run a series of matches for a score table like crobots -m.

To keep a robot, create a wiki page named robot/<name> whose Markdown contains exactly one fenced code block; that block is the robot. It then appears on the overview (with its first paragraph as a description and a "fight" link), in the battle picker, and at /ext/crystal-robots/wiki/<name> with its derivation and checks. Five such robots ship in robots/*.md (hunter, circler, dodger, wallhugger, turret); publish them to a repository's wiki with:

scripts/publish_wiki_robots.sh -R /path/to/crystal-robots.fossil

A CROBOTS rule worth knowing when writing one: a heading change only takes at 50 percent speed or less. Ask for a turn while faster and the drive disengages, so slow down first (the shipped robots show both ways).

Cycles are charged the way the CROBOTS virtual machine did: one per operand fetch, operator, store, branch and statement, two per builtin call, three around a user function call. -l limits those cycles. A rebuild is the deploy: the CGI runs fresh on every request. To put the app in the Fossil menu, paste fossil-skin/mainmenu into Admin, Skins, Main Menu. It mirrors the deployed menu (Agents, Docs and a "Run" entry for this app); merge rather than replace if your skin has other rows. Who may use the app is decided by the repository's user capabilities: reading the overview and examples needs o or h (what anonymous usually has); running battles and parsing needs check-in (i); seeing saved robots needs wiki read (j).

Tournament

/ext/crystal-robots/tournament lets you pick robots (or Check everyone) into a tournament: pool play (round-robin, win +1 / loss -1, a refight on a tie or a no-winner fight) followed by a single-elimination bracket (best of 3, byes for the top seeds) down to one champion. The whole thing is stateless like a battle: every stage's outcome round-trips through the tournament's own link, so it replays exactly and can be shared or resumed from that link alone. Running one needs check-in (i), the same permission battles need.

Self-hosted server without Fossil

Planned: bin/crystal-robots -p 8080 will serve the same pages directly.

Compiled to native code with crystal

To setup the environment for your robots, use prelude.cr ...

crystal run --prelude=../src/prelude robot1.cr robot2.cr robot3.cr robot4.cr -- -m 500

Command-line interpretation by crystal-robots

Using the crystal-robots compiler, you can perform battles by running the built-in interpreter ...

bin/crystal-robots -i -m 5 robot1.cr robot2.cr robot3.cr robot4.cr

Compiled to WASM by crystal-robots and executed with wasmer

Support

TODO: Write support instructions here

Roadmap

See docs/PLAN.md for the phased development plan, the current baseline, and the open parser-architecture decision.

Development

One command runs everything the review pipeline runs:

crystal run ci.cr --                 # shards, build-docs, build, spec, format check, example builds, CLI smoke
crystal run ci.cr -- --with-wasmer   # also runs the WebAssembly specs under wasmer 4.4.0 (installed under ./.wasmer if absent)
crystal run ci.cr -- --with-wasm32   # also builds site/crystal-robots.wasm, the browser compiler (installed libs under ./.wasm32-wasi-libs if absent)

The pieces, if you want them separately:

crystal spec                       # everything except running WebAssembly (those specs are pending)
crystal spec -Dwasmer              # also runs the emitted modules with wasmer
crystal tool format --check src spec scripts
bin/crystal-robots build-docs      # crystal docs into docs-api/; the next shards build embeds them at /ext/crystal-robots/docs (shown inside the Fossil skin)
bin/crystal-robots --version       # "crystal-robots 0.0.1 (check-in <hash>)", the hash from manifest.uuid at build time

The wasmer runtime is optional. Wasmer 4.4.0 is the last release with a linux-musl build, so pin it:

scripts/install_wasmer.sh v4.4.0
export WASMER_DIR=$HOME/.wasmer

The browser compiler (site/, published at jadonk.github.io/crystal-robots by .github/workflows/pages.yml) needs the wasm32-wasi-libs sysroot to link, pinned to release 0.0.3 the same way; crystal run ci.cr -- --with-wasm32 installs it under ./.wasm32-wasi-libs and builds site/crystal-robots.wasm in one step (its install_wasm32_wasi_libs function is the only installer, downloaded and extracted directly, no shell script involved).

The parser design is described in docs/PARSER.md; the phased plan and current status in docs/PLAN.md.

Roadmap

See docs/PLAN.md. Longer-term ideas kept from the original list:

Contributing

The repository is Fossil, hosted at https://ollama.openbeagle.org/crystal-robots.

  1. fossil clone https://ollama.openbeagle.org/crystal-robots crystal-robots.fossil and fossil open it.
  2. Work on a branch: fossil commit --branch my-feature -m "...".
  3. Run crystal run ci.cr before asking for review; it is the same gate the merge pipeline runs.
  4. Ask for review in the project forum. Merges to trunk are done by the trunk operator after the suite passes on a merge stand-in; the served app is rebuilt from trunk after the merge.
  5. Robots, as opposed to code, need no branch: a wiki page named robot/<name> is enough (see Usage).

License

crystal-robots is distributed under terms of the GNU General Public License, version 2.

This is in line with Tom Poindexter's release of CROBOTS. While more restrictive than Colin Eberhardt's release of chasm under an MIT license, it seems to me to be better to follow the more restrictive license. I hope that Colin agrees and if I ever complete this, I'll be sure to engage to find a suitable compromise.

Contributors