forge-lcdl

Games engine + LCDL layer — alpha status

Snapshot for forge_lcdl.games and related governed tasks/contracts. Intended for engineer handoff: what exists, how to invoke it, and what is deliberately out of scope for this alpha.

Implemented modules (src/forge_lcdl/games)

Area Paths Role
Engine core games.engineinterfaces, models, errors, loop, log, serialization, replay, rng, cli Game protocol; moves, views, transitions; hashing; replay; CLI; JSON facade
Topology games.engine.mechanicsgrid, graph, connectivity Positions, square grid, graph boards, flood-fill / path checks, line detection on grids
Reference rules games.engine.referencetic_tac_toe, nim, connect_four_like (+ REFERENCE_GAMES_META, new_reference_game) Small rulesets implementing Game
Adapters games.adapters.web_json state_response, legal_moves_response, apply_move_request, error_response (stdlib JSON only)
Task shapes games.tasks.schemas TypedDict helpers for payloads (no transport)
Placeholders games.agents Reserved for policies / play loops
Shared errors games.errors Thin-layer exceptions

Related (older / parallel): forge_lcdl.game_engine — separate reference registry and types; see GAME-ENGINE.md. Long-term, consumers may prefer games.engine as the primary façade.

Reference games

  • tic_tac_toe — full-information 3×3; stable place_<r>_<c> move ids.
  • nim — take tokens; configurable start; stable take_<n> ids.
  • connect_four_like — rectangular column-drop grid, four-in-a-row win; drop_col_* ids; uses mechanics.connectivity for line detection.

Supported mechanics

  • GridPosition, SquareGrid, JSON helpers position_to_json / position_from_json.
  • GraphGraphBoard for edge-adjacency games.
  • Connectivityflood_fill, path_exists_grid, path_exists_graph, find_lines_on_grid.

Supported LCDL tasks (v1)

Registered via TASK_REGISTRY_V1 and forge_lcdl.tasks.registry (lazy ensure_builtin_tasks_registered):

task_id Contract folder Purpose
game_move_parse contracts/game_move_parse/v1/ NL utterance → selected / ambiguous / illegal_or_unmatched against caller-supplied legal_moves
game_move_explain contracts/game_move_explain/v1/ Explanation for one validated selected_move_id
game_move_rank contracts/game_move_rank/v1/ Rank subset of moves; heuristic_scores keys must match legal ids

Validation lives in forge_lcdl.game_lcdl.validate (confidence_in_unit_interval, subset checks, rankings). Model output must not introduce unknown move_id values before Ok results are returned.

How to run (developers)

cd forge-lcdl
python -m pytest tests/ --ignore=tests/integration

Engine CLI (stdlib only)

PYTHONPATH=src python -m forge_lcdl.games.engine list-reference-games
PYTHONPATH=src python -m forge_lcdl.games.engine replay tests/games/fixtures/replay/tic_tac_toe_three_moves.json
PYTHONPATH=src python -m forge_lcdl.games.engine random-play nim --seed 1

Examples

Run from repo root with PYTHONPATH=src:

  • examples/games/play_tic_tac_toe.py
  • examples/games/play_connect_four_like.py
  • examples/games/replay_fixture.py (wraps CLI replay)
  • examples/games/llm_advisor_fake.py — offline TaskRunner + game_move_explain

Using the engine in code

  1. state = game.setup(seed=..., ...)
  2. view = game.player_view(state, player_id) — JSON-serializable dict fields only.
  3. moves = game.legal_moves(state, player_id)
  4. result = game.apply_move(state, move) — check result.ok.
  5. Repeat until game.is_terminal(state), then game.score(state).

Using LCDL tasks

Build input_data with player_view (object) and legal_moves (list of objects with move_id). Call run_task("game_move_parse", "v1", input_data, profile=..., chat=fake) in tests with a ChatFn returning JSON strings.

Test coverage checklist (alpha)

Concern Location / notes
Engine forbids LLM/transport imports tests/games/test_architecture_imports.py, tests/games/test_no_engine_llm_imports.py — AST scans of games/engine.
move_id validation tests/tasks/test_game_move_*.py.
Replay + hash tests/games/engine/test_replay.py, tests/games/fixtures/replay/*.json.
CLI tests/games/test_cli.py.
Adapters tests/games/adapters/test_web_json.py.
Serialization tests/games/engine/test_serialization_roundtrip.py.
Seeded RNG tests/games/engine/test_rng.py.
Fake transport for game tasks tests/tasks/test_game_move_*.py.
Docs present tests/docs/test_game_docs_exist.py.
Hidden information Gap: asymmetric Game + dedicated tests for PlayerView.private.

Known limitations (alpha)

  • games.agents stub only.
  • Hidden information — no first-class “secret hand” reference rule in games.engine.reference yet.
  • game_engine vs games.engine — two stacks coexist.
  • Operators / full play tree — not wired; tasks are single-step assist (parse / explain / rank).
  1. Hidden-info reference + test_hidden_information.py.
  2. Flesh out games.agents (heuristic / scripted players).
  3. Converge game_engine façade with games.engine where practical.
  4. Broader adapter coverage (batch apply, score snapshots).
  5. Optional package entry point for forge-lcdl-games-cli.

Doc index