advent24-llm / day17 /solution_jerpint.py
jerpint's picture
Add solution files
a4da721
from ast import literal_eval
def load_data(file):
with open(file) as f:
data = f.readlines()
registers = {}
for line in data:
line = line.strip("\n")
if "A" in line:
registers["A"] = int(line.split(" ")[-1])
if "B" in line:
registers["B"] = int(line.split(" ")[-1])
if "C" in line:
registers["C"] = int(line.split(" ")[-1])
if "Program" in line:
program = [int(c) for c in line.split(" ")[-1].split(",")]
return registers, program
class Computer:
def __init__(self, registers, program):
self.OPS = {
0: "adv",
1: "bxl",
2: "bst",
3: "jnz",
4: "bxc",
5: "out",
6: "bdv",
7: "cdv",
}
self.registers = registers
self.program = program
self.instruction_pointer = 0
self.outputs = []
def combo(self, operand):
if 0 <= operand <= 3:
return operand
elif operand == 4:
return self.registers["A"]
elif operand == 5:
return self.registers["B"]
elif operand == 6:
return self.registers["C"]
elif operand == 7:
raise ValueError("Reserved!")
else:
raise ValueError("Unknown")
def adv(self, operand):
combo = self.combo(operand)
numerator = self.registers["A"]
denominator = 2 ** combo
self.registers["A"] = int(numerator / denominator)
def bxl(self, operand):
self.registers["B"] = self.registers["B"] ^ operand
def bst(self, operand):
self.registers["B"] = self.combo(operand) % 8
def jnz(self, operand):
if self.registers["A"] == 0:
return
self.instruction_pointer = operand - 2
def bxc(self, operand):
self.registers["B"] = self.registers["B"] ^ self.registers["C"]
def out(self, operand):
combo = self.combo(operand)
self.outputs.append(combo % 8)
def bdv(self, operand):
combo = self.combo(operand)
numerator = self.register["A"]
denominator = 2 ** combo
self.registers["B"] = int(numerator / denominator)
def cdv(self, operand):
combo = self.combo(operand)
numerator = self.registers["A"]
denominator = 2 ** combo
self.registers["C"] = int(numerator / denominator)
def evaluate(self, instruction, operand):
op = self.OPS[instruction]
if op == "adv":
return self.adv(operand)
elif op == "bxl":
return self.bxl(operand)
elif op == "bst":
return self.bst(operand)
elif op == "jnz":
return self.jnz(operand)
elif op == "bxc":
return self.bxc(operand)
elif op == "out":
return self.out(operand)
elif op == "bdv":
return self.bdv(operand)
elif op == "cdv":
return self.cdv(operand)
else:
raise ValueError(f"Uknown op: {op}")
def get_next_instruction_and_operand(self):
instruction, operand = self.program[self.instruction_pointer], self.program[self.instruction_pointer+1]
return instruction, operand
def step(self):
while self.instruction_pointer < len(program):
inst, operand = self.get_next_instruction_and_operand()
self.evaluate(inst, operand)
self.instruction_pointer += 2
# print("Halt")
# print("Outputs: ", ",".join([str(out) for out in self.outputs]))
return self.outputs
registers, program = load_data("input.txt")
# print(registers, program)
computer = Computer(registers.copy(), program)
outputs = computer.step()
print(",".join([str(out) for out in outputs]))
## Part 2
# # Tried Brute force, ran all night, didnt produce an answer.
# # Halt program as soon as output not equal program
# # There's probably a smarter way...
#
# class Computer2(Computer):
# def step(self):
#
# while self.instruction_pointer < len(program):
# inst, operand = self.get_next_instruction_and_operand()
# self.evaluate(inst, operand)
# self.instruction_pointer += 2
#
# if len(self.outputs) > 0:
# for out, prog in zip(self.outputs, self.program):
# if out != prog:
# return
#
# # print("Halt")
# # print("Outputs: ", ",".join([str(out) for out in self.outputs]))
# return self.outputs
#
# registers, program = load_data("input.txt")
#
#
# # A = 4063000000 Reached here with brute force
# A = 0
# while True:
# if A % 100000 == 0:
# print(A)
# input_registers = registers.copy()
# input_registers["A"] = A
# computer = Computer2(input_registers, program)
# outputs = computer.step()
#
# if outputs == program:
# print("DONE")
# break
#
# else:
# A += 1
#
# print(A)