aoc-2021/day_8/code.py
2021-12-10 13:42:11 +01:00

205 lines
No EOL
3.7 KiB
Python

import fileinput
import itertools
# key: the digit, value: the number of segments
digit_segment_count = {
0: 6,
1: 2, #
2: 5,
3: 5,
4: 4, #
5: 5,
6: 6,
7: 3, #
8: 7, #
9: 6
}
unique_digit = { # easy digits: 1,4,7,8
2: 1,
4: 4,
3: 7,
7: 8
}
actual_digit = 'abcdefg'
actual_digit_mapping = {
0: 'abcefg',
1: 'cf',
2: 'acdeg',
3: 'acdfg',
4: 'bcdf',
5: 'abdfg',
6: 'abdefg',
7: 'acf',
8: 'abcdefg',
9: 'abcdfg'
}
# ab: digit 1
# dab: digit 7
# eafb: digit 4
# acedgfb: digit 8
def get_keys(d, value):
keys = []
ls = filter(lambda i: i[1] == value, list(d.items()))
ls = map(lambda i: i[0], ls)
return list(ls)
data = []
ex =[]
#ex = ['acedgfb cdfbe gcdfa fbcad dab cefabd cdfgeb eafb cagedb ab | cdfeb fcadb cdfeb cdbaf']
for line in ex+list(fileinput.input()):
content = line.strip()
if content == '': continue
def parse(x):
l = map(str, x.split(' '))
l = filter(lambda x: x != '', l)
return list(l)
ls = list(map(parse, content.split('|')))
data.append((ls[0], ls[1]))
def part_1():
count = 0
for _,output in data:
for x in output:
out = get_keys(digit_segment_count, len(x))
if len(out) == 1:
count += 1
return count
def is_similar(a, b):
return set(list(a)) == set(list(b))
#print(part_1())
def find_by_length(ls, length):
return list(filter(lambda x: len(x) == length, ls))[0]
def diff_str(a, b):
commons = []
longest,shortest = a, b
if len(b) > len(a): longest, shortest = b, a
for e in longest:
if e in shortest:
commons.append(e)
all_d = list(set(a+b))
diff = []
for e in all_d:
if e not in commons:
diff.append(e)
return diff
def remove_char_from_str(subject, char):
return ''.join(list(filter(lambda x: x != char, subject)))
def remove_set(subject, char_set):
return ''.join(list(filter(lambda x: not (x in char_set), subject)))
def remove_char_to_entry(entry, char):
new_entry = []
for e in entry:
new_entry.append(e.replace(char, ''))
return new_entry
# return true
def included_in_str(subject, char_set):
pass
def process_entry(entry):
str_3 = find_by_length(entry, 3)
str_2 = find_by_length(entry, 2)
a = diff_str(str_3, str_2)[0]
cf = str_2
# on récupère le bd à partir du 4
str_4 = find_by_length(entry, 4)
bd = remove_set(str_4, cf)
# enlever a
entry = remove_char_to_entry(entry, a)
# trouver g
# trouver le str_5 qui continent cf et bd
str_5 = list(
filter(
lambda x: included_in_str(x, cf+bd),
find_by_length(entry, 5)
))
print(str_5)
return entry
def digit_with_mapping(mapping, digit):
assert(digit in actual_digit_mapping)
actual = actual_digit_mapping[digit]
encoded = [mapping[actual_digit.index(a)] for i,a in enumerate(actual)]
return ''.join(encoded)
def process_entry_force(entry):
sets = [set(s) for s in entry]
poss = list(itertools.permutations('abcdefg'))
for p in poss:
# we do an hypothesis that poss is the mapping
mapping = ''.join(p)
ok = True
for d in range(10):
s = set(digit_with_mapping(mapping, d))
if not (s in sets):
ok = False
break
if ok:
return mapping
def compute_output(mapping, segments):
def match(w):
i = mapping.index(w)
return actual_digit[i]
a = list(map(match, segments))
a = list(sorted(a))
key = ''.join(a)
d = get_keys(actual_digit_mapping, key)[0]
return d
def part_2():
res = 0
for entry in data:
mapping = process_entry_force(entry[0])
val = int(
''.join([str(compute_output(mapping, d)) for d in entry[1]])
)
print(f'{mapping=} {val=}')
res += val
print(res)
print(part_2())
"""
{dab} = {acf}
{ab} = {cf}
so d = a
using the "unique signal patterns" hypothesis will give:
0,1,2,3,4,5,6,7,8,9
on enlève les digits faciles (1,4,7,8)
1 = cf
4 = bcdf
7 = acf
8 = abcdefg
il reste donc 0,2,3,5,6,9
"""