clone

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

chore/app-model-decomp
puzzletea / store / metadata.go
metadata.go 2.5K
1package store23import (4 "regexp"5 "strconv"6 "strings"7 "time"89 "github.com/FelineStateMachine/puzzletea/puzzle"10)1112var weeklyNamePattern = regexp.MustCompile(`^Week (\d{2})-(\d{4}) - #(\d{2})$`)1314func NormalRunMetadata() RunMetadata {15 return RunMetadata{Kind: RunKindNormal}16}1718func DailyRunMetadata(date time.Time) RunMetadata {19 day := dayOnly(date)20 return RunMetadata{21 Kind: RunKindDaily,22 Date: &day,23 }24}2526func WeeklyRunMetadata(year, week, index int) RunMetadata {27 return RunMetadata{28 Kind: RunKindWeekly,29 WeekYear: year,30 WeekNumber: week,31 WeekIndex: index,32 }33}3435func SeededRunMetadata(seed string) RunMetadata {36 return RunMetadata{37 Kind: RunKindSeeded,38 SeedText: strings.TrimSpace(seed),39 }40}4142func RunKindForName(name string) RunKind {43 switch {44 case RunDateForName(name) != nil:45 return RunKindDaily46 case isWeeklyName(name):47 return RunKindWeekly48 case SeedTextForName(name) != "":49 return RunKindSeeded50 default:51 return RunKindNormal52 }53}5455func RunDateForName(name string) *time.Time {56 if !strings.HasPrefix(name, "Daily ") {57 return nil58 }59 label, _, found := strings.Cut(strings.TrimPrefix(name, "Daily "), " - ")60 if !found {61 return nil62 }63 t, err := time.ParseInLocation("Jan _2 06", label, time.Local)64 if err != nil {65 return nil66 }67 day := dayOnly(t)68 return &day69}7071func WeeklyIdentityForName(name string) (year, week, index int, ok bool) {72 matches := weeklyNamePattern.FindStringSubmatch(name)73 if len(matches) != 4 {74 return 0, 0, 0, false75 }7677 week, err := strconv.Atoi(matches[1])78 if err != nil {79 return 0, 0, 0, false80 }81 year, err = strconv.Atoi(matches[2])82 if err != nil {83 return 0, 0, 0, false84 }85 index, err = strconv.Atoi(matches[3])86 if err != nil {87 return 0, 0, 0, false88 }89 return year, week, index, true90}9192func SeedTextForName(name string) string {93 if strings.HasPrefix(name, "Daily ") || isWeeklyName(name) {94 return ""95 }96 seedPart, _, found := strings.Cut(name, " - ")97 if !found {98 return ""99 }100 seedPart = strings.TrimSpace(seedPart)101 if seedPart == "" {102 return ""103 }104 if before, _, hasGame := strings.Cut(seedPart, " ["); hasGame {105 return strings.TrimSpace(before)106 }107 return seedPart108}109110func CanonicalGameID(gameType string) string {111 return string(puzzle.CanonicalGameID(gameType))112}113114func CanonicalModeID(mode string) string {115 return string(puzzle.CanonicalModeID(mode))116}117118func isWeeklyName(name string) bool {119 _, _, _, ok := WeeklyIdentityForName(name)120 return ok121}122123func dayOnly(t time.Time) time.Time {124 return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())125}