@@ -8,12 +8,48 @@ def part_one(input)
88
99 cpu = Cpu . new ( ra , rb , rc , instructions )
1010 output = cpu . run
11-
12- output
11+
12+ output . map ( & :to_s ) . join ( ',' )
1313 end
1414
1515 def part_two ( input )
16- 0
16+ lines = input . split ( "\n " )
17+ ra = lines [ 0 ] . scan ( /Register A: (\d +)/ ) . first . first . to_i
18+ rb = lines [ 1 ] . scan ( /Register B: (\d +)/ ) . first . first . to_i
19+ rc = lines [ 2 ] . scan ( /Register C: (\d +)/ ) . first . first . to_i
20+ instructions = lines [ 4 ] . split ( ":" ) . last . split ( "," ) . map ( &:to_i )
21+
22+ target = instructions . dup
23+
24+ # Instead of bruteforcing the full solution at once, we want
25+ # to create partial solutions and work towards a full one.
26+ #
27+ # Since the "Cpu" will output 3-bit chunks, we can work backwards
28+ # with a minimal A for outputting the last output chunk correctly.
29+ #
30+ # Given the example 0,3,5,4,3,0 we try to figure out which
31+ # minimal value of A results in the right most 0 in the output.
32+
33+ # Given an empty output, A is 0 (that is when the program ends.)
34+ results = [ 0 ]
35+
36+ # Incrementally find more chunks, right to left
37+ target . size . times do |i |
38+ # Use the results from the previous iteration to find the next
39+ results = results . flat_map do |n |
40+ # Bit-shift n by 3 to the left, and add a number between 0 and 7
41+ # For these values of A, see which are valid candidates
42+ ( 0 ..7 ) . map do |a |
43+ candidate = n * 8 + a
44+ output = Cpu . new ( candidate , rb , rc , target ) . run
45+ candidate if target [ -i - 1 ..] == output
46+ end . compact
47+ end
48+ end
49+
50+ # results now has, probably, one or more values for A, so pick
51+ # the first, and smallest, one.
52+ results . first
1753 end
1854end
1955
@@ -59,7 +95,7 @@ def run
5995 step
6096 # puts to_s
6197 end
62- @ output. map ( & :to_s ) . join ( ',' )
98+ output
6399 end
64100
65101 # Single CPU cycle
0 commit comments