fastcatan
A deterministic Settlers of Catan simulator with a C++ core and Python bindings through nanobind.
- Complete four-player game state and rule transitions.
- Seeded, reproducible board setup and chance events.
- Legal-action validation with strict no-op behavior for illegal actions.
- Snapshot and restore support for replay and debugging.
- Optional batched stepping with OpenMP.
Install
pip install fastcatan
Prebuilt wheels target Linux x86_64 and macOS Apple Silicon on CPython 3.12+. Other supported systems build from the source distribution and need a C++23 compiler and CMake 3.27 or newer.
Simulate a game
import random
import fastcatan
rng = random.Random(0)
game = fastcatan.Env()
game.reset(seed=0)
while not game.done:
action = rng.choice(game.legal_actions())
game.step(action)
print("winner:", game.winner)
print("victory points:", [
game.player_vp(seat) for seat in range(fastcatan.NUM_PLAYERS)
])
step(action) returns whether the game is terminal. An action that is not in
legal_actions() leaves the game unchanged. action_mask(out) exposes the same
legal set as a packed NumPy bitset when allocation-free access is needed.
The semantic state API includes board tiles, nodes, edges, bank contents,
development cards, player inventories, trade state, the robber, awards, and the
acting seat. snapshot() and load_snapshot() preserve the complete game and
random-number state.
Batched simulation
import numpy as np
import fastcatan
n = 1024
games = fastcatan.BatchedEnv(n, seed=0)
games.reset()
masks = np.zeros((n, fastcatan.MASK_WORDS), dtype=np.uint64)
actions = np.zeros(n, dtype=np.uint32)
dones = np.zeros(n, dtype=np.uint8)
games.write_masks(masks)
# Fill actions with one legal action per game.
games.step(actions, dones)
step preserves terminal states so they can be inspected or saved. Use
step_autoreset for continuous simulation; it records the completed game's
winning seat in last_winner(index) before resetting that slot. NO_ACTION
leaves an independently progressing slot unchanged.
save_snapshots, load_snapshots, and reseed operate on whole batches without
per-game Python calls. They use arrays shaped (n, SNAPSHOT_BYTES) for snapshots
and (n,) for seeds.
Exact chance outcomes
The simulator can enumerate physical chance transitions without selecting what any player should do:
for probability, snapshot in game.enumerate_outcomes(action):
successor = fastcatan.Env()
successor.load_snapshot(snapshot)
Dice rolls, development-card draws, and robber steals produce weighted successors. Deterministic actions produce one successor, and probabilities sum to one. Each successor also advances its stored random-number state exactly as a sampled transition would. This keeps Catan's probability rules in the simulator while leaving any decision-making logic to downstream packages.
Player-visible state
state_view(seat) returns unnormalized semantic data for a player. It includes
public board and player information plus that seat's own resources and
development cards. Opponents' private fields are None, unopened trade drafts
remain private, and legal actions are included only for the acting seat. The
dictionary schema is versioned by STATE_VIEW_VERSION.
Main API
| Symbol | Purpose |
|---|---|
Env |
One game: reset, inspect, list legal actions, step, snapshot, restore |
BatchedEnv |
Contiguous collection of independently progressing games |
action |
Action-ID constants |
NUM_ACTIONS, MASK_WORDS |
Legal-action bitset dimensions |
NUM_PLAYERS, NUM_RESOURCES |
Game-wide counts |
NUM_NODES, NUM_EDGES, NUM_HEXES, NUM_PORTS |
Board dimensions |
NO_PLAYER |
Sentinel used when no seat owns an award or terminal result |
NO_ACTION |
Explicit no-op sentinel for a batched slot |
SNAPSHOT_BYTES |
Snapshot size for the current package version |
MAX_ACTION_OUTCOMES |
Maximum successors from exact chance enumeration |
STATE_VIEW_VERSION |
Semantic player-view schema version |
Snapshots are an internal binary format. Only load snapshots created by the same package version; malformed snapshots are rejected.
Upgrading from 1.x
Version 2.0 is a simulator-only release with a smaller public API:
Env.step(action)returns only the terminal-state boolean.BatchedEnv.steppreserves terminal states. Usestep_autoresetwhen a completed slot should immediately start a new game.- Tensor encoders, configurable scoring, and search diagnostics are no longer part of this package.
state_view,enumerate_outcomes, and bulk snapshot methods provide neutral simulator data for downstream projects.
See CHANGELOG.md for the complete release summary.
Development
pip install .
pytest
The standalone C++ invariant harness can also be built and run:
cmake -S . -B build -DFASTCATAN_ARCH=off
cmake --build build -j
ctest --test-dir build --output-on-failure
Run the simulator-only batch benchmark with:
python examples/benchmark_simulator.py --envs 1024 --steps 200
License
MIT © 2026 s1nbo
Release files for fastcatan 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fastcatan-2.0.0.tar.gz | 60.3 kB | Details |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fastcatan-2.0.0-cp312-abi3-musllinux_1_2_x86_64.whl | CPython 3.12 | abi3 | Linux musl 1.2+ x86-64 | Details |
| fastcatan-2.0.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | CPython 3.12 | abi3 | Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 | Details |
| fastcatan-2.0.0-cp312-abi3-macosx_11_0_arm64.whl | CPython 3.12 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 703.3 kB
Release files / fastcatan-2.0.0.tar.gz
| Download URL | fastcatan-2.0.0.tar.gz |
|---|---|
| Size | 60.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
73a5ae45271d57274d28b6ae86df488593161d11dfaae285e0374f2262f89797
|
|
BLAKE2b-256 checksum How to use checksums |
419ab5fffbb687aae59bc0afbeae36f0f70c83e2f9b3f8f3a4ad59b53e8a596c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.
Transparency logRelease files / fastcatan-2.0.0-cp312-abi3-musllinux_1_2_x86_64.whl
| Download URL | fastcatan-2.0.0-cp312-abi3-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 348.7 kB |
| Tags | CPython 3.12 Linux musl 1.2+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
51e62ea4838730cd414bf7ec5594bfff9f8cc9bb99d2883f2954f25121ddb216
|
|
BLAKE2b-256 checksum How to use checksums |
0373de70f9766c831ee80a0e948711a3ae76cd8cfa6125ee03b0e4d8673ebeca
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.
Transparency logRelease files / fastcatan-2.0.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | fastcatan-2.0.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 208.6 kB |
| Tags | CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
d3333ad9b339553baf5553bef2f94cd23a54e340a405d07276f4eab7efc457a7
|
|
BLAKE2b-256 checksum How to use checksums |
c64cab57c7fe0e1e0c4595a24841e99bd6b3d5fe0c9c380b0b0c20ad846b9859
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.
Transparency logRelease files / fastcatan-2.0.0-cp312-abi3-macosx_11_0_arm64.whl
| Download URL | fastcatan-2.0.0-cp312-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 85.7 kB |
| Tags | CPython 3.12 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
aadbe198a4830165979840ed2b04f2b8de239caf5c08e2782a66d67896064719
|
|
BLAKE2b-256 checksum How to use checksums |
f0c925d60f6400a3ac805d8fdb237ba18f993997206bbf111a9d0234b115db87
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 25, 2026.
Transparency log