How to play
Write a program that steers a fleet of Grocery Bots to deliver orders. Everything you need to connect a bot and understand your score is on this page.
-
Your bot sees the store
Every round your program receives the shelves, robots and trucks with their orders as JSON. The CLI handles the connection. Any language works.
-
It moves every robot
Move, pick up, load or wait: one action per robot per round. Robots carry three items and block each other in the aisles.
-
Every loaded item scores
One point for each item loaded into a truck, five more for each full truck. Score as much as you can within the round and time limits.
The game
A fixed dark store on a grid: refrigerated dairy cabinets, bakery racks, produce bins, pantry shelves and loading bays in the back wall. Each product has its own local section. Each docked truck carries one online order, so several orders are open at once and you decide which truck each robot serves.
- Each round
- Your bot receives the full store state and replies with one action per robot: move, pick up, load or wait.
- Robots
- Carry up to three items. Pick up from an adjacent shelf; shelves never run out. Robots block each other except at the spawn, and moves resolve in robot ID order. There is no way to discard an item, so a wrong pick keeps its slot until an order needs it.
- Loading
- From the three cells in front of a bay, a robot loads every item that truck’s order still needs with
load. A full truck leaves and returns with a new order, which you can see while it is away. Each trip draws a new away time: 6–10 rounds on Easy, 7–13 on Medium and Hard, 12–20 on Expert, and 15–25 on Nightmare. Leaving and arriving take one round each. Once it leaves,rounds_until_backshows the exact return countdown. - Score
- 1 point per loaded item, awarded immediately even if the truck is not full, and 5 more when its order is complete.
- Time
- 300 rounds (500 on Nightmare), with a total time limit of 2 minutes (5 on Nightmare). The server must receive each reply within its 2-second response window; leave margin for network latency. If you miss a reply, all robots wait that round and the game continues. A disconnect ends the game.
| Store | Grid | Robots | Trucks | Products | Items per order |
|---|---|---|---|---|---|
| Easy | 12 × 10 | 1 | 2 | 4 | 3–4 |
| Medium | 16 × 12 | 3 | 3 | 8 | 3–5 |
| Hard | 22 × 14 | 5 | 3 | 12 | 3–5 |
| Expert | 28 × 18 | 10 | 4 | 16 | 4–6 |
| Nightmare | 30 × 18 | 20 | 6 | 21 | 4–7 |
Build and run your bot
Install the CLI, or copy the setup prompt for your AI assistant. The installer works on macOS, Linux and Windows with WSL, and requires Python 3.11 or newer.
curl -fsSL https://grocerybot.no/static/install.sh | sh
Create your bot project, log in and play:
grocerybot init my-bot
cd my-bot
grocerybot login
grocerybot play --store easy
This creates a Python bot. For JavaScript, use grocerybot init my-bot --template javascript with Node.js installed. The generated PROTOCOL.md explains the JSON messages and actions.
Login opens your browser for your NM i AI account. Approve the CLI, then follow any remaining prompts in your terminal to choose your leaderboard name. The CLI saves its own credential; you do not need to copy an API key.
The play command starts one game. See your best scores and recent games on your account page, or use grocerybot games list. To inspect a game recorded on this computer, run grocerybot replay latest.
If you write your own WebSocket connection, the protocol reference explains how to connect with the API key from your account.
Scores and limits
- Every store and its product locations are fixed. Orders and truck trip times vary. Games submitted to the leaderboard use a private scenario chosen by the server; you cannot select its seed.
- Your best game score in each difficulty counts. Your total is the sum of your five best scores. A lower score in a later game will not reduce your best score or total.
- Games ended by a time limit or disconnect keep the score earned so far. Games voided because of a server error do not affect your best scores or daily limit.
- Play one game at a time per account, with up to 50 games per day. The daily limit resets at midnight in Oslo.
- Equal totals share the same rank.
- There is no scheduled end date. Games may be paused for maintenance.
Errors
The CLI explains errors in the terminal. If you connect directly over WebSocket, check the close code and reason:
| Code | Meaning |
|---|---|
| 4001 | Invalid, expired or revoked credential. Log in again, or check your API key. |
| 4002 | Unknown difficulty |
| 4003 | Daily game limit reached. It resets at midnight in Oslo. |
| 4004 | Server at capacity, try again shortly |
| HTTP 403 | Browser origin not allowed; the connection is refused before a WebSocket opens. |
| 4006 | Unsupported protocol, changed ruleset or invalid run ID. Check the reason; update the CLI if needed. |
| 4008 | This run already exists. Look up its result instead of starting it again. |
| 4009 | You already have a game running. Wait for it to finish. |
| 4010 | Games are unavailable or paused. Please try again later. |
| 1011 | Could not start the game or confirm its result. Check your game history before trying again. |
Fair play
- One account per person. Play individually: one account, one leaderboard entry.
- Any method and any language are welcome: search, optimisation, learning, AI coding assistants.
- Keep your credentials private. Creating a new API key disables the old API key immediately. Don’t try to overload or break the server.
- We may void games or remove entries that break these rules.