2021-12-08 - Seven Segment Search
(original .ipynb)
Day 8 puzzle input is a collection of:
1. patterns that represent all digits 0
-9
in a random order in a 7-digit display followed by a pipe ...
2. then a pattern representing four digits that comprise an output
The segments in the display are addressed as a
through g
and the digits are constructed like the below:
0: 1: 2: 3: 4:
aaaa .... aaaa aaaa ....
b c . c . c . c b c
b c . c . c . c b c
.... .... dddd dddd dddd
e f . f e . . f . f
e f . f e . . f . f
gggg .... gggg gggg ....
5: 6: 7: 8: 9:
aaaa aaaa aaaa aaaa aaaa
b . b . . c b c b c
b . b . . c b c b c
dddd dddd .... dddd dddd
. f e f . f e f . f
. f e f . f e f . f
gggg gggg .... gggg gggg
My puzzle input is here. Part 1 involves finding the number of times the digits 1
, 4
, 7
and 8
(which are easy and unambiguous to spot) appear in the output. Part 2 involves finding a way to decode each line sum the resulting outputs.
puzzle_input_str = open("puzzle_input/day8.txt").read() test_input_str = """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""" digits = [ "abcefg", "cf", "acdeg", "acdfg", "bcdf", "abdfg", "abdefg", "acf", "abcdefg", "abcdfg" ] to_digits = {pattern:i for i, pattern in enumerate(digits)} def parse_line(line): input_values_str, output_values_str = line.split(" | ") return ( input_values_str.split(" "), output_values_str.split(" ") ) def parse_input_lines(input_str): return [parse_line(line) for line in input_str.split("\n")] def is_1478(v): v_len = len(v) return v_len == len(digits[1]) or v_len == len(digits[4]) or v_len == len(digits[7]) or v_len == len(digits[8]) def part_one(input_str): count = 0 for inputs, outputs in parse_input_lines(input_str): count += sum(1 for o in outputs if is_1478(o)) return count assert 26 == part_one(test_input_str) print("part one:", part_one(puzzle_input_str))
part one: 476
def find_known(input_values, n): return [set(v) for v in input_values if len(v) == len(digits[n])][0] def find_with_len(input_values, l): return [set(v) for v in input_values if len(v) == l] def find_with_segments(input_values, segments): return [set(v) for v in input_values if segments.issubset(set(v))] # get the value contained within a set with 1 item def single(some_set): assert len(some_set) == 1 return next(iter(some_set)) def find_a(input_values, signal_map): one = find_known(input_values, 1) seven = find_known(input_values, 7) signal_map["a"] = single(seven.difference(one)) def find_g(input_values, signal_map): modified_four = find_known(input_values, 4) modified_four.add(signal_map["a"]) maybe_nines = find_with_len(input_values, len(digits[9])) nine = find_with_segments(maybe_nines, modified_four)[0] signal_map["g"] = single(nine.difference(modified_four)) def find_c_d_f(input_values, signal_map): # construct a 9 nine = find_known(input_values, 4) nine.add(signal_map["a"]) nine.add(signal_map["g"]) # zs1, zs2 are either zero or six zs1, zs2 = [n for n in find_with_len(input_values, len(nine)) if n != nine] c_and_d = zs1.difference(zs2).union(zs2.difference(zs1)) one = find_known(input_values, 1) c = single(one.intersection(c_and_d)) signal_map["c"] = c c_and_d.discard(c) d = single(c_and_d) signal_map["d"] = d one.discard(c) one.discard(d) signal_map["f"] = single(one) def find_b(input_values, signal_map): four = find_known(input_values, 4) four.discard(signal_map["c"]) four.discard(signal_map["d"]) four.discard(signal_map["f"]) signal_map["b"] = single(four) def find_e(input_values, signal_map): # its early im tired this is stupid but whatever eight = find_known(input_values, 8) for char in "abcdfg": eight.discard(signal_map[char]) signal_map["e"] = single(eight) def get_signal_map(input_values): signal_map = {} for f in (find_a, find_g, find_c_d_f, find_b, find_e): f(input_values, signal_map) # fuck its the wrong way round return {v:k for k,v in signal_map.items()} def decode(output, signal_map): return "".join(sorted(signal_map[c] for c in output)) def part_two(input_str): count = 0 for inputs, outputs in parse_input_lines(input_str): signal_map = get_signal_map(inputs) decoded = "".join(str(to_digits[decode(output, signal_map)]) for output in outputs) count += int(decoded) return count assert 61229 == part_two(test_input_str) print("part two:", part_two(puzzle_input_str))
part two: 1011823