Refactor common guard code into library.
This commit is contained in:
parent
66ae468435
commit
fd4f9be7d0
115
2018/day04-1.go
115
2018/day04-1.go
|
@ -2,42 +2,39 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
|
"internal/guards"
|
||||||
"internal/util"
|
"internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
data := util.ReadInput()
|
data := util.ReadInput()
|
||||||
shifts := ParseInput(data)
|
shifts := guards.ParseInput(data)
|
||||||
guards := BuildGuards(shifts)
|
guards := guards.BuildGuards(shifts)
|
||||||
|
|
||||||
sleepiest, sleepiestMinute := FindSleepiestData(guards)
|
sleepiest, sleepiestMinute := FindSleepiestData(guards)
|
||||||
|
|
||||||
fmt.Printf("Sleepiest Guard: %d\n", sleepiest.id)
|
fmt.Printf("Sleepiest Guard: %d\n", sleepiest.ID)
|
||||||
fmt.Printf("Sleepiest Minute: %d\n", sleepiestMinute)
|
fmt.Printf("Sleepiest Minute: %d\n", sleepiestMinute)
|
||||||
fmt.Printf("Result: %d\n", sleepiest.id*sleepiestMinute)
|
fmt.Printf("Result: %d\n", sleepiest.ID*sleepiestMinute)
|
||||||
}
|
}
|
||||||
|
|
||||||
func FindSleepiestData(guards map[int]*Guard) (*Guard, int) {
|
func FindSleepiestData(data map[int]*guards.Guard) (*guards.Guard, int) {
|
||||||
var sleepiest *Guard
|
var sleepiest *guards.Guard
|
||||||
for _, guard := range guards {
|
for _, guard := range data {
|
||||||
if sleepiest == nil {
|
if sleepiest == nil {
|
||||||
sleepiest = guard
|
sleepiest = guard
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if guard.sleepTotal > sleepiest.sleepTotal {
|
if guard.SleepTotal > sleepiest.SleepTotal {
|
||||||
sleepiest = guard
|
sleepiest = guard
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sleepiestMinute := -1
|
sleepiestMinute := -1
|
||||||
sleepiestCount := 0
|
sleepiestCount := 0
|
||||||
for minute, sleepiness := range sleepiest.sleep {
|
for minute, sleepiness := range sleepiest.Sleep {
|
||||||
if sleepiness > sleepiestCount {
|
if sleepiness > sleepiestCount {
|
||||||
sleepiestCount = sleepiness
|
sleepiestCount = sleepiness
|
||||||
sleepiestMinute = minute
|
sleepiestMinute = minute
|
||||||
|
@ -46,95 +43,3 @@ func FindSleepiestData(guards map[int]*Guard) (*Guard, int) {
|
||||||
|
|
||||||
return sleepiest, sleepiestMinute
|
return sleepiest, sleepiestMinute
|
||||||
}
|
}
|
||||||
|
|
||||||
type Guard struct {
|
|
||||||
id int
|
|
||||||
sleep [60]int
|
|
||||||
sleepTotal int
|
|
||||||
}
|
|
||||||
|
|
||||||
type SleepEvent struct {
|
|
||||||
start, end int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Shift struct {
|
|
||||||
start time.Time
|
|
||||||
guard int
|
|
||||||
sleepEvents []*SleepEvent
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseInput takes the input data and creates a series of "Shift" objects,
|
|
||||||
// which are just a structured form of the data.
|
|
||||||
func ParseInput(rawData []string) []*Shift {
|
|
||||||
sort.Strings(rawData)
|
|
||||||
|
|
||||||
shifts := []*Shift{}
|
|
||||||
var currentShift *Shift
|
|
||||||
var currentSleepEvent *SleepEvent
|
|
||||||
|
|
||||||
for _, line := range rawData {
|
|
||||||
data := strings.Split(line, "]")
|
|
||||||
timestamp, _ := time.Parse("2006-01-02 15:04", data[0][1:])
|
|
||||||
event := data[1][1:]
|
|
||||||
|
|
||||||
// handle beginning of shift
|
|
||||||
if strings.HasPrefix(event, "Guard #") {
|
|
||||||
// save old shift first
|
|
||||||
if currentShift != nil {
|
|
||||||
shifts = append(shifts, currentShift)
|
|
||||||
}
|
|
||||||
|
|
||||||
// now extract the guard ID and create a new Shift object
|
|
||||||
guardID, _ := strconv.Atoi(strings.Split(event, " ")[1][1:])
|
|
||||||
currentShift = &Shift{
|
|
||||||
guard: guardID,
|
|
||||||
start: timestamp,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(event, "falls") {
|
|
||||||
currentSleepEvent = &SleepEvent{
|
|
||||||
start: timestamp.Minute(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasPrefix(event, "wakes") {
|
|
||||||
currentSleepEvent.end = timestamp.Minute()
|
|
||||||
currentShift.sleepEvents = append(currentShift.sleepEvents, currentSleepEvent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// save last shift
|
|
||||||
shifts = append(shifts, currentShift)
|
|
||||||
|
|
||||||
return shifts
|
|
||||||
}
|
|
||||||
|
|
||||||
// BuildGuards takes the shift data created by ParseInput and builds a map of
|
|
||||||
// 'guards', with a per-minute counter (and handy sum) of their sleep habits.
|
|
||||||
func BuildGuards(data []*Shift) map[int]*Guard {
|
|
||||||
guards := make(map[int]*Guard)
|
|
||||||
|
|
||||||
for _, shift := range data {
|
|
||||||
// fetch the guard for this shift, initialize if necessary
|
|
||||||
var guard *Guard
|
|
||||||
// declaring 'ok' here seems to be the only way to keep 'guard' from becoming
|
|
||||||
// a local variable inside the conditional. This seems like a flaw.
|
|
||||||
var ok bool
|
|
||||||
if guard, ok = guards[shift.guard]; !ok {
|
|
||||||
guard = &Guard{
|
|
||||||
id: shift.guard,
|
|
||||||
}
|
|
||||||
guards[guard.id] = guard
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, event := range shift.sleepEvents {
|
|
||||||
guard.sleepTotal += event.end - event.start
|
|
||||||
for i := event.start; i < event.end; i++ {
|
|
||||||
guard.sleep[i]++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return guards
|
|
||||||
}
|
|
||||||
|
|
100
2018/internal/guards/guards.go
Normal file
100
2018/internal/guards/guards.go
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
package guards
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Guard struct {
|
||||||
|
ID int
|
||||||
|
Sleep [60]int
|
||||||
|
SleepTotal int
|
||||||
|
}
|
||||||
|
|
||||||
|
type SleepEvent struct {
|
||||||
|
start, end int
|
||||||
|
}
|
||||||
|
|
||||||
|
type Shift struct {
|
||||||
|
start time.Time
|
||||||
|
guard int
|
||||||
|
sleepEvents []*SleepEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseInput takes the input data and creates a series of "Shift" objects,
|
||||||
|
// which are just a structured form of the data.
|
||||||
|
func ParseInput(rawData []string) []*Shift {
|
||||||
|
sort.Strings(rawData)
|
||||||
|
|
||||||
|
shifts := []*Shift{}
|
||||||
|
var currentShift *Shift
|
||||||
|
var currentSleepEvent *SleepEvent
|
||||||
|
|
||||||
|
for _, line := range rawData {
|
||||||
|
data := strings.Split(line, "]")
|
||||||
|
timestamp, _ := time.Parse("2006-01-02 15:04", data[0][1:])
|
||||||
|
event := data[1][1:]
|
||||||
|
|
||||||
|
// handle beginning of shift
|
||||||
|
if strings.HasPrefix(event, "Guard #") {
|
||||||
|
// save old shift first
|
||||||
|
if currentShift != nil {
|
||||||
|
shifts = append(shifts, currentShift)
|
||||||
|
}
|
||||||
|
|
||||||
|
// now extract the guard ID and create a new Shift object
|
||||||
|
guardID, _ := strconv.Atoi(strings.Split(event, " ")[1][1:])
|
||||||
|
currentShift = &Shift{
|
||||||
|
guard: guardID,
|
||||||
|
start: timestamp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(event, "falls") {
|
||||||
|
currentSleepEvent = &SleepEvent{
|
||||||
|
start: timestamp.Minute(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(event, "wakes") {
|
||||||
|
currentSleepEvent.end = timestamp.Minute()
|
||||||
|
currentShift.sleepEvents = append(currentShift.sleepEvents, currentSleepEvent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// save last shift
|
||||||
|
shifts = append(shifts, currentShift)
|
||||||
|
|
||||||
|
return shifts
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildGuards takes the shift data created by ParseInput and builds a map of
|
||||||
|
// 'guards', with a per-minute counter (and handy sum) of their sleep habits.
|
||||||
|
func BuildGuards(data []*Shift) map[int]*Guard {
|
||||||
|
guards := make(map[int]*Guard)
|
||||||
|
|
||||||
|
for _, shift := range data {
|
||||||
|
// fetch the guard for this shift, initialize if necessary
|
||||||
|
var guard *Guard
|
||||||
|
// declaring 'ok' here seems to be the only way to keep 'guard' from becoming
|
||||||
|
// a local variable inside the conditional. This seems like a flaw.
|
||||||
|
var ok bool
|
||||||
|
if guard, ok = guards[shift.guard]; !ok {
|
||||||
|
guard = &Guard{
|
||||||
|
ID: shift.guard,
|
||||||
|
}
|
||||||
|
guards[guard.ID] = guard
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, event := range shift.sleepEvents {
|
||||||
|
guard.SleepTotal += event.end - event.start
|
||||||
|
for i := event.start; i < event.end; i++ {
|
||||||
|
guard.Sleep[i]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return guards
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user