Skip to content

Commit ec88334

Browse files
committed
feat: day 10, part 2 solution
1 parent 5bdc890 commit ec88334

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed

day10/day10.go

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,10 @@ func main() {
149149
} else {
150150
fmt.Printf("Day 10, Part 1 answer is %d\n", fewestPresses)
151151
}
152+
fewestPressesPart2, err := day10.GetFewestButtonPresesPart2()
153+
if err != nil {
154+
fmt.Printf("An error occured while getting solution for day 10 part 2 - %v\n", err)
155+
} else {
156+
fmt.Printf("Day 10, Part 2 answer is %d\n", fewestPressesPart2)
157+
}
152158
}

0 commit comments

Comments
 (0)