|
| 1 | +# -------------------------------- Input data ---------------------------------------- # |
| 2 | +import os, grid, graph, dot, assembly, re, itertools |
| 3 | +from collections import Counter, deque, defaultdict |
| 4 | + |
| 5 | +from compass import * |
| 6 | + |
| 7 | + |
| 8 | +# This functions come from https://github.com/mcpower/adventofcode - Thanks! |
| 9 | +def lmap(func, *iterables): |
| 10 | + return list(map(func, *iterables)) |
| 11 | + |
| 12 | + |
| 13 | +def ints(s: str): |
| 14 | + return lmap(int, re.findall(r"-?\d+", s)) # thanks mserrano! |
| 15 | + |
| 16 | + |
| 17 | +def positive_ints(s: str): |
| 18 | + return lmap(int, re.findall(r"\d+", s)) # thanks mserrano! |
| 19 | + |
| 20 | + |
| 21 | +def floats(s: str): |
| 22 | + return lmap(float, re.findall(r"-?\d+(?:\.\d+)?", s)) |
| 23 | + |
| 24 | + |
| 25 | +def positive_floats(s: str): |
| 26 | + return lmap(float, re.findall(r"\d+(?:\.\d+)?", s)) |
| 27 | + |
| 28 | + |
| 29 | +def words(s: str): |
| 30 | + return re.findall(r"[a-zA-Z]+", s) |
| 31 | + |
| 32 | + |
| 33 | +test_data = {} |
| 34 | + |
| 35 | +test = 1 |
| 36 | +test_data[test] = { |
| 37 | + "input": """acedgfb cdfbe gcdfa fbcad dab cefabd cdfgeb eafb cagedb ab | cdfeb fcadb cdfeb cdbaf""", |
| 38 | + "expected": ["Unknown", "5353"], |
| 39 | +} |
| 40 | + |
| 41 | +test = 2 |
| 42 | +test_data[test] = { |
| 43 | + "input": """be cfbegad cbdgef fgaecd cgeb fdcge agebfd fecdb fabcd edb | fdgacbe cefdb cefbgd gcbe |
| 44 | +edbfga begcd cbg gc gcadebf fbgde acbgfd abcde gfcbed gfec | fcgedb cgb dgebacf gc |
| 45 | +fgaebd cg bdaec gdafb agbcfd gdcbef bgcad gfac gcb cdgabef | cg cg fdcagb cbg |
| 46 | +fbegcd cbd adcefb dageb afcb bc aefdc ecdab fgdeca fcdbega | efabcd cedba gadfec cb |
| 47 | +aecbfdg fbg gf bafeg dbefa fcge gcbea fcaegb dgceab fcbdga | gecf egdcabf bgf bfgea |
| 48 | +fgeab ca afcebg bdacfeg cfaedg gcfdb baec bfadeg bafgc acf | gebdcfa ecba ca fadegcb |
| 49 | +dbcfg fgd bdegcaf fgec aegbdf ecdfab fbedc dacgb gdcebf gf | cefg dcbef fcge gbcadfe |
| 50 | +bdfegc cbegaf gecbf dfcage bdacg ed bedf ced adcbefg gebcd | ed bcgafe cdgba cbgef |
| 51 | +egadfb cdbfeg cegd fecab cgb gbdefca cg fgcdab egfdb bfceg | gbdfcae bgc cg cgb |
| 52 | +gcafb gcf dcaebfg ecagb gf abcdeg gaef cafbge fdbac fegbdc | fgae cfgab fg bagce""", |
| 53 | + "expected": [ |
| 54 | + "26", |
| 55 | + "8394, 9781, 1197, 9361, 4873, 8418, 4548, 1625, 8717, 4315 ==> 61229", |
| 56 | + ], |
| 57 | +} |
| 58 | + |
| 59 | +test = "real" |
| 60 | +input_file = os.path.join( |
| 61 | + os.path.dirname(__file__), |
| 62 | + "Inputs", |
| 63 | + os.path.basename(__file__).replace(".py", ".txt"), |
| 64 | +) |
| 65 | +test_data[test] = { |
| 66 | + "input": open(input_file, "r+").read(), |
| 67 | + "expected": ["Unknown", "Unknown"], |
| 68 | +} |
| 69 | + |
| 70 | + |
| 71 | +# -------------------------------- Control program execution ------------------------- # |
| 72 | + |
| 73 | +case_to_test = "real" |
| 74 | +part_to_test = 2 |
| 75 | + |
| 76 | +# -------------------------------- Initialize some variables ------------------------- # |
| 77 | + |
| 78 | +puzzle_input = test_data[case_to_test]["input"] |
| 79 | +puzzle_expected_result = test_data[case_to_test]["expected"][part_to_test - 1] |
| 80 | +puzzle_actual_result = "Unknown" |
| 81 | + |
| 82 | + |
| 83 | +# -------------------------------- Actual code execution ----------------------------- # |
| 84 | + |
| 85 | +# Conver integer to 36-character binary |
| 86 | +# str_value = "{0:>036b}".format(value) |
| 87 | +# Convert binary string to number |
| 88 | +# value = int(str_value, 2) |
| 89 | + |
| 90 | + |
| 91 | +if part_to_test == 1: |
| 92 | + nb_digits = 0 |
| 93 | + for string in puzzle_input.split("\n"): |
| 94 | + output = words(string)[-4:] |
| 95 | + nb_digits += len([x for x in output if len(x) in [2, 3, 4, 7]]) |
| 96 | + |
| 97 | + puzzle_actual_result = nb_digits |
| 98 | + |
| 99 | + |
| 100 | +else: |
| 101 | + digit_to_real_segments = { |
| 102 | + "0": "abcefg", |
| 103 | + "1": "cf", |
| 104 | + "2": "acdeg", |
| 105 | + "3": "acdfg", |
| 106 | + "4": "bcdf", |
| 107 | + "5": "abdfg", |
| 108 | + "6": "abdefg", |
| 109 | + "7": "acf", |
| 110 | + "8": "abcdefg", |
| 111 | + "9": "abcdfg", |
| 112 | + } |
| 113 | + digit_container = { |
| 114 | + "0": ["8"], |
| 115 | + "1": ["0", "3", "4", "7", "8", "9"], |
| 116 | + "2": ["8"], |
| 117 | + "3": ["8", "9"], |
| 118 | + "4": ["8", "9"], |
| 119 | + "5": ["6", "8", "9"], |
| 120 | + "6": ["8"], |
| 121 | + "7": ["0", "3", "8", "9"], |
| 122 | + "8": [], |
| 123 | + "9": ["8"], |
| 124 | + } |
| 125 | + shared_segments = { |
| 126 | + digit1: { |
| 127 | + digit2: len( |
| 128 | + [ |
| 129 | + segment |
| 130 | + for segment in digit_to_real_segments[digit2] |
| 131 | + if segment in digit_to_real_segments[digit1] |
| 132 | + ] |
| 133 | + ) |
| 134 | + for digit2 in digit_to_real_segments |
| 135 | + } |
| 136 | + for digit1 in digit_to_real_segments |
| 137 | + } |
| 138 | + nb_segments = { |
| 139 | + digit: len(digit_to_real_segments[digit]) for digit in digit_to_real_segments |
| 140 | + } |
| 141 | + for digit in digit_to_real_segments: |
| 142 | + digit_to_real_segments[digit] = [ |
| 143 | + "r_" + x for x in digit_to_real_segments[digit] |
| 144 | + ] |
| 145 | + digit_to_real_segments[digit].sort() |
| 146 | + |
| 147 | + digits = [str(i) for i in range(10)] |
| 148 | + |
| 149 | + sum_displays = 0 |
| 150 | + |
| 151 | + for string in puzzle_input.split("\n"): |
| 152 | + signals = ["".join(sorted(x)) for x in words(string.replace("| ", ""))[:-4]] |
| 153 | + displayed_words = ["".join(sorted(x)) for x in words(string)[-4:]] |
| 154 | + |
| 155 | + edges = {} |
| 156 | + vertices = signals + digits |
| 157 | + for word in signals: |
| 158 | + edges[word] = [ |
| 159 | + digit for digit in nb_segments if nb_segments[digit] == len(word) |
| 160 | + ] |
| 161 | + |
| 162 | + mapping = {} |
| 163 | + i = 0 |
| 164 | + while len(mapping) != 9 and i != 5: |
| 165 | + i += 1 |
| 166 | + changed = True |
| 167 | + while changed: |
| 168 | + changed = False |
| 169 | + for word in edges: |
| 170 | + if len(edges[word]) == 1: |
| 171 | + mapping[word] = edges[word][0] |
| 172 | + edges = { |
| 173 | + w: [edge for edge in edges[w] if edge != mapping[word]] |
| 174 | + for w in edges |
| 175 | + } |
| 176 | + changed = True |
| 177 | + del edges[word] |
| 178 | + |
| 179 | + for known_word in mapping: # abd |
| 180 | + digit = mapping[known_word][0] # 7 |
| 181 | + |
| 182 | + for word in edges: # bcdef |
| 183 | + same_letters = len([x for x in word if x in known_word]) |
| 184 | + for possible_digit in edges[word]: # '2', '3', '5' |
| 185 | + if shared_segments[digit][possible_digit] != same_letters: |
| 186 | + edges[word].remove(possible_digit) |
| 187 | + |
| 188 | + # exit() |
| 189 | + |
| 190 | + # Second try, not the right approach (easier to do with shared_segments) |
| 191 | + |
| 192 | + # for known_word in mapping: # abd |
| 193 | + # digit = mapping[known_word][0] # 7 |
| 194 | + # #print ('known_word', known_word, '- digit', digit, 'container', digit_container[digit]) |
| 195 | + # if digit_container[digit] == []: |
| 196 | + # continue |
| 197 | + # for word in edges: # bcdef |
| 198 | + # #print ('tried word', word, '- digits', edges[word]) |
| 199 | + # for possible_digit in edges[word]: # '2', '3', '5' |
| 200 | + # #print ('possible_digit', possible_digit, possible_digit in digit_container[digit]) |
| 201 | + # if possible_digit in digit_container[digit]: # '0', '3', '8', '9' |
| 202 | + # #print ([(letter, letter in word) for letter in known_word]) |
| 203 | + # if not all([letter in word for letter in known_word]): |
| 204 | + # edges[word].remove(possible_digit) |
| 205 | + |
| 206 | + # print (edges, mapping) |
| 207 | + output = "" |
| 208 | + for displayed_word in displayed_words: |
| 209 | + output += "".join(mapping[displayed_word]) |
| 210 | + |
| 211 | + sum_displays += int(output) |
| 212 | + |
| 213 | + puzzle_actual_result = sum_displays |
| 214 | + |
| 215 | +# First try, too complex |
| 216 | + |
| 217 | +# for string in puzzle_input.split("\n"): |
| 218 | +# randomized_words = words(string.replace('| ', '')) |
| 219 | +# randomized_displayed_words = words(string)[-4:] |
| 220 | + |
| 221 | +# randomized_segments = [x for x in 'abcdefg'] |
| 222 | +# real_segments = ['r_'+x for x in 'abcdefg'] |
| 223 | +# edges = {randomized: {real:1 for real in real_segments} for randomized in randomized_segments} |
| 224 | +# vertices = randomized_segments + real_segments |
| 225 | + |
| 226 | +# for randomized_word in randomized_words: |
| 227 | +# for randomized_segment in randomized_word: |
| 228 | +# possible_segments = [] |
| 229 | +# for digit in nb_segments: |
| 230 | +# if nb_segments[digit] == len(randomized_word): |
| 231 | +# possible_segments += digit_to_real_segments[digit] |
| 232 | +# possible_segments = set(possible_segments) |
| 233 | + |
| 234 | + |
| 235 | +# for real_segment in real_segments: |
| 236 | +# if real_segment in possible_segments: |
| 237 | +# continue |
| 238 | +# if randomized_segment in edges: |
| 239 | +# if real_segment in edges[randomized_segment]: |
| 240 | +# del edges[randomized_segment][real_segment] |
| 241 | + |
| 242 | +# #if randomized_segment in 'be': |
| 243 | +# #print (randomized_word, digit, nb_segments[digit], randomized_segment, possible_segments, edges[randomized_segment]) |
| 244 | +# print (randomized_words) |
| 245 | +# print ([x for x in randomized_words if len(x) in [2,3,4,7]]) |
| 246 | +# print ({x: list(edges[x].keys()) for x in edges}) |
| 247 | + |
| 248 | +# mapping = graph.WeightedGraph(vertices, edges) |
| 249 | +# result = mapping.bipartite_matching(randomized_segments, real_segments) |
| 250 | +# print ('flow_graph ', mapping.flow_graph) |
| 251 | +# segment_mapping = {} |
| 252 | +# for randomized_segment in mapping.flow_graph: |
| 253 | +# segment_mapping[randomized_segment] = mapping.flow_graph[randomized_segment] |
| 254 | + |
| 255 | +# final_number = '' |
| 256 | +# for randomized_word in randomized_displayed_words: |
| 257 | +# print('') |
| 258 | +# real_segments = [] |
| 259 | +# for letter in randomized_word: |
| 260 | +# real_segments.append(''.join([k for k in mapping.flow_graph[letter]])) |
| 261 | +# print ('real_segments', real_segments) |
| 262 | +# real_segments = list(set(real_segments)) |
| 263 | +# real_segments.sort() |
| 264 | +# real_segments = ''.join(real_segments) |
| 265 | + |
| 266 | + |
| 267 | +# final_number += ''.join([str(key) for key in digit_to_real_segments if ''.join(digit_to_real_segments[key]) == real_segments]) |
| 268 | +# print ('real_segments', real_segments) |
| 269 | +# print (randomized_word, [(str(key), ''.join(digit_to_real_segments[key])) for key in digit_to_real_segments]) |
| 270 | +# print (randomized_word, final_number) |
| 271 | + |
| 272 | +# print (final_number) |
| 273 | + |
| 274 | + |
| 275 | +# break |
| 276 | + |
| 277 | + |
| 278 | +# -------------------------------- Outputs / results --------------------------------- # |
| 279 | + |
| 280 | +print("Case :", case_to_test, "- Part", part_to_test) |
| 281 | +print("Expected result : " + str(puzzle_expected_result)) |
| 282 | +print("Actual result : " + str(puzzle_actual_result)) |
| 283 | +# Date created: 2021-12-08 08:11:57.138188 |
| 284 | +# Part 1 : 2021-12-08 08:13:56 |
| 285 | +# Part 2 : 2021-12-08 14:12:15 |
0 commit comments