package eight import ( "bufio" "os" "sort" "strings" ) const ( one = 2 four = 4 seven = 3 eight = 7 ) type output struct { signals []string outputs []string } type display struct { outputs []output } func (d *display) load(filename string) error { file, err := os.Open(filename) if err != nil { return err } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { o := output{} insOuts := strings.Split(scanner.Text(), " | ") o.signals = strings.Split(insOuts[0], " ") o.outputs = strings.Split(insOuts[1], " ") d.outputs = append(d.outputs, o) } return nil } func (d *display) uniqueOuputs() int { count := 0 for _, o := range d.outputs { for _, s := range o.outputs { switch len(s) { case one, four, seven, eight: count++ } } } return count } func (o *output) decode() (value int) { decoded := make(map[string]int, 10) twoThreeFive := []string{} zeroSixNine := []string{} sortedSignals := []string{} for _, s := range o.signals { segments := sort.StringSlice(strings.Split(s, "")) sort.Sort(segments) sortedSignals = append(sortedSignals, strings.Join(segments, "")) } // Find known digits for _, s := range sortedSignals { switch len(s) { case one: decoded[s] = 1 case four: decoded[s] = 4 case seven: decoded[s] = 7 case eight: decoded[s] = 8 case 5: twoThreeFive = append(twoThreeFive, s) case 6: zeroSixNine = append(zeroSixNine, s) } } // Decode twoThreeFive twoFive := []string{} // Find 3 string for s, v := range decoded { if v == 1 { for _, v := range twoThreeFive { sharedSegments := 0 for _, segment := range s { if strings.Contains(v, string(segment)) { sharedSegments++ } } if sharedSegments == 2 { decoded[v] = 3 } else { twoFive = append(twoFive, v) } } } } // Find 5 and 2 string for s, v := range decoded { if v == 4 { for _, v := range twoFive { sharedSegments := 0 for _, segment := range s { if strings.Contains(v, string(segment)) { sharedSegments++ } } if sharedSegments == 3 { decoded[v] = 5 } else { decoded[v] = 2 } } } } // Decode zeroSixNine // Find 0 string sixNine := []string{} for s, v := range decoded { if v == 5 { for _, v := range zeroSixNine { sharedSegments := 0 for _, segment := range s { if strings.Contains(v, string(segment)) { sharedSegments++ } } if sharedSegments != 5 { decoded[v] = 0 } else { sixNine = append(sixNine, v) } } } } // Find the 9 and 6 strings for s, v := range decoded { if v == 1 { for _, v := range sixNine { sharedSegments := 0 for _, segment := range s { if strings.Contains(v, string(segment)) { sharedSegments++ } } if sharedSegments == 2 { decoded[v] = 9 } else { decoded[v] = 6 } } } } for i, signal := range o.outputs { scale := 1 switch i { case 0: scale = 1000 case 1: scale = 100 case 2: scale = 10 } segments := sort.StringSlice(strings.Split(signal, "")) sort.Sort(segments) sortedSignal := strings.Join(segments, "") value += scale * decoded[sortedSignal] } return value } func (d *display) outputSum() (sum int) { for _, o := range d.outputs { sum += o.decode() } return sum }