153 lines
3.0 KiB
Go
153 lines
3.0 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"os"
|
||
|
"sort"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
var guards map[int]*Guard
|
||
|
|
||
|
func main() {
|
||
|
inp := StdinToStringSlice()
|
||
|
buildGuardMap(inp)
|
||
|
part1()
|
||
|
part2()
|
||
|
}
|
||
|
|
||
|
func buildGuardMap(inp []string) {
|
||
|
sort.Strings(inp)
|
||
|
guards = make(map[int]*Guard)
|
||
|
var currGuard int
|
||
|
var sleepStart time.Time
|
||
|
for _, v := range inp {
|
||
|
t, _ := time.Parse("2006-01-02 15:04", v[1:17])
|
||
|
actionParts := strings.Split(v[19:], " ")
|
||
|
switch actionParts[0][0] {
|
||
|
case 'G':
|
||
|
currGuard = Atoi(actionParts[1][1:])
|
||
|
case 'f':
|
||
|
sleepStart = t
|
||
|
case 'w':
|
||
|
if _, ok := guards[currGuard]; !ok {
|
||
|
guards[currGuard] = &Guard{
|
||
|
id: currGuard,
|
||
|
totalSleepTime: 0,
|
||
|
sleepLog: make([]Nap, 0, 5),
|
||
|
}
|
||
|
}
|
||
|
guards[currGuard].TakeNap(sleepStart, t)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func part1() {
|
||
|
var sleepiest int
|
||
|
var sleepiestTime int
|
||
|
for k, v := range guards {
|
||
|
if v.TotalNapTime() > sleepiestTime {
|
||
|
sleepiest = k
|
||
|
sleepiestTime = v.TotalNapTime()
|
||
|
}
|
||
|
}
|
||
|
min, _ := guards[sleepiest].GetSleepiestMinute()
|
||
|
fmt.Println("= Part 1 =")
|
||
|
fmt.Println("Sleepiest Guard:", sleepiest, "(", sleepiestTime, ") Sleepiest Minute:", min)
|
||
|
fmt.Println("= Answer =")
|
||
|
fmt.Println(sleepiest * min)
|
||
|
}
|
||
|
|
||
|
func part2() {
|
||
|
var sleepiestTime int
|
||
|
type tuple struct {
|
||
|
v1, v2 int
|
||
|
}
|
||
|
sleepiestMinutes := make(map[int]tuple)
|
||
|
for _, v := range guards {
|
||
|
v1, v2 := v.GetSleepiestMinute()
|
||
|
sleepiestMinutes[v.id] = tuple{v1, v2}
|
||
|
if v.TotalNapTime() > sleepiestTime {
|
||
|
sleepiestTime = v.TotalNapTime()
|
||
|
}
|
||
|
}
|
||
|
var highestCount, highestCountGuard, highestCountMinute int
|
||
|
for k, v := range sleepiestMinutes {
|
||
|
if v.v2 > highestCount {
|
||
|
highestCount = v.v2
|
||
|
highestCountGuard = k
|
||
|
highestCountMinute = v.v1
|
||
|
}
|
||
|
}
|
||
|
fmt.Println("= Part 2 =")
|
||
|
fmt.Printf("Guard: %d\nMinute: %d\nCount: %d\n", highestCountGuard, highestCountMinute, highestCount)
|
||
|
fmt.Println("= Answer =")
|
||
|
fmt.Println(highestCountGuard * highestCountMinute)
|
||
|
}
|
||
|
|
||
|
type Guard struct {
|
||
|
id int
|
||
|
totalSleepTime int
|
||
|
sleepLog []Nap
|
||
|
}
|
||
|
|
||
|
func (g *Guard) TakeNap(start, end time.Time) {
|
||
|
g.sleepLog = append(
|
||
|
g.sleepLog,
|
||
|
Nap{start: start, end: end})
|
||
|
}
|
||
|
|
||
|
func (g *Guard) TotalNapTime() int {
|
||
|
var ret int
|
||
|
for _, v := range g.sleepLog {
|
||
|
ret += int(v.end.Sub(v.start).Minutes())
|
||
|
}
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
func (g *Guard) GetSleepiestMinute() (int, int) {
|
||
|
minuteMap := make(map[int]int)
|
||
|
for _, v := range g.sleepLog {
|
||
|
wrkMin := v.start.Minute()
|
||
|
for wrkMin < v.end.Minute() {
|
||
|
minuteMap[wrkMin]++
|
||
|
wrkMin++
|
||
|
}
|
||
|
}
|
||
|
var sleepiestMinute, sleepiestCount int
|
||
|
for k, v := range minuteMap {
|
||
|
if v > sleepiestCount {
|
||
|
sleepiestMinute = k
|
||
|
sleepiestCount = v
|
||
|
}
|
||
|
}
|
||
|
return sleepiestMinute, minuteMap[sleepiestMinute]
|
||
|
}
|
||
|
|
||
|
type Nap struct {
|
||
|
start time.Time
|
||
|
end time.Time
|
||
|
}
|
||
|
|
||
|
func StdinToStringSlice() []string {
|
||
|
var input []string
|
||
|
scanner := bufio.NewScanner(os.Stdin)
|
||
|
for scanner.Scan() {
|
||
|
input = append(input, scanner.Text())
|
||
|
}
|
||
|
return input
|
||
|
}
|
||
|
|
||
|
func Atoi(i string) int {
|
||
|
var ret int
|
||
|
var err error
|
||
|
if ret, err = strconv.Atoi(i); err != nil {
|
||
|
log.Fatal("Invalid Atoi")
|
||
|
}
|
||
|
return ret
|
||
|
}
|