On this page

Robot manual

Write a robot, watch it fight, then change one idea and try again.

What the game is

You give a robot a set of instructions before a fight. It follows them on its own: it can move, look for other robots, and fire missiles. The last robot standing wins. Start by watching a battle, then change a robot in the editor.

crystal-robots is inspired by Tom Poindexter’s CROBOTS. The fights and the code checks run in your browser.

The battlefield

The field is a square, 1,000 meters on each side. loc_x tells you how far your robot is from the left edge; loc_y tells you how far it is from the bottom. Both range from 0 to 999. Touching a wall hurts your robot.

A square battlefieldThe starting corner is zero, zero at bottom left. East is right, north is up. A robot is near the middle.north (90°)east (0°)(0, 0)(999, 999)
Directions are measured in degrees: east is 0°, north 90°, west 180°, and south 270°.

Moving and turning

drive(direction, speed) sets a direction and a speed from 0 (stop) to 100 (fastest). Your robot speeds up or slows down gradually. At top speed it travels about 7 meters each movement step. It can turn only when its current speed is 50 or less, so it slows down before a fast turn. A wall or robot collision costs 2% damage and stops it.

Looking and shooting

scan(direction, width) looks in a wedge up to 10° either side of a direction. It tells you the distance to the nearest robot in that wedge, or 0 when it sees none. cannon(direction, distance) aims a missile at a spot up to 700 meters away. Missiles move 50 meters per movement step. A robot can have two missiles in flight and must wait 15 movement steps between shots.

Scanner and missileA blue robot scans a wedge toward an orange opponent. A missile travels along the middle of the wedge.your robotopponentscanner looks in a wedge
Scan first. If it finds a robot, fire in that direction at the distance it reports.

Damage

A close missile blast deals 10% damage within 5 meters, 5% within 20 meters, or 3% within 40 meters. Damage adds up; at 100% the robot is out. A damaged robot can still move and shoot normally until then.

Write your first robot

Paste this entire robot into the editor and press Fight:

main("Scout") do
  drive(0, 50)
  while true
    range = scan(0, 10)
    if range > 0
      cannon(0, range)
    end
    sleep
  end
end

main("Scout") do gives it a name. drive(0, 50) starts it eastward. while true repeats the instructions inside it. scan(0, 10) looks east. When it sees a rival, cannon(0, range) fires at that distance. sleep lets the fight advance. Each end closes one block. Try 90 instead of 0 in both calls and watch what changes.

Make a moving robot

This robot keeps moving while it looks for a target in front of it:

main("Patrol") do
  drive(90, 50)
  while true
    distance = scan(90, 10)
    if distance > 0
      cannon(90, distance)
    end
    sleep
  end
end

Change the direction in all three calls together. If you change only the cannon’s direction, the robot will look one way and shoot another.

More ways to give instructions

Use # to add a note for yourself. Use if to make a choice, while to repeat, and puts to write a number below the replay. Names such as shots hold whole numbers. global(shots, 0) makes a number that keeps its value between turns. A name assigned outside main is a fixed value.

# Count how many times this robot finds someone.
global(sightings, 0)
main("Lookout") do
  while true
    distance = scan(0, 10)
    if distance > 0
      sightings += 1
      puts sightings
      cannon(0, distance)
    end
    sleep
  end
end

You can use + - * / // % to work with numbers and == != < <= > >= to compare them. Both / and // give a whole-number answer, rounded down. Dividing by zero gives zero. Zero counts as false in a choice; any other number counts as true. true and false work too. Use && for “and,” || for “or,” and = or += to change a number.

For longer robots, def name(value) gives a group of instructions a name; return sends back its answer. The language also accepts elsif, else, until, break, and case/when. It does not accept every Crystal feature, including decimal numbers, lists, for, next, or !. Keep a robot below about 20 KB of text.

Robot commands

These are all the commands your robot can use. The words in parentheses are the numbers you pass in. For angles, 0° points east and 90° points north.

Loading robot commands…

Tips and tactics

The bundled robots show different ways to play. Open one in the editor, change a number, and see whether it helps.

  • sniper finds a corner, then scans and fires. The wall protects two sides, but a moving opponent can dodge its aim.
  • counter searches for rivals and moves when hit. Moving after a hit makes the next missile less likely to land in the same place.
  • rook patrols straight lines and shoots nearby robots. A simple route keeps it moving while it looks for a shot.
  • rabbit runs without shooting. It is good practice for tracking a moving target.
  • hunter follows what it finds with its scanner. Use its changing direction as an example of aiming at a moving rival.
  • target stays still. Try it first when testing a new shot.

How it works inside

Curious about the machinery? The browser first checks the words and structure of your robot, then turns the instructions into WebAssembly, a form the browser can run. These fast browser robots fight by default. The battle gives each robot a little time to act, moves them and their missiles, and records what happened for replay. The notes on reading code explain how the program is broken into small pieces and put together.

Running it yourself

Install Crystal, get the project files, and run:

git clone https://github.com/jadonk/crystal-robots.git
cd crystal-robots
crystal run ci.cr -- --with-wasm32

This builds the site files and checks the project. Run bin/crystal-robots -h to see the command-line options.

References