Skip to content

Maze module: generator playground, wall-follower, and maze-solver integration - #21

Merged
tytremblay merged 5 commits into
mainfrom
maze-module
Aug 2, 2026
Merged

Maze module: generator playground, wall-follower, and maze-solver integration#21
tytremblay merged 5 commits into
mainfrom
maze-module

Conversation

@tytremblay

Copy link
Copy Markdown
Contributor

Adds a new lesson 35 "Navigating a maze" and the tooling behind it, plus the plumbing to run the team's maze-solver-java library in the browser. Also carries the in-flight lessons ordering refactor + module docs that were already in the working tree.

Maze playground (MazePlayground.tsx)

  • Renders a generated maze. (Note: the maze-generator npm package's shuffle is broken — it returns before ever calling Math.random, so it emits the same degenerate maze every time. We generate the same N/S/E/W bitmask grid with a correct recursive-backtracking walk instead.)
  • Drivable robot with start/goal markers, arrow-key + d-pad control.
  • Animated wall-follower (right-hand rule) button.
  • Copy for Java — serializes the current maze to an int[][] bitmask literal that pastes straight into the Java playground.

Lesson flow

"What a maze is" → robot navigation → algorithms as sense/decide/move → the wall follower → the same algorithm in raw Java → the same algorithm against the maze-solver library's Robot/Cell API (no bitmasks).

Site wiring

  • New ```maze fence (lessons.ts + LessonView.tsx), with a solver: directive to reveal the wall-follower button.
  • maze-solver.jar added to the CheerpJ classpath (javaRuntime.ts).
  • CI step (deploy-pages.yml) builds the jar fresh from maze-solver-java@main on each deploy; scripts/vendor-maze-solver.sh + npm run vendor:maze-solver do the same locally. The jar is gitignored, never committed (unlike the frozen tools.jar).

Also included (pre-existing working-tree changes)

  • Lessons ordering refactor across lessons/01..34.
  • Module docs: CONTEXT.md glossary, docs/adr/0001-derive-lesson-order-from-position.md, docs/handoffs/ordering-refactor.md.
  • .claude/settings.json enabling the team skills plugin.

Depends on

🤖 Generated with Claude Code

@tytremblay

Copy link
Copy Markdown
Contributor Author

📚 Stacked on #22 (lesson-ordering). This PR's base is the lesson-ordering branch, so the diff shows only the maze module. Merge #22 first; GitHub will then auto-retarget this PR to main.

tytremblay and others added 2 commits July 27, 2026 12:16
…egration

New lesson "Navigating a maze" and its interactive tooling, plus the plumbing
to run FRC2713/maze-solver-java in the browser (builds on the ordering refactor).

- MazePlayground: renders a generated maze (correct recursive-backtracking,
  since the maze-generator npm package's shuffle is broken), with a drivable
  robot, start/goal markers, an animated wall-follower, and "Copy for Java"
  serialization to an int[][] bitmask literal.
- Lesson pages build from "what a maze is" -> robot navigation -> algorithms
  (sense/decide/move) -> the wall follower -> the same algorithm in raw Java
  -> the same algorithm against the maze-solver library's Robot/Cell API.
- Site wiring: `maze` fence (lessons.ts/LessonView), maze-solver.jar on the
  CheerpJ classpath, a CI step + vendor script that build the jar (gitignored).
- CONTEXT.md glossary for the maze module.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rithms section

Reframe the maze lesson around a progressive disclosure of what an algorithm
is: a random walk (no plan — unrepeatable), a fixed no-memory rule (a real
algorithm, but it ping-pongs between two cells), and the wall follower (an
algorithm that works, thanks to one remembered fact: its facing). The
sense/decide/move skeleton now lands at the end, after three concrete "decide"
steps instead of zero.

- MazePlayground: widen `solver` from a boolean to a 'random' | 'naive' | 'wall'
  mode; generalize the runner and add visible "stuck in a loop" detection for
  the naive rule (stops once a cell is hit 4x so the oscillation is watchable).
- lessons.ts: `mazeShowsSolver` -> `mazeSolver` returning the mode.
- Move the lesson into a new "Algorithms" section (order 195), above State
  Machines; rename its folder 35-maze-generator -> algorithms.
- CONTEXT.md: clarify that orientation is the robot's interface constraint, not
  a ban on an algorithm tracking its own `facing`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
tytremblay and others added 2 commits July 27, 2026 12:48
Add developer-facing design spec for passing a JS-generated maze into Java,
solving it with a student algorithm against the maze-solver library, and
animating the resulting trail back on the JS side. The round-trip is not wired
yet — this documents the seams and data contracts so it can be built.

- docs/maze-roundtrip.md: data flow, the 7 seams (exists vs new), the wire
  contract (interpolated int[][] down; sentinel-tagged `__TRAIL__` JSON line up),
  the [row,col]<->[x,y] coordinate swap, harness sketch, edge cases, and an
  exists-vs-to-build checklist.
- CLAUDE.md: pointer to the doc from the Site architecture section.
- CONTEXT.md: add "Maze Trail" glossary term (the Cells occupied — distinct from
  Solution, the Moves emitted).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wire the JS->Java->animated-steps round-trip from docs/maze-roundtrip.md so
students can write a solve(Robot) algorithm and watch their path animate back
in the maze.

- mazeHarness.ts: build a MazeRun compilation unit (grid interpolated as an
  int[][] literal + spliced student solve), emit the Maze Trail as a
  __TRAIL__ sentinel line, parse it back with the single [row,col]->[x,y] swap,
  and retarget compile-error lines to the student's editor.
- MazePlayground: new 'java' solver mode (CodeMirror editor + Run, replays the
  parsed Trail through the existing animation loop).
- lessons.ts: the maze fence accepts `solver: java`.
- maze-engine.jar: concrete GridMaze/GridRobot/GridCell implementing the
  library interfaces, vendored on the CheerpJ classpath (Java 8 bytecode) while
  maze-solver ships interfaces only. Built by scripts/build-maze-engine.sh,
  committed like tools.jar; delete once the library ships its own GridMaze.

Lesson (algorithms): drop the raw-bitmask "same algorithm in Java" page for a
clean library wall follower (runnable), then the interactive "write your own
solver" page. Reworded so the library owns the maze bookkeeping while `facing`
is framed as the algorithm's own remembered fact.

Verified end-to-end against both jars with a real JDK: harness + page-6 program
compile and reach the goal; trail parsing / error retargeting unit-checked;
tsc, oxlint, vite build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
space divided into a **grid** of cells, some paths open, some blocked by
**walls**, a place you **start**, and a place you're trying to **reach**.

- The **grid of cells** is the field, chopped into squares the robot can occupy.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont think we introduce 2D arrays yet, might be worth a quick lesson as a pre-cursor

Comment thread lessons/algorithms/README.md Outdated
}
}

// Move one step in an absolute direction if that side is open; report

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think tryMove() is worth having a whole lesson on, where students write it themselves. We could add some documentation for the functions in the Robot class, and frame it as practice reading and understanding an API so they know how to use robot.canMoveUp()

return maze.cellAt(row, col);
}

public boolean canMoveUp() {

@unbun unbun Jul 27, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In context of our lessons, I would phrase this method as a method that calls a sensor, like readNorthWallSensor() or readWallSensor(Direction.UP)

return (mask() & GridCell.RIGHT) != 0;
}

public void moveUp() {

@unbun unbun Jul 27, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In context of our lessons, I would phrase/refactor this method as a method as moving a robot/drivetrain, something like driveUp() or drive(Direction.UP)

Comment thread lessons/algorithms/README.md Outdated
public static void main(String[] args) {
// A maze serialized from the generator: each cell is an N/S/E/W bitmask.
int[][] grid = {
{4, 12, 10, 6, 10, 4, 14, 10, 4, 12, 14, 12, 12, 10},

@unbun unbun Jul 27, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mazes in the more visual lessons are fine, but i think once we start students on Java i think it will be easier if the maze is like... 5x5 or smaller.

Comment thread lessons/algorithms/README.md Outdated
Comment on lines +267 to +277
while (!robot.atGoal() && robot.trail().length <= cap) {
// Try right, straight, left, back — relative to the way we're facing
// — and take the first one that's open, remembering it as the new facing.
int[] order = { (facing + 1) % 4, facing, (facing + 3) % 4, (facing + 2) % 4 };
for (int dir : order) {
if (tryMove(robot, dir)) {
facing = dir;
break;
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused on what we are trying to teach by including this loop-based facing logic in the lesson content.

If I were to write code for keeping the robot's direction, I would store facing in the Robot class, and update it any time moveUp/Down/Left/Right is called in tryMove(), bc if a robot successfully moved up, it should be facing up.

So in my mind, it would be a simpler lesson to grasp if maybe we had students implement tryMove() in a whole seperate lesson and add facing-updates there in the final lesson. Then hopefully there's still a real critical-thinking part of the lesson in implementing the algorirthm itself. And the facing logic is another tool that's available to them while implementing that.

@@ -0,0 +1,53 @@
package com.frc2713.mazesolver;

/** One square of a {@link GridMaze}. Wall flags come from the cell's bitmask. */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really like the bitmask implementation, but im concerned its too complicated for students to conceptualize the Maze object and interface with it. What if we just give cells a boolean list of length 4 where index 0 is true if there's an UP wall, index 1 is true if theres a Down wall, etc? Basically the same as a binary number/bitmask but a bit more obvious when looking at code.

To help with readability, when we are providing actual Java code of a maze, we keep the number of rows and columns low.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They won't see the bitmask ever.

Address the PR review by splitting the dense single maze lesson into a sequence
and moving to the maze-solver library's real interactive API.

- Delete the maze-engine shim (jar, build script, sources, ENGINE_JAR classpath
  entry); GridMaze/Robot/Cell/Direction now come from maze-solver.jar itself.
- Retarget the harness, the solver: java starter, and "Copy for Java" to the
  new API: readWallSensor(Direction)/drive(Direction)/facing(), with Direction
  turns for the wall follower.
- Lessons: trim "Navigating a maze" (195) to the visual concept, and add
  algorithms-maze-data (196, 2D arrays), algorithms-robot-api (197, reading the
  API + writing tryMove), and algorithms-maze-solver (198, the wall follower +
  the round-trip playground). Java snippets use a small 5x5 maze.
- Update docs/maze-roundtrip.md and CLAUDE.md.

Requires FRC2713/maze-solver-java branch maze-interactive-api to be merged so CI
builds a matching jar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tytremblay
tytremblay changed the base branch from lesson-ordering to main August 2, 2026 18:15
@tytremblay
tytremblay merged commit 3f3b48d into main Aug 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants