1// Package game defines the plugin interface for puzzle games.2package game34import (5 "context"6 "math/rand/v2"78 "charm.land/bubbles/v2/key"9 tea "charm.land/bubbletea/v2"10 "github.com/FelineStateMachine/puzzletea/puzzle"11)1213// Gamer is the interface that an active game instance must implement.14type Gamer interface {15 GetDebugInfo() string16 GetFullHelp() [][]key.Binding1718 GetSave() ([]byte, error)19 IsSolved() bool20 Reset() Gamer21 SetTitle(string) Gamer2223 Init() tea.Cmd24 View() string25 Update(msg tea.Msg) (Gamer, tea.Cmd)26}2728// Mode describes a game mode for menu display.29type Mode interface {30 Title() string31 Description() string32 FilterValue() string33}3435// Spawner creates a new game instance. Implemented by concrete mode types36// but kept separate from Mode so that Category (which also satisfies Mode)37// does not need a Spawn method.38type Spawner interface {39 Spawn() (Gamer, error)40}4142// SeededSpawner creates a new game instance using a deterministic RNG.43// This enables reproducible puzzle generation for daily puzzles.44type SeededSpawner interface {45 Spawner46 SpawnSeeded(rng *rand.Rand) (Gamer, error)47}4849// CancellableSpawner optionally supports context-aware generation so callers50// can cancel long-running spawn work.51type CancellableSpawner interface {52 SpawnContext(ctx context.Context) (Gamer, error)53}5455// CancellableSeededSpawner optionally supports context-aware deterministic56// generation so callers can cancel long-running seeded spawn work.57type CancellableSeededSpawner interface {58 SeededSpawner59 SpawnSeededContext(ctx context.Context, rng *rand.Rand) (Gamer, error)60}6162// BaseMode provides the common title/description fields and the three63// Mode-interface methods so that concrete mode structs can embed it64// instead of duplicating boilerplate.65type BaseMode struct {66 title string67 description string68}6970func NewBaseMode(title, description string) BaseMode {71 return BaseMode{title: title, description: description}72}7374func (b BaseMode) Title() string { return b.title }75func (b BaseMode) Description() string { return b.description }76func (b BaseMode) FilterValue() string { return b.title + " " + b.description }7778func AdaptImport[T Gamer](fn func([]byte) (T, error)) func([]byte) (Gamer, error) {79 return func(data []byte) (Gamer, error) {80 return fn(data)81 }82}8384// NormalizeName lowercases and replaces hyphens/underscores with spaces for85// fuzzy matching of CLI arguments to game names and aliases.86func NormalizeName(s string) string {87 return puzzle.NormalizeName(s)88}8990// SpawnCompleteMsg is sent when an async Spawn() call finishes.91type SpawnCompleteMsg struct {92 Game Gamer93 Err error94}9596// HelpToggleMsg is sent from the root model to games when the user toggles97// the full help display with Ctrl+H.98type HelpToggleMsg struct{ Show bool }