CynMeith is a Python-first board-game engine for experimenting with custom rules. It helps you test original turn-based board-game ideas without rewriting board state, turn flow, and move history every time.
Its purpose is not to be the fastest way to implement standard chess. It is to let you prototype original rule systems on a clean, programmable engine.
The main goal is to help creative users test original board-game ideas quickly:
- custom movement rules
- custom turn structures
- irregular side effects after moves
- square and hexagonal boards, unusual sizes and setups
- fast iteration in code, not engine-level performance work
Everything follows from one decision: the engine is stateless.
GameStateis an immutable value holding everything mutable about a game: the board, the turn state, the phase, the resources, the ply count.Engineis a pure function of that value:legal_moves(state),apply(state, move) -> new state,outcome(state). Applying a move never touches the input state.GameSessionis a small convenience wrapper for interactive play; its only "mutability" is a list of past states, which is why undo/redo needs no code.
Around that core sit three supporting ideas:
- Geometry as a strategy.
SquareGridandHexGridimplement oneGeometrycontract (cells, neighbors, distance, lines, areas). Piece movement asks the geometry instead of doing coordinate math, so pieces can be board-shape agnostic. - Pieces as data. A piece on the board is a
PieceState(kind + side + attrs). Its behavior is aPieceDeflooked up by kind — usually built from movement combinators likeleaper(...)andrider(...)rather than written by hand. - Stateless rule components. Turn, phase, resource, win, and scoring rules
hold no game data; the values they produce live inside
GameState, so one rule object serves any number of concurrent games.
- Describe the game in one
GameDef(geometry, pieces, starting position, rules). - Call
GameDef.new_session()to get an interactiveGameSession(pass a customsetupfor puzzles). - Ask
session.legal_moves(...)/session.can_move(...), thensession.move(start, end). - Let move payloads and
Effectvalues handle irregular behavior. - Use
session.undo()/session.redo()freely.
For AI search, skip the session: take GameDef.engine() and work with
GameState values directly — engine.apply(state, move) returns a new state
you can fork, hash, and discard at will.
CynMeith is a good fit if you:
- can write small Python functions
- want to prototype custom board-game rules, not just replay standard chess
- prefer explicit code over a purely visual editor
- want undo/redo, serialization, and reusable engine primitives while experimenting
- want to try hexagonal variants without re-deriving hex math
It is a weaker fit if you:
- want a no-code game editor
- want a polished end-user app more than a Python package
- want a tournament-grade chess engine or heavily optimized search backend
At its core, CynMeith gives you:
- a single
GameDefthat describes geometry, pieces, and rules, withnew_session()to play andengine()for pure-function access - square and hex geometries with O(1) spatial math (
SquareGrid,HexGrid) - declarative pieces (
PieceDef+leaper/rider/stepper/compose/filtered) - a pure side-effect system for irregular moves (
Remove,Relocate,Promote,Place) - turn control (
FreeTurn,QuotaTurn) and first-class hooks for win conditions, phases, resources, and scoring - a royal-safety family for chess-like games (check, checkmate, stalemate)
- free undo/redo and JSON/FEN serialization, both consequences of immutability
- Tk sample applications for chess, xiangqi, and Exist
Right now, CynMeith is not:
- a complete board-game authoring application
- a DSL-driven game-definition system
- a built-in AI/search engine (it is deliberately search-friendly, but ships no searcher)
- a rules database for many historical games
CynMeith deliberately keeps the engine programmable. It should stay good at:
- deterministic, immutable game state
- composable rule logic
- debuggable Python extension points
Design-first authoring tools such as a web, desktop, or mobile app should sit on top of this engine rather than distort it into a visual tool before the rules model is ready.
- game authoring is still code-driven
- sides are player indexes (
0,1, ...); the engine supports N players structurally, but most built-in win conditions default their winners with two-player logic - graph-shaped boards (arbitrary adjacency) have a designed seam but no implementation yet
- no built-in AI search — you bring your own Minimax/MCTS on top of the pure engine
- Start with a tiny ruleset.
- Build pieces from combinators; write a custom generator only when a combinator cannot express the movement.
- Add game-wide restrictions as legality filters, irregular consequences as effects.
- Use
QuotaTurn()unless your game truly needs something stranger. - Only build UI after the core rules feel stable.
For the minimum Python subset needed to extend the engine, read Python Enough for CynMeith. To go from a blank slate to a playable prototype, use Your First Custom Game.