clone

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

feat/elo-difficulty
puzzletea / puzzle / puzzle.go
puzzle.go 4.1K
1package puzzle23import (4 "strings"56 "github.com/FelineStateMachine/puzzletea/difficulty"7)89type GameID string1011type ModeID string1213type ModeDef struct {14 ID ModeID15 Title string16 Description string17 Seeded bool18 PresetElo *difficulty.Elo19}2021type VariantID string2223type VariantDef struct {24 ID VariantID25 Title string26 Description string27 DefaultElo difficulty.Elo28}2930type VariantSpec struct {31 ID VariantID32 Title string33 Description string34 DefaultElo difficulty.Elo35}3637type LegacyModeAlias struct {38 ID ModeID39 Title string40 Description string41 TargetVariantID VariantID42 PresetElo difficulty.Elo43 XPWeight int44 CLIAliases []string45}4647type LegacyModeAliasSpec struct {48 ID ModeID49 Title string50 Description string51 TargetVariantID VariantID52 PresetElo difficulty.Elo53 XPWeight int54 CLIAliases []string55}5657type ModeSpec struct {58 ID ModeID59 Title string60 Description string61 Seeded bool62 PresetElo *difficulty.Elo63}6465type Definition struct {66 ID GameID67 Name string68 Description string69 Aliases []string70 Variants []VariantDef71 LegacyModes []LegacyModeAlias72 Modes []ModeDef73 DailyModeIDs []ModeID74}7576type DefinitionSpec struct {77 ID GameID78 Name string79 Description string80 Aliases []string81 Variants []VariantDef82 LegacyModes []LegacyModeAlias83 Modes []ModeDef84 DailyModeIDs []ModeID85}8687func NewModeDef(spec ModeSpec) ModeDef {88 id := spec.ID89 if id == "" {90 id = CanonicalModeID(spec.Title)91 }92 return ModeDef{93 ID: id,94 Title: spec.Title,95 Description: spec.Description,96 Seeded: spec.Seeded,97 PresetElo: cloneElo(spec.PresetElo),98 }99}100101func NewVariantDef(spec VariantSpec) VariantDef {102 id := spec.ID103 if id == "" {104 id = CanonicalVariantID(spec.Title)105 }106 return VariantDef{107 ID: id,108 Title: spec.Title,109 Description: spec.Description,110 DefaultElo: spec.DefaultElo,111 }112}113114func NewLegacyModeAlias(spec LegacyModeAliasSpec) LegacyModeAlias {115 id := spec.ID116 if id == "" {117 id = CanonicalModeID(spec.Title)118 }119 xpWeight := spec.XPWeight120 if xpWeight < 1 {121 xpWeight = 1122 }123 return LegacyModeAlias{124 ID: id,125 Title: spec.Title,126 Description: spec.Description,127 TargetVariantID: spec.TargetVariantID,128 PresetElo: spec.PresetElo,129 XPWeight: xpWeight,130 CLIAliases: append([]string(nil), spec.CLIAliases...),131 }132}133134func NewDefinition(spec DefinitionSpec) Definition {135 id := spec.ID136 if id == "" {137 id = CanonicalGameID(spec.Name)138 }139 return Definition{140 ID: id,141 Name: spec.Name,142 Description: spec.Description,143 Aliases: append([]string(nil), spec.Aliases...),144 Variants: append([]VariantDef(nil), spec.Variants...),145 LegacyModes: append([]LegacyModeAlias(nil), spec.LegacyModes...),146 Modes: append([]ModeDef(nil), spec.Modes...),147 DailyModeIDs: append([]ModeID(nil), spec.DailyModeIDs...),148 }149}150151func cloneElo(elo *difficulty.Elo) *difficulty.Elo {152 if elo == nil {153 return nil154 }155 v := *elo156 return &v157}158159func SelectModeIDsByIndex(modes []ModeDef, indexes ...int) []ModeID {160 selected := make([]ModeID, 0, len(indexes))161 for _, idx := range indexes {162 if idx < 0 || idx >= len(modes) {163 continue164 }165 selected = append(selected, modes[idx].ID)166 }167 return selected168}169170func NormalizeName(s string) string {171 s = strings.ToLower(strings.TrimSpace(s))172 s = strings.ReplaceAll(s, "-", " ")173 s = strings.ReplaceAll(s, "_", " ")174 return strings.Join(strings.Fields(s), " ")175}176177func CanonicalGameID(name string) GameID {178 return GameID(NormalizeName(name))179}180181func CanonicalModeID(title string) ModeID {182 return ModeID(NormalizeName(title))183}184185func CanonicalVariantID(title string) VariantID {186 return VariantID(NormalizeName(title))187}188189func (d Definition) HasMode(id ModeID) bool {190 for _, mode := range d.Modes {191 if mode.ID == id {192 return true193 }194 }195 return false196}197198func (d Definition) HasVariant(id VariantID) bool {199 for _, variant := range d.Variants {200 if variant.ID == id {201 return true202 }203 }204 return false205}