package main import ( "fmt" log "github.com/sirupsen/logrus" ) const ( OPERATIONAL = iota DAMAGED UNKNOWN ) var records []record type record struct { format []int springs []spring } func newRecord() record { return record{} } // raw returns the state of all springs for this record as int array func (r record) raw() []int { vals := make([]int, len(r.springs)) for j, spring := range r.springs { vals[j] = spring.state } return vals } type spring struct { state int } func newSpring(state int) spring { return spring{state: state} } // tracker keeps track of results for function calls type tracker struct { checked map[string]int } func newTracker() tracker { return tracker{checked: make(map[string]int)} } func (t tracker) add(key string, res int) { t.checked[key] = res } func validate(springs, format []int) bool { return !contains(springs[:format[0]], OPERATIONAL) && (format[0] == len(springs) || springs[format[0]] != DAMAGED) } // count returns the number of arrangements possible for a set of springs func count(springs, format []int) int { if len(springs) == 0 { if len(format) == 0 { return 1 } return 0 } if len(format) == 0 { if contains(springs, DAMAGED) { return 0 } return 1 } identifier := fmt.Sprintf("%v%v", format, springs) if res, ok := fnTracker.checked[fmt.Sprintf("%v%v", format, springs)]; ok { log.Debug("returning cached value for ", identifier) return res } result := 0 if springs[0] == OPERATIONAL || springs[0] == UNKNOWN { result += count(springs[1:], format) } if springs[0] == DAMAGED || springs[0] == UNKNOWN { if format[0] < len(springs) && validate(springs, format) { result += count(springs[format[0]+1:], format[1:]) } else if format[0] == len(springs) && validate(springs, format) { result += count(springs[format[0]:], format[1:]) } } fnTracker.add(identifier, result) return result } var fnTracker tracker // one returns the sum of all arrangement counts func one(lines []string) int { parselines(lines) fnTracker = newTracker() sum := 0 for _, record := range records { raw := record.raw() sum += count(raw, record.format) } return sum }