Skip to content

1. Render the first room

Current source: curriculum/arrowfall/checkpoints/01-scene · Flecha 0.3.0 · 1/7.

The program at this checkpoint

Previously: You start with an installed Flecha v0.3.0 toolchain and an empty program.

Arrowfall begins with the smallest useful result: a terminal program that can already be recognized as a game. There is no state or input yet. The current program only establishes the title, the room boundary, the archer, the floor, and the exit.

This static frame is intentional. Before rules can move a symbol, the symbols need a stable meaning. The same four characters will remain visible as later checkpoints replace literal text with state, collision, enemies, and rendering logic.

Current limitation

There is nothing to play or recognize yet.

Required next behavior: Make one unmistakable terminal frame before adding state or rules.

Model and invariants

Print the title and a tiny room directly. The symbols establish the visual contract: # wall, . floor, @ archer, and > exit.

Plain functions and stdout are sufficient for this version. Adding a state model now would add structure without supporting any behavior.

The terminal is a grid of characters, so one printed line represents one row. Calling stdoutln once per row makes the spatial layout visible directly in source: the outer # characters are walls, @ is the archer, . is traversable floor, and > is the exit.

At this stage the source text is also the scene data. That is acceptable only because nothing can change. It gives us a precise baseline without introducing a structure whose responsibilities are still unknown.

The important invariant is visual rather than dynamic: every row has the same width and the room remains enclosed. Movement and collision are deliberately out of scope until the program has state to modify.

Implementation

The implementation is split into the changes below. Each excerpt is taken verbatim from the qualified checkpoint and is explained in the part of the data flow where it is used. The excerpts are not standalone programs; the complete compiled source is available after the run.

  • Create the Longbow program manifest.
  • Add the first complete main module.
  • Record exact input, stdout, text, and SVG frames.

The complete first program

The complete program fits in one module. The module declaration gives Longbow an entry module, while main writes the four-line frame in display order.

Excerpt: src/main.fl:1–8. The complete file appears in the source section below.

src/main.fl:1-8 (excerpt)
module main;
void main() {
stdoutln("ARROWFALL");
stdoutln("#####");
stdoutln("#@.>#");
stdoutln("#####");
}

Each call ends its row with a newline. Keeping the title separate from the room means later renderers can redraw the map without treating the title as a map cell.

There is no loop because there is no repeated rule yet. A loop would hide the only information this checkpoint needs to teach: the exact first frame.

Run and inspect the result

The command uses the checkpoint’s recorded input, so the behavior described above can be reproduced without manual timing.

Run command
longbow run tutorial/checkpoints/01-scene < tutorial/checkpoints/01-scene/tests/input.txt

The recorded run has no standard input. Its frame should contain the same four rows as the source, with the archer at the only floor cell before the exit.

Terminal frame produced by version 1: Render the first room
Representative frame from the recorded run of checkpoint 1.

This output becomes the first visual contract. If one character changes, the frame fixture changes with it; later checkpoints can therefore show which visible behavior came from a code change.

Accessible frame transcript
Frame transcript
ARROWFALL
#####
#@.>#
#####
Complete recorded stdout
Expected stdout
ARROWFALL
#####
#@.>#
#####

What this checkpoint establishes

We now have a compilable Longbow program and an exact terminal baseline, but the archer is still part of a string. There is no value that represents its location.

The next checkpoint introduces that value and makes rendering consult it. Only then can movement mean changing data instead of editing text.

Exercise

Change one floor dot to a wall. Exactly one frame character must change; restore it before continuing.

Complete source and verification

The sections below preserve the complete qualified source, the exact predecessor diff, and the command sequence used by CI. They are supporting evidence for the implementation explained above.

Complete tested source (3 files)

longbow.toml

longbow.toml
[package]
name = "arrowfall-step-01"
version = "0.1.0"
kind = "program"
flecha = ">=0.3.0, <0.4.0"
[dependencies]

longbow.lock

longbow.lock
{
"schema": 1,
"root": "root",
"packages": [
{
"id": "root",
"identity": "local/arrowfall_step_01",
"source": {
"kind": "workspace",
"path": "."
},
"version": "0.1.0",
"flecha": ">=0.3.0, <0.4.0",
"dependencies": {
"std": "toolchain-std"
}
},
{
"id": "toolchain-std",
"identity": "flecha/std",
"source": {
"kind": "toolchain"
},
"dependencies": {}
}
]
}

src/main.fl

src/main.fl
module main;
void main() {
stdoutln("ARROWFALL");
stdoutln("#####");
stdoutln("#@.>#");
stdoutln("#####");
}
Exact diff from the preceding version
--- /dev/null
+++ tutorial/checkpoints/01-scene/README.md
@@ -0,0 +1,50 @@
+# 01 — A room appears
+
+## Starting point
+
+There is no previous checkpoint: we begin with an empty Flecha program.
+
+## Why now?
+
+A terminal game first needs something recognisable on screen. Before state,
+input, or rules, a static room gives the project a visible identity.
+
+## New behaviour
+
+Running the program prints Arrowfall's title and a tiny room containing the
+player (`@`), floor (`.`), walls (`#`), and exit (`>`).
+
+## Files changed
+
+- `README.md`
+- `longbow.lock`
+- `longbow.toml`
+- `src/main.fl`
+- `tests/input.txt`
+- `tests/output.txt`
+- `tests/frame.txt`
+- `tests/frame.svg`
+
+The exact source diff is `../../diffs/01-scene.patch`. This directory contains
+the complete current code, not a fragment.
+
+## Verify
+
+```sh
+longbow check tutorial/checkpoints/01-scene
+longbow test tutorial/checkpoints/01-scene
+longbow build tutorial/checkpoints/01-scene
+longbow run tutorial/checkpoints/01-scene < tutorial/checkpoints/01-scene/tests/input.txt
+```
+
+Expected stdout is `tests/output.txt`; the representative frame is
+`tests/frame.txt` and `tests/frame.svg`.
+
+## Timeline
+
+1. **A room appears** — a static scene establishes the game's visual goal.
+
+## Challenge / acceptance
+
+Change one floor dot to a wall, rebuild, and verify exactly one character in
+the frame changes. Restore it before moving on.
--- /dev/null
+++ tutorial/checkpoints/01-scene/longbow.lock
@@ -0,0 +1,27 @@
+{
+ "schema": 1,
+ "root": "root",
+ "packages": [
+ {
+ "id": "root",
+ "identity": "local/arrowfall_step_01",
+ "source": {
+ "kind": "workspace",
+ "path": "."
+ },
+ "version": "0.1.0",
+ "flecha": ">=0.3.0, <0.4.0",
+ "dependencies": {
+ "std": "toolchain-std"
+ }
+ },
+ {
+ "id": "toolchain-std",
+ "identity": "flecha/std",
+ "source": {
+ "kind": "toolchain"
+ },
+ "dependencies": {}
+ }
+ ]
+}
--- /dev/null
+++ tutorial/checkpoints/01-scene/longbow.toml
@@ -0,0 +1,7 @@
+[package]
+name = "arrowfall-step-01"
+version = "0.1.0"
+kind = "program"
+flecha = ">=0.3.0, <0.4.0"
+
+[dependencies]
--- /dev/null
+++ tutorial/checkpoints/01-scene/src/main.fl
@@ -0,0 +1,8 @@
+module main;
+
+void main() {
+ stdoutln("ARROWFALL");
+ stdoutln("#####");
+ stdoutln("#@.>#");
+ stdoutln("#####");
+}
--- /dev/null
+++ tutorial/checkpoints/01-scene/tests/frame.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="360" height="124" viewBox="0 0 360 124" role="img">
+ <title>01-scene representative frame</title>
+ <rect width="100%" height="100%" rx="12" fill="#10151c"/>
+ <style>.terminal { fill: #d7f9e9; font: 15px monospace; white-space: pre; }</style>
+ <text x="24" y="37" class="terminal">ARROWFALL</text>
+ <text x="24" y="56" class="terminal">#####</text>
+ <text x="24" y="75" class="terminal">#@.&gt;#</text>
+ <text x="24" y="94" class="terminal">#####</text>
+</svg>
--- /dev/null
+++ tutorial/checkpoints/01-scene/tests/frame.txt
@@ -0,0 +1,4 @@
+ARROWFALL
+#####
+#@.>#
+#####
--- /dev/null
+++ tutorial/checkpoints/01-scene/tests/output.txt
@@ -0,0 +1,4 @@
+ARROWFALL
+#####
+#@.>#
+#####
Check, test, build, and run commands
Verification commands
longbow check tutorial/checkpoints/01-scene
longbow test tutorial/checkpoints/01-scene
longbow build tutorial/checkpoints/01-scene
longbow run tutorial/checkpoints/01-scene < tutorial/checkpoints/01-scene/tests/input.txt

Versions in this tutorial

  1. 1. Render the first room

Next version

The room is currently one fixed string. The next version derives the player position from owned game state.

Represent game state

References

Source: Arrowfall commit 56bb003, verified with official Flecha 0.3.0. The source, input, output, diff, and frame on this page are read from that committed snapshot.