1// Package gameentry builds concrete runtime game entries from puzzle definitions2// and runtime mode implementations.3package gameentry45import (6 "fmt"78 "github.com/FelineStateMachine/puzzletea/export/pdf"9 "github.com/FelineStateMachine/puzzletea/game"10 "github.com/FelineStateMachine/puzzletea/puzzle"11)1213type ModeEntry struct {14 Definition puzzle.ModeDef15 Spawner game.Spawner16 Seeded game.SeededSpawner17}1819type Entry struct {20 Definition puzzle.Definition21 Help string22 Import func([]byte) (game.Gamer, error)23 Modes []ModeEntry24 Print pdfexport.PrintAdapter25}2627type EntrySpec struct {28 Definition puzzle.Definition29 Help string30 Import func([]byte) (game.Gamer, error)31 Modes []game.Mode32 Print pdfexport.PrintAdapter33}3435func BuildModeDefs(modes []game.Mode) []puzzle.ModeDef {36 defs := make([]puzzle.ModeDef, 0, len(modes))37 for _, mode := range modes {38 def := puzzle.NewModeDef(puzzle.ModeSpec{39 Title: mode.Title(),40 Description: mode.Description(),41 })42 if _, ok := mode.(game.SeededSpawner); ok {43 def.Seeded = true44 }45 defs = append(defs, def)46 }47 return defs48}4950func NewEntry(spec EntrySpec) Entry {51 if len(spec.Definition.Modes) != len(spec.Modes) {52 panic(fmt.Sprintf(53 "gameentry: definition %q has %d mode definitions but %d runtime modes",54 spec.Definition.Name,55 len(spec.Definition.Modes),56 len(spec.Modes),57 ))58 }5960 entries := make([]ModeEntry, 0, len(spec.Modes))61 for i, mode := range spec.Modes {62 spawner, ok := mode.(game.Spawner)63 if !ok {64 panic(fmt.Sprintf(65 "gameentry: definition %q mode %q does not implement game.Spawner",66 spec.Definition.Name,67 mode.Title(),68 ))69 }7071 modeDef := spec.Definition.Modes[i]72 if modeDef.Title != mode.Title() || modeDef.Description != mode.Description() {73 panic(fmt.Sprintf(74 "gameentry: definition %q mode %d metadata does not match runtime mode %q",75 spec.Definition.Name,76 i,77 mode.Title(),78 ))79 }8081 entry := ModeEntry{82 Definition: modeDef,83 Spawner: spawner,84 }85 if seeded, ok := mode.(game.SeededSpawner); ok {86 entry.Seeded = seeded87 }88 if entry.Definition.Seeded != (entry.Seeded != nil) {89 panic(fmt.Sprintf(90 "gameentry: definition %q mode %q seeded flag does not match runtime mode",91 spec.Definition.Name,92 modeDef.Title,93 ))94 }95 entries = append(entries, entry)96 }9798 return Entry{99 Definition: spec.Definition,100 Help: spec.Help,101 Import: spec.Import,102 Modes: entries,103 Print: spec.Print,104 }105}