Robot Playtester: Let an AI Agent Play Your Text Adventure and Report Where It Got Stuck
Intermediate2–4 hoursText adventures with agents
Description
Parser text adventures die on one thing: the player knows what to do but the game doesn't understand how they said it. Build a tiny text adventure engine that loads a world from JSON, then point an AI agent at it as a blind playtester. The agent only sees what a human would see, types commands, and keeps playing until it wins or gives up. Afterwards you get a playtest report: every command the parser rejected, the rooms where it wandered in circles, the puzzle that took the most turns, and suggested synonyms and hints to fix it. Run it again after your fixes and watch the turns-to-win number drop.
Starter Prompt
Build "Robot Playtester", a browser tool with two halves: a small parser text adventure engine and an AI agent that playtests games made with it. Single index.html plus engine.js, playtester.js, report.js and style.css, vanilla JS, no build step, no frameworks, no server. It must be fully usable with NO API key thanks to a built-in offline playtester (see below).
Part 1: the engine (engine.js, pure and deterministic, no DOM access)
- A world is a JSON file: rooms (id, name, description, exits like {"north": "hall"}, items), items (id, names/aliases, description, portable, use rules), locked exits (requires item or flag), flags, a win condition and an optional turn limit.
- Ship a demo world, "The Overdue Library": 6-8 rooms, about 8 items, 3 chained puzzles (e.g. find a stamp to get a library card, use the card to borrow a ladder key, climb to the rare-books shelf). Deliberately leave 3 rough edges in the demo so the playtester has something to find: an item that only answers to an odd noun, a verb the parser doesn't know ("climb" works but "go up" doesn't), and a clue that's only in one room description.
- Parser: verb + optional noun + optional preposition phrase. Verbs: look, examine/x, go/n/s/e/w/u/d, take/get, drop, inventory/i, open, unlock ... with ..., use ... on ..., read, talk, help. Matches item aliases. Unknown input returns a typed failure: {ok:false, reason: "unknown_verb" | "unknown_noun" | "not_here" | "locked" | "cant_do_that", text}.
- API: createGame(world, seed) -> state; step(state, command) -> {state, output, ok, reason, events}. Same seed + same commands always gives the same transcript.
- A manual "Play" tab so a human can play the world in a terminal-style view.
Part 2: the playtester (playtester.js)
- The agent sees ONLY the game's output text and its own notes: never the world JSON. Each turn it returns JSON: {"thought": "...", "command": "...", "notes": "updated short memory of map, items, open goals"}. Validate the JSON; on bad output retry once, then count it as a wasted turn.
- LLM mode: user pastes an API key for an OpenAI-compatible chat completions endpoint (base URL + model fields, key kept in memory only, never in localStorage). System prompt: you are a first-time player, be curious, try natural phrasings first, don't brute-force every verb on every noun.
- Offline mode (default, no key): a heuristic bot that explores exits breadth-first, examines every noun it sees mentioned in descriptions, tries take/use/open on them, and tries 2-3 phrasings for each idea (e.g. "go up", "climb", "climb ladder"). Seeded so runs are reproducible.
- Controls: run with turn budget (default 150), step one turn, pause, speed slider, run N times with different seeds. Live transcript with the agent's "thought" shown dimmed above each command.
Part 3: the playtest report (report.js)
- Outcome: won or not, turns used, wasted turns, puzzles solved in order with the turn each was solved.
- Rejected commands grouped by reason with counts, e.g. "unknown_verb: 'go up' x4, 'search' x3". Highlight phrasings that failed and were later succeeded with a different phrasing (the strongest signal of a parser gap).
- Loop detector: rooms revisited many times without new progress, shown on a simple auto-laid-out map (rooms as boxes, exits as lines, colored by visits).
- Stuck points: the longest stretch of turns without a new flag or item, and what the agent's notes said during it.
- Suggestions, generated by rules (and by the LLM in LLM mode): add alias X for item Y, add verb synonym, add a hint near the stuck point. A "Apply suggested aliases" button patches the world JSON in memory so you can re-run and compare.
- Compare view: two runs side by side (turns to win, rejected commands, stuck time), before and after fixes.
- Export: the world JSON (patched), the full transcript as .txt and the report as Markdown.
Quality bar: no console errors, the engine has a tests.html with at least 15 assertions (parser cases, locked doors, win condition, determinism), the offline playtester wins the demo world within 150 turns after the suggested fixes are applied, and total code under ~1200 lines.
When done, explain how you kept the agent blind to the world data, list the three parser gaps the playtester found in the demo, show before/after turns-to-win, and describe one thing an LLM playtester caught that the offline bot didn't (or vice versa).Success Criteria
- The demo world is winnable by a human in the Play tab, and the engine is deterministic: the same seed and commands always produce the same transcript.
- The playtester never reads the world JSON; it plays only from game output and its own notes, and works offline with no API key.
- The report finds all three planted rough edges in the demo world (odd item noun, missing verb synonym, hidden clue) and suggests a concrete fix for each.
- After applying suggested aliases and re-running, the compare view shows fewer rejected commands and fewer turns to win.
- Transcript, patched world JSON and Markdown report export correctly.
Optional Extensions
- Persona playtesters: run a "speedrunner", a "confused newcomer" and a "completionist" prompt on the same world and compare where each struggles.
- Let the agent write the bug report as GitHub-issue-ready Markdown with repro steps (seed + command list).
- Add an "author mode" where a second agent proposes a new puzzle, inserts it into the world, and the playtester checks it's still winnable.
- Headless Node runner that playtests every world file in a folder in CI and fails if any world becomes unwinnable.