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

Commit 8d56482

Browse files
committed
Add solution day 24 part 1
1 parent 124d753 commit 8d56482

File tree

3 files changed

+219
-2
lines changed

3 files changed

+219
-2
lines changed

README.md

+1-1
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

+112-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,120 @@
11
package main
22

33
import (
4+
"fmt"
45
"github.com/terminalnode/adventofcode2024/common"
6+
"log"
7+
"slices"
8+
"strconv"
9+
"strings"
510
)
611

712
func main() {
8-
common.Setup(24, nil, nil)
13+
common.Setup(24, part1, nil)
14+
}
15+
16+
func part1(
17+
input string,
18+
) string {
19+
r, wm, err := parse(input)
20+
if err != nil {
21+
return fmt.Sprintf("Failed to parse input: %v", err)
22+
}
23+
zNames := findZIndexes(r, wm)
24+
depSet := make(map[name]bool)
25+
for _, zName := range zNames {
26+
depSet[zName] = true
27+
}
28+
29+
for len(depSet) > 0 {
30+
newDepSet := make(map[name]bool)
31+
for dep := range depSet {
32+
depDeps, w := resolveDeps(r, wm, dep)
33+
for _, depDep := range depDeps {
34+
newDepSet[depDep] = true
35+
}
36+
37+
if len(depDeps) == 1 {
38+
w.execute(r)
39+
}
40+
}
41+
depSet = newDepSet
42+
}
43+
44+
zValues := make([]string, len(zNames))
45+
for i, zName := range zNames {
46+
if r[zName] {
47+
zValues[i] = "1"
48+
} else {
49+
zValues[i] = "0"
50+
}
51+
}
52+
slices.Reverse(zValues)
53+
zString := strings.Join(zValues, "")
54+
out, err := strconv.ParseInt(zString, 2, 0)
55+
if err != nil {
56+
return fmt.Sprintf("Failed to read %s as binary: %v", zString, err)
57+
}
58+
59+
return fmt.Sprintf("Decimal output is %d (binary %s)", out, zString)
60+
}
61+
62+
func resolveDeps(
63+
r registry,
64+
wm wireMap,
65+
target name,
66+
) ([]name, wire) {
67+
out := make([]name, 0, 3)
68+
if _, ok := r[target]; ok {
69+
return out, wire{}
70+
}
71+
out = append(out, target)
72+
73+
w, ok := wm[target]
74+
if !ok {
75+
log.Println("WARNING: target unresolvable", target)
76+
return out, w
77+
}
78+
79+
if _, ok := r[w.p1]; !ok {
80+
out = append(out, w.p1)
81+
}
82+
if _, ok := r[w.p2]; !ok {
83+
out = append(out, w.p2)
84+
}
85+
86+
return out, w
87+
}
88+
89+
func (w wire) execute(
90+
r registry,
91+
) {
92+
p1 := r[w.p1]
93+
p2 := r[w.p2]
94+
switch w.op {
95+
case AND:
96+
r[w.out] = p1 && p2
97+
case OR:
98+
r[w.out] = p1 || p2
99+
case XOR:
100+
r[w.out] = (p1 || p2) && (p1 != p2)
101+
}
102+
}
103+
104+
func findZIndexes(
105+
r registry,
106+
wm wireMap,
107+
) []name {
108+
out := make([]name, 0, 30)
109+
for curr := 0; ; curr++ {
110+
key := name(fmt.Sprintf("z%02d", curr))
111+
_, inR := r[key]
112+
_, inWM := wm[key]
113+
if !inR && !inWM {
114+
break
115+
}
116+
out = append(out, key)
117+
}
118+
slices.Sort(out)
119+
return out
9120
}

solutions/day24/parse.go

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
)
7+
8+
type name string
9+
type registry = map[name]bool
10+
type wireMap = map[name]wire
11+
12+
type op int
13+
14+
const (
15+
AND = op(iota)
16+
OR
17+
XOR
18+
)
19+
20+
type wire struct {
21+
p1 name
22+
op op
23+
p2 name
24+
out name
25+
}
26+
27+
func parse(
28+
input string,
29+
) (registry, wireMap, error) {
30+
rawRegistry, rawWires, err := splitInput(input)
31+
outRegistry := make(registry)
32+
outWires := make(wireMap)
33+
if err != nil {
34+
return outRegistry, outWires, err
35+
}
36+
37+
for _, raw := range rawRegistry {
38+
n, v, err := parseReg(raw)
39+
if err != nil {
40+
return outRegistry, outWires, err
41+
}
42+
outRegistry[n] = v
43+
}
44+
45+
for _, raw := range rawWires {
46+
w, err := parseWire(raw)
47+
if err != nil {
48+
return outRegistry, outWires, err
49+
}
50+
outWires[w.out] = w
51+
}
52+
53+
return outRegistry, outWires, nil
54+
}
55+
56+
func splitInput(
57+
input string,
58+
) ([]string, []string, error) {
59+
split := strings.Split(input, "\n\n")
60+
if len(split) != 2 {
61+
return []string{}, []string{}, fmt.Errorf("failed to split input, got %d parts", len(split))
62+
}
63+
64+
return strings.Split(split[0], "\n"), strings.Split(split[1], "\n"), nil
65+
}
66+
67+
func parseReg(
68+
raw string,
69+
) (name, bool, error) {
70+
split := strings.Split(raw, ": ")
71+
if len(split) != 2 {
72+
return "", false, fmt.Errorf("failed to split raw registry %s, got %d parts (%v)", raw, len(split), split)
73+
} else if split[1] != "1" && split[1] != "0" {
74+
return "", false, fmt.Errorf("failed to parse registry %s with initial value %s", raw, split[1])
75+
}
76+
77+
return name(split[0]), split[1] == "1", nil
78+
}
79+
80+
func parseWire(
81+
raw string,
82+
) (wire, error) {
83+
split := strings.Split(raw, " ")
84+
if len(split) != 5 {
85+
return wire{}, fmt.Errorf("failed to split raw wire %s, got %d parts (%v)", raw, len(split), split)
86+
}
87+
88+
p1 := name(split[0])
89+
rawOp := split[1]
90+
p2 := name(split[2])
91+
out := name(split[4])
92+
93+
var realOp op
94+
switch rawOp {
95+
case "AND":
96+
realOp = AND
97+
case "OR":
98+
realOp = OR
99+
case "XOR":
100+
realOp = XOR
101+
default:
102+
return wire{}, fmt.Errorf("failed to parse operation %s", rawOp)
103+
}
104+
105+
return wire{p1: p1, op: realOp, p2: p2, out: out}, nil
106+
}

0 commit comments

Comments
 (0)