clone

fifteen puzzle games for the terminal, with daily puzzles, weekly ladders and xp, built on bubble tea

bug/architecture-test-trim-path
puzzletea / registry / registry.go
registry.go 3.9K
1// Package registry is the concrete runtime composition root for built-in games,2// imports, help text, and daily-capable modes.3package registry45import (6 "fmt"78 "github.com/FelineStateMachine/puzzletea/catalog"9 "github.com/FelineStateMachine/puzzletea/game"10 "github.com/FelineStateMachine/puzzletea/gameentry"11 "github.com/FelineStateMachine/puzzletea/games/fillomino"12 "github.com/FelineStateMachine/puzzletea/games/hashiwokakero"13 "github.com/FelineStateMachine/puzzletea/games/hitori"14 "github.com/FelineStateMachine/puzzletea/games/lightsout"15 "github.com/FelineStateMachine/puzzletea/games/netwalk"16 "github.com/FelineStateMachine/puzzletea/games/nonogram"17 "github.com/FelineStateMachine/puzzletea/games/nurikabe"18 "github.com/FelineStateMachine/puzzletea/games/rippleeffect"19 "github.com/FelineStateMachine/puzzletea/games/shikaku"20 "github.com/FelineStateMachine/puzzletea/games/spellpuzzle"21 "github.com/FelineStateMachine/puzzletea/games/sudoku"22 "github.com/FelineStateMachine/puzzletea/games/sudokurgb"23 "github.com/FelineStateMachine/puzzletea/games/takuzu"24 "github.com/FelineStateMachine/puzzletea/games/takuzuplus"25 "github.com/FelineStateMachine/puzzletea/games/wordsearch"26 "github.com/FelineStateMachine/puzzletea/puzzle"27)2829type (30 ModeEntry = gameentry.ModeEntry31 VariantEntry = gameentry.VariantEntry32 Entry = gameentry.Entry33)3435type DailyEntry struct {36 Spawner game.SeededSpawner37 GameID puzzle.GameID38 GameType string39 ModeID puzzle.ModeID40 Mode string41}4243var all = []Entry{44 fillomino.Entry,45 hashiwokakero.Entry,46 hitori.Entry,47 lightsout.Entry,48 netwalk.Entry,49 nonogram.Entry,50 nurikabe.Entry,51 rippleeffect.Entry,52 shikaku.Entry,53 spellpuzzle.Entry,54 sudoku.Entry,55 sudokurgb.Entry,56 takuzu.Entry,57 takuzuplus.Entry,58 wordsearch.Entry,59}6061var (62 definitions = buildDefinitions(all)63 index = catalog.MustBuild(definitions)64 entriesByID = buildEntriesByID(all)65)6667func buildDefinitions(entries []Entry) []puzzle.Definition {68 defs := make([]puzzle.Definition, 0, len(entries))69 for _, entry := range entries {70 defs = append(defs, entry.Definition)71 }72 return defs73}7475func buildEntriesByID(entries []Entry) map[puzzle.GameID]Entry {76 result := make(map[puzzle.GameID]Entry, len(entries))77 for _, entry := range entries {78 result[entry.Definition.ID] = entry79 }80 return result81}8283func Entries() []Entry {84 return append([]Entry(nil), all...)85}8687func Definitions() []puzzle.Definition {88 return index.Definitions()89}9091func Names() []string {92 return index.Names()93}9495func Lookup(name string) (Entry, bool) {96 def, ok := index.Lookup(name)97 if !ok {98 return Entry{}, false99 }100 entry, ok := entriesByID[def.ID]101 return entry, ok102}103104func Resolve(name string) (Entry, bool) {105 def, ok := index.Resolve(name)106 if !ok {107 return Entry{}, false108 }109 entry, ok := entriesByID[def.ID]110 return entry, ok111}112113func Import(gameType string, data []byte) (game.Gamer, error) {114 entry, ok := Lookup(gameType)115 if !ok {116 return nil, fmt.Errorf("unknown game type %q in save data", gameType)117 }118 g, err := entry.Import(data)119 if err != nil {120 return nil, fmt.Errorf("failed to import game: %w", err)121 }122 return g, nil123}124125func DailyEntries() []DailyEntry {126 dailies := index.DailyEntries()127 result := make([]DailyEntry, 0, len(dailies))128 seen := make(map[puzzle.GameID]struct{}, len(dailies))129 for _, daily := range dailies {130 if _, ok := seen[daily.GameID]; ok {131 continue132 }133 entry, ok := entriesByID[daily.GameID]134 if !ok {135 continue136 }137 if len(entry.Variants) > 0 && entry.Variants[0].Seeded != nil {138 variant := entry.Variants[0]139 seen[daily.GameID] = struct{}{}140 result = append(result, DailyEntry{141 Spawner: variant.Seeded,142 GameID: daily.GameID,143 GameType: entry.Definition.Name,144 ModeID: puzzle.ModeID(variant.Definition.ID),145 Mode: variant.Definition.Title,146 })147 }148 }149 return result150}151152func Help(name string) (string, bool) {153 entry, ok := Resolve(name)154 if !ok {155 return "", false156 }157 return entry.Help, true158}