Python reference implementation of Oana & Chiru (2026) — A Mathematical Framework for Four-Dimensional Chess (DOI 10.3390/appliedmath6030048).
Project description
python-chess4d-oana-chiru
Python reference implementation of:
Oana & Chiru, A Mathematical Framework for Four-Dimensional Chess, MDPI AppliedMath 6(3):48, 2026. DOI 10.3390/appliedmath6030048.
The source paper lives in hoodoos/ (treat as read-only reference).
Install
From PyPI (recommended):
# Core engine + corpus CLI (.c4d + NDJSON outputs; no encoder).
pip install python-chess4d-oana-chiru
# With the chess-spectral encoder pulled in (45 056-dim float32
# vectors + spectralz v4 frame format; brings numpy/scipy along).
pip install "python-chess4d-oana-chiru[spectral]"
From source (for local development):
git clone https://github.com/lemonforest/python-chess4d-oana-chiru
cd python-chess4d-oana-chiru
pip install -e ".[dev,spectral]"
Type hints ship with the package (py.typed marker per PEP 561) and are
checked with mypy --strict in CI.
Coordinate convention
Internally 0-based: B = {0,…,7}^4 ⊂ Z^4 (4096 cells). The paper's 1-based
{1,…,8}^4 notation is preserved in docstrings and converted only at the
UI boundary. See CLAUDE.md for the indexing gotcha (the reference UI is
also 0-based; the central mixed-color slice block is at theoretical
(z, w) ∈ {4, 5}×{4, 5} / UI (z, w) ∈ {3, 4}×{3, 4}).
Status
0.3.2 — core engine, legality, and corpus tooling are in. Implemented:
all six piece types with paper-faithful move generation (rook / bishop /
knight / queen / king / pawn), multi-king legality per §3.4 Def 3
(a move is legal iff no king of the mover is attacked afterwards),
X-axis castling with global attack safety, Y- and W-axis en passant,
pawn promotion on the terminal rank of each forward axis, draw detection
(50-move rule + threefold repetition via 4D state hash), .c4d move
notation with round-trip I/O, chess-spectral integration (optional),
and a random-playout corpus generator writing the
chess-maths-the-movie nested layout.
Not yet implemented: search / evaluation, a UI, Oana-Chiru 4D-aware
opening books. See CLAUDE.md for architectural invariants.
Spectral encoding (optional)
chess4d integrates with the
chess-spectral framework
(developed in the sibling mlehaptics repo, published to PyPI) for
physics-grounded analysis of 4D positions. The encoder maps a
GameState to an 11-channel, 45 056-dimensional float32 spectral
vector and writes streams of frames as spectralz v4 files. Install
the spectral extra to pull in chess-spectral (brings numpy + scipy
along transitively):
pip install "python-chess4d-oana-chiru[spectral]"
Encode a single position:
from chess4d import initial_position
from chess4d.spectral import encode_position
gs = initial_position()
vec = encode_position(gs) # (45056,) float32
Encode a game and write it to a spectralz v4 file:
from chess4d.spectral import write_spectralz
write_spectralz("game.spectralz", start_state, move_list)
The 11 channels cover the six piece types (with pawns split by forward
axis per Oana & Chiru Def. 11) plus board-parity and side-to-move
signals. See the chess-spectral notebooks in the mlehaptics repo for
channel semantics and reconstruction examples.
Corpus generation
chess4d-corpus-gen writes a reproducible random-playout corpus in the
chess-maths-the-movie nested layout:
./corpus/<run_id>/
manifest.json # run metadata + per-game rows
c4d/game_NNN.c4d # compact 4D move notation
ndjson/game_NNN.ndjson # per-ply pos4 snapshots + moves
spectralz/game_NNN.spectralz # 45 056-dim per-ply encoding (optional)
<run_id> is auto-minted as corpus_YYYYMMDD_HHMMSS_seedN (or
..._unseeded) and can be overridden with --run-id. Generation is
two-pass: the playout pass writes c4d + NDJSON unconditionally, then an
optional encoding pass reads the NDJSON and produces spectralz frames
with absolute ply numbers.
# default: full-game spectralz for every ply
chess4d-corpus-gen --n-games 10 --seed 42 --output ./corpus
# only encode the final 30 plies per game (c4d + NDJSON still full)
chess4d-corpus-gen --n-games 1 --max-plies 500 --encode-last 30
# playout only — c4d + NDJSON, no spectralz, no [spectral] extra needed
chess4d-corpus-gen --n-games 10 --seed 42 --no-encode
# reproducible named run
chess4d-corpus-gen --n-games 10 --seed 42 --run-id fixed-corpus-v1
Seeding semantics
--seed N seeds a single random.Random(N) instance that is
shared across every game in the run. The only thing that RNG drives
is the move choice (rng.choice(legal_moves)); the starting position
is always the canonical Oana-Chiru §3.3 layout and is not seeded.
Because the RNG is deterministic, a corpus produced with a given
(max_plies, seed) is actually an infinite deterministic sequence
of games, and --n-games N just asks for the first N of them. That
gives you this prefix property:
| Run A | Run B | Overlap |
|---|---|---|
--n-games 10 --seed 42 |
--n-games 5 --seed 42 |
Games 1..5 are byte-identical |
--n-games 3 --seed 42 |
--n-games 100 --seed 42 |
Games 1..3 are byte-identical |
--n-games 10 --seed 42 |
--n-games 10 --seed 43 |
Share nothing; different stream |
So growing or shrinking --n-games extends the corpus forward or
truncates it — it never changes earlier games. The same is true of
all three outputs (c4d, ndjson, spectralz).
What the shared-RNG design doesn't give you is the ability to
reproduce game i in isolation: to get game 5's exact moves you have
to run games 1..4 first, because game 5's starting RNG state is "seed
42, advanced past the draws games 1..4 consumed." Per-game seed
derivation (so each game's RNG is derived independently from the base
seed + game index) is deliberately deferred to a future release — the
corpus-level seed is enough for the full-corpus replay use case, which
is what the fetch_params.seed field in manifest.json records.
Retro-encoding an existing corpus
Because encoding reads from the NDJSON sidecar, you can turn a
--no-encode corpus into a spectralz corpus at any point without
replaying the games:
# encode every ply of every game in an existing run
chess4d-corpus-encode ./corpus/corpus_20260419_180342_seed42
# tail-only: encode just the final 30 plies of each game
chess4d-corpus-encode ./corpus/corpus_20260419_180342_seed42 --last-n 30
The standalone CLI is driven entirely by NDJSON and updates
manifest.json in place. For a given (seed, last_n), the
retro-encoded spectralz bytes are identical to those produced by
chess4d-corpus-gen --encode-last N on the same inputs.
The NDJSON schema is chess4d-ndjson-v1: line 1 is the format header,
line 2 is a game_header record with termination / ply count / seed,
and subsequent lines carry per-ply records with the applied move,
side_to_move, and a full pos4 dict (2-char pawn values
Pw/Py/pw/py, 1-char non-pawns, keyed by linear square index
(x<<9) | (y<<6) | (z<<3) | w).
Development
pip install -e .[dev]
pytest -v
mypy --strict src/chess4d
ruff check src tests
License
Unlicense (public domain). See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file python_chess4d_oana_chiru-0.3.3.tar.gz.
File metadata
- Download URL: python_chess4d_oana_chiru-0.3.3.tar.gz
- Upload date:
- Size: 134.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
962c94eb72453641758bb3fefa9ca3bda18c5c4eb4152f764f12d1c148102cac
|
|
| MD5 |
0897f42b707bbece76bb0ece7b95ebe6
|
|
| BLAKE2b-256 |
42770f8d7e2b1dde4b15ab17ada76df241db5ed86a4dffffe21fa07e8a3ee7c2
|
Provenance
The following attestation bundles were made for python_chess4d_oana_chiru-0.3.3.tar.gz:
Publisher:
publish-to-pypi.yml on lemonforest/python-chess4d-oana-chiru
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
python_chess4d_oana_chiru-0.3.3.tar.gz -
Subject digest:
962c94eb72453641758bb3fefa9ca3bda18c5c4eb4152f764f12d1c148102cac - Sigstore transparency entry: 1373841893
- Sigstore integration time:
-
Permalink:
lemonforest/python-chess4d-oana-chiru@812c1a1add93076329edd2122b1d523b81029ccc -
Branch / Tag:
refs/tags/v0.3.3 - Owner: https://github.com/lemonforest
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@812c1a1add93076329edd2122b1d523b81029ccc -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file python_chess4d_oana_chiru-0.3.3-py3-none-any.whl.
File metadata
- Download URL: python_chess4d_oana_chiru-0.3.3-py3-none-any.whl
- Upload date:
- Size: 78.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fdec26a312ae7d2b5b73fcdce0199e8ee9da17376baa299f309f5439e53764a4
|
|
| MD5 |
a7e11478d092147064aea4ee93085630
|
|
| BLAKE2b-256 |
554c4e85e5860f14fca6ea7732d824926adcf720afa0d5d1b87e0d26b650c32a
|
Provenance
The following attestation bundles were made for python_chess4d_oana_chiru-0.3.3-py3-none-any.whl:
Publisher:
publish-to-pypi.yml on lemonforest/python-chess4d-oana-chiru
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
python_chess4d_oana_chiru-0.3.3-py3-none-any.whl -
Subject digest:
fdec26a312ae7d2b5b73fcdce0199e8ee9da17376baa299f309f5439e53764a4 - Sigstore transparency entry: 1373842039
- Sigstore integration time:
-
Permalink:
lemonforest/python-chess4d-oana-chiru@812c1a1add93076329edd2122b1d523b81029ccc -
Branch / Tag:
refs/tags/v0.3.3 - Owner: https://github.com/lemonforest
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@812c1a1add93076329edd2122b1d523b81029ccc -
Trigger Event:
workflow_dispatch
-
Statement type: