Skip to content

Latest commit

 

History

History
68 lines (55 loc) · 3.24 KB

architecture.md

File metadata and controls

68 lines (55 loc) · 3.24 KB

Architecture

SuperHirn uses a lightweight ports-and-adapters architecture. The game rules are independent of PySide6, HTTP, and concrete algorithms.

UI -> ApplicationControl -> CoreDomainModel <- Implementation / Networking
                              ^
                              |
                            main.py

main.py is the composition root: it selects concrete adapters and injects them into the domain module. Dependencies point inward; the core domain never imports the UI, networking client, or a concrete algorithm.

Modules and seams

Module Responsibility Seam
CoreDomainModel Mastermind rules, game state, GameSession, value objects, and provider interfaces IGame, IGuessProvider, IEvaluationProvider, ISecretCodeProvider, IProviderFactory
ApplicationControl Coordinates UI requests and domain events IBoundary
Implementation Concrete algorithms and local/UI providers Domain provider interfaces
Networking HTTP adapter for remote evaluation NetworkService
UI PySide6 rendering and user interaction IBoundary

Patterns

  • Ports and adapters: the domain owns the interfaces; UI, network, and providers are adapters at those seams.
  • Strategy: Consistency and Knuth algorithms share the IGuessProvider interface and can be selected per game or per spectator board.
  • Factory: ProviderFactory assembles the provider strategy appropriate for the selected game mode.
  • Observer: Game publishes game events to the controller, which forwards them to registered UI callbacks.
  • Composition root: main.py owns concrete dependency construction.

Session composition

GameSession is the domain aggregate for one game board. It groups the secret provider, guess provider, evaluation provider, round history, and state. The spectator mode creates two sessions with one shared secret and independent guess strategies. Code Maker routes the player-entered secret through UISecretCodeProvider, while the domain deliberately does not expose that secret through its game view; only the player UI retains it for display.

SOLID rules

  • Single responsibility: UI rendering, game rules, algorithm selection, persistence, and HTTP communication stay in separate modules.
  • Open/closed: add an algorithm or an evaluator by adding an adapter that satisfies its domain interface; callers do not need mode-specific changes.
  • Liskov substitution: all guess-provider adapters support generating, updating, checking, and pre-validating feedback through the same interface.
  • Interface segregation: provider interfaces are narrow and model only a provider's responsibility. Optional input methods explicitly fail when an adapter cannot support them.
  • Dependency inversion: the domain depends on provider interfaces, while adapters depend on the domain; main.py performs the wiring.

Guardrails

  • Keep framework, HTTP, and filesystem imports out of CoreDomainModel.
  • Keep adapter internals private. Callers must use the provider interface, including would_remain_consistent, rather than inspect candidate lists.
  • Add a regression test for every behavioural change at the domain interface or adapter seam.