package main import ( "bufio" "fmt" "os" "sort" "strings" "time" ) type TimeAction struct { DateTime time.Time Action string } type ByTime []TimeAction func (t ByTime) Len() int { return len(t) } func (t ByTime) Swap(i, j int) { t[i], t[j] = t[j], t[i] } func (t ByTime) Less(i, j int) bool { return t[i].DateTime.Before(t[j].DateTime) } type Puzzle struct { RawLog []TimeAction GuardSleep map[int][60]int } func (p *Puzzle) Add(dt time.Time, action string) { if p.RawLog == nil { p.RawLog = make([]TimeAction, 0, 100) } p.RawLog = append(p.RawLog, TimeAction{ DateTime: dt, Action: action, }) } func (p *Puzzle) Finish() { sort.Sort(ByTime(p.RawLog)) p.GuardSleep = make(map[int][60]int) var m, d int var guard int var sleep int for _, item := range p.RawLog { if int(item.DateTime.Month()) > m { m = int(item.DateTime.Month()) } if item.DateTime.Day() > d { d = item.DateTime.Day() } switch item.Action { case "falls asleep": sleep = item.DateTime.Minute() case "wakes up": g, _ := p.GuardSleep[guard] for t := sleep; t < item.DateTime.Minute(); t++ { g[t]++ } p.GuardSleep[guard] = g default: fmt.Sscanf(item.Action, "Guard #%d", &guard) sleep = 0 } } } func (p *Puzzle) Solution1() int { most := 0 guard := 0 favMinute := 0 for gid, g := range p.GuardSleep { totalSleep := 0 highestTimes := 0 minute := 0 for min, times := range g { if times > 0 { totalSleep += times } if times > highestTimes { highestTimes = times minute = min } } if totalSleep > most { most = totalSleep guard = gid favMinute = minute } } return guard * favMinute } func (p *Puzzle) Solution2() int { highestMinute := 0 highestMinuteVal := 0 guard := 0 for gid, g := range p.GuardSleep { highMin := 0 highMinVal := 0 for min, times := range g { if times > highMinVal { highMinVal = times highMin = min } } if highMinVal > highestMinuteVal { highestMinuteVal = highMinVal highestMinute = highMin guard = gid } } return guard * highestMinute } func main() { input, err := os.Open("input.txt") if err != nil { panic(err.Error()) } defer input.Close() scanner := bufio.NewScanner(input) p := Puzzle{} for scanner.Scan() { split := strings.SplitAfter(scanner.Text(), "] ") dt, _ := time.Parse("2006-01-02 15:04", strings.Trim(split[0], "[] ")) action := split[1] p.Add(dt, action) } if err := scanner.Err(); err != nil { panic(err.Error()) } p.Finish() fmt.Println(p.Solution1()) fmt.Println(p.Solution2()) }