diff --git a/d8/d8.go b/d8/d8.go new file mode 100644 index 0000000..b8ec4ab --- /dev/null +++ b/d8/d8.go @@ -0,0 +1,264 @@ +package d8 + +import ( + "log" + "sort" + "strconv" + "strings" +) + +func D8(in string) int { + lines := strings.Split(strings.TrimSpace(in), "\n") + + sum := 0 + + for _, line := range lines { + for _, digit := range strings.Split(strings.Split(line, "|")[1], " ") { + if len(digit) == 2 || len(digit) == 3 || len(digit) == 4 || len(digit) == 7 { + sum++ + } + } + } + + return sum +} + +func difference(a []string, b []string) []string { + needle := a + haystack := b + + if len(a) > len(b) { + needle = b + haystack = a + } + + mb := make(map[string]struct{}, len(needle)) + for _, x := range needle { + mb[x] = struct{}{} + } + var diff []string + for _, x := range haystack { + if _, found := mb[x]; !found { + diff = append(diff, x) + } + } + return diff +} + +func merge(a []string, b []string) []string { + return append(append([]string{}, a...), b...) +} + +func findSegment(digits [][]string, part []string) string { + for _, digit := range digits { + diff := difference(digit, part) + + if len(digit) > len(part) && len(diff) == 1 { + return diff[0] + } + } + + log.Fatal("can't find segment") + + return "" +} + +// aaaa +// b c +// b c +// dddd +// e f +// e f +// gggg +// +// a: 0, c: 1, f: 2, g: 3, e: 4, b: 5, d: 6 +func findDisplay(digitsAsString string) []string { + display := make([]string, 7) + + digits := [][]string{} + splitted := strings.Split(digitsAsString, " ") + sort.Slice(splitted, func(i, j int) bool { return len(splitted[i]) < len(splitted[j]) }) + for _, digit := range splitted { + digits = append(digits, strings.Split(digit, "")) + } + + // a + display[0] = findSegment(digits, digits[0]) + // g + display[3] = findSegment(digits, merge(digits[2], []string{display[0]})) + // e + display[4] = findSegment(digits, merge(digits[2], []string{display[0], display[3]})) + // d + display[6] = findSegment(digits, merge(digits[1], []string{display[3]})) + // b + display[5] = findSegment(digits, merge(digits[1], []string{display[3], display[4], display[6]})) + // f + display[2] = findSegment(digits, []string{display[0], display[3], display[4], display[5], display[6]}) + // c + display[1] = findSegment(digits, []string{display[0], display[2], display[3], display[4], display[5], display[6]}) + + return display +} + +func isOne(digit []string, display []string) bool { + return len(digit) == 2 +} + +func isTwo(digit []string, display []string) bool { + + if len(digit) != 5 { + return false + } + + two := strings.Join([]string{display[0], display[1], display[3], display[4], display[6]}, "") + + for _, segment := range digit { + if !strings.Contains(two, segment) { + return false + } + } + + return true +} + +func isThree(digit []string, display []string) bool { + + if len(digit) != 5 { + return false + } + + three := strings.Join([]string{display[0], display[1], display[2], display[3], display[6]}, "") + + for _, segment := range digit { + if !strings.Contains(three, segment) { + return false + } + } + + return true +} + +func isFour(digit []string, display []string) bool { + return len(digit) == 4 +} + +func isFive(digit []string, display []string) bool { + + if len(digit) != 5 { + return false + } + + three := strings.Join([]string{display[0], display[2], display[3], display[5], display[6]}, "") + + for _, segment := range digit { + if !strings.Contains(three, segment) { + return false + } + } + + return true +} + +func isSix(digit []string, display []string) bool { + + if len(digit) != 6 { + return false + } + + three := strings.Join([]string{display[0], display[2], display[3], display[4], display[5], display[6]}, "") + + for _, segment := range digit { + if !strings.Contains(three, segment) { + return false + } + } + + return true +} + +func isSeven(digit []string, display []string) bool { + return len(digit) == 3 +} + +func isEight(digit []string, display []string) bool { + return len(digit) == 7 +} + +func isNine(digit []string, display []string) bool { + + if len(digit) != 6 { + return false + } + + three := strings.Join([]string{display[0], display[1], display[2], display[3], display[5], display[6]}, "") + + for _, segment := range digit { + if !strings.Contains(three, segment) { + return false + } + } + + return true +} + +func isZero(digit []string, display []string) bool { + + if len(digit) != 6 { + return false + } + + three := strings.Join([]string{display[0], display[1], display[2], display[3], display[4], display[5]}, "") + + for _, segment := range digit { + if !strings.Contains(three, segment) { + return false + } + } + + return true +} + +func digitToNumber(digit []string, display []string) int { + numberMap := map[int]func([]string, []string) bool{ + 0: isZero, + 1: isOne, + 2: isTwo, + 3: isThree, + 4: isFour, + 5: isFive, + 6: isSix, + 7: isSeven, + 8: isEight, + 9: isNine, + } + + for number, f := range numberMap { + if f(digit, display) { + return number + } + } + log.Fatal("wrong digit", digit, display) + return 0 +} + +func findCode(digitsAsString string, display []string) int { + numbers := []string{} + for _, digit := range strings.Split(digitsAsString, " ") { + numbers = append(numbers, strconv.Itoa(digitToNumber(strings.Split(digit, ""), display))) + } + asInt, _ := strconv.Atoi(strings.Join(numbers, "")) + + return asInt +} + +func D8P2(in string) int { + lines := strings.Split(strings.TrimSpace(in), "\n") + sum := 0 + for _, line := range lines { + wiringsAndCode := strings.Split(line, " | ") + display := findDisplay(wiringsAndCode[0]) + sum += findCode(wiringsAndCode[1], display) + } + + return sum +} diff --git a/d8/d8_test.go b/d8/d8_test.go new file mode 100644 index 0000000..9fb850a --- /dev/null +++ b/d8/d8_test.go @@ -0,0 +1,37 @@ +package d8 + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestD8(t *testing.T) { + input := `be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb | fdgacbe cefdb cefbgd gcbe +edbfga begcd cbg gc gcadebf fbgde acbgfd abcde gfcbed gfec | fcgedb cgb dgebacf gc +fgaebd cg bdaec gdafb agbcfd gdcbef bgcad gfac gcb cdgabef | cg cg fdcagb cbg +fbegcd cbd adcefb dageb afcb bc aefdc ecdab fgdeca fcdbega | efabcd cedba gadfec cb +aecbfdg fbg gf bafeg dbefa fcge gcbea fcaegb dgceab fcbdga | gecf egdcabf bgf bfgea +fgeab ca afcebg bdacfeg cfaedg gcfdb baec bfadeg bafgc acf | gebdcfa ecba ca fadegcb +dbcfg fgd bdegcaf fgec aegbdf ecdfab fbedc dacgb gdcebf gf | cefg dcbef fcge gbcadfe +bdfegc cbegaf gecbf dfcage bdacg ed bedf ced adcbefg gebcd | ed bcgafe cdgba cbgef +egadfb cdbfeg cegd fecab cgb gbdefca cg fgcdab egfdb bfceg | gbdfcae bgc cg cgb +gcafb gcf dcaebfg ecagb gf abcdeg gaef cafbge fdbac fegbdc | fgae cfgab fg bagce` + + assert.EqualValues(t, 26, D8(input)) +} + +func TestD8P2(t *testing.T) { + input := `be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb | fdgacbe cefdb cefbgd gcbe +edbfga begcd cbg gc gcadebf fbgde acbgfd abcde gfcbed gfec | fcgedb cgb dgebacf gc +fgaebd cg bdaec gdafb agbcfd gdcbef bgcad gfac gcb cdgabef | cg cg fdcagb cbg +fbegcd cbd adcefb dageb afcb bc aefdc ecdab fgdeca fcdbega | efabcd cedba gadfec cb +aecbfdg fbg gf bafeg dbefa fcge gcbea fcaegb dgceab fcbdga | gecf egdcabf bgf bfgea +fgeab ca afcebg bdacfeg cfaedg gcfdb baec bfadeg bafgc acf | gebdcfa ecba ca fadegcb +dbcfg fgd bdegcaf fgec aegbdf ecdfab fbedc dacgb gdcebf gf | cefg dcbef fcge gbcadfe +bdfegc cbegaf gecbf dfcage bdacg ed bedf ced adcbefg gebcd | ed bcgafe cdgba cbgef +egadfb cdbfeg cegd fecab cgb gbdefca cg fgcdab egfdb bfceg | gbdfcae bgc cg cgb +gcafb gcf dcaebfg ecagb gf abcdeg gaef cafbge fdbac fegbdc | fgae cfgab fg bagce` + + assert.EqualValues(t, 61229, D8P2(input)) +} diff --git a/main.go b/main.go index 376febb..34c79b1 100644 --- a/main.go +++ b/main.go @@ -14,6 +14,7 @@ import ( "github.com/fotonmoton/aoc2021/d5" "github.com/fotonmoton/aoc2021/d6" "github.com/fotonmoton/aoc2021/d7" + "github.com/fotonmoton/aoc2021/d8" ) func main() { @@ -40,4 +41,6 @@ func main() { fmt.Printf("day 6 part 2: %v\n", d6.D6P2(client.Day(6), 256)) fmt.Printf("day 7: %v\n", d7.D7(client.Day(7))) fmt.Printf("day 7 part 2: %v\n", d7.D7P2(client.Day(7))) + fmt.Printf("day 8: %v\n", d8.D8(client.Day(8))) + fmt.Printf("day 8 part 2: %v\n", d8.D8P2(client.Day(8))) }