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 """