clone

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

chore/app-model-decomp
puzzletea / games / nurikabe / gamemode.go
gamemode.go 3.0K
1package nurikabe23import (4 "context"5 _ "embed"6 "fmt"7 "math/rand/v2"89 "github.com/FelineStateMachine/puzzletea/difficulty"10 "github.com/FelineStateMachine/puzzletea/game"11 "github.com/FelineStateMachine/puzzletea/gameentry"12 "github.com/FelineStateMachine/puzzletea/puzzle"13)1415//go:embed help.md16var HelpContent string1718type NurikabeMode struct {19 game.BaseMode20 Width int21 Height int22 ClueDensity float6423 MaxIslandSize int24}2526var (27 _ game.Mode = NurikabeMode{}28 _ game.Spawner = NurikabeMode{}29 _ game.SeededSpawner = NurikabeMode{}30 _ game.CancellableSpawner = NurikabeMode{}31 _ game.CancellableSeededSpawner = NurikabeMode{}32 _ game.EloSpawner = NurikabeMode{}33)3435func NewMode(title, desc string, width, height int, clueDensity float64, maxIslandSize int) NurikabeMode {36 return NurikabeMode{37 BaseMode: game.NewBaseMode(title, desc),38 Width: width,39 Height: height,40 ClueDensity: clueDensity,41 MaxIslandSize: maxIslandSize,42 }43}4445func (n NurikabeMode) Spawn() (game.Gamer, error) {46 return n.SpawnContext(context.Background())47}4849func (n NurikabeMode) SpawnContext(ctx context.Context) (game.Gamer, error) {50 p, err := GenerateWithContext(ctx, n)51 if err != nil {52 return nil, err53 }54 return New(n, p)55}5657func (n NurikabeMode) SpawnSeeded(rng *rand.Rand) (game.Gamer, error) {58 return n.SpawnSeededContext(context.Background(), rng)59}6061func (n NurikabeMode) SpawnSeededContext(ctx context.Context, rng *rand.Rand) (game.Gamer, error) {62 if rng == nil {63 return nil, fmt.Errorf("nil RNG")64 }65 p, err := GenerateSeededWithContext(ctx, n, rng)66 if err != nil {67 return nil, err68 }69 return New(n, p)70}7172var Modes = []game.Mode{73 NewMode("Mini", "5x5 grid, gentle introduction.", 5, 5, 0.28, 5),74 NewMode("Easy", "7x7 grid, balanced logic.", 7, 7, 0.24, 7),75 NewMode("Medium", "9x9 grid, moderate deduction.", 9, 9, 0.20, 9),76 NewMode("Hard", "11x11 grid, lower clue density.", 11, 11, 0.16, 11),77 NewMode("Expert", "12x12 grid, sparse clues and long chains.", 12, 12, 0.14, 12),78}7980var ModeDefinitions = nurikabeModeDefinitions(Modes)8182func nurikabeModeDefinitions(modes []game.Mode) []puzzle.ModeDef {83 defs := gameentry.BuildModeDefs(modes)84 presets := []difficulty.Elo{300, 800, 1400, 2100, 2700}85 for i, mode := range modes {86 if i >= len(defs) || i >= len(presets) {87 break88 }89 if _, ok := mode.(game.EloSpawner); !ok {90 continue91 }92 elo := presets[i]93 defs[i].PresetElo = &elo94 }95 return defs96}9798var Definition = puzzle.NewDefinition(puzzle.DefinitionSpec{99 Name: "Nurikabe",100 Description: "Split the land while keeping one connected sea.",101 Aliases: []string{"islands", "sea"},102 Modes: ModeDefinitions,103 DailyModeIDs: puzzle.SelectModeIDsByIndex(ModeDefinitions, 1, 2),104})105106var Entry = gameentry.NewEntry(gameentry.EntrySpec{107 Definition: Definition,108 Help: HelpContent,109 Import: game.AdaptImport(ImportModel),110 Modes: Modes,111 Print: PDFPrintAdapter,112})