package day04 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 }