Compare commits

...

2 Commits

Author SHA1 Message Date
e9dc91a4b1 day17 - tile 2024-12-18 14:35:49 +01:00
161bd10ca3 day17 - FINALLY 2024-12-18 14:35:39 +01:00
5 changed files with 39 additions and 110 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -2,7 +2,7 @@
<!-- AOC TILES BEGIN --> <!-- AOC TILES BEGIN -->
<h1 align="center"> <h1 align="center">
2024 - 33 ⭐ - Python 2024 - 36 ⭐ - Python
</h1> </h1>
<a href="day01.py"> <a href="day01.py">
<img src=".aoc_tiles/tiles/2024/01.png" width="161px"> <img src=".aoc_tiles/tiles/2024/01.png" width="161px">
@ -55,4 +55,7 @@
<a href="day17.py"> <a href="day17.py">
<img src=".aoc_tiles/tiles/2024/17.png" width="161px"> <img src=".aoc_tiles/tiles/2024/17.png" width="161px">
</a> </a>
<a href="day18.py">
<img src=".aoc_tiles/tiles/2024/18.png" width="161px">
</a>
<!-- AOC TILES END --> <!-- AOC TILES END -->

139
day17.py
View File

@ -1,5 +1,3 @@
import math
import sys
from enum import Enum from enum import Enum
from tools.aoc import AOCDay from tools.aoc import AOCDay
from typing import Any from typing import Any
@ -28,7 +26,6 @@ class Computer:
self.instr_pointer = 0 self.instr_pointer = 0
self.__code = code self.__code = code
self.code = [(OpCode(code[x]), code[x + 1]) for x in range(0, len(code), 2)] self.code = [(OpCode(code[x]), code[x + 1]) for x in range(0, len(code), 2)]
self.check_output = False
self.op = { self.op = {
OpCode.ADV: self.adv, OpCode.ADV: self.adv,
OpCode.BXL: self.bxl, OpCode.BXL: self.bxl,
@ -87,14 +84,8 @@ class Computer:
def out(self, operand: int) -> None: def out(self, operand: int) -> None:
value = self.get_combo_value(operand) % 8 value = self.get_combo_value(operand) % 8
if not self.check_output: self.output.append(value)
self.instr_pointer += 1 self.instr_pointer += 1
self.output.append(value)
elif value != self.__code[len(self.output)]:
self.instr_pointer = len(self.code)
else:
self.instr_pointer += 1
self.output.append(value)
def bdv(self, operand: int) -> None: def bdv(self, operand: int) -> None:
self.reg_b = self.reg_a // (2 ** self.get_combo_value(operand)) self.reg_b = self.reg_a // (2 ** self.get_combo_value(operand))
@ -107,25 +98,31 @@ class Computer:
def get_output(self) -> str: def get_output(self) -> str:
return ",".join(str(x) for x in self.output) return ",".join(str(x) for x in self.output)
def run_code(self) -> None: def run(self, init_a: int = None) -> str:
self.reset()
if init_a is not None:
self.reg_a = init_a
while self.instr_pointer < len(self.code): while self.instr_pointer < len(self.code):
# print("Exec", self.instr_pointer)
op_code, operand = self.code[self.instr_pointer] op_code, operand = self.code[self.instr_pointer]
self.op[op_code](operand) self.op[op_code](operand)
return self.get_output()
class Day(AOCDay): class Day(AOCDay):
inputs = [ inputs = [
[ [
("4,6,3,5,6,3,5,2,1,0", "input17_test"), ("4,6,3,5,6,3,5,2,1,0", "input17_test"),
("7,1,2,3,2,6,7,2,5", "input17_neil"), ("7,1,2,3,2,6,7,2,5", "input17_neil"),
("1,7,6,5,1,0,5,0,7", "input17_dennis"),
("1,6,3,6,5,6,5,1,7", "input17"), ("1,6,3,6,5,6,5,1,7", "input17"),
], ],
[ [
(117440, "input17_test2"), (117440, "input17_test2"),
(202356708354602, "input17_neil"), (202356708354602, "input17_neil"),
(236555995274861, "input17_dennis"), (236555995274861, "input17_dennis"),
(None, "input17"), (247839653009594, "input17"),
], ],
] ]
@ -135,111 +132,35 @@ class Day(AOCDay):
def part1(self) -> Any: def part1(self) -> Any:
computer = Computer(*self.parse_input()) computer = Computer(*self.parse_input())
computer.run_code() return computer.run()
return computer.get_output()
def part2(self) -> Any: def part2(self) -> Any:
a, b, c, prog = self.parse_input() a, b, c, prog = self.parse_input()
expected_output = ",".join(str(x) for x in prog) expected_output = ",".join(str(x) for x in prog)
computer = Computer(a, b, c, prog) computer = Computer(a, b, c, prog)
computer.check_output = True
def run_computer(v: int) -> str: def get_match_pos(a: str, b: str) -> int:
computer.reset() m = 0
computer.reg_a = v for x, y in zip(reversed(a), reversed(b)):
computer.run_code() if x == y:
return computer.get_output() m += 1
init_a = 0
init_reg = 0
output = ""
bit_match = ""
bit_width = 6
bit_add = bit_width - 1
factor = 0
additive = 0
best = 0
while output != expected_output:
init_reg = init_a * (8**factor) + additive
output = run_computer(init_reg)
if len(output) > best and output == expected_output[: len(output)]:
# if output == expected_output[: len(output)]:
o = oct(init_reg)
if o[-bit_width:] != bit_match:
bit_match = o[-bit_width:]
else: else:
additive = int(bit_match, 8) break
factor = bit_width
bit_width += bit_add
bit_add -= 1
init_a = 0
print( return m
f"{init_reg=} ({oct(init_reg)}), {factor=}, additive={oct(additive)}, {output=}, {expected_output=}"
)
best = len(output)
if init_a % 1_000_000 == 0: num = 0
print(init_a, init_reg) for factor in range(len(prog)):
init_a += 1 for i in range(8**len(prog)):
output = computer.run(num + i)
if get_match_pos(output, expected_output) == (2 * factor) + 1:
if factor < len(prog) - 1:
num = (i + num) * 8
else:
num += i
break
print(init_a - 1, (init_a - 1) * (8**factor) + additive) return num
output = run_computer(init_reg)
print(output)
if output == expected_output:
return init_reg
return ""
first = []
for i, c in enumerate(prog):
reg_a_init = 0
while len(first) <= i:
computer.reset()
computer.reg_a = reg_a_init
computer.run_code()
if int(computer.get_output()[0]) == c:
first.append(reg_a_init)
reg_a_init += 1
print(first)
result = 0
for i, c in enumerate(reversed(first)):
result = result << 3
result += c // 8
# result = sum(((x * (8 ** i) for i, x in enumerate(first))))
print(result)
computer.reset()
computer.reg_a = result
computer.run_code()
print(computer.get_output())
if computer.get_output() == expected_output:
return result
while computer.get_output() != expected_output:
result -= 1
computer.reset()
computer.reg_a = result
computer.run_code()
return result
for i in range(len(first)):
result = sum(((x * (8**i) for i, x in enumerate(first[: i + 1]))))
print("Testing ", first[: i + 1], "=", result)
computer.reset()
computer.reg_a = result
computer.run_code()
print(expected_output)
print(computer.get_output())
if computer.get_output() == expected_output:
return result
else:
return ""
if __name__ == "__main__": if __name__ == "__main__":

5
inputs/input17_jonathan Normal file
View File

@ -0,0 +1,5 @@
Register A: 27334280
Register B: 0
Register C: 0
Program: 2,4,1,2,7,5,0,3,1,7,4,1,5,5,3,0