Skip to content

Commit 74d3d26

Browse files
committed
feat(2024): add day 17
1 parent 976497a commit 74d3d26

File tree

7 files changed

+242
-18
lines changed

7 files changed

+242
-18
lines changed

go/2024/README.md

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,25 @@ Collect stars by solving puzzles. Two puzzles will be made available on each day
1212

1313
## Days
1414

15-
| Day | #1 | #1 Answer | #2 | #2 Answer |
16-
| -------------------------------------------------------------------------------------------------------------------- | --- | ------------: | --- | --------------: |
17-
| [Day 1: Historian Hysteria](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day01/main.go) | 🌟 | 1666427 | 🌟 | 24316233 |
18-
| [Day 2: Red-Nosed Reports](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day02/main.go) | 🌟 | 564 | 🌟 | 604 |
19-
| [Day 3: Mull It Over](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day03/main.go) | 🌟 | 161085926 | 🌟 | 82045421 |
20-
| [Day 4: Ceres Search](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day04/main.go) | 🌟 | 2562 | 🌟 | 1902 |
21-
| [Day 5: Print Queue](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day05/main.go) | 🌟 | 3608 | 🌟 | 4922 |
22-
| [Day 6: Guard Gallivant](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day06/main.go) | 🌟 | 4778 | 🌟 | 1618 |
23-
| [Day 7: Bridge Repair](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day07/main.go) | 🌟 | 1399219271639 | 🌟 | 275791737999003 |
24-
| [Day 8: Resonant Collinearity](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day08/main.go) | 🌟 | 220 | 🌟 | 813 |
25-
| [Day 9: Disk Fragmenter](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day09/main.go) | 🌟 | 6384282079460 | 🌟 | 6408966547049 |
26-
| [Day 10: Hoof It](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day10/main.go) | 🌟 | 652 | 🌟 | 1432 |
27-
| [Day 11: Plutonian Pebbles](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day11/main.go) | 🌟 | 187738 | 🌟 | 223767210249237 |
28-
| [Day 12: Garden Groups](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day12/main.go) | 🌟 | 1522850 | 🌟 | 953738 |
29-
| [Day 13: Claw Contraption](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day13/main.go) | 🌟 | 26299 | 🌟 | 107824497933339 |
30-
| [Day 14: Restroom Redoubt](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day14/main.go) | 🌟 | 228690000 | 🌟 | 7093 |
31-
| [Day 15: Warehouse Woes](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day15/main.go) | 🌟 | 1526018 | 🌟 | 1550677 |
32-
| [Day 16: Reindeer Maze](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day16/main.go) | 🌟 | 78428 | 🌟 | 463 |
15+
| Day | #1 | #1 Answer | #2 | #2 Answer |
16+
| ---------------------------------------------------------------------------------------------------------------------- | --- | ----------------: | --- | --------------: |
17+
| [Day 1: Historian Hysteria](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day01/main.go) | 🌟 | 1666427 | 🌟 | 24316233 |
18+
| [Day 2: Red-Nosed Reports](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day02/main.go) | 🌟 | 564 | 🌟 | 604 |
19+
| [Day 3: Mull It Over](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day03/main.go) | 🌟 | 161085926 | 🌟 | 82045421 |
20+
| [Day 4: Ceres Search](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day04/main.go) | 🌟 | 2562 | 🌟 | 1902 |
21+
| [Day 5: Print Queue](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day05/main.go) | 🌟 | 3608 | 🌟 | 4922 |
22+
| [Day 6: Guard Gallivant](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day06/main.go) | 🌟 | 4778 | 🌟 | 1618 |
23+
| [Day 7: Bridge Repair](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day07/main.go) | 🌟 | 1399219271639 | 🌟 | 275791737999003 |
24+
| [Day 8: Resonant Collinearity](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day08/main.go) | 🌟 | 220 | 🌟 | 813 |
25+
| [Day 9: Disk Fragmenter](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day09/main.go) | 🌟 | 6384282079460 | 🌟 | 6408966547049 |
26+
| [Day 10: Hoof It](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day10/main.go) | 🌟 | 652 | 🌟 | 1432 |
27+
| [Day 11: Plutonian Pebbles](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day11/main.go) | 🌟 | 187738 | 🌟 | 223767210249237 |
28+
| [Day 12: Garden Groups](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day12/main.go) | 🌟 | 1522850 | 🌟 | 953738 |
29+
| [Day 13: Claw Contraption](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day13/main.go) | 🌟 | 26299 | 🌟 | 107824497933339 |
30+
| [Day 14: Restroom Redoubt](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day14/main.go) | 🌟 | 228690000 | 🌟 | 7093 |
31+
| [Day 15: Warehouse Woes](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day15/main.go) | 🌟 | 1526018 | 🌟 | 1550677 |
32+
| [Day 16: Reindeer Maze](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day16/main.go) | 🌟 | 78428 | 🌟 | 463 |
33+
| [Day 17: Chronospatial Computer](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day17/main.go) | 🌟 | 2,0,1,3,4,0,2,1,7 | 🌟 | 236580836040301 |
3334

3435
## Benchmarks
3536

@@ -53,6 +54,7 @@ Using Go's built-in benchmarking with the [testing](https://pkg.go.dev/testing#h
5354
| 14 | 55522 ns/op | 56488050 ns/op | `90.67%` / - |
5455
| 15 | 477450 ns/op | 3498110 ns/op | |
5556
| 16 | 97868160 ns/op | 99166694 ns/op | |
57+
| 17 | 13964 ns/op | 561424 ns/op | |
5658

5759
\* compared to first solution
5860

go/2024/puzzles/day17/main.go

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"regexp"
6+
"slices"
7+
"strconv"
8+
"strings"
9+
10+
"github.com/believer/aoc-2024/utils"
11+
"github.com/believer/aoc-2024/utils/files"
12+
)
13+
14+
type Computer struct {
15+
A, B, C int
16+
Iteration int
17+
Instructions []int
18+
Output []string
19+
}
20+
21+
func (c *Computer) Operand() int {
22+
index := c.Iteration + 1
23+
24+
switch c.Instructions[index] {
25+
case 0, 1, 2, 3:
26+
return c.Instructions[index]
27+
case 4:
28+
return c.A
29+
case 5:
30+
return c.B
31+
case 6:
32+
return c.C
33+
default:
34+
panic("This should be unreachable")
35+
}
36+
}
37+
38+
func (c *Computer) Run() {
39+
for c.Iteration < len(c.Instructions) {
40+
opcode := c.Instructions[c.Iteration]
41+
operand := c.Operand()
42+
literalOperand := c.Instructions[c.Iteration+1]
43+
44+
switch opcode {
45+
// adv :: A / 2^operand -> A
46+
case 0:
47+
// Found this fancy and performant way of doing the calculation
48+
// using right shift assignment. It's the same as dividing by a
49+
// power of 2 for integers and truncates the value.
50+
// So exactly what the puzzle description hints to.
51+
// For part 1 it doesn't make a difference, but in part 2 it actually
52+
// makes quite a larger difference in performance.
53+
c.A >>= operand
54+
// bxl :: bitwise XOR of B and the _literal_ operand -> B
55+
case 1:
56+
c.B ^= literalOperand
57+
// bst :: operand % 8 -> B
58+
case 2:
59+
// When we calculate modulo of a % b, where b is a power of 2 (like we have),
60+
// we can also do a & (b-1) (Bitwise AND). This should be faster in theory, but
61+
// I tested it and found that it wasn't in this case. Still a nice learning
62+
// to keep around.
63+
c.B = operand % 8
64+
// jnz :: Nothing if A is zero. Otherwise, jump to _literal_ operand.
65+
case 3:
66+
if c.A != 0 {
67+
c.Iteration = literalOperand
68+
continue
69+
}
70+
// bxc :: bitwise XOR of B and C -> B
71+
case 4:
72+
c.B ^= c.C
73+
// out :: Output value as operand % 8
74+
case 5:
75+
c.Output = append(c.Output, strconv.Itoa(operand%8))
76+
// bdv :: A / 2^operand -> B
77+
case 6:
78+
c.B = c.A >> operand
79+
// cdv :: A / 2^operand -> C
80+
case 7:
81+
c.C = c.A >> operand
82+
}
83+
84+
c.Iteration += 2
85+
}
86+
}
87+
88+
func main() {
89+
fmt.Println("Part 1: ", part1("input.txt"))
90+
fmt.Println("Part 2: ", part2("input.txt"))
91+
}
92+
93+
func part1(name string) string {
94+
A, B, C, instructions := parseInput(name)
95+
96+
computer := Computer{A: A, B: B, C: C, Instructions: instructions}
97+
computer.Run()
98+
99+
return strings.Join(computer.Output, ",")
100+
}
101+
102+
func part2(name string) int {
103+
_, B, C, instructions := parseInput(name)
104+
validPrograms := []int{0}
105+
106+
// Run through the instructions of the program in reverse since that's
107+
// how they are added to the list
108+
instructionsReversed := append([]int{}, instructions...)
109+
slices.Reverse(instructionsReversed)
110+
111+
for _, instruction := range instructionsReversed {
112+
next := []int{}
113+
114+
for _, v := range validPrograms {
115+
for n := range 8 {
116+
// Increase the value three bits, since we're in a 3-bit computer.
117+
// This is effectively v * 2^3. Then insert the value of n in the lower bits.
118+
a := (v << 3) | n
119+
120+
computer := Computer{A: a, B: B, C: C, Instructions: instructions}
121+
computer.Run()
122+
123+
// If the instruction matches, add it to the list of valid inputs
124+
if instruction == utils.MustIntFromString(computer.Output[0]) {
125+
next = append(next, a)
126+
}
127+
}
128+
}
129+
130+
validPrograms = next
131+
}
132+
133+
return slices.Min(validPrograms)
134+
}
135+
136+
func parseInput(name string) (int, int, int, []int) {
137+
lines := files.ReadParagraphs(name)
138+
registerRe := regexp.MustCompile(`\d+`)
139+
140+
A := utils.MustIntFromString(registerRe.FindString(lines[0][0]))
141+
B := utils.MustIntFromString(registerRe.FindString(lines[0][1]))
142+
C := utils.MustIntFromString(registerRe.FindString(lines[0][2]))
143+
instructionList := registerRe.FindAllString(lines[1][0], -1)
144+
instructions := []int{}
145+
146+
for _, instruction := range instructionList {
147+
instructions = append(instructions, utils.MustIntFromString(instruction))
148+
}
149+
150+
return A, B, C, instructions
151+
}

go/2024/puzzles/day17/main_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestPart1Small(t *testing.T) {
10+
t.Run("Part 1", func(t *testing.T) {
11+
expected := "0,1,2"
12+
actual := part1("test-input-small.txt")
13+
assert.Equal(t, expected, actual)
14+
})
15+
}
16+
17+
func TestPart1SmallTwo(t *testing.T) {
18+
t.Run("Part 1", func(t *testing.T) {
19+
expected := "4,2,5,6,7,7,7,7,3,1,0"
20+
actual := part1("test-input-small-two.txt")
21+
assert.Equal(t, expected, actual)
22+
})
23+
}
24+
25+
func TestPart1(t *testing.T) {
26+
t.Run("Part 1", func(t *testing.T) {
27+
expected := "4,6,3,5,6,3,5,2,1,0"
28+
actual := part1("test-input.txt")
29+
assert.Equal(t, expected, actual)
30+
})
31+
}
32+
33+
func TestPart2(t *testing.T) {
34+
t.Run("Part 2", func(t *testing.T) {
35+
expected := 117440
36+
actual := part2("test-input-part2.txt")
37+
assert.Equal(t, expected, actual)
38+
})
39+
}
40+
41+
func BenchmarkPart1(b *testing.B) {
42+
for i := 0; i < b.N; i++ {
43+
part1("input.txt")
44+
}
45+
}
46+
47+
func BenchmarkPart2(b *testing.B) {
48+
for i := 0; i < b.N; i++ {
49+
part2("input.txt")
50+
}
51+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 2024
2+
Register B: 0
3+
Register C: 0
4+
5+
Program: 0,3,5,4,3,0
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 2024
2+
Register B: 0
3+
Register C: 0
4+
5+
Program: 0,1,5,4,3,0
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 10
2+
Register B: 0
3+
Register C: 0
4+
5+
Program: 5,0,5,1,5,4

go/2024/puzzles/day17/test-input.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 729
2+
Register B: 0
3+
Register C: 0
4+
5+
Program: 0,1,5,4,3,0

0 commit comments

Comments
 (0)