@@ -102,3 +102,152 @@ func getFewestButtonPresesFromLine(line string) (int, error) {
102102
103103 return 0 , fmt .Errorf ("didnt found a result" )
104104}
105+
106+ func GetFewestButtonPresesPart2 () (int , error ) {
107+ lines , err := utils .ReadLines ("day10/input.txt" )
108+ if err != nil {
109+ return 0 , err
110+ }
111+ total := 0
112+ for i , line := range lines {
113+ presses , err := solveJoltageLine (line )
114+ if err != nil {
115+ return 0 , fmt .Errorf ("line %d: %w" , i + 1 , err )
116+ }
117+ total += presses
118+ }
119+ return total , nil
120+ }
121+
122+ type Machine struct {
123+ buttons []uint32
124+ joltages []int32
125+ }
126+
127+ type SubsetXOR struct {
128+ subset []int
129+ xor uint32
130+ }
131+
132+ func solveJoltageLine (line string ) (int , error ) {
133+ buttonsRe := regexp .MustCompile (`\(([^)]*)\)` )
134+ joltagesRe := regexp .MustCompile (`\{([^}]*)\}` )
135+
136+ var buttons []uint32
137+ for _ , m := range buttonsRe .FindAllStringSubmatch (line , - 1 ) {
138+ if len (m ) < 2 {
139+ continue
140+ }
141+ content := strings .TrimSpace (m [1 ])
142+ mask := uint32 (0 )
143+ if content != "" {
144+ for _ , s := range strings .Split (content , "," ) {
145+ s = strings .TrimSpace (s )
146+ if s != "" {
147+ v , err := strconv .Atoi (s )
148+ if err != nil {
149+ return 0 , fmt .Errorf ("invalid button index '%s'" , s )
150+ }
151+ mask |= 1 << uint32 (v )
152+ }
153+ }
154+ }
155+ buttons = append (buttons , mask )
156+ }
157+
158+ joltagesMatch := joltagesRe .FindStringSubmatch (line )
159+ if len (joltagesMatch ) < 2 {
160+ return 0 , fmt .Errorf ("invalid joltages pattern" )
161+ }
162+ var joltages []int32
163+ for _ , s := range strings .Split (joltagesMatch [1 ], "," ) {
164+ s = strings .TrimSpace (s )
165+ if s != "" {
166+ v , err := strconv .Atoi (s )
167+ if err != nil {
168+ return 0 , fmt .Errorf ("invalid joltage '%s'" , s )
169+ }
170+ joltages = append (joltages , int32 (v ))
171+ }
172+ }
173+
174+ var subsetXors []SubsetXOR
175+ numButtons := len (buttons )
176+ for mask := 0 ; mask < (1 << numButtons ); mask ++ {
177+ var subset []int
178+ xorVal := uint32 (0 )
179+ for i := 0 ; i < numButtons ; i ++ {
180+ if (mask & (1 << i )) != 0 {
181+ subset = append (subset , i )
182+ xorVal ^= buttons [i ]
183+ }
184+ }
185+ subsetXors = append (subsetXors , SubsetXOR {subset , xorVal })
186+ }
187+
188+ machine := & Machine {buttons , joltages }
189+ result , found := machine .solveRecursive (subsetXors , joltages )
190+ if found {
191+ return result , nil
192+ }
193+ return 0 , fmt .Errorf ("no solution found" )
194+ }
195+
196+ func (m * Machine ) solveRecursive (subsetXors []SubsetXOR , joltages []int32 ) (int , bool ) {
197+ allZero := true
198+ for _ , j := range joltages {
199+ if j != 0 {
200+ allZero = false
201+ break
202+ }
203+ }
204+ if allZero {
205+ return 0 , true
206+ }
207+
208+ parity := uint32 (0 )
209+ for i , j := range joltages {
210+ if j % 2 != 0 {
211+ parity |= 1 << uint32 (i )
212+ }
213+ }
214+
215+ var best * int = nil
216+ for _ , su := range subsetXors {
217+ if su .xor != parity {
218+ continue
219+ }
220+
221+ newJoltages := make ([]int32 , len (joltages ))
222+ valid := true
223+ for i := 0 ; i < len (joltages ); i ++ {
224+ count := int32 (0 )
225+ for _ , btnIdx := range su .subset {
226+ if (m .buttons [btnIdx ] & (1 << uint32 (i ))) != 0 {
227+ count ++
228+ }
229+ }
230+ diff := joltages [i ] - count
231+ if diff < 0 {
232+ valid = false
233+ break
234+ }
235+ newJoltages [i ] = diff / 2
236+ }
237+ if ! valid {
238+ continue
239+ }
240+
241+ if recResult , found := m .solveRecursive (subsetXors , newJoltages ); found {
242+ pressesSoFar := len (su .subset ) + 2 * recResult
243+ if best == nil || pressesSoFar < * best {
244+ best = & pressesSoFar
245+ }
246+ }
247+ }
248+
249+ if best != nil {
250+ return * best , true
251+ }
252+ return 0 , false
253+ }
0 commit comments