gridworld.online
# grid_world: first frames
grid_world is a world that runs on its own, in real time. Your program connects over a websocket, is
given one character, is told what that character sees, and sends orders. What the program does
with that is up to you: fixed rules, a language model, or a person typing.
You do not need to run anything but your own program. The world is already running at
`wss://gridworld.online/demo`. It needs no account, and each connection gets a world of its own that
stops when you leave. The server keeps a log of the messages sent to and from the demo, including
anything a character says, so that the world can be tested and fixed.
## Glossary
- **World:** one map with its characters. Your connection gets its own.
- **Character (player):** the body you control. The wire calls it your `player`.
- **Observation:** everything your character knows now: what it sees, what it carries, where it is.
- **Update:** twice a second the world sends what changed, as a JSON Merge Patch (RFC 7386) of the
observation. A key set to `null` is gone; anything else replaces or merges.
- **Order:** one thing to do, such as `{"task": "rest"}`. Your character does one order at a time.
- **NAC:** a non-agent character, a mind made of fixed rules and no language model.
## Why it works like this
The world does not wait for you. It runs 20 ticks a second whether or not your program has
answered. The server also does not think for you: it does not sort what you see, measure
distances or plan paths. Those are your program's job, and the example client shows a first
small answer to each. The full rules are at `/protocol`, and every setting at `/rules`.
## First frames
Connect to `wss://gridworld.online/demo` and the server speaks first. The first message is the
`world` message. Its `first` field holds your character's whole observation, and its `t` is the
world's tick. Then an `update` arrives twice a second, with the tick in `t` and, for your character,
only what changed (nothing: it is left out). To send an order, send one line of JSON:
{"protocol": 1, "type": "order", "player": "player", "order": {"task": "rest"}, "seq": 1}
The next update says in `last_order` how the order went. The `/observation.schema.json` page
describes the observation. The 20 lines of Python below do exactly this; to see every message
as it goes by, run the example client with `python client.py --seconds 10`.
## The same in 20 lines of Python
Install the one package it needs with `pip install websockets`, then save and run this:
```python
import asyncio
import json
from websockets.asyncio.client import connect
async def main():
async with connect("wss://gridworld.online/demo", max_size=2 ** 24) as ws:
world = json.loads(await ws.recv())
print(world["type"], "- you are", list(world["first"]))
order = {"protocol": 1, "type": "order", "player": "player", "order": {"task": "rest"}, "seq": 1}
await ws.send(json.dumps(order))
update = json.loads(await ws.recv())
patch = update["players"].get("player", {}).get("obs", {}) # a player with no change is left out
print(update["type"], "- tick", update["t"], "- last order:", patch.get("last_order"))
asyncio.run(main())
```
It prints the `world` message's type and your character's name, sends a `rest` order and prints
the next update.
## Going on
Download `/client.zip`, or read the files one by one under `/client/`. They need only Python and
`websockets`, and each is short and made to be changed:
- `client.py` is the wire: connect, merge updates, keep the observation, send orders, record every
message. Run `python client.py --seconds 10` to see it play.
- `see.py` reads what the character sees: blocks, loose items, trees, distances.
- `walk.py` plans a path (breadth-first search). The server wants your path in the order, so this
is the file to replace with something better.
- `nac.py` is a NAC: it picks up two logs and a stone, crafts an axe and rests.
- `picker.py` is a mind that asks a language model to pick from numbered choices. It uses Ollama on
your own machine, and it is optional: nothing else needs a model.
To set it up: install Ollama from ollama.com, run it, then `ollama pull qwen2.5:3b` (the model the
examples are built against). If Ollama is not running or the model is missing, `picker.py` prints
that command.
Run the NAC against the public world with `python client.py`, or the model with
`python client.py --mind llm`.