Maze module: generator playground, wall-follower, and maze-solver integration - #21
Conversation
…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>
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. |
There was a problem hiding this comment.
I dont think we introduce 2D arrays yet, might be worth a quick lesson as a pre-cursor
| } | ||
| } | ||
|
|
||
| // Move one step in an absolute direction if that side is open; report |
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
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)
| 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}, |
There was a problem hiding this comment.
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.
| 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; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
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. */ | |||
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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>
Adds a new lesson 35 "Navigating a maze" and the tooling behind it, plus the plumbing to run the team's
maze-solver-javalibrary in the browser. Also carries the in-flight lessons ordering refactor + module docs that were already in the working tree.Maze playground (
MazePlayground.tsx)maze-generatornpm package'sshuffleis broken — it returns before ever callingMath.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.)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/CellAPI (no bitmasks).Site wiring
```mazefence (lessons.ts+LessonView.tsx), with asolver:directive to reveal the wall-follower button.maze-solver.jaradded to the CheerpJ classpath (javaRuntime.ts).deploy-pages.yml) builds the jar fresh frommaze-solver-java@mainon each deploy;scripts/vendor-maze-solver.sh+npm run vendor:maze-solverdo the same locally. The jar is gitignored, never committed (unlike the frozentools.jar).Also included (pre-existing working-tree changes)
lessons/01..34.CONTEXT.mdglossary,docs/adr/0001-derive-lesson-order-from-position.md,docs/handoffs/ordering-refactor.md..claude/settings.jsonenabling the team skills plugin.Depends on
GridMazeimplementation. Until the jar hasGridMaze, the final lesson page's snippet won't run — everything else works. Verified: site builds, jar loads on the classpath, lint clean; the wall-follower algorithm is verified by simulation (214 steps on the embedded maze).🤖 Generated with Claude Code