1414from aoc .vm import Program
1515from aoc .vm import VirtualMachine
1616
17- Input = InputData
17+ Input = tuple [ int , int , int , list [ int ]]
1818Output1 = str
1919Output2 = int
2020
3737
3838class Solution (SolutionBase [Input , Output1 , Output2 ]):
3939 def parse_input (self , input_data : InputData ) -> Input :
40- return input_data
40+ lines = list (input_data )
41+ a , b , c = map (int , (lines [i ][12 :] for i in range (3 )))
42+ ops = list (map (int , lines [4 ][9 :].split ("," )))
43+ return a , b , c , ops
4144
42- def run_program (self , lines : list [str ]) -> list [str ]:
45+ def create_instructions (self , ops : list [int ]) -> list [Instruction ]:
4346 def combo (operand : int ) -> str :
4447 match operand :
4548 case 0 | 1 | 2 | 3 :
@@ -51,30 +54,21 @@ def combo(operand: int) -> str:
5154
5255 ins = []
5356 ip_map = dict [int , int ]()
54- ins .append (Instruction .SET ("A" , lines [0 ][12 :]))
55- ins .append (Instruction .SET ("B" , lines [1 ][12 :]))
56- ins .append (Instruction .SET ("C" , lines [2 ][12 :]))
57- ip = 3
58- ops = list (map (int , lines [4 ][9 :].split ("," )))
57+ ip = 0
5958 for i in range (0 , len (ops ), 2 ):
6059 ip_map [i ] = ip
6160 opcode , operand = ops [i ], ops [i + 1 ]
6261 match opcode :
6362 case 0 :
64- ins .append (Instruction .SET ("X" , "2" ))
65- ins .append (Instruction .SET ("Y" , combo (operand )))
66- ins .append (Instruction .ADD ("Y" , - 1 ))
67- ins .append (Instruction .LSH ("X" , "*Y" ))
68- ins .append (Instruction .DIV ("A" , "*X" ))
69- ip += 5
63+ ins .append (Instruction .RSH ("A" , combo (operand )))
64+ ip += 1
7065 case 1 :
7166 ins .append (Instruction .XOR ("B" , str (operand )))
7267 ip += 1
7368 case 2 :
74- ins .append (Instruction .SET ("X" , str (combo (operand ))))
75- ins .append (Instruction .MOD ("X" , "8" ))
76- ins .append (Instruction .SET ("B" , "*X" ))
77- ip += 3
69+ ins .append (Instruction .SET ("B" , str (combo (operand ))))
70+ ins .append (Instruction .AND ("B" , "7" ))
71+ ip += 2
7872 case 3 :
7973 ins .append (
8074 Instruction .JN0 ("*A" , "!" + str (ip_map [operand ]))
@@ -85,61 +79,55 @@ def combo(operand: int) -> str:
8579 ip += 1
8680 case 5 :
8781 ins .append (Instruction .SET ("X" , str (combo (operand ))))
88- ins .append (Instruction .MOD ("X" , "8 " ))
82+ ins .append (Instruction .AND ("X" , "7 " ))
8983 ins .append (Instruction .OUT ("*X" ))
9084 ip += 3
9185 case 6 :
92- ins .append (Instruction .SET ("X" , "2" ))
93- ins .append (Instruction .SET ("Y" , combo (operand )))
94- ins .append (Instruction .ADD ("Y" , - 1 ))
95- ins .append (Instruction .LSH ("X" , "*Y" ))
96- ins .append (Instruction .SET ("B" , "*A" ))
97- ins .append (Instruction .DIV ("B" , "*X" ))
98- ip += 6
86+ ins .append (Instruction .SET ("C" , "*B" ))
87+ ins .append (Instruction .RSH ("C" , combo (operand )))
88+ ip += 2
9989 case 7 :
100- ins .append (Instruction .SET ("X" , "2" ))
101- ins .append (Instruction .SET ("Y" , combo (operand )))
102- ins .append (Instruction .ADD ("Y" , - 1 ))
103- ins .append (Instruction .LSH ("X" , "*Y" ))
10490 ins .append (Instruction .SET ("C" , "*A" ))
105- ins .append (Instruction .DIV ("C" , "*X" ))
106- ip += 6
91+ ins .append (Instruction .RSH ("C" , combo (operand )))
92+ ip += 2
93+ case _:
94+ raise ValueError
95+ return ins
96+
97+ def run_program (
98+ self , ins : list [Instruction ], a : int , b : int , c : int
99+ ) -> list [str ]:
107100 output = []
108101 program = Program (ins , output_consumer = lambda s : output .append (s ))
109- vm = VirtualMachine ()
110- vm .run_program (program )
102+ program .registers ["A" ] = int (a )
103+ program .registers ["B" ] = int (b )
104+ program .registers ["C" ] = int (c )
105+ VirtualMachine ().run_program (program )
111106 return output
112107
113108 def part_1 (self , input : Input ) -> Output1 :
114- lines = list ( input )
115- output = self .run_program ( lines )
116- return "," .join (map ( str , output ))
109+ a , b , c , ops = input
110+ ins = self .create_instructions ( ops )
111+ return "," .join (self . run_program ( ins , a , b , c ))
117112
118113 def part_2 (self , input : Input ) -> Output2 :
119- lines = list (input )
120-
121- def run_with (a : str ) -> list [str ]:
122- lines [0 ] = "Register A: " + a
123- return self .run_program (lines )
124-
125- wanted = lines [4 ][9 :].replace ("," , "" )
114+ _ , b , c , ops = input
115+ ins = self .create_instructions (ops )
116+ wanted = list (str (_ ) for _ in ops )
126117 log (f"{ wanted = } " )
127- seen = set (["0" ])
128- q = deque (["0" ])
118+ seen = set ([0 ])
119+ q = deque ([0 ])
129120 while q :
130- a = q .popleft ()
131- if "" .join (str (_ ) for _ in run_with (a )) == wanted :
132- return int (a )
133- na = int (a ) * 8
121+ cand_a = q .popleft () * 8
134122 for i in range (8 ):
135- test = str ( na + i )
136- res = "" . join ( str ( _ ) for _ in run_with ( test ) )
137- size = len ( res )
138- if res == wanted [ - size :]:
139- if test not in seen :
140- seen .add (test )
141- log (test )
142- q .append (test )
123+ na = cand_a + i
124+ res = self . run_program ( ins , na , b , c )
125+ if res == wanted :
126+ return na
127+ if res == wanted [ - len ( res ) :] and na not in seen : # noqa E203
128+ seen .add (na )
129+ log (na )
130+ q .append (na )
143131 raise RuntimeError ("unsolvable" )
144132
145133 @aoc_samples (
0 commit comments