146 lines
3.3 KiB
Go
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, ®ion, 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, ®ion, 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
|
|
} |