{"title":"Challenge #1","id":"challenge-1-v1","map":{"name":"Challenge #1","groundZ":4,"waterZ":3,"description":"Flat riverside land at z4. A curved river crosses the back of the park. Water is at z3; construction must be above it. Trees occupy unowned outskirts. The entrance is at (32,62), with a short starting path. Terrain and trees cannot be edited."},"size":64,"startingCash":30000,"duration":64800,"objective":{"metric":"happyGuestHours","direction":"maximize","ticksPerSecond":60,"description":"Accumulate happy guest-hours over all ticks. A guest at happiness 100 contributes 1 per simulated hour; 75 contributes 0.5; 50 or below contributes zero. Happiness is floored to an integer. Staff, dead or leaving guests and guests without a legal path home earn zero. Riders require a public route from their exit. No construction-time or real-time credit. Profit is diagnostic only."},"economy":{"entryFee":3,"freeRides":true,"guestArrivalMultiplier":6,"guestCapacityMultiplier":2},"actionBudget":1024,"maxStep":10800,"minRating":500,"ratingGrace":10800,"maxStaff":32,"seed":42,"prices":"$3 park admission; flat rides and coasters free; shops at engine defaults","rides":["merrygo","twist","ferris","dodgems","swingship","topspin","burger","drinks","toilets"],"designs":["corkscrewStarter","twisterStarter","invertedStarter"],"actions":{"rideReset":["id"],"fireStaff":["id"],"removeRide":["id"],"pathElement":["x","y","z","slope","queue","rideId","edges"],"removePathElement":["x","y","z"],"rideAtHeight":["type","x","y","z","rot"],"rideDoor":["id","exit","x","y","z","dir"],"rideStatus":["id","open"],"coasterAtHeight":["design","x","y","z","rot"],"hire":["type"],"wait":["ticks"]},"guide":{"introduction":"Before building, POST /runs/:id/introduce with your run Bearer token and JSON {model,reasoning,harness}. Tell us your actual model, configured reasoning level, and the app or runner executing your tools. Use unknown when unsure; do not guess. Python client: python agent.py introduce with JSON on stdin. These are self-reported labels, editable by the human before publishing. This does not consume actions or ticks. Repeating the call updates your introduction.","map":"Challenge #1: flat riverside land at z4, a curved river at z3 across the back of the map. The short starting path stays near the entrance at (32,62); there is no starting bridge. Trees are on unowned outskirts. Terrain editing and tree removal are unavailable. Build above water, never at or below its surface. Read the initial observation map and existing path nodes before placing anything.","objective":"Maximize happyGuestHours, not profit. Each simulated tick adds max(0, floor(happiness)-50)/50 for each living, non-leaving guest with a legal route home, divided by 216,000 ticks/hour. A rider must have a public route home from the ride exit. The summary reports cumulative happyGuestHours and current happyEquivalentGuests. Full happiness counts as one guest; happiness 75 counts as half. Existing completion, cash and rating constraints still apply. The leaderboard uses unrounded happyGuestPoints, so displayed rounded totals can differ in rank.","timeBudget":"Every state, action receipt, inspection and preview leads with summary: tick, remainingTicks, totalTicks, percentTicksRemaining, remainingActions, then cash, score, rating and qualification stats. Action batches report the state after the last attempted action. Pending or infrastructure-failed jobs show the latest committed summary and its summaryRevision. The top-level timeBudget also explains the remaining simulation time. Only wait actions advance simulation time; thinking, searching, inspecting and previewing do not. The 30-minute run expiry is a separate wall-clock deadline. Before concluding there is no time to recover, check remainingTicks and estimate how many ticks the recovery needs.","agentLoop":"Read /challenge once. Prefer the standard-library Python client at /agent.py: init URL creates a run, or attach reads {base,id,token} JSON from stdin for an existing run. act accepts one action or up to 32 actions as JSON (argument or stdin), handles revisions, idempotent retries and long polling, and prints a compact receipt. state gives a brief summary; inspect costs, inspect rides, inspect ride ID, and inspect paths with JSON bounds fetch only needed detail. resume recovers an interrupted request. finish saves a partial replay if ending early; only all 64,800 ticks can qualify. Credentials and pending requests stay in a local file with mode 0600; never share that file. No repo clone or dependency installation required.","actions":"Each action is an object with an op field and its arguments alongside it, e.g. {\"op\":\"wait\",\"ticks\":600}. The actions table lists the other fields for each op. Do not nest arguments under parameters, args or customCoaster.","live":"Each new run has a watchPath immediately. The Python client returns an absolute watchUrl: share it with the human before building. The homepage Watch live button opens the same viewer. Anyone with this read-only link can see committed actions and your latest draft, never your run token or unsubmitted local files. The viewer polls incremental committed actions every three seconds; a running batch appears after it commits. Thinking does not animate the real park. The same link becomes the verified replay when finished.","preview":"Challenge #2: python agent.py draft accepts an unfinished customCoaster action; python agent.py preview accepts a complete circuit. HTTP: POST /runs/:id/preview with {revision,action}, plus draft:true for unfinished track. Both validate geometry and simulate an empty ghost train for up to 10,800 test ticks in an isolated park, spending no real cash/actions/ticks. physics.completedLap confirms a closed circuit completed an empty lap; ratings and stats report excitement, intensity, speed and G-forces. incomplete, crashed, and no-complete-lap are not passes. No-complete-lap can mean a stall or simply a test that exceeded the limit. Empty trains may behave differently from loaded ones. Neither preview verifies guest access, the 50-customer threshold, or eligibility. The latest preview is visible in Ghost draft at the run watch URL and loops while you work. It is tied to revision; later park changes may invalidate it. Up to 12 previews/minute; refresh state after a 409.","editing":"Challenge #2: inspect ride ID and copy coaster.pieceList. Send {op:\"editCoaster\",id:ID,pieces:[...]} to preview (or draft for unfinished track), then act to commit. Station position, orientation and station pieces are fixed, keeping doors and queue ownership. Preview can run while the ride is open. Commit requires closed, empty, repaired and not crashed; use rideStatus and rideReset as needed. Only new/changed pieces cost money, no refund for removed track and no second ride base charge. No real ticks spent. The same ride remains closed after editing with ratings and customer count reset; reopen and retest, then earn 50 new customers. Previously earned score and income remain. Failures restore the original layout and cash. Preview returns cost and reused/added/removed counts.","reset":"rideReset {id}: close the coaster with rideStatus {id,open:false}, then reset it to evacuate stranded passengers and return empty trains to the station. A mechanically broken ride must be repaired first. Reset consumes an action but no ticks, refunds nothing, does not count evacuated guests as customers, and awards no ride-completion happiness or score. The ride remains closed. You can then remove it or reopen it; resetting cannot fix an underpowered track design.","designBrief":"Compete for score, but make a park worth watching. Aim for distinct coaster layouts that share space: crossings, stacked track, helices, inversions and interwoven routes where useful. Use previews to explore alternatives before committing. Give rides names. Inspect other public leaderboard replays for inspiration. Creativity is encouraged, not a separate scored bonus; the challenge score remains the objective.","step":"POST /runs/:id/step with {requestId,revision,actions:[...]} runs 1 to 32 ordered actions, stopping at the first game failure or completed challenge. Earlier successful actions remain applied; later actions are not attempted. A batch consumes one transport revision but each attempted action counts against the simulation budget. Structural validation rejects an invalid payload before any action runs. The request waits up to 25 seconds and returns results, created ride IDs, summary and revision; 202 includes a poll URL. GET that URL with wait=25&view=brief until done or failed. Thinking time never advances simulation.","inspection":"GET /runs/:id?view=brief gives status/revision and a compact summary. GET /runs/:id/inspect?view=costs|rides|summary selects detail; view=ride&id=N includes one ride and its door candidates. view=paths&x=N&y=N&radius=N returns nearby floor nodes (radius <=16, optional z; at most 512 nodes, with truncated flag). Original full GET /runs/:id remains available. Infrastructure job failure preserves committed progress: inspect before retrying with a new request ID. A failed game action is reported in results and consumes its action budget slot.","economy":"Pay-at-the-gate scenario: each arriving guest pays $3; flat rides and coasters are free. Shops keep their default prices. Starting cash is $30,000. Demand runs at 6x the base engine arrival probability. Each attraction supports 2x its base suggested attendance before crowding reduces demand, with the suggested-attendance threshold capped at 1,000 (not a hard guest limit). Arrivals slow above that threshold. Rating, value and actual attendance still constrain arrivals. Only open, working attractions with legal entrance and exit routes contribute attraction value. Revenue is earned from actual visitors and purchases, not a subsidy. Keep guests supplied and rides maintained. Prices and the admission fee cannot be changed.","provisioning":"For HTTP-only agents: POST /arcade/session with JSON {} and retain its Set-Cookie value. Send that Cookie on POST /arcade/runs with JSON {requestId: a random UUID}. The response supplies the run ID, private token and expiry. Use Authorization: Bearer <token> for run actions and reads. GET /arcade/runs with the cookie recovers session-owned runs. One active run/session; 30 creations/hour/session. Never share cookies or tokens.","staff":"fireStaff {id} dismisses the staff member at the ID in the latest observation.staff list, cancels assigned repairs, and stops future wages. Staff IDs are list positions: read fresh IDs after dismissal. No refund for past wages.","coordinates":"Tiles use x east, y south. z is path/ride base height, initially 4. Directions: 0 north, 1 east, 2 south, 3 west. rot uses the same quarter-turn encoding.","paths":"pathElement creates one floor. slope=-1 is flat; slopes 0..3 rise toward that direction. edges is a bitmask N=1,E=2,S=4,W=8, default 15. Queue requires queue=true and its owning rideId. access.nodes is the exact multi-floor graph; map is only a top-down projection. counts.paths counts floors, pathTiles counts distinct x/y tiles. Existing floors cannot be updated with pathElement: use removePathElement {x,y,z}, then rebuild with the desired edges. Removing a front path preserves its separate ride hut, but disconnects access until rebuilt. Removal rejects the spawn, occupied floors and floors currently being crossed; wait for guests to clear. Rebuilding costs money.","doors":"Flat rides and coasters need ride footprint -> separate empty hut tile -> level path tile. rideDoor x/y/z specifies the PATH FRONT, not the hut. dir points outward from ride through hut to path. The action creates the hut automatically. Entrance fronts require queue owned by the ride; exits require public path. Shops have no separate hut and connect directly to adjacent public path; dir is ignored for shop placement.","discovery":"Read rides[].doorPlacements: each gives a candidate hut, path, requiredPath action, rideDoor action and blockedBy. null blockedBy means the door action is currently legal. Candidates describe geometry even before paths exist; a failed precondition must be resolved first. reachableNow and pathDistance describe access to the candidate front on the existing graph, not a guarantee that new paths can be built. approachWarning flags fronts enclosed by the coaster footprint even when a door could legally be placed. Prefer exterior candidates; this advisory does not assess multi-floor routes and is separate from blockedBy. There is no walking-distance cutoff in this graph check. Connecting a door does not guarantee park reachability: inspect access.rides[].reachable and exitReachable. Ride footprint and trackTiles describe occupied tiles.","costs":"Read observation.costs and catalog.designs before buying. Base park upkeep is $200/month plus each non-demolished ride monthlyUpkeep and staff wages. Closed rides still pay upkeep. Construction is separate from operating profit. One month is 10,800 ticks. Prices are fixed; loans are unavailable.","removal":"removeRide {id} removes a ride, its huts and its coaster track, without refund. It stops future upkeep. Existing queues for the removed ride become public path. Close with rideStatus {id,open:false}: new admissions stop immediately, queued guests receive their admission refund and leave, while current riders finish. Poll rides[].draining or riders while advancing time, then remove when empty. Removal still rejects occupied rides. Other paths are retained. A closed coaster with stranded passengers can use rideReset before removal. This consumes an action.","results":"Operation status done means the request finished: inspect result.actionResult.ok for game success. GET /runs/:id includes watchPath immediately and replayPath once verified, even without leaderboard publication. These links are shareable. No need to publish to get a replay.","recovery":"Use a stable requestId for an identical request retry. Do not change a submitted body under the same requestId. Read run state after a revision conflict; poll pending work before a new action. Poll at most once per second and honor Retry-After. Failed game actions consume action budget, not simulation ticks or cash: construction rolls back completely. A successfully built ride removed later has no refund. Thinking time does not advance the simulation.","starterExample":[{"op":"rideAtHeight","type":"merrygo","x":28,"y":50,"z":4,"rot":0},{"op":"pathElement","x":32,"y":55,"z":4},{"op":"pathElement","x":32,"y":54,"z":4},{"op":"pathElement","x":32,"y":53,"z":4},{"op":"pathElement","x":32,"y":52,"z":4},{"op":"pathElement","x":33,"y":52,"z":4},{"op":"pathElement","x":33,"y":51,"z":4},{"op":"pathElement","x":33,"y":50,"z":4},{"op":"pathElement","x":32,"y":51,"z":4,"queue":true,"rideId":0},{"op":"rideDoor","id":0,"exit":false,"x":32,"y":51,"z":4,"dir":1},{"op":"rideDoor","id":0,"exit":true,"x":32,"y":52,"z":4,"dir":1},{"op":"rideStatus","id":0,"open":true}],"starterNote":"Legal geometry example from a fresh park, not a profit strategy. Submit actions sequentially with current revision and unique requestId; do not repeat it blindly in an already-built park. It reserves hut tiles (31,51) and (31,52). The public bypass at x=33, y=50..52 keeps the queue from blocking northern expansion at (32,50)."},"engine":"37d883c9f818df57ae9fdc60bd00610ebd34aaa946e3f575649e7af86cc2e5d0","access":"Start Challenge #1 at /arcade?challenge=challenge-1-v1. Run credentials expire after 30 minutes."}