Skip to content

Adaptive coding game · AEII 2026

Program a robotto cut hair.Nothing gets hurt.

HCR is a coding game where students drag blocks to drive a five-joint arm across a voxel hairstyle. A digital twin runs every move first and refuses anything that would reach the head — so a beginner can drive, and the only cost of being wrong is one more try.

It runs in a browser. There is no robot to buy, and the level fits the student rather than the class.

Neat Short HaircutRunning
  1. shoulderRoll15°
  2. shoulder72°
  3. elbow10°
  4. elbow−48°
  5. baseYaw−30°
  6. baseYaw
  7. baseYaw30°
  8. wrist−20°
Completion57.6
Cut thisKeep this

Why

Teaching robotics does not scale

One arm, one student

A real robot arm is expensive and serves one student at a time, with a teacher standing over it.

One course, one pace

A class gets a single sequence of lessons. The quick students are bored and the struggling ones give up.

Mistakes are expensive

On real hardware a wrong angle is a collision. That makes the safe move to not let beginners drive at all.

The loop

Write, check, score — then change one number and go again

Three steps, and the third sends you back to the first. That loop is the whole lesson.

  1. 1Program

    Drag blocks, not syntax

    Three block types and nothing else: set a joint to an absolute angle, wait, or repeat. No typing and no syntax errors — but the order still decides everything, which is what makes it real programming.

    set-joint-angle · wait (0–5000 ms) · repeat (1–20×)

  2. 2Check

    A twin runs it first

    Before the arm moves, the same program is swept through a geometric model of the head. A move that would enter the head is refused: the arm holds its last safe pose and the block that caused it is highlighted.

    Continuous swept contact · deterministic, no physics engine

  3. 3Score

    A score, not a grade

    Getting it wrong costs one more attempt. The result is scored on how closely the haircut matches the target, how compact the program is, and how long it would take to run.

    0.60 completion + 0.25 efficiency + 0.15 time

The guarantee

Every challenge can definitely be finished.

The obvious way to build a level is to draw the haircut you want and hope the arm can manage it. One of our own early challenges asked for 91 pieces of hair when the arm could reach 20 — unwinnable, and nothing in the level said so.

Now the solver runs first. A candidate target is swept against the collision-free joint space, then handed to a reference solver; anything the solver cannot finish is rejected at generation and never served. The solution becomes the level’s reference cost and reference time.

One early hand-drawn challenge

Hair the level asked for91
Hair the arm could reach20

Unwinnable, and nothing on screen said so. A student would have read that as their own failure.

Adaptive

One level per student, not one level per class

After every attempt the platform re-estimates how the learner is doing and picks the next challenge to match. Finish comfortably and the next one is harder; struggle and it steps back. One level per student, not one level per class.

Ability θ
Robot-programming proficiency on a logit scale, updated from each replayed program.
2PL, not 3PL
You cannot guess your way into a correct haircut, so the guessing parameter is fixed at zero and the third parameter is dropped rather than estimated from noise.
Item selection
Challenges are ranked by Fisher information at the current θ, then exposure-capped so the same handful of items is not served to everyone at the same level.
Partial credit
Scores are continuous, so a raw score is remapped around a per-item mastery threshold before the estimator sees it. The raw score is kept separately — nothing is discarded.
Calibration
A new challenge starts provisional: exposure-capped and excluded from ability updates that count, until it has enough responses to refit its difficulty.
One θ, for now
Ability is a single composite value in this version, with dimension tags recorded on every response for reporting. A genuinely multidimensional model is the next step, not a current claim.

Modes

Practise alone, or play the room

Solo practice

Untimed. The workbench, a challenge, and as many attempts as you want.

  • Run, pause, resume, step one command at a time, stop, or reset — the program survives a reset.
  • Test evaluates the program headlessly in milliseconds instead of watching it animate.
  • Toggle the target hairstyle preview on or off while you work.

Versus round

Everyone in the room gets the same challenge at the same moment.

  • A fixed wall-clock window, judged by the server clock rather than any player’s.
  • No score is visible to anyone — including you — until the round closes.
  • Resubmit as often as you like; only your best attempt counts.
  • Programs are replayed server-side, so a faster laptop wins nothing.

With no backend configured a versus round is scored by your own browser against scripted bots. The app says so on the menu, in the lobby, and on the scoreboard — it exists so the mode is playable offline, and nothing it reports is a result.

Underneath

Four pieces, one protocol

Simulator

HCR_Simulator_Frontend

React · TypeScript · Vite · React Three Fiber · Blockly

The whole demo loop runs client-side. With no backend configured it makes no network request at all.

Service

hcr-backend

Rust · MQTT over WebSocket · HTTP binding

Replays programs server-side, runs the adaptive question bank, and owns round deadlines and standings.

Protocol

hcr-backend/schema

hcr.v1 · JSON and CBOR

One envelope for every message, correlated by ULID. Minor versions are additive only; receivers drop what they do not recognise rather than failing.

Hardware

hcr-fw

Rust (no_std) · ESP8266 · Arduino C++ as a hardware library

A physical five-servo arm. Rust owns startup policy, routing, HTTP and servo state; C++ is confined behind a byte-oriented C ABI.

Try it

Adaptive, coding, game, simulation, education — five words, one platform.

No robots to buy, a whole class at once, each at their own level. Open the first challenge in a browser tab.

Client-side loop complete · cross-browser acceptance open