Skip to content
This repository was archived by the owner on Dec 28, 2024. It is now read-only.

Commit cf5e45c

Browse files
committed
Add solution day 24 part 2
1 parent a70d8af commit cf5e45c

File tree

3 files changed

+101
-8
lines changed

3 files changed

+101
-8
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,6 @@ automatically rebuilt and redeployed every time the `common` module or their own
5656
| 08 | ⭐ ⭐ | 21 | |
5757
| 09 | ⭐ ⭐ | 22 | ⭐ ⭐ |
5858
| 10 | ⭐ ⭐ | 23 | ⭐ ⭐ |
59-
| 11 | ⭐ ⭐ | 24 | |
59+
| 11 | ⭐ ⭐ | 24 | |
6060
| 12 | ⭐ ⭐ | 25 | |
6161
| 13 | ⭐ ⭐ | | |

solutions/day24/main.go

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ import (
44
"fmt"
55
"github.com/terminalnode/adventofcode2024/common"
66
"log"
7+
"math/bits"
78
"slices"
89
"strconv"
910
"strings"
1011
)
1112

1213
func main() {
13-
common.Setup(24, part1, nil)
14+
common.Setup(24, part1, part2)
1415
}
1516

1617
func part1(
@@ -30,6 +31,93 @@ func part1(
3031
return fmt.Sprintf("Decimal output is %d (binary %s)", out, strOut)
3132
}
3233

34+
func part2(
35+
input string,
36+
) string {
37+
r, wm, err := parse(input)
38+
if err != nil {
39+
return fmt.Sprintf("Failed to parse input: %v", err)
40+
}
41+
42+
zWrong := make([]name, 0)
43+
carryWrong := make([]name, 0)
44+
45+
// Rules deduced by people who know how a ripple adder works and who have figured out the structure of the
46+
// input. Most people just plopped it into a graphing tool or solved it with pen and paper it seems.
47+
// I hated every second of this problem with a passion.
48+
for out, w := range wm {
49+
if out[0] == 'z' && out != "z45" && w.op != XOR {
50+
zWrong = append(zWrong, out)
51+
}
52+
53+
inputsNotXY := out[0] != 'z' &&
54+
w.p1[0] != 'x' && w.p1[0] != 'y' &&
55+
w.p2[0] != 'x' && w.p2[0] != 'y'
56+
if inputsNotXY && out[0] != 'z' && w.op == XOR {
57+
carryWrong = append(carryWrong, out)
58+
}
59+
}
60+
61+
pairs := make([][2]name, 0, 3)
62+
for _, carry := range carryWrong {
63+
zOutput := findFirstZ(carry, wm)
64+
zNum, _ := strconv.Atoi(string(zOutput[1:]))
65+
pairs = append(pairs, [2]name{carry, name(fmt.Sprintf("z%02d", zNum-1))})
66+
}
67+
68+
xNames := findIndexes('x', r, wm)
69+
yNames := findIndexes('y', r, wm)
70+
zNames := findIndexes('z', r, wm)
71+
resolveNames(r, wm, zNames, yNames, xNames)
72+
73+
xOut, _, _ := toInt(r, xNames)
74+
yOut, _, _ := toInt(r, yNames)
75+
zOut, _, _ := toInt(r, zNames)
76+
77+
expected := xOut + yOut
78+
wrongBits := zOut ^ expected
79+
falseCarry := bits.TrailingZeros64(uint64(wrongBits))
80+
81+
lastPair := make([]name, 0, 2)
82+
for out, w := range wm {
83+
suffix := fmt.Sprintf("%02d", falseCarry)
84+
if strings.HasSuffix(w.p1, suffix) &&
85+
strings.HasSuffix(w.p2, suffix) {
86+
lastPair = append(lastPair, out)
87+
}
88+
}
89+
90+
final := make([]name, 0, 6)
91+
final = append(final, zWrong...)
92+
final = append(final, carryWrong...)
93+
final = append(final, lastPair...)
94+
slices.Sort(final)
95+
96+
return strings.Join(final, ",")
97+
}
98+
99+
func findFirstZ(
100+
start name,
101+
wm wireMap,
102+
) name {
103+
visited := make(map[name]bool)
104+
current := start
105+
106+
for {
107+
if current[0] == 'z' {
108+
return current
109+
}
110+
visited[current] = true
111+
112+
for _, w := range wm {
113+
if (w.p1 == current || w.p2 == current) && !visited[w.out] {
114+
current = w.out
115+
break
116+
}
117+
}
118+
}
119+
}
120+
33121
func toInt(
34122
r registry,
35123
names []name,
@@ -66,18 +154,23 @@ func resolveNames(
66154
}
67155
}
68156

69-
for len(depSet) > 0 {
157+
anyNew := true
158+
for len(depSet) > 0 && anyNew {
159+
anyNew = false
70160
newDepSet := make(map[name]bool)
71161
for dep := range depSet {
72162
depDeps, w := resolveDeps(r, wm, dep)
73163
for _, depDep := range depDeps {
164+
anyNew = anyNew || !depSet[depDep]
74165
newDepSet[depDep] = true
75166
}
76167

77168
if len(depDeps) == 1 {
78169
w.execute(r)
79170
}
80171
}
172+
173+
anyNew = anyNew || len(depSet) != len(newDepSet)
81174
depSet = newDepSet
82175
}
83176
}

solutions/day24/parse.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"strings"
66
)
77

8-
type name string
8+
type name = string
99
type registry = map[name]bool
1010
type wireMap = map[name]wire
1111

@@ -74,7 +74,7 @@ func parseReg(
7474
return "", false, fmt.Errorf("failed to parse registry %s with initial value %s", raw, split[1])
7575
}
7676

77-
return name(split[0]), split[1] == "1", nil
77+
return split[0], split[1] == "1", nil
7878
}
7979

8080
func parseWire(
@@ -85,10 +85,10 @@ func parseWire(
8585
return wire{}, fmt.Errorf("failed to split raw wire %s, got %d parts (%v)", raw, len(split), split)
8686
}
8787

88-
p1 := name(split[0])
88+
p1 := split[0]
8989
rawOp := split[1]
90-
p2 := name(split[2])
91-
out := name(split[4])
90+
p2 := split[2]
91+
out := split[4]
9292

9393
var realOp op
9494
switch rawOp {

0 commit comments

Comments
 (0)