Refactor common guard code into library.

This commit is contained in:
Anna Rose 2018-12-04 03:30:22 -05:00
parent 66ae468435
commit fd4f9be7d0
No known key found for this signature in database
GPG Key ID: 8D9ACA841015C59A
2 changed files with 110 additions and 105 deletions

View File

@ -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
}

View 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
}