@@ -3,8 +3,8 @@ package main
33import (
44 "fmt"
55 "log"
6- "math"
76 "regexp"
7+ "slices"
88 "strconv"
99 "strings"
1010
@@ -22,6 +22,17 @@ type Computer struct {
2222 Out []int
2323}
2424
25+ func (c * Computer ) String () string {
26+ return fmt .Sprintf ("Register A: %b\n Register B: %b\n Register C: %b" , c .A , c .B , c .C )
27+ }
28+
29+ func (c * Computer ) Run (program []int ) {
30+ for c .IP >= 0 && c .IP < len (program ) {
31+ opcode , operand := program [c .IP ], program [c .IP + 1 ]
32+ exec (opcode , operand , c )
33+ }
34+ }
35+
2536func parseInput (input string ) (Computer , []int , error ) {
2637 var comp Computer
2738 var registers , program []int
@@ -61,23 +72,57 @@ func main() {
6172 }
6273
6374 fmt .Println ("solution to part one: " , PartOne (computer , program ))
75+ fmt .Println ("solution to part two: " , PartTwo (computer , program ))
6476}
6577
66- func PartOne (computer Computer , program []int ) string {
67- curr := computer
68- for curr .IP >= 0 && curr .IP < len (program ) {
69- opcode , operand := program [curr .IP ], program [curr .IP + 1 ]
70- exec (opcode , operand , & curr )
71- }
78+ func PartOne (comp Computer , program []int ) string {
79+ comp .Run (program )
7280
7381 var res []string
74- for _ , out := range curr .Out {
82+ for _ , out := range comp .Out {
7583 res = append (res , strconv .Itoa (out ))
7684 }
7785
7886 return strings .Join (res , "," )
7987}
8088
89+ func PartTwo (computer Computer , program []int ) int {
90+ // Note: you'll need to walkthrough your program to know how many bits each segment should
91+ // be.
92+
93+ // we reverse engineer the segments of the A register 3-bits at a time,
94+ // the first 3 bits of the A register are responsible for producing
95+ // the last output — in my case, 0. Then we expand by an extra 3 bits, searching through
96+ // values 0 (0b000) to 7 (0b111), noting values that produce the last 2 outputs and so on...
97+
98+ // from hacking around, 0b111 or 7 is known to produce the last output 0
99+ // at least, based on my given input
100+ knownSegments := []int {0b111 }
101+
102+ // we try to find the remaining segments of the output, we skip the last output 0, since
103+ // we already know that
104+ for i := 2 ; i <= len (program ); i ++ {
105+ var expandedSegments []int
106+ expectedOutput := program [len (program )- i :]
107+
108+ for _ , f := range knownSegments {
109+ for i := 0b000 ; i <= 0b111 ; i ++ {
110+ regA := f << 3 + i
111+ comp := Computer {A : regA }
112+ comp .Run (program )
113+
114+ if slices .Equal (comp .Out , expectedOutput ) {
115+ expandedSegments = append (expandedSegments , regA )
116+ }
117+ }
118+ }
119+
120+ knownSegments = expandedSegments
121+ }
122+
123+ return slices .Min (knownSegments )
124+ }
125+
81126func combo (operand int , computer * Computer ) int {
82127 switch operand {
83128 case 4 :
@@ -98,7 +143,7 @@ func exec(opCode, operand int, computer *Computer) {
98143 case 0 :
99144 numerator := computer .A
100145 comboOp := combo (operand , computer )
101- computer .A = numerator / int ( math . Pow ( 2 , float64 ( comboOp )) )
146+ computer .A = numerator / ( 1 << comboOp )
102147 case 1 :
103148 computer .B = computer .B ^ operand
104149 case 2 :
@@ -116,11 +161,11 @@ func exec(opCode, operand int, computer *Computer) {
116161 case 6 :
117162 numerator := computer .A
118163 comboOp := combo (operand , computer )
119- computer .B = numerator / int ( math . Pow ( 2 , float64 ( comboOp )) )
164+ computer .B = numerator / ( 1 << comboOp )
120165 case 7 :
121166 numerator := computer .A
122167 comboOp := combo (operand , computer )
123- computer .C = numerator / int ( math . Pow ( 2 , float64 ( comboOp )) )
168+ computer .C = numerator / ( 1 << comboOp )
124169 }
125170
126171 if ! jumped {
0 commit comments