Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ current state and then transitions it. Illegal moves are rejected (the state is
crashed on. The HTTP API is a thin shell that translates requests into engine actions; all the rules
live in the engine.

- The rules, in human-readable form: [`game-docs/SPEC.md`](./game-docs/SPEC.md)
- The card catalog: [`game-docs/CARDS.md`](./game-docs/CARDS.md)
The rules and card catalog live in the [`mundane`](https://github.com/letsbuilda/mundane) meta/spec
repo:

- The rules, in human-readable form:
[`game-docs/SPEC.md`](https://github.com/letsbuilda/mundane/blob/main/game-docs/SPEC.md)
- The card catalog:
[`game-docs/CARDS.md`](https://github.com/letsbuilda/mundane/blob/main/game-docs/CARDS.md)

## Layout

Expand Down
6 changes: 6 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
Changelog
=========

* :feature:`0` The Mundane rules engine — :func:`mundane.engine.rules.apply_action` as the single
state-transition function, an event-sourced :class:`mundane.engine.game.Game` log, and a fully
JSON-serialisable :class:`mundane.engine.state.GameState` that stores cards by id.
* :feature:`0` A thin `Litestar <https://litestar.dev>`_ HTTP API (:mod:`mundane.api`) to create
games, read state, submit moves (rejected moves become HTTP 422), and export the action log.
67 changes: 63 additions & 4 deletions docs/index.rst
Original file line number Diff line number Diff line change
@@ -1,11 +1,70 @@
Mundane
=======
Mundane Backend
===============

Magic: The Gathering without the, you know, magic
*Magic: The Gathering without the, you know, magic.*

Module Index
This is the reference implementation of `Mundane <https://github.com/letsbuilda/mundane>`_: a rules
**engine** and a thin HTTP **API** over it. The engine is a referee, not a player — a whole game is a
fold over a stream of *actions*, and one function, :func:`mundane.engine.rules.apply_action`,
validates each action against the current state and then transitions it. Illegal moves are rejected
and the state is left untouched, never crashed on. The API is a thin shell that turns HTTP requests
into engine actions; all the rules live in the engine.

.. note::

The game's rules and card catalog live in the meta/spec repository, not here:
`SPEC.md <https://github.com/letsbuilda/mundane/blob/main/game-docs/SPEC.md>`_ and
`CARDS.md <https://github.com/letsbuilda/mundane/blob/main/game-docs/CARDS.md>`_. This site
documents the *implementation*; the spec describes the *game*.

Architecture
------------

The engine
~~~~~~~~~~

:func:`mundane.engine.rules.apply_action` is the one door: every state change goes through it. Each
move checks its preconditions first — a failed check raises :class:`mundane.engine.actions.IllegalAction`
and mutates nothing — and only then transitions. Because it returns the state, it composes as a
reducer::

final_state = reduce(apply_action, actions, initial_state)

The state is fully JSON-serialisable. Cards are referenced **by id** everywhere; card *objects* and
the effect functions they carry live only in :data:`mundane.engine.cards.CARD_LIBRARY`, never in the
state. That separation is what lets a whole :class:`mundane.engine.state.GameState` round-trip through
JSON. A :class:`mundane.engine.game.Game` pairs that state with the ordered log of accepted actions,
so games are event-sourced: the log alone can rebuild — and replay — the state.

The API
~~~~~~~

:mod:`mundane.api` is a `Litestar <https://litestar.dev>`_ application. It never mutates game state
directly: it parses each request body into an engine action, calls ``Game.submit``, and maps a
rejected move (:class:`~mundane.engine.actions.IllegalAction`) onto **HTTP 422**. Games are kept in an
in-memory store behind a small ``create`` / ``get`` / ``save`` interface, so they are volatile (lost
when the process restarts) but the store is swappable for Redis or SQLite later.

.. list-table::
:header-rows: 1
:widths: 40 60

* - Method and path
- Purpose
* - ``POST /games``
- Create a game; return its id and initial state.
* - ``GET /games/{id}``
- Read the current state.
* - ``POST /games/{id}/actions``
- Submit a move (HTTP 422 if illegal; the stored game is unchanged).
* - ``GET /games/{id}/export``
- Download the action log and final state.

API reference
-------------

The full module reference is generated from the source.

.. toctree::
:maxdepth: 1

Expand Down
23 changes: 0 additions & 23 deletions game-docs/CARDS.md

This file was deleted.

184 changes: 0 additions & 184 deletions game-docs/SPEC.md

This file was deleted.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ dependencies = [
]

[project.urls]
repository = "https://github.com/letsbuilda/mundane/"
repository = "https://github.com/letsbuilda/mundane-backend"
documentation = "https://docs.letsbuilda.dev/mundane/"

[build-system]
Expand Down