Files
adventofcode/2024/go/day12/day12.go
2025-01-13 23:48:55 +00:00

146 lines
3.3 KiB
Go

package day12
import (
"adventofcode2024/utils/grid2d"
"adventofcode2024/utils/inputs"
"fmt"
)
type Plot struct {
crop string
visited bool
region int
x int
y int
}
type Region struct {
plots []Plot
crop string
id int
area int
perimteter int
sides int
}
func Part1(input string) int {
var val int
region_id := 0
regions := make(map[int]Region)
grid := inputs.ToGrid2D(input, "\n", "", Plot{}, func(c string) Plot { return Plot{crop: c, region: -1} })
fmt.Println(grid.StringWithFormatter(formatter))
for y := 0; y < grid.SizeY(); y++ {
for x := 0; x < grid.SizeX(); x++ {
var region Region
plot := grid.Get(x, y)
if plot.visited {
continue
}
region_id++
region = Region{id: region_id, area: 1, crop: plot.crop, sides: 4}
plot.region = region_id
plot.visited = true
plot.x = x
plot.y = y
grid.Set(x, y, plot)
region.plots = append(region.plots, plot)
regions[region_id] = region
try_neighours(grid, &region, x, y)
regions[region.id] = region
}
}
for _, region := range regions {
val += region.area * region.perimteter
}
return val
}
func Part2(input string) int {
var val int
region_id := 0
regions := make(map[int]Region)
grid := inputs.ToGrid2D(input, "\n", "", Plot{}, func(c string) Plot { return Plot{crop: c, region: -1} })
fmt.Println(grid.StringWithFormatter(formatter))
for y := 0; y < grid.SizeY(); y++ {
for x := 0; x < grid.SizeX(); x++ {
var region Region
plot := grid.Get(x, y)
if plot.visited {
continue
}
region_id++
region = Region{id: region_id, area: 1, crop: plot.crop}
plot.region = region_id
plot.visited = true
plot.x = x
plot.y = y
grid.Set(x, y, plot)
region.plots = append(region.plots, plot)
regions[region_id] = region
try_neighours(grid, &region, x, y)
regions[region.id] = region
}
}
for _, region := range regions {
val += region.area * get_sides(grid, region)
}
return val
}
func formatter(p Plot, x int, y int) string {
return fmt.Sprintf("%v", p.crop)
}
func try_neighours(grid *grid2d.Grid[Plot], region *Region, x int, y int) {
directions := [][]int{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}
plot := grid.Get(x, y)
perimeters := 0
for _, dir := range directions {
x1 := x + dir[0]
y1 := y + dir[1]
nplot := grid.Get(x1, y1)
if nplot.crop == plot.crop {
if !nplot.visited {
region.area++
nplot.visited = true
nplot.region = plot.region
nplot.x = x1
nplot.y = y1
grid.Set(x1, y1, nplot)
region.plots = append(region.plots, nplot)
try_neighours(grid, region, x1, y1)
}
} else {
perimeters++
}
}
}
func get_sides(grid *grid2d.Grid[Plot], region Region) int {
sides := 0
corners := [][][]int{{{-1, 0}, {0, -1}, {-1, -1}},
{{+1, 0}, {0, -1}, {+1, -1}},
{{-1, 0}, {0, +1}, {-1, +1}},
{{+1, 0}, {0, +1}, {+1, +1}}}
for _, plot := range region.plots {
for _, o_corners := range corners {
c1 := grid.Get(plot.x + o_corners[0][0], plot.y + o_corners[0][1])
c2 := grid.Get(plot.x + o_corners[1][0], plot.y + o_corners[1][1])
c3 := grid.Get(plot.x + o_corners[2][0], plot.y + o_corners[2][1])
if c1.crop != region.crop && c2.crop != region.crop {
sides++
} else if c1.crop == region.crop && c2.crop == region.crop && c3.crop != region.crop {
sides++
}
}
}
return sides
}