Skip to content

Commit

Permalink
feat(2024): add day 6 part 2
Browse files Browse the repository at this point in the history
  • Loading branch information
believer committed Dec 6, 2024
1 parent 5d188c2 commit 4279473
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 21 deletions.
18 changes: 9 additions & 9 deletions go/2024/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,20 @@ Collect stars by solving puzzles. Two puzzles will be made available on each day
| [Day 3: Mull It Over](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day03/main.go) | 🌟 | 161085926 | 🌟 | 82045421 |
| [Day 4: Ceres Search](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day04/main.go) | 🌟 | 2562 | 🌟 | 1902 |
| [Day 5: Print Queue](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day05/main.go) | 🌟 | 3608 | 🌟 | 4922 |
| [Day 6: Guard Gallivant](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day06/main.go) | 🌟 | 4778 | | |
| [Day 6: Guard Gallivant](https://github.com/believer/advent-of-code/blob/master/go/2024/puzzles/day06/main.go) | 🌟 | 4778 | 🌟 | 1618 |

## Benchmarks

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.

| Day | #1 | #2 | Improvement\* |
| --- | -----------: | ------------: | ------------------- |
| 1 | 116264 ns/op | 131233 ns/op | `3.53%` / `68.43%` |
| 2 | 310935 ns/op | 723512 ns/op | |
| 3 | 336448 ns/op | 785320 ns/op | - / `36.98%` |
| 4 | 523315 ns/op | 217584 ns/op | `81.73%` / `26.09%` |
| 5 | 778880 ns/op | 3129873 ns/op | `53.34%` / `81.91%` |
| 5 | 349256 ns/op | | |
| Day | #1 | #2 | Improvement\* |
| --- | -----------: | ---------------: | ------------------- |
| 1 | 116264 ns/op | 131233 ns/op | `3.53%` / `68.43%` |
| 2 | 310935 ns/op | 723512 ns/op | |
| 3 | 336448 ns/op | 785320 ns/op | - / `36.98%` |
| 4 | 523315 ns/op | 217584 ns/op | `81.73%` / `26.09%` |
| 5 | 778880 ns/op | 3129873 ns/op | `53.34%` / `81.91%` |
| 6 | 312461 ns/op | 1153391125 ns/op | |

\* compared to first solution

Expand Down
98 changes: 87 additions & 11 deletions go/2024/puzzles/day06/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import (
"github.com/believer/aoc-2024/utils/files"
)

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

type PositionWithDirection struct {
r, c, dr, dc int
}

func part1(name string) int {
lines := files.ReadLines(name)
visitedLocations := make(map[Position]struct{})
guardLocation := initialGuardLocation(lines)

return len(getPath(lines, guardLocation))
}

func part2(name string) int {
lines := files.ReadLines(name)
possibleLoops := 0
guardLocation := initialGuardLocation(lines)

// Create a grid to modify
var grid [][]byte

for _, l := range lines {
grid = append(grid, []byte(l))
}

guardPath := getPath(lines, guardLocation)

for p := range guardPath {
if lines[p.r][p.c] != '.' {
continue
}

grid[p.r][p.c] = '#'

if isLoop(grid, guardLocation.r, guardLocation.c) {
possibleLoops++
}

grid[p.r][p.c] = '.'
}

return possibleLoops
}

func initialGuardLocation(lines []string) Position {
guardLocation := Position{0, 0}
rows := len(lines)
cols := len(lines[0])
guardLocation := Position{0, 0}

// Find initial guard location
outer:
for r := range rows {
for c := range cols {
if string(lines[r][c]) == "^" {
if lines[r][c] == '^' {
guardLocation = Position{r, c}
break outer
}
}
}

return guardLocation
}

func getPath(lines []string, guard Position) map[Position]struct{} {
visitedLocations := make(map[Position]struct{})
rows := len(lines)
cols := len(lines[0])
dr := -1
dc := 0

for {
r, c := guardLocation.r, guardLocation.c
visitedLocations[guardLocation] = struct{}{}
r, c := guard.r, guard.c
visitedLocations[guard] = struct{}{}

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

// We always rotate to the right on obstacles
// (-1,0) becomes (0,1) becomes (1,0) becomes (0,-1)
if string(lines[r+dr][c+dc]) == "#" {
if lines[r+dr][c+dc] == '#' {
dc, dr = -dr, dc
} else {
guardLocation = Position{r: r + dr, c: c + dc}
guard = Position{r: r + dr, c: c + dc}
}
}

return len(visitedLocations)
return visitedLocations
}

func part2(name string) int {
return 0
func isLoop(grid [][]byte, r, c int) bool {
visitedLocations := make(map[PositionWithDirection]struct{})
dr := -1
dc := 0
rows := len(grid)
cols := len(grid[0])

for {
// Save with direction as well to find when we're looping
visitedLocations[PositionWithDirection{r, c, dr, dc}] = struct{}{}

// Check bounds
if r+dr < 0 || r+dr >= rows || c+dc < 0 || c+dc >= cols {
return false
}

// We always rotate to the right on obstacles
// (-1,0) becomes (0,1) becomes (1,0) becomes (0,-1)
if grid[r+dr][c+dc] == '#' {
dc, dr = -dr, dc
} else {
r += dr
c += dc
}

if _, ok := visitedLocations[PositionWithDirection{r, c, dr, dc}]; ok {
return true
}
}
}
2 changes: 1 addition & 1 deletion go/2024/puzzles/day06/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func TestPart1(t *testing.T) {

func TestPart2(t *testing.T) {
t.Run("Part 2", func(t *testing.T) {
expected := 0
expected := 6
actual := part2("test-input.txt")
assert.Equal(t, expected, actual)
})
Expand Down

0 comments on commit 4279473

Please sign in to comment.