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())
}