Skip to content

Commit 4279473

Browse files
committed
feat(2024): add day 6 part 2
1 parent 5d188c2 commit 4279473

File tree

3 files changed

+97
-21
lines changed

3 files changed

+97
-21
lines changed

go/2024/README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,20 @@ Collect stars by solving puzzles. Two puzzles will be made available on each day
1919
| [Day 3: Mull It Over](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day03/main.go) | 🌟 | 161085926 | 🌟 | 82045421 |
2020
| [Day 4: Ceres Search](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day04/main.go) | 🌟 | 2562 | 🌟 | 1902 |
2121
| [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 | | |
22+
| [Day 6: Guard Gallivant](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day06/main.go) | 🌟 | 4778 | 🌟 | 1618 |
2323

2424
## Benchmarks
2525

2626
Using Go's built-in benchmarking with the [testing](https://pkg.go.dev/testing#hdr-Benchmarks) package. Computer is a 2021 MacBook Pro M1 Pro, 32 GB RAM.
2727

28-
| Day | #1 | #2 | Improvement\* |
29-
| --- | -----------: | ------------: | ------------------- |
30-
| 1 | 116264 ns/op | 131233 ns/op | `3.53%` / `68.43%` |
31-
| 2 | 310935 ns/op | 723512 ns/op | |
32-
| 3 | 336448 ns/op | 785320 ns/op | - / `36.98%` |
33-
| 4 | 523315 ns/op | 217584 ns/op | `81.73%` / `26.09%` |
34-
| 5 | 778880 ns/op | 3129873 ns/op | `53.34%` / `81.91%` |
35-
| 5 | 349256 ns/op | | |
28+
| Day | #1 | #2 | Improvement\* |
29+
| --- | -----------: | ---------------: | ------------------- |
30+
| 1 | 116264 ns/op | 131233 ns/op | `3.53%` / `68.43%` |
31+
| 2 | 310935 ns/op | 723512 ns/op | |
32+
| 3 | 336448 ns/op | 785320 ns/op | - / `36.98%` |
33+
| 4 | 523315 ns/op | 217584 ns/op | `81.73%` / `26.09%` |
34+
| 5 | 778880 ns/op | 3129873 ns/op | `53.34%` / `81.91%` |
35+
| 6 | 312461 ns/op | 1153391125 ns/op | |
3636

3737
\* compared to first solution
3838

go/2024/puzzles/day06/main.go

Lines changed: 87 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import (
66
"github.com/believer/aoc-2024/utils/files"
77
)
88

9+
// Brute forced part 2 first by checking every position on the grid.
10+
// It worked, but was slow. We can instead check only the path that
11+
// the guard took during the first run which was more that 78% faster.
12+
// Still over a second, but a lot better.
913
func main() {
1014
fmt.Println("Part 1: ", part1("input.txt"))
1115
fmt.Println("Part 2: ", part2("input.txt"))
@@ -15,31 +19,76 @@ type Position struct {
1519
r, c int
1620
}
1721

22+
type PositionWithDirection struct {
23+
r, c, dr, dc int
24+
}
25+
1826
func part1(name string) int {
1927
lines := files.ReadLines(name)
20-
visitedLocations := make(map[Position]struct{})
28+
guardLocation := initialGuardLocation(lines)
29+
30+
return len(getPath(lines, guardLocation))
31+
}
32+
33+
func part2(name string) int {
34+
lines := files.ReadLines(name)
35+
possibleLoops := 0
36+
guardLocation := initialGuardLocation(lines)
37+
38+
// Create a grid to modify
39+
var grid [][]byte
40+
41+
for _, l := range lines {
42+
grid = append(grid, []byte(l))
43+
}
44+
45+
guardPath := getPath(lines, guardLocation)
2146

47+
for p := range guardPath {
48+
if lines[p.r][p.c] != '.' {
49+
continue
50+
}
51+
52+
grid[p.r][p.c] = '#'
53+
54+
if isLoop(grid, guardLocation.r, guardLocation.c) {
55+
possibleLoops++
56+
}
57+
58+
grid[p.r][p.c] = '.'
59+
}
60+
61+
return possibleLoops
62+
}
63+
64+
func initialGuardLocation(lines []string) Position {
65+
guardLocation := Position{0, 0}
2266
rows := len(lines)
2367
cols := len(lines[0])
24-
guardLocation := Position{0, 0}
2568

26-
// Find initial guard location
2769
outer:
2870
for r := range rows {
2971
for c := range cols {
30-
if string(lines[r][c]) == "^" {
72+
if lines[r][c] == '^' {
3173
guardLocation = Position{r, c}
3274
break outer
3375
}
3476
}
3577
}
3678

79+
return guardLocation
80+
}
81+
82+
func getPath(lines []string, guard Position) map[Position]struct{} {
83+
visitedLocations := make(map[Position]struct{})
84+
rows := len(lines)
85+
cols := len(lines[0])
3786
dr := -1
3887
dc := 0
3988

4089
for {
41-
r, c := guardLocation.r, guardLocation.c
42-
visitedLocations[guardLocation] = struct{}{}
90+
r, c := guard.r, guard.c
91+
visitedLocations[guard] = struct{}{}
4392

4493
// Check bounds
4594
if r+dr < 0 || r+dr >= rows || c+dc < 0 || c+dc >= cols {
@@ -48,16 +97,43 @@ outer:
4897

4998
// We always rotate to the right on obstacles
5099
// (-1,0) becomes (0,1) becomes (1,0) becomes (0,-1)
51-
if string(lines[r+dr][c+dc]) == "#" {
100+
if lines[r+dr][c+dc] == '#' {
52101
dc, dr = -dr, dc
53102
} else {
54-
guardLocation = Position{r: r + dr, c: c + dc}
103+
guard = Position{r: r + dr, c: c + dc}
55104
}
56105
}
57106

58-
return len(visitedLocations)
107+
return visitedLocations
59108
}
60109

61-
func part2(name string) int {
62-
return 0
110+
func isLoop(grid [][]byte, r, c int) bool {
111+
visitedLocations := make(map[PositionWithDirection]struct{})
112+
dr := -1
113+
dc := 0
114+
rows := len(grid)
115+
cols := len(grid[0])
116+
117+
for {
118+
// Save with direction as well to find when we're looping
119+
visitedLocations[PositionWithDirection{r, c, dr, dc}] = struct{}{}
120+
121+
// Check bounds
122+
if r+dr < 0 || r+dr >= rows || c+dc < 0 || c+dc >= cols {
123+
return false
124+
}
125+
126+
// We always rotate to the right on obstacles
127+
// (-1,0) becomes (0,1) becomes (1,0) becomes (0,-1)
128+
if grid[r+dr][c+dc] == '#' {
129+
dc, dr = -dr, dc
130+
} else {
131+
r += dr
132+
c += dc
133+
}
134+
135+
if _, ok := visitedLocations[PositionWithDirection{r, c, dr, dc}]; ok {
136+
return true
137+
}
138+
}
63139
}

go/2024/puzzles/day06/main_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ func TestPart1(t *testing.T) {
1616

1717
func TestPart2(t *testing.T) {
1818
t.Run("Part 2", func(t *testing.T) {
19-
expected := 0
19+
expected := 6
2020
actual := part2("test-input.txt")
2121
assert.Equal(t, expected, actual)
2222
})

0 commit comments

Comments
 (0)