HexSet implements a hex-tile trading and building game based on the rules of Settlers of Catan: a NumPy rules engine, heuristic bots, ONNX model inference, a browser interface, HTTP and MCP interfaces, Gymnasium and PettingZoo adapters, and batched environments for training and evaluation.
The engine covers resource production, construction, development cards, the robber, victory conditions and player trading. It owns the rules, information sets, encoding, game loops, seating and board pairing, records and replay, and trade evaluation. A training project supplies the model runtime and the learning algorithm through those interfaces; neural-network training and checkpoint export are maintained separately, in the sibling HexN project.
Games are hosted here even when the opponent comes from elsewhere: HexSet owns the rules, the legal actions and the ledger, and Catanatron is an external reference opponent seated at a HexSet table.
Start with guide.md; the rest are listed by name.
| Document | Contents |
|---|---|
| api.md | JSON routes, seat tokens, client identity and reclaim |
| evaluation.md | Designing a comparison, the intervals the runners report, experiment records |
| guide.md | Running games, bundled opponents, trade rounds, implementing a bot, records, bench commands |
| heximax.md | The built-in search bot: strength, search, evaluation, the move vector |
| hosted.md | A bot seat at a table hosted elsewhere: the observed game it plays forward |
| mcp.md | MCP tools and their semantics |
| onnx.md | The ONNX model contract, and checking a file against it |
| server.md | Running the server: configuration, Docker, saved games |
| testing.md | Markers, optional extras, what CI covers |
| trading.md | Trading's three parts: the table's rules, a gate's own TradeParams, the shared protocol |
| training.md | Batched collection, model runtimes, PettingZoo and Gymnasium adapters |
| worlds.md | Cached votes over sampled worlds |
Heximax is HexSet's built-in search bot and the default opponent. It uses a budgeted expectimax/max^n search over the seat's information set, with one fixed move vector and a separate evaluator pricing trades.
| Matchup | Heximax wins | Win rate (95% CI) |
|---|---|---|
| 2 player, variant | 678 / 800 | 84.75% (82.2-87.3%) |
| 2 player, standard | 619 / 800 | 77.38% (74.4-80.3%) |
| 4 player, 1 Heximax seat | 451 / 800 | 56.38% (53.1-59.6%) |
All games against Catanatron's depth-two alpha-beta player (AB2), hosted in
the HexSet engine as the catanatron preset seats it, at 0.99.0. The duel variant (rules.DUEL_VARIANT_GAME) is
colonist.io's ranked 1v1 format,
and it is a two-seat game type: a GameType carries the seat counts its
ruleset is played at, so the engine will not deal it to a four-seat table.
docs/heximax.md has the search, the evaluation terms, the
measurement conditions and the move vector.
It is also faster than the reference it beats. On one core, a four-player game of Heximax self-play takes 4.2 CPU-seconds; upstream Catanatron's AB2 playing itself in its own engine takes 28.9 -- about 7x faster at four players and 4x at two.
Rehex is a rules bot: one stated rule per decision, no search and no
weights. It places its settlements by the same opening value as Heximax (pips,
plus a little for each resource type and more for a scarce one), plays a win
its hand holds, builds whenever it can, saves for the
city or settlement it is closest to and banks the trade that completes it,
spends down a hand over the discard limit, and robs the public leader. It
trades one card for one at a price: a trade's share of a purchase, weighted by
what the purchase is worth, less a risk for each card given -- higher on its
own asks than on its answers, and answers discounted as the asker closes on
the win. It never trades with a seat that could be a point from winning, picks
the leader as a partner less as the leader closes in (a curve, its one seeded
draw), and does not trade at all at two seats. It reads only its own
information set and takes its thresholds from the game's Rules, so it plays
the standard game and the duel variant at two to four seats -- fast enough to
fill a training table, and a fixed point between AB2 and Heximax.
| Matchup | Rehex wins | Win rate (95% CI) |
|---|---|---|
| 2 player, variant | 686 / 800 | 85.75% (83.3-88.2%) |
| 2 player, standard | 564 / 800 | 70.50% (67.5-73.5%) |
| 4 player, 1 Rehex seat | 353 / 800 | 44.12% (40.7-47.5%) |
Against AB2 on Heximax's boards and seed, at 0.99.0, no unfinished games. Head to head in the duel variant, Heximax beats Rehex 454 / 800, 56.75% (53.9-59.6%).
| One core, self-play | CPU-seconds per game, 4 players | vs AB2 | 2 players | vs AB2 |
|---|---|---|---|---|
| AB2 (upstream Catanatron, its own engine) | 28.9 | 1x | 4.86 | 1x |
| Heximax | 4.20 | 7x | 1.14 | 4x |
| Rehex | 0.061 (16 games/s) | ~470x | 0.035 (28 games/s) | ~140x |
Rehex beats AB2 and plays a four-player game about 470 times faster. The AB2 row is Catanatron's engine, the others HexSet's, so each ratio is bot and engine together; standard rules, imports untimed.
Requires Python 3.11 or later. From the repository root:
pip install -e .The base installation requires only NumPy. Install extras for the interfaces you use:
| Extra | Provides |
|---|---|
.[server] |
ONNX Runtime for embedded model opponents; Heximax needs only the base install |
.[clients] |
ONNX Runtime for standalone model clients |
.[gym] |
Gymnasium and PettingZoo environments |
.[catanatron] |
Catanatron integration, pinned to a specific Git commit |
.[export] |
ONNX and ONNX Runtime libraries; no training or export command is included |
.[test] |
pytest |
Extras can be combined, for example pip install -e ".[server,gym,test]".
python -m hexset.server.webThe server opens a browser at http://127.0.0.1:8770. Share a game's URL to
invite other players. Each new game starts with its creator seated and the
remaining seats open. Fill them with people or bots, or close unused seats
with the picker's none option. Play waits until every seat is filled or
closed. Closed seats can be reopened before the first move; the participating
seats are fixed once play starts.
The opponent picker lists heximax, rehex, catanatron when its extra is installed,
and the models found in models/. A compatible .onnx file dropped there
appears in the next listing under its filename stem; the requirements are the
ONNX model contract.
The trade modal supports bank and port trades, offers to other players, and responses to their offers. How many cards a player trade moves is each seat's own declared limit — a manual seat is bounded only by the cards it holds. A bot makes as many offers a turn as its own gate asks for and waits for manual seats to answer before continuing. A seat with no resource cards passes automatically.
Games have a public spectator view that reveals all hands, development cards, and victory points. Anyone with the game URL can access it, including players at that table. Seat-specific responses filter hidden information, but the public view means a server game does not enforce secrecy between participants.
Running it anywhere but a local default -- ports, Docker, journals and the recovery rules -- is docs/server.md.
| Path | Contents |
|---|---|
hexset/ |
Rules, board topology, state, ledger, encoding, records, search, and arena |
hexset/bots/ |
Heximax, Rehex, bot protocols, random policy and shared evaluation |
hexset/bench/ |
Duels, throughput measurements, record generation, ablations and weight sweeps |
hexset/catanatron/ |
Seats a Catanatron Player as a bot at a HexSet table: board, state and action translation |
hexset/server/ |
HTTP and MCP server, sessions, journals, and static browser UI |
hexset/clients/ |
Runtime-independent policy, trade, and search interfaces; ONNX inference; bot clients |
hexset/gym/ |
Lane, PettingZoo, and Gymnasium environments |
tests/ |
Engine and integration tests |
models/ |
Local ONNX opponents |
docs/ |
The documents indexed above |
pip install -e ".[test,server,export,catanatron,gym]"
pytest
pytest -m slowThe default run excludes tests marked slow; pytest -m "" runs every
marker. Tests for an optional dependency skip themselves when it is absent, so
which extras are installed decides what a green run covered:
docs/testing.md maps each extra to what it tests, and covers
the browser tests, which need a Chromium download beyond their extra.
HexSet is licensed under GPL-3.0-only. See LICENSE. Development history is in CHANGELOG.md; each release is also one commit here, whose message is that version's entry.
Dependencies are installed from PyPI or from git, never vendored into this
repository, and each carries its own licence; the set and their extras are
declared in pyproject.toml. Catanatron is GPL-3.0. The browser interface in
hexset/server/static/index.html loads no third-party scripts, stylesheets or
web fonts; its system font stack names fonts on the user's device rather than
bundling them.
CATAN and SETTLERS OF CATAN are trademarks of Catan GmbH and Catan Studio. HexSet is not affiliated with, endorsed by, or sponsored by either company. The names identify the game whose rules this project implements.