205 lines
3.7 KiB
Python
205 lines
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
|
||
|
|
||
|
"""
|