Skip to content

Search is only available in production builds. Try building and previewing the site to test it out locally.

🤖 Virtual Lab: Robot Arena

In these two labs you assemble a small C++ program from a palette of instruction tiles, then watch a deterministic interpreter run it as a robot’s per-tick control loop on a grid. A pseudo-compiler checks your program before it can run, emitting g++-style diagnostics for unbalanced braces or empty blocks, so a clean compile is the price of admission. The goal each time is to locate the enemy, close in, and fire before you run out of actions or energy.

The two labs are a deliberate sequence. The first isolates control flow. The second keeps that exact structure and adds variables and mutable state, plus an enemy that no longer holds still, so you have to reason about a value that changes over time and a target that reacts to what you do.

The first arena is about ordering and shaping the flow of execution. Every win comes from sequencing a few actions and wrapping them in the right block, with nothing to track but position, heading, and two budgets.

Language elementWhere it shows up
SequencingStatements run top to bottom as the robot’s tick() loop.
if (conditional)if (enemy_visible()) runs its body only when the last scan() saw the enemy.
for (counted loop)for (int i = 0; i < 3; i++) repeats its body a fixed number of times.
while (condition loop)while (distance() > 3) repeats until a sensor condition stops holding.
Block scope and bracesEvery { must be matched by a }; an empty block is a compile error.
Side effects and costEach action spends from an action limit and an energy budget, so wasted statements have a price.

The key insight the lab pushes you toward is that a program hard-wired to one approach fails, because the start position and facing are random every run. The robust answer is a loop: scan to locate, turn to face, move to close the gap, then fire.

C++ arena game

Robot Arena: Control Flow

Mission

Destroy the enemy robot within 22 actions.

Your tick() program is the robot’s control loop. You have two limits. First, an ACTION limit: the robot can run at most 22 instructions per battle (scan, move, turn, and fire each count as one action). Second, an ENERGY budget of 50: each action also spends energy, and firing is the most expensive at 5. Either running out of actions or running out of energy ends the battle. Each Run drops both robots at random positions with your tank facing a random direction, and a hit needs you facing the enemy with distance() <= 3. Because the start changes every time, a program hard-wired to one approach will not work. Scan to locate the enemy, turn to face it, close the gap with a loop, then fire.

Instruction palette: tap to add
robot::tick(): your program
arena.cpp
Tap instructions above to assemble the robot's per-tick program.

Have a go yourself first. A strong solution unlocks after 3 runs (0 of 3 so far).

Arena random start
you enemy
How the pseudo-compiler thinks

Before anything runs, the structural pass checks your braces balance, that every block actually contains a statement, and that no } appears without an open block. These are exactly the class of errors g++ reports first. Only a clean compile is allowed to run. The interpreter then walks your program as the robot's tick() loop: if runs its body once when its condition holds, for repeats a fixed number of times, and whilerepeats until its sensor condition stops holding. Watch the energy and distance readouts as you scrub the frames. Every instruction counts as one action against the 22-action limit, and each one also spends energy you may need later for fire().


The second arena reuses the same instruction set and narrative, then introduces the one idea the first lab cannot express: a variable your program reads and writes as it runs. You now carry ammo, and the numbers are deliberately tight. The enemy must be hit three times to destroy, but your robot stores only two rounds before it has to reload(). Two shots are never enough on their own, so somewhere in the fight you have to notice you are empty and reload. The only way to know that is to read the variable with if (ammo() == 0). A program that ignores ammo, like any Lab 1 solution, lands at most two hits and always loses.

On top of that, the enemy is now skittish: as you approach, it sometimes darts a cell away at the edge of your range, though once you have closed right in it can no longer escape. So you close the gap, pin it, and then fire and reload until its three hit points reach zero.

Language elementWhere it shows up
Mutable state (a variable over time)ammo starts at 2, drops by one on each fire(), and resets to 2 on reload().
A constraint that forces the readThe enemy needs 3 hits but you hold only 2 rounds, so you cannot win without checking ammo and reloading.
Reading a variable in a conditionif (ammo() == 0) branches on the variable’s current value to decide when to reload.
State changing across iterationsInside the fire loop, ammo and the enemy’s remaining hit points both change every pass.
Stale vs fresh dataThe cached distance() is only as current as your last scan(); the dodging enemy makes re-scanning matter.
Everything from Lab 1The same control-flow elements still apply; the variable sits on top of them.

Because the enemy reacts only when you move, turning, firing, and reloading are “free time” it cannot dodge. The strong solution closes all the way in where the enemy is pinned, then loops: reload when empty, aim, fire, and re-scan, repeating until all three hit points are gone.

C++ arena game

Robot Arena: Variables & a Moving Enemy

Mission

Destroy the moving enemy robot, which takes three hits, within 40 actions.

Your tick() program is the robot’s control loop. You have several things to manage. An ACTION limit: at most 40 instructions per battle (scan, move, turn, fire, and reload each count as one action). An ENERGY budget of 80: every action spends energy, and firing is the priciest at 5. And AMMO: you start with only 2 rounds, each fire() uses one, and reload() refills you back to 2. The enemy needs THREE hits to destroy, so two rounds is never enough on their own. You must notice when you are empty and reload mid-fight, which means reading the ammo variable with if (ammo() == 0). A hit needs you facing the enemy with distance() <= 3. The enemy is also skittish: as you approach it sometimes darts a cell away, though once you are right next to it (distance 1 or 2) it can no longer escape. Scan to locate it, turn and close the gap with a loop, then keep firing, reloading whenever you run dry, until it is down.

Instruction palette: tap to add
robot::tick(): your program
arena.cpp
Tap instructions above to assemble the robot's per-tick program.

Have a go yourself first. A strong solution unlocks after 3 runs (0 of 3 so far).

Arena random start
you enemy
How the pseudo-compiler thinks

Before anything runs, the structural pass checks your braces balance, that every block actually contains a statement, and that no } appears without an open block. These are exactly the class of errors g++ reports first. Only a clean compile is allowed to run. The interpreter then walks your program as the robot's tick() loop: if runs its body once when its condition holds, for repeats a fixed number of times, and whilerepeats until its sensor condition stops holding. Watch the energy, ammo, distance, and enemy-hp readouts as you scrub the frames. Every instruction counts as one action against the 40-action limit, and each one also spends energy. The heart of this lab is the ammo variable: the enemy takes three hits but you carry only two rounds, so no fixed burst offire() calls can win. Your program has to notice when it is empty and reload, which means reading the variable with if (ammo() == 0)and acting on the result. The enemy also dodges at the edge of your range, so the cached distance() is only as fresh as your lastscan(); re-scanning inside the loop keeps your decisions honest. Notice that the strong solution wins by closing all the way in, where the enemy can no longer flee, then firing and reloading until its hit points reach zero.


Across the two labs you have built working programs out of the same primitives that structure all C++ code: sequencing, conditionals, counted and conditional loops, block scope, and a mutable variable that carries state from one step to the next. The progression mirrors how these ideas are normally taught. First you control which statements run and how often, then you add a value that those statements change and read back, which is the foundation of every algorithm that has to remember anything.

Quiz
Select 0/1

In Lab 1, why does a program with a fixed sequence of moves (rather than a loop guarded by a sensor) usually fail?

Quiz
Select 0/1

In Lab 2, what is the core new concept that 'ammo' introduces compared with Lab 1?

Quiz
Select 0/1

In Lab 2 the enemy takes three hits but your robot stores only two rounds. What does this force every winning program to do?