package domain import "time" // XpForLevel returns the total XP required to reach level n. func XpForLevel(n int) int64 { return int64(n) * int64(n+1) * XPCurveMultiplier } // LevelForXP returns the level for a given total XP amount. func LevelForXP(xp int64) int { l := 1 for XpForLevel(l) <= xp { l++ } return l - 1 } // XpForWorkSeconds calculates XP earned for a given amount of work. func XpForWorkSeconds(sec int64) int64 { return sec } // StreakBonus returns bonus XP for maintaining a streak. func StreakBonus(streak int) int64 { b := int64(streak) * XPCurveMultiplier if b > StreakBonusCap { b = StreakBonusCap } return b } // ComputeStreakFromDates computes current and longest streak from a sorted list of date strings. func ComputeStreakFromDates(dates []string, today string) (current, longest int) { if len(dates) == 0 { return 0, 0 } dateSet := make(map[string]struct{}, len(dates)) for _, d := range dates { dateSet[d] = struct{}{} } if _, ok := dateSet[today]; ok { current = 1 for i := 1; ; i++ { t, _ := time.Parse(DateLayout, today) prev := t.AddDate(0, 0, -i).Format(DateLayout) if _, ok := dateSet[prev]; ok { current++ } else { break } } } longest = 0 run := 1 for i := 1; i < len(dates); i++ { prev, _ := time.Parse(DateLayout, dates[i-1]) curr, _ := time.Parse(DateLayout, dates[i]) if curr.Sub(prev).Hours() == 24 { run++ } else { if run > longest { longest = run } run = 1 } } if run > longest { longest = run } return current, longest }