|
| 1 | +# -------------------------------- Input data ---------------------------------------- # |
| 2 | +import os |
| 3 | + |
| 4 | +test_data = {} |
| 5 | + |
| 6 | +test = 1 |
| 7 | +test_data[test] = { |
| 8 | + "input": """Before: [3, 2, 1, 1] |
| 9 | +9 2 1 2 |
| 10 | +After: [3, 2, 2, 1]""", |
| 11 | + "expected": ["Unknown", "Unknown"], |
| 12 | +} |
| 13 | + |
| 14 | +test = "real" |
| 15 | +input_file = os.path.join( |
| 16 | + os.path.dirname(__file__), |
| 17 | + "Inputs", |
| 18 | + os.path.basename(__file__).replace(".py", ".txt"), |
| 19 | +) |
| 20 | +test_data[test] = { |
| 21 | + "input": open(input_file, "r+").read().strip(), |
| 22 | + "expected": ["Unknown", "Unknown"], |
| 23 | +} |
| 24 | + |
| 25 | +# -------------------------------- Control program execution ------------------------- # |
| 26 | + |
| 27 | +case_to_test = "real" |
| 28 | +part_to_test = 2 |
| 29 | + |
| 30 | +# -------------------------------- Initialize some variables ------------------------- # |
| 31 | + |
| 32 | +puzzle_input = test_data[case_to_test]["input"] |
| 33 | +puzzle_expected_result = test_data[case_to_test]["expected"][part_to_test - 1] |
| 34 | +puzzle_actual_result = "Unknown" |
| 35 | + |
| 36 | + |
| 37 | +# -------------------------------- Actual code execution ----------------------------- # |
| 38 | + |
| 39 | +registers = [0] * 4 |
| 40 | + |
| 41 | +i = 0 |
| 42 | +file_contents = puzzle_input.splitlines() |
| 43 | +nb_lines = len(file_contents) |
| 44 | + |
| 45 | +more_than_3_opcodes = 0 |
| 46 | +opcodes_mapping = {i: [] for i in range(16)} |
| 47 | +while i < nb_lines: |
| 48 | + if file_contents[i] == "": |
| 49 | + i += 1 |
| 50 | + continue |
| 51 | + elif file_contents[i][:4] != "Befo": |
| 52 | + i += 1 |
| 53 | + continue |
| 54 | + |
| 55 | + test_program = file_contents[i + 6 :] |
| 56 | + |
| 57 | + before, operation, after = file_contents[i : i + 3] |
| 58 | + |
| 59 | + numeric_opcode = int(operation.split(" ")[0]) |
| 60 | + a, b, c = map(int, operation.split(" ")[1:]) |
| 61 | + |
| 62 | + init = before[9:-1].split(", ") |
| 63 | + init = [int(x) for x in init] |
| 64 | + |
| 65 | + final = after[9:-1].split(", ") |
| 66 | + final = [int(x) for x in final] |
| 67 | + |
| 68 | + matching_opcodes = [] |
| 69 | + |
| 70 | + for opcode in [ |
| 71 | + "addr", |
| 72 | + "addi", |
| 73 | + "mulr", |
| 74 | + "muli", |
| 75 | + "banr", |
| 76 | + "bani", |
| 77 | + "borr", |
| 78 | + "bori", |
| 79 | + "setr", |
| 80 | + "seti", |
| 81 | + "gtir", |
| 82 | + "gtri", |
| 83 | + "gtrr", |
| 84 | + "eqir", |
| 85 | + "eqri", |
| 86 | + "eqrr", |
| 87 | + ]: |
| 88 | + registers = init.copy() |
| 89 | + |
| 90 | + if opcode == "addr": |
| 91 | + registers[c] = registers[a] + registers[b] |
| 92 | + elif opcode == "addi": |
| 93 | + registers[c] = registers[a] + b |
| 94 | + |
| 95 | + elif opcode == "mulr": |
| 96 | + registers[c] = registers[a] * registers[b] |
| 97 | + elif opcode == "muli": |
| 98 | + registers[c] = registers[a] * b |
| 99 | + |
| 100 | + elif opcode == "banr": |
| 101 | + registers[c] = registers[a] & registers[b] |
| 102 | + elif opcode == "bani": |
| 103 | + registers[c] = registers[a] & b |
| 104 | + |
| 105 | + elif opcode == "borr": |
| 106 | + registers[c] = registers[a] | registers[b] |
| 107 | + elif opcode == "bori": |
| 108 | + registers[c] = registers[a] | b |
| 109 | + |
| 110 | + elif opcode == "setr": |
| 111 | + registers[c] = registers[a] |
| 112 | + elif opcode == "seti": |
| 113 | + registers[c] = a |
| 114 | + |
| 115 | + elif opcode == "gtir": |
| 116 | + registers[c] = 1 if a > registers[b] else 0 |
| 117 | + elif opcode == "gtri": |
| 118 | + registers[c] = 1 if registers[a] > b else 0 |
| 119 | + elif opcode == "gtrr": |
| 120 | + registers[c] = 1 if registers[a] > registers[b] else 0 |
| 121 | + |
| 122 | + elif opcode == "eqir": |
| 123 | + registers[c] = 1 if a == registers[b] else 0 |
| 124 | + elif opcode == "eqri": |
| 125 | + registers[c] = 1 if registers[a] == b else 0 |
| 126 | + elif opcode == "eqrr": |
| 127 | + registers[c] = 1 if registers[a] == registers[b] else 0 |
| 128 | + |
| 129 | + if registers == final: |
| 130 | + opcodes_mapping[numeric_opcode].append(opcode) |
| 131 | + matching_opcodes.append(opcode) |
| 132 | + |
| 133 | + if len(matching_opcodes) >= 3: |
| 134 | + more_than_3_opcodes += 1 |
| 135 | + |
| 136 | + i += 3 |
| 137 | + |
| 138 | +if part_to_test == 1: |
| 139 | + puzzle_actual_result = more_than_3_opcodes |
| 140 | + |
| 141 | +else: |
| 142 | + opcodes_mapping = {i: set(opcodes_mapping[i]) for i in opcodes_mapping} |
| 143 | + |
| 144 | + final_mapping = [0] * 16 |
| 145 | + |
| 146 | + while 0 in final_mapping: |
| 147 | + new_match = [i for i in opcodes_mapping if len(opcodes_mapping[i]) == 1] |
| 148 | + numeric, alpha = new_match[0], opcodes_mapping[new_match[0]].pop() |
| 149 | + |
| 150 | + final_mapping[numeric] = alpha |
| 151 | + |
| 152 | + for i in opcodes_mapping: |
| 153 | + if alpha in opcodes_mapping[i]: |
| 154 | + opcodes_mapping[i].remove(alpha) |
| 155 | + |
| 156 | + registers = [0] * 4 |
| 157 | + for operation in test_program: |
| 158 | + opcode = final_mapping[int(operation.split(" ")[0])] |
| 159 | + a, b, c = map(int, operation.split(" ")[1:]) |
| 160 | + |
| 161 | + print(operation, opcode, a, b, c) |
| 162 | + |
| 163 | + if opcode == "addr": |
| 164 | + registers[c] = registers[a] + registers[b] |
| 165 | + elif opcode == "addi": |
| 166 | + registers[c] = registers[a] + b |
| 167 | + |
| 168 | + elif opcode == "mulr": |
| 169 | + registers[c] = registers[a] * registers[b] |
| 170 | + elif opcode == "muli": |
| 171 | + registers[c] = registers[a] * b |
| 172 | + |
| 173 | + elif opcode == "banr": |
| 174 | + registers[c] = registers[a] & registers[b] |
| 175 | + elif opcode == "bani": |
| 176 | + registers[c] = registers[a] & b |
| 177 | + |
| 178 | + elif opcode == "borr": |
| 179 | + registers[c] = registers[a] | registers[b] |
| 180 | + elif opcode == "bori": |
| 181 | + registers[c] = registers[a] | b |
| 182 | + |
| 183 | + elif opcode == "setr": |
| 184 | + registers[c] = registers[a] |
| 185 | + elif opcode == "seti": |
| 186 | + registers[c] = a |
| 187 | + |
| 188 | + elif opcode == "gtir": |
| 189 | + registers[c] = 1 if a > registers[b] else 0 |
| 190 | + elif opcode == "gtri": |
| 191 | + registers[c] = 1 if registers[a] > b else 0 |
| 192 | + elif opcode == "gtrr": |
| 193 | + registers[c] = 1 if registers[a] > registers[b] else 0 |
| 194 | + |
| 195 | + elif opcode == "eqir": |
| 196 | + registers[c] = 1 if a == registers[b] else 0 |
| 197 | + elif opcode == "eqri": |
| 198 | + registers[c] = 1 if registers[a] == b else 0 |
| 199 | + elif opcode == "eqrr": |
| 200 | + registers[c] = 1 if registers[a] == registers[b] else 0 |
| 201 | + |
| 202 | + puzzle_actual_result = registers[0] |
| 203 | + |
| 204 | +# -------------------------------- Outputs / results --------------------------------- # |
| 205 | + |
| 206 | +print("Expected result : " + str(puzzle_expected_result)) |
| 207 | +print("Actual result : " + str(puzzle_actual_result)) |
0 commit comments