day16
This commit is contained in:
parent
1a8d7ccf96
commit
eaaa845503
@ -140,5 +140,17 @@
|
|||||||
"wrong": [],
|
"wrong": [],
|
||||||
"correct": 20298300
|
"correct": 20298300
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"16": {
|
||||||
|
"1": {
|
||||||
|
"wrong": [
|
||||||
|
629
|
||||||
|
],
|
||||||
|
"correct": 580
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"wrong": [],
|
||||||
|
"correct": 537
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
169
day16.py
Normal file
169
day16.py
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
from tools.aoc import AOCDay
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
STR_OP_CODES = [
|
||||||
|
"addr",
|
||||||
|
"addi",
|
||||||
|
"mulr",
|
||||||
|
"muli",
|
||||||
|
"banr",
|
||||||
|
"bani",
|
||||||
|
"borr",
|
||||||
|
"bori",
|
||||||
|
"setr",
|
||||||
|
"seti",
|
||||||
|
"gtir",
|
||||||
|
"gtri",
|
||||||
|
"gtrr",
|
||||||
|
"eqir",
|
||||||
|
"eqri",
|
||||||
|
"eqrr",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class WristDevice:
|
||||||
|
def __init__(self):
|
||||||
|
self.registers = [0, 0, 0, 0]
|
||||||
|
self.op_code_learner: dict[int, set[str]] = defaultdict(set)
|
||||||
|
self.op_code_by_id: dict[int, str] = {}
|
||||||
|
|
||||||
|
def set_reg(self, a: int, b: int, c: int, d: int) -> None:
|
||||||
|
self.registers = [a, b, c, d]
|
||||||
|
|
||||||
|
def execute_by_name(self, op_code_name: str, arg0: int, arg1: int, arg2: int):
|
||||||
|
if op_code_name == "addr":
|
||||||
|
self.registers[arg2] = self.registers[arg0] + self.registers[arg1]
|
||||||
|
elif op_code_name == "addi":
|
||||||
|
self.registers[arg2] = self.registers[arg0] + arg1
|
||||||
|
elif op_code_name == "mulr":
|
||||||
|
self.registers[arg2] = self.registers[arg0] * self.registers[arg1]
|
||||||
|
elif op_code_name == "muli":
|
||||||
|
self.registers[arg2] = self.registers[arg0] * arg1
|
||||||
|
elif op_code_name == "banr":
|
||||||
|
self.registers[arg2] = self.registers[arg0] & self.registers[arg1]
|
||||||
|
elif op_code_name == "bani":
|
||||||
|
self.registers[arg2] = self.registers[arg0] & arg1
|
||||||
|
elif op_code_name == "borr":
|
||||||
|
self.registers[arg2] = self.registers[arg0] | self.registers[arg1]
|
||||||
|
elif op_code_name == "bori":
|
||||||
|
self.registers[arg2] = self.registers[arg0] | arg1
|
||||||
|
elif op_code_name == "setr":
|
||||||
|
self.registers[arg2] = self.registers[arg0]
|
||||||
|
elif op_code_name == "seti":
|
||||||
|
self.registers[arg2] = arg0
|
||||||
|
elif op_code_name == "gtir":
|
||||||
|
self.registers[arg2] = int(arg0 > self.registers[arg1])
|
||||||
|
elif op_code_name == "gtri":
|
||||||
|
self.registers[arg2] = int(self.registers[arg0] > arg1)
|
||||||
|
elif op_code_name == "gtrr":
|
||||||
|
self.registers[arg2] = int(self.registers[arg0] > self.registers[arg1])
|
||||||
|
elif op_code_name == "eqir":
|
||||||
|
self.registers[arg2] = int(arg0 == self.registers[arg1])
|
||||||
|
elif op_code_name == "eqri":
|
||||||
|
self.registers[arg2] = int(self.registers[arg0] == arg1)
|
||||||
|
elif op_code_name == "eqrr":
|
||||||
|
self.registers[arg2] = int(self.registers[arg0] == self.registers[arg1])
|
||||||
|
|
||||||
|
def execute_by_id(self, op_code: int, arg0: int, arg1: int, arg2: int) -> None:
|
||||||
|
if op_code not in self.op_code_by_id:
|
||||||
|
raise ValueError(f"Unknown OP Code: {op_code}")
|
||||||
|
|
||||||
|
self.execute_by_name(self.op_code_by_id[op_code], arg0, arg1, arg2)
|
||||||
|
|
||||||
|
def learn(self, op_code: int, possibles: set[str]) -> None:
|
||||||
|
if not self.op_code_learner[op_code]:
|
||||||
|
self.op_code_learner[op_code] = possibles
|
||||||
|
else:
|
||||||
|
self.op_code_learner[op_code] &= possibles
|
||||||
|
|
||||||
|
def finish_learn(self) -> None:
|
||||||
|
while len(self.op_code_by_id) < len(self.op_code_learner):
|
||||||
|
for op_code, possibles in self.op_code_learner.items():
|
||||||
|
if len(possibles) == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if len(possibles) == 1:
|
||||||
|
self.op_code_by_id[op_code] = possibles.pop()
|
||||||
|
for remove_code in self.op_code_learner:
|
||||||
|
if self.op_code_by_id[op_code] in self.op_code_learner[remove_code]:
|
||||||
|
self.op_code_learner[remove_code].remove(self.op_code_by_id[op_code])
|
||||||
|
|
||||||
|
def test_code(self, op_code: list[int], reg_before: list[int], reg_after: list[int]) -> set[str]:
|
||||||
|
possible_codes = set()
|
||||||
|
for test_code in STR_OP_CODES:
|
||||||
|
self.set_reg(*reg_before)
|
||||||
|
self.execute_by_name(test_code, *op_code[1:])
|
||||||
|
if self.registers == reg_after:
|
||||||
|
possible_codes.add(test_code)
|
||||||
|
|
||||||
|
return possible_codes
|
||||||
|
|
||||||
|
|
||||||
|
class Day(AOCDay):
|
||||||
|
inputs = [
|
||||||
|
[
|
||||||
|
(1, "input16_test1"),
|
||||||
|
(580, "input16"),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
(537, "input16"),
|
||||||
|
],
|
||||||
|
]
|
||||||
|
|
||||||
|
def parse_input(self) -> (list[(list[int], list[int], list[int])], list[list[int]]):
|
||||||
|
"""
|
||||||
|
first return value is a list of (op_code, reg_before, reg_after)
|
||||||
|
second one is just a list of op_code
|
||||||
|
"""
|
||||||
|
lines = self.getInput()
|
||||||
|
index = 0
|
||||||
|
|
||||||
|
tests = []
|
||||||
|
op_codes = []
|
||||||
|
|
||||||
|
while index < len(lines):
|
||||||
|
if lines[index].startswith("Before:"):
|
||||||
|
reg_before = list(map(int, lines[index][:-1].split("[")[1].split(", ")))
|
||||||
|
op_code = list(map(int, lines[index + 1].split()))
|
||||||
|
reg_after = list(map(int, lines[index + 2][:-1].split("[")[1].split(", ")))
|
||||||
|
tests.append((op_code, reg_before, reg_after))
|
||||||
|
index += 4
|
||||||
|
elif not lines[index]:
|
||||||
|
index += 1
|
||||||
|
else:
|
||||||
|
op_codes.append(list(map(int, lines[index].split())))
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
return tests, op_codes
|
||||||
|
|
||||||
|
def part1(self) -> Any:
|
||||||
|
tests, _ = self.parse_input()
|
||||||
|
count = 0
|
||||||
|
device = WristDevice()
|
||||||
|
|
||||||
|
for test in tests:
|
||||||
|
if len(device.test_code(*test)) >= 3:
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
return count
|
||||||
|
|
||||||
|
def part2(self) -> Any:
|
||||||
|
tests, opcodes = self.parse_input()
|
||||||
|
device = WristDevice()
|
||||||
|
|
||||||
|
for test in tests:
|
||||||
|
device.learn(test[0][0], device.test_code(*test))
|
||||||
|
|
||||||
|
device.finish_learn()
|
||||||
|
device.set_reg(0, 0, 0, 0)
|
||||||
|
for opcode in opcodes:
|
||||||
|
device.execute_by_id(*opcode)
|
||||||
|
|
||||||
|
return device.registers[0]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
day = Day(2018, 16)
|
||||||
|
day.run(verbose=True)
|
||||||
4041
inputs/input16
Normal file
4041
inputs/input16
Normal file
File diff suppressed because it is too large
Load Diff
3
inputs/input16_test1
Normal file
3
inputs/input16_test1
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Before: [3, 2, 1, 1]
|
||||||
|
9 2 1 2
|
||||||
|
After: [3, 2, 2, 1]
|
||||||
Loading…
Reference in New Issue
Block a user