diff --git a/2018/day04-1.go b/2018/day04-1.go index 5c01886..59cd3b5 100644 --- a/2018/day04-1.go +++ b/2018/day04-1.go @@ -2,42 +2,39 @@ package main import ( "fmt" - "sort" - "strconv" - "strings" - "time" + "internal/guards" "internal/util" ) func main() { data := util.ReadInput() - shifts := ParseInput(data) - guards := BuildGuards(shifts) + shifts := guards.ParseInput(data) + guards := guards.BuildGuards(shifts) 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("Result: %d\n", sleepiest.id*sleepiestMinute) + fmt.Printf("Result: %d\n", sleepiest.ID*sleepiestMinute) } -func FindSleepiestData(guards map[int]*Guard) (*Guard, int) { - var sleepiest *Guard - for _, guard := range guards { +func FindSleepiestData(data map[int]*guards.Guard) (*guards.Guard, int) { + var sleepiest *guards.Guard + for _, guard := range data { if sleepiest == nil { sleepiest = guard continue } - if guard.sleepTotal > sleepiest.sleepTotal { + if guard.SleepTotal > sleepiest.SleepTotal { sleepiest = guard } } sleepiestMinute := -1 sleepiestCount := 0 - for minute, sleepiness := range sleepiest.sleep { + for minute, sleepiness := range sleepiest.Sleep { if sleepiness > sleepiestCount { sleepiestCount = sleepiness sleepiestMinute = minute @@ -46,95 +43,3 @@ func FindSleepiestData(guards map[int]*Guard) (*Guard, int) { 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 -} diff --git a/2018/internal/guards/guards.go b/2018/internal/guards/guards.go new file mode 100644 index 0000000..19c456e --- /dev/null +++ b/2018/internal/guards/guards.go @@ -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 +}