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`.