|
| 1 | +# -------------------------------- Input data ---------------------------------------- # |
| 2 | +importos,grid,graph,dot,assembly,re,itertools |
| 3 | +fromcollectionsimportCounter,deque,defaultdict |
| 4 | + |
| 5 | +fromcompassimport* |
| 6 | + |
| 7 | + |
| 8 | +# This functions come from https://github.com/mcpower/adventofcode - Thanks! |
| 9 | +deflmap(func,*iterables): |
| 10 | +returnlist(map(func,*iterables)) |
| 11 | + |
| 12 | + |
| 13 | +defints(s:str): |
| 14 | +returnlmap(int,re.findall(r"-?\d+",s))# thanks mserrano! |
| 15 | + |
| 16 | + |
| 17 | +defpositive_ints(s:str): |
| 18 | +returnlmap(int,re.findall(r"\d+",s))# thanks mserrano! |
| 19 | + |
| 20 | + |
| 21 | +deffloats(s:str): |
| 22 | +returnlmap(float,re.findall(r"-?\d+(?:\.\d+)?",s)) |
| 23 | + |
| 24 | + |
| 25 | +defpositive_floats(s:str): |
| 26 | +returnlmap(float,re.findall(r"\d+(?:\.\d+)?",s)) |
| 27 | + |
| 28 | + |
| 29 | +defwords(s:str): |
| 30 | +returnre.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 | +ifpart_to_test==1: |
| 92 | +nb_digits=0 |
| 93 | +forstringinpuzzle_input.split("\n"): |
| 94 | +output=words(string)[-4:] |
| 95 | +nb_digits+=len([xforxinoutputiflen(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 | +forsegmentindigit_to_real_segments[digit2] |
| 131 | +ifsegmentindigit_to_real_segments[digit1] |
| 132 | + ] |
| 133 | + ) |
| 134 | +fordigit2indigit_to_real_segments |
| 135 | + } |
| 136 | +fordigit1indigit_to_real_segments |
| 137 | + } |
| 138 | +nb_segments= { |
| 139 | +digit:len(digit_to_real_segments[digit])fordigitindigit_to_real_segments |
| 140 | + } |
| 141 | +fordigitindigit_to_real_segments: |
| 142 | +digit_to_real_segments[digit]= [ |
| 143 | +"r_"+xforxindigit_to_real_segments[digit] |
| 144 | + ] |
| 145 | +digit_to_real_segments[digit].sort() |
| 146 | + |
| 147 | +digits= [str(i)foriinrange(10)] |
| 148 | + |
| 149 | +sum_displays=0 |
| 150 | + |
| 151 | +forstringinpuzzle_input.split("\n"): |
| 152 | +signals= ["".join(sorted(x))forxinwords(string.replace("| ",""))[:-4]] |
| 153 | +displayed_words= ["".join(sorted(x))forxinwords(string)[-4:]] |
| 154 | + |
| 155 | +edges= {} |
| 156 | +vertices=signals+digits |
| 157 | +forwordinsignals: |
| 158 | +edges[word]= [ |
| 159 | +digitfordigitinnb_segmentsifnb_segments[digit]==len(word) |
| 160 | + ] |
| 161 | + |
| 162 | +mapping= {} |
| 163 | +i=0 |
| 164 | +whilelen(mapping)!=9andi!=5: |
| 165 | +i+=1 |
| 166 | +changed=True |
| 167 | +whilechanged: |
| 168 | +changed=False |
| 169 | +forwordinedges: |
| 170 | +iflen(edges[word])==1: |
| 171 | +mapping[word]=edges[word][0] |
| 172 | +edges= { |
| 173 | +w: [edgeforedgeinedges[w]ifedge!=mapping[word]] |
| 174 | +forwinedges |
| 175 | + } |
| 176 | +changed=True |
| 177 | +deledges[word] |
| 178 | + |
| 179 | +forknown_wordinmapping:# abd |
| 180 | +digit=mapping[known_word][0]# 7 |
| 181 | + |
| 182 | +forwordinedges:# bcdef |
| 183 | +same_letters=len([xforxinwordifxinknown_word]) |
| 184 | +forpossible_digitinedges[word]:# '2', '3', '5' |
| 185 | +ifshared_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 | +fordisplayed_wordindisplayed_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 |