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