package main import ( "bytes" "fmt" "sort" "strings" h "git.bullercodeworks.com/brian/adventofcode/helpers" ) func main() { inp := h.StdinToStringSlice() solve(inp) } func solve(inp []string) { var segments []seg for i := range inp { pts := strings.Split(inp[i], "|") var patterns [][]byte for _, v := range strings.Fields(pts[0]) { patterns = append(patterns, []byte(v)) } var output [][]byte for _, v := range strings.Fields(pts[1]) { output = append(output, []byte(v)) } segments = append(segments, DeduceSeg(patterns, output)) } var c1, c4, c7, c8 int var total int for i := range segments { c1 += segments[i].instances(1) c4 += segments[i].instances(4) c7 += segments[i].instances(7) c8 += segments[i].instances(8) total += segments[i].value() } fmt.Println("# Part 1") fmt.Println("1,4,7,8 appear", c1+c4+c7+c8, "times") fmt.Println("") fmt.Println("# Part 2") fmt.Println("Total", total) } type seg struct { N, NE, SE, S, SW, NW, C byte Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine []byte Output []int } func DeduceSeg(pInput, oInput [][]byte) seg { segments := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'} // 0, 3, 5, 9 var patterns [][]byte for _, p := range pInput { sort.Slice(p, func(i int, j int) bool { return p[i] < p[j] }) patterns = append(patterns, p) } var output [][]byte for _, o := range oInput { sort.Slice(o, func(i int, j int) bool { return o[i] < o[j] }) output = append(output, o) } var removeFromSegments = func(v ...byte) { for k := range v { rem := -1 for b := range segments { if segments[b] == v[k] { rem = b } } if rem > -1 { segments = append(segments[:rem], segments[rem+1:]...) } } } var removeFromPatterns = func(v ...[]byte) { for k := range v { rem := -1 for i := range patterns { if string(patterns[i]) == string(v[k]) { rem = i } } if rem > -1 { patterns = append(patterns[:rem], patterns[rem+1:]...) } } } s := seg{ N: '-', NE: '-', SE: '-', S: '-', SW: '-', NW: '-', C: '-', } for i := range patterns { switch { case len(patterns[i]) == 2: s.One = patterns[i] case len(patterns[i]) == 4: s.Four = patterns[i] case len(patterns[i]) == 3: s.Seven = patterns[i] case len(patterns[i]) == 7: s.Eight = patterns[i] } } removeFromPatterns(s.One, s.Four, s.Seven, s.Eight) //First, we know the N segment, it's what shows up in 'seven' , but not in 'one' for i := range s.Seven { if bytes.IndexByte(s.One, s.Seven[i]) == -1 { s.N = s.Seven[i] removeFromSegments(s.N) break } } // Six length numbers: // 0, 9, 6 // We know that 'seven' is inside of 'nine' and 'zero' but not 'six' for _, p := range patterns { if len(p) == 6 { for _, v := range s.Seven { if bytes.IndexByte(p, v) == -1 { // 'v' also has to be the NE segment s.NE = v removeFromSegments(s.NE) s.Six = p break } } } } removeFromPatterns(s.Six) for _, v := range s.Seven { if v != s.N && v != s.NE { s.SE = v removeFromSegments(s.SE) } } // Five length numbers: 2, 3, 5 // Two is missing the SE segment // Five is missing the NE segment for _, p := range patterns { if len(p) == 5 { if bytes.IndexByte(p, s.SE) == -1 { s.Two = p } if bytes.IndexByte(p, s.NE) == -1 { s.Five = p } } } removeFromPatterns(s.Two, s.Five) // The remaining 5 length is Three for _, p := range patterns { if len(p) == 5 { s.Three = p break } } removeFromPatterns(s.Three) // Nine is the same as Five except for NE for _, p := range patterns { for _, b := range p { if b != s.NE && bytes.IndexByte(s.Five, b) == -1 { s.Zero = p break } } } removeFromPatterns(s.Zero) s.Nine = patterns[0] // NW is the non-SE that is missing from Two for _, b := range segments { if b != s.SE && bytes.IndexByte(s.Two, b) == -1 { s.NW = b removeFromSegments(s.NW) break } } // SW is the segment in Six that's not in Five for _, b := range segments { if bytes.IndexByte(s.Five, b) == -1 && bytes.IndexByte(s.Six, b) != -1 { s.SW = b removeFromSegments(s.SW) } } // C is the remaining segment in Four that's not in 0 for _, b := range segments { if bytes.IndexByte(s.Zero, b) == -1 && bytes.IndexByte(s.Four, b) != -1 { s.C = b removeFromSegments(s.C) } } // The last segment is S s.S = segments[0] // Now fill in the outputs for i := range output { s.Output = append(s.Output, s.valueOf(output[i])) } return s } func (s seg) instances(v int) int { var t int for _, o := range s.Output { if o == v { t++ } } return t } func (s seg) value() int { var retStr string for _, o := range s.Output { retStr = retStr + h.Itoa(o) } return h.Atoi(retStr) } func (s seg) valueOf(b []byte) int { sort.Slice(b, func(i int, j int) bool { return b[i] < b[j] }) switch string(b) { case string(s.Zero): return 0 case string(s.One): return 1 case string(s.Two): return 2 case string(s.Three): return 3 case string(s.Four): return 4 case string(s.Five): return 5 case string(s.Six): return 6 case string(s.Seven): return 7 case string(s.Eight): return 8 case string(s.Nine): return 9 } return -1 } func (s seg) String() string { ret := fmt.Sprintf("%s\n", string([]byte{' ', s.N, s.N, s.N, s.N, ' '})) ret = fmt.Sprintf("%s%s\n", ret, string([]byte{s.NW, ' ', ' ', ' ', ' ', s.NE})) ret = fmt.Sprintf("%s%s\n", ret, string([]byte{s.NW, ' ', ' ', ' ', ' ', s.NE})) ret = fmt.Sprintf("%s%s\n", ret, string([]byte{' ', s.C, s.C, s.C, s.C, ' '})) ret = fmt.Sprintf("%s%s\n", ret, string([]byte{s.SW, ' ', ' ', ' ', ' ', s.SE})) ret = fmt.Sprintf("%s%s\n", ret, string([]byte{s.SW, ' ', ' ', ' ', ' ', s.SE})) ret = fmt.Sprintf("%s%s\n", ret, string([]byte{' ', s.S, s.S, s.S, s.S, ' '})) return ret }