Documentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/treasure-hunt-game/llms.txt
Use this file to discover all available pages before exploring further.
q-agent.js defines the AI opponent that races the player through the maze. It exports two items: a DIFFICULTY_SETTINGS configuration object that controls how fast and how smart the agent plays, and a CompetitiveAgent class that combines BFS pathfinding with probabilistic exploration and hesitation to produce behavior that genuinely varies by difficulty level. The module imports findShortestPath, ACTION_DELTAS, ACTION_NAMES, and key from treasure-maze.js — it has no other dependencies.
DIFFICULTY_SETTINGS
DIFFICULTY_SETTINGS is a plain object keyed by difficulty name. Each entry contains six properties that CompetitiveAgent and app.js read to control timing and decision-making.
Property Reference
| Property | Type | Description |
|---|---|---|
label | string | Display name shown in the HUD. |
moveDelay | number (ms) | Interval between agent moves once the race starts. |
startDelay | number (ms) | Delay before the agent takes its first move after the race begins. |
mistakeRate | number (0–1) | Probability per move that the agent uses chooseExplorationMove instead of choosePolicyMove. |
hesitateRate | number (0–1) | Probability per move that the agent skips the turn entirely (returns current snapshot without moving). |
description | string | Narrative description shown below the difficulty selector in the UI. |
Values by Difficulty
| Property | Easy | Medium | Hard |
|---|---|---|---|
label | "Easy" | "Medium" | "Hard" |
moveDelay | 1150 ms | 780 ms | 470 ms |
startDelay | 1600 ms | 900 ms | 350 ms |
mistakeRate | 0.42 | 0.18 | 0 |
hesitateRate | 0.2 | 0.08 | 0 |
description | "The agent explores more, hesitates sometimes, and gives the player a head start." | "The agent usually follows the learned route but still makes occasional exploration choices." | "The agent exploits the optimal path aggressively and rarely gives the player breathing room." |
On Hard difficulty
mistakeRate and hesitateRate are both 0, meaning the agent always follows the BFS-optimal path and never skips a turn. It is effectively unbeatable on a short maze unless the player already knows the route.CompetitiveAgent Class
CompetitiveAgent is the AI opponent. On every call to move(), it decides whether to hesitate, whether to explore a random open cell, or whether to follow the BFS-shortest path to the treasure. It tracks its own position, visited trail, and step count independently of the TreasureMaze environment.
Constructor
The 8×8 grid. Must be the same maze the
TreasureMaze environment is using.One of
"easy", "medium", or "hard". Controls which DIFFICULTY_SETTINGS entry is loaded.The agent’s starting position. Also used as the initial key in
trail.The treasure cell the agent is racing toward.
configure() internally, so every property listed below is set on construction.
Properties
| Property | Type | Description |
|---|---|---|
maze | number[][] | The maze grid passed to the constructor. |
difficulty | string | Active difficulty name ("easy", "medium", or "hard"). |
settings | object | The active DIFFICULTY_SETTINGS entry. Falls back to medium for unknown keys. |
position | [number, number] | The agent’s current [row, col]. |
target | [number, number] | The treasure cell [row, col]. |
trail | Set<string> | All cell keys the agent has visited, including the start. |
steps | number | Total number of successful moves taken (hesitations don’t count). |
lastMove | string | Human-readable description of the most recent action. Initialized to "waiting" on construction; updated to values such as "exploited right", "explored down", "hesitated", or "blocked" after each move() call. |
policy | { path, actions } | The most recently computed BFS result from choosePolicyMove(). |
Methods
configure({ maze, difficulty, start, target })
Resets the agent in-place with new parameters. Called by the constructor and by app.js when the difficulty selector changes. Returns this for chaining.
this
validActions(from?)
Returns all moves the agent can make from a given position — only moves that land on an open cell (1) inside the grid are included.
The cell to check from.
Array<{ action: number, row: number, col: number }> — each entry contains the action integer and the destination coordinates.
chooseExplorationMove()
Picks a random valid move, preferring unvisited cells. If all neighbors have already been visited, any valid neighbor is eligible.
Returns: { action: number, row: number, col: number } | null — null if there are no valid moves.
choosePolicyMove()
Recomputes the BFS shortest path from the current position to target, then returns the move that takes the agent to the next cell on that path.
Returns: { action: number, row: number, col: number } | null — null if no path exists or the agent is already at the target.
choosePolicyMove calls findShortestPath on every invocation. This keeps the policy fresh after exploration detours instead of following a stale path computed from the starting cell.move()
The main per-tick method called by app.js on the setInterval timer. Implements a three-level decision flow:
Hesitation check
Roll against
settings.hesitateRate. If the roll hits, set lastMove = "hesitated" and return the current snapshot without updating position or steps.Exploration vs. exploitation
Roll against
settings.mistakeRate. If the roll hits, call chooseExplorationMove(); otherwise call choosePolicyMove().Safe fallback
If the primary choice returns
null, fall back first to choosePolicyMove(), then to chooseExplorationMove(). If both return null, the agent is fully blocked — set lastMove = "blocked" and return snapshot.snapshot object (see below).
hasReachedTreasure()
Returns true if the agent’s current position matches target.
Returns: boolean
optimalPathLength()
Computes the BFS shortest path length from [0, 0] to target on the current maze. Note: this always starts from [0, 0], not from the agent’s current position — it reflects the theoretical minimum number of steps to solve the maze from scratch.
Returns: number — total cells in the BFS path (including start and end).
snapshot()
Returns a plain object capturing the agent’s current state. Called at the end of every move() call and by app.js inside render() via env.snapshot({ agent: agent.snapshot() }).
Returns: