Wanderland

Wanderland Core: Game Engine

Session management, blank-filling, and scoring for the scenario learning game. Extracted from Crossing::Game::Engine, made operation-agnostic.

What It Does

The game engine doesn't know what it's testing. It knows:

Phases

MENU → BROWSE → PLAY → RESULT
  ↑                       |
  └───────────────────────┘

Session Flow

engine = Wanderland::Game::Engine.new("spec/scenarios/")

# Menu auto-generated from registered boundaries
engine.menu_items
# [{ key: :all, label: "All Scenarios", desc: "Play through everything" },
#  { key: :route_match, label: "Route match", desc: "7 scenarios" },
#  { key: :middleware_walk, label: "Middleware walk", desc: "4 scenarios" }]

engine.select_operation!   # picks current menu item
engine.play!               # enter blank-filling mode

# Fill blanks
engine.current_blank       # "slug_value"
engine.answer_blank!("sprout-api")
engine.current_blank       # "layout"
engine.answer_blank!("node-view")

# Auto-checks when all blanks filled
engine.result
# { results: [...], score: { correct: 2, total: 2, percentage: 100.0 } }
engine.phase               # :result

# Navigate
engine.next_scenario!
engine.play!

Board Generation

The board is the scenario YAML with blank answers replaced by <____:key> markers:

engine.board
# ---
# name: parameter extraction from path
# description: |
#   The route pattern /node/:slug has one dynamic segment...
# expected:
#   matched: true
#   params:
#     slug: "<____:slug_value>"
#   route:
#     layout: "<____:layout>"

Emacs renders this in a yaml-mode buffer. The player navigates between <____> markers and fills them in.

Skip

engine.skip!
# Shows correct answers without scoring
# { skipped: true, results: [{ blank: "slug_value", expected: "sprout-api", actual: "sprout-api" }] }

Game Logging

Every completed scenario (pass or fail) is logged to ~/.local/share/wanderland/games/ as YAML:

20260401-212617_route_match_a1b2c3d4.yaml

Contains timestamp, session ID, scenario name, player answers, scoring, engine output.

API Integration

The game engine is the backend for:

All three talk to the same engine instance. The API is just JSON wrappers around engine.play!, engine.answer_blank!, engine.board, etc.