fix: resolve go vet error and dayStart logic in ComputeDailyTotals
- Fix 'string(d)' int-to-rune conversion in rpg_test.go by using fmt.Sprintf - Fix ComputeDailyTotals dayStart logic: initial state should be StateWorking when dayStart > 0, correctly counting work from dayStart to first out event - Update README project structure to reflect new domain/handler/repo layout - Implement missing achievements: rpg_pioneer (on RPG enable) and salary_setter (on first rate set) - Add tryUnlockAchievement helper to Handler
This commit is contained in:
76
internal/domain/rpg.go
Normal file
76
internal/domain/rpg.go
Normal file
@@ -0,0 +1,76 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user