Skip to content

Commit 9eb53db

Browse files
committed
perf(2024): add grid/point helper and refactor day 12
1 parent 7a220ed commit 9eb53db

File tree

4 files changed

+95
-67
lines changed

4 files changed

+95
-67
lines changed

go/2024/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Using Go's built-in benchmarking with the [testing](https://pkg.go.dev/testing#h
4444
| 9 | 381476181 ns/op | 171042257 ns/op | |
4545
| 10 | 1424599 ns/op | 1789071 ns/op | |
4646
| 11 | 424021 ns/op | 15488584 ns/op | |
47-
| 12 | 10984420 ns/op | 16856988 ns/op | |
47+
| 12 | 6677348 ns/op | 12339733 ns/op | `39.21%` / `26.80%` |
4848

4949
\* compared to first solution
5050

@@ -59,6 +59,7 @@ Using Go's built-in benchmarking with the [testing](https://pkg.go.dev/testing#h
5959
| 5 | 1669175 ns/op | 17299190 ns/op | Baseline | [Link](https://github.com/believer/advent-of-code/blob/1db858ae3d391319511787d8935c76eecdf6b22f/go/2024/puzzles/day05/main.go) |
6060
| 7 | 126892714 ns/op | 10124683583 ns/op | Baseline | [Link](https://github.com/believer/advent-of-code/blob/dd735747021ce43ca3a7427c529813139737271e/go/2024/puzzles/day07/main.go) |
6161
| 7 | 110164692 ns/op | 7135839625 ns/op | `13.18%` / `29.52%` | [Link](https://github.com/believer/advent-of-code/blob/640d9604dfefa71f7bfef876750f378bd1a58a8b/go/2024/puzzles/day07/main.go) |
62+
| 12 | 10984420 ns/op | 16856988 ns/op | Baseline | [Link](https://github.com/believer/advent-of-code/blob/7a220ed0e6deae74d0a293615e6348e6ce1a9a22/go/2024/puzzles/day12/main.go) |
6263

6364
## Running
6465

go/2024/puzzles/day12/main.go

Lines changed: 35 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,27 @@ import (
44
"fmt"
55

66
"github.com/believer/aoc-2024/utils/files"
7+
"github.com/believer/aoc-2024/utils/grid"
78
)
89

910
// BFS to find plant regions and perimeters
1011
// For part 2 find corners of areas which show how many sides it has
12+
// Added a similar Grid/Point solution like I've used in my Rust solutions
13+
// in previous years. Made things faster (one dimensional array of bytes) and cleaner!
1114
func main() {
1215
fmt.Println("Part 1: ", part1("input.txt"))
1316
fmt.Println("Part 2: ", part2("input.txt"))
1417
}
1518

16-
type Location struct {
17-
r, c int
18-
}
19-
20-
var directions = [][]int{
21-
{-1, 0}, // Above
22-
{0, 1}, // Right
23-
{1, 0}, // Below
24-
{0, -1}, // Left
25-
}
26-
2719
func part1(name string) int {
28-
plants := files.ReadLines(name)
29-
grid := map[Location]byte{}
30-
visited := map[Location]bool{}
31-
32-
rows := len(plants)
33-
cols := len(plants[0])
20+
lines := files.ReadLines(name)
21+
plants := grid.New(lines)
22+
visited := map[grid.Point]bool{}
3423
price := 0
3524

36-
for r := range rows {
37-
for c := range cols {
38-
grid[Location{r, c}] = plants[r][c]
39-
}
40-
}
41-
42-
for r := range rows {
43-
for c := range cols {
44-
area, perimeter := findPlantBed(grid, visited, Location{r, c})
25+
for y := range plants.Height {
26+
for x := range plants.Width {
27+
area, perimeter := findPlantBed(plants, visited, grid.Point{X: x, Y: y})
4528
price += len(area) * perimeter
4629
}
4730
}
@@ -50,23 +33,14 @@ func part1(name string) int {
5033
}
5134

5235
func part2(name string) int {
53-
plants := files.ReadLines(name)
54-
grid := map[Location]byte{}
55-
visited := map[Location]bool{}
56-
57-
rows := len(plants)
58-
cols := len(plants[0])
36+
lines := files.ReadLines(name)
37+
plants := grid.New(lines)
38+
visited := map[grid.Point]bool{}
5939
price := 0
6040

61-
for r := range rows {
62-
for c := range cols {
63-
grid[Location{r, c}] = plants[r][c]
64-
}
65-
}
66-
67-
for r := range rows {
68-
for c := range cols {
69-
area, _ := findPlantBed(grid, visited, Location{r, c})
41+
for y := range plants.Height {
42+
for x := range plants.Width {
43+
area, _ := findPlantBed(plants, visited, grid.Point{X: x, Y: y})
7044
price += len(area) * findCorners(area)
7145
}
7246
}
@@ -75,32 +49,32 @@ func part2(name string) int {
7549
}
7650

7751
// The number of corners shows how many sides we have
78-
func findCorners(area map[Location]bool) int {
52+
func findCorners(area map[grid.Point]bool) int {
7953
corners := 0
8054

8155
cornerChecks := []struct {
82-
offsets []Location
56+
offsets []grid.Point
8357
requiredStates []bool
8458
}{
8559
// Outer corners
86-
{[]Location{{0, -1}, {-1, 0}}, []bool{false, false}}, // Top left
87-
{[]Location{{0, 1}, {-1, 0}}, []bool{false, false}}, // Top right
88-
{[]Location{{0, -1}, {1, 0}}, []bool{false, false}}, // Bottom left
89-
{[]Location{{0, 1}, {1, 0}}, []bool{false, false}}, // Bottom right
60+
{[]grid.Point{{Y: 0, X: -1}, {Y: -1, X: 0}}, []bool{false, false}}, // Top left
61+
{[]grid.Point{{Y: 0, X: 1}, {Y: -1, X: 0}}, []bool{false, false}}, // Top right
62+
{[]grid.Point{{Y: 0, X: -1}, {Y: 1, X: 0}}, []bool{false, false}}, // Bottom left
63+
{[]grid.Point{{Y: 0, X: 1}, {Y: 1, X: 0}}, []bool{false, false}}, // Bottom right
9064

9165
// Inner corners
92-
{[]Location{{-1, -1}, {-1, 0}, {0, -1}}, []bool{false, true, true}}, // Inside top left
93-
{[]Location{{-1, 1}, {-1, 0}, {0, 1}}, []bool{false, true, true}}, // Inside top right
94-
{[]Location{{1, -1}, {1, 0}, {0, -1}}, []bool{false, true, true}}, // Inside bottom left
95-
{[]Location{{1, 1}, {1, 0}, {0, 1}}, []bool{false, true, true}}, // Inside bottom right
66+
{[]grid.Point{{Y: -1, X: -1}, {Y: -1, X: 0}, {Y: 0, X: -1}}, []bool{false, true, true}}, // Inside top left
67+
{[]grid.Point{{Y: -1, X: 1}, {Y: -1, X: 0}, {Y: 0, X: 1}}, []bool{false, true, true}}, // Inside top right
68+
{[]grid.Point{{Y: 1, X: -1}, {Y: 1, X: 0}, {Y: 0, X: -1}}, []bool{false, true, true}}, // Inside bottom left
69+
{[]grid.Point{{Y: 1, X: 1}, {Y: 1, X: 0}, {Y: 0, X: 1}}, []bool{false, true, true}}, // Inside bottom right
9670
}
9771

9872
for a := range area {
9973
for _, check := range cornerChecks {
10074
match := true
10175

10276
for i, offset := range check.offsets {
103-
neighbor := Location{a.r + offset.r, a.c + offset.c}
77+
neighbor := a.Add(offset)
10478

10579
if _, ok := area[neighbor]; ok != check.requiredStates[i] {
10680
match = false
@@ -117,10 +91,10 @@ func findCorners(area map[Location]bool) int {
11791
return corners
11892
}
11993

120-
func findPlantBed(grid map[Location]byte, visited map[Location]bool, start Location) (map[Location]bool, int) {
121-
queue := []Location{start}
94+
func findPlantBed(g grid.Grid, visited map[grid.Point]bool, start grid.Point) (map[grid.Point]bool, int) {
95+
queue := []grid.Point{start}
96+
area := map[grid.Point]bool{}
12297
perimeter := 0
123-
area := map[Location]bool{}
12498

12599
for len(queue) > 0 {
126100
current := queue[0]
@@ -130,7 +104,7 @@ func findPlantBed(grid map[Location]byte, visited map[Location]bool, start Locat
130104
continue
131105
}
132106

133-
neighbors := getNeighbors(grid, current)
107+
neighbors := getNeighbors(g, current)
134108
perimeter += 4 - len(neighbors)
135109
area[current] = true
136110
visited[current] = true
@@ -143,13 +117,13 @@ func findPlantBed(grid map[Location]byte, visited map[Location]bool, start Locat
143117
return area, perimeter
144118
}
145119

146-
func getNeighbors(grid map[Location]byte, current Location) []Location {
147-
neighbors := []Location{}
120+
func getNeighbors(g grid.Grid, current grid.Point) []grid.Point {
121+
neighbors := []grid.Point{}
148122

149-
for _, d := range directions {
150-
next := Location{current.r + d[0], current.c + d[1]}
123+
for _, d := range grid.CARDINALS {
124+
next := current.Add(d)
151125

152-
if value, ok := grid[next]; ok && value == grid[current] {
126+
if value, ok := g.Contains(next); ok && value == g.Get(current) {
153127
neighbors = append(neighbors, next)
154128
}
155129
}

go/2024/utils/grid/grid.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package grid
2+
3+
/* Point
4+
/* ====================================================== */
5+
6+
type Point struct {
7+
X, Y int
8+
}
9+
10+
var UP = Point{0, -1}
11+
var DOWN = Point{0, 1}
12+
var RIGHT = Point{1, 0}
13+
var LEFT = Point{-1, 0}
14+
var CARDINALS = []Point{UP, DOWN, LEFT, RIGHT}
15+
16+
func (p *Point) Add(p2 Point) Point {
17+
return Point{p.X + p2.X, p.Y + p2.Y}
18+
}
19+
20+
/* Grid
21+
/* ====================================================== */
22+
23+
type Grid struct {
24+
Data []byte
25+
Height int
26+
Width int
27+
}
28+
29+
func New(lines []string) Grid {
30+
data := []byte{}
31+
height := len(lines)
32+
width := len(lines[0])
33+
34+
for r := range height {
35+
for c := range width {
36+
current := lines[r][c]
37+
data = append(data, current)
38+
}
39+
}
40+
41+
return Grid{
42+
Data: data,
43+
Height: height,
44+
Width: width,
45+
}
46+
}
47+
48+
func (g *Grid) Get(p Point) byte {
49+
return g.Data[g.Width*p.Y+p.X]
50+
}
51+
52+
func (g *Grid) Contains(p Point) (byte, bool) {
53+
if p.X >= 0 && p.X < g.Width && p.Y >= 0 && p.Y < g.Height {
54+
return g.Get(p), true
55+
}
56+
57+
return 0, false
58+
}

go/2024/utils/utils.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@ package utils
22

33
import "strconv"
44

5-
type Point struct {
6-
x int
7-
y int
8-
}
9-
105
// Ints
116
// -----------------------------------------------------------
127

0 commit comments

Comments
 (0)