File size: 2,751 Bytes
a4da721
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
def parse_input(file):
    with open(file, 'r') as f:
        lines = f.read().strip().split('\n')
    
    # Parse register values
    registers = {}
    for line in lines[:3]:
        reg, val = line.split(': ')
        registers[reg[-1]] = int(val)
    
    # Parse program
    program = [int(x) for x in lines[-1].split(',')]
    return registers, program

class Computer:
    def __init__(self, registers, program):
        self.registers = registers.copy()
        self.program = program
        self.ip = 0
        self.output = []
    
    def get_combo_value(self, operand):
        if operand <= 3:
            return operand
        elif operand <= 6:
            return self.registers[chr(ord('A') + operand - 4)]
        return None  # operand 7 is reserved
    
    def run(self):
        while self.ip < len(self.program):
            opcode = self.program[self.ip]
            operand = self.program[self.ip + 1]
            
            if opcode == 0:  # adv
                power = self.get_combo_value(operand)
                self.registers['A'] //= (2 ** power)
            elif opcode == 1:  # bxl
                self.registers['B'] ^= operand
            elif opcode == 2:  # bst
                self.registers['B'] = self.get_combo_value(operand) % 8
            elif opcode == 3:  # jnz
                if self.registers['A'] != 0:
                    self.ip = operand
                    continue
            elif opcode == 4:  # bxc
                self.registers['B'] ^= self.registers['C']
            elif opcode == 5:  # out
                value = self.get_combo_value(operand) % 8
                self.output.append(str(value))
            elif opcode == 6:  # bdv
                power = self.get_combo_value(operand)
                self.registers['B'] = self.registers['A'] // (2 ** power)
            elif opcode == 7:  # cdv
                power = self.get_combo_value(operand)
                self.registers['C'] = self.registers['A'] // (2 ** power)
            
            self.ip += 2
        
        return ','.join(self.output)

def solve_part1(registers, program):
    computer = Computer(registers, program)
    return computer.run()

def solve_part2(registers, program):
    target = ','.join(str(x) for x in program)
    a = 1
    while True:
        test_registers = registers.copy()
        test_registers['A'] = a
        computer = Computer(test_registers, program)
        output = computer.run()
        if output == target:
            return str(a)
        a += 1

def main():
    registers, program = parse_input("./input.txt")
    
    # Part 1
    print(solve_part1(registers, program))
    
    # Part 2
    print(solve_part2(registers, program))

if __name__ == "__main__":
    main()