-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay12GardenGroups.kt
83 lines (66 loc) · 2.92 KB
/
Day12GardenGroups.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package adventofcode.year2024
import adventofcode.Puzzle
import adventofcode.PuzzleInput
import adventofcode.common.spatial.Grid2d
import adventofcode.common.spatial.Point2d
import adventofcode.common.spatial.Point2d.Companion.EAST
import adventofcode.common.spatial.Point2d.Companion.NORTH
import adventofcode.common.spatial.Point2d.Companion.SOUTH
import adventofcode.common.spatial.Point2d.Companion.WEST
class Day12GardenGroups(customInput: PuzzleInput? = null) : Puzzle(customInput) {
private val garden by lazy { Grid2d(input) }
private val regions by lazy { garden.mapRegions() }
override fun partOne() = regions.sumOf { region -> region.area * region.perimeter }
override fun partTwo() = regions.sumOf { region -> region.area * region.sides(garden) }
companion object {
private data class Region(
val type: Char,
val plots: Set<Point2d>,
) {
val area = plots.size
val perimeter =
plots.sumOf { plot ->
setOf(NORTH, EAST, SOUTH, WEST)
.map { direction -> plot + direction }
.filterNot { side -> side in plots }
.size
}
fun sides(garden: Grid2d<Char>): Int =
plots.sumOf { plot ->
setOf(NORTH to EAST, EAST to SOUTH, SOUTH to WEST, WEST to NORTH)
.map { (first, second) ->
listOf(plot, plot + first, plot + second, plot + first + second)
.map { a -> garden.getOrNull(a) }
}
.count { (plot, sideA, sideB, corner) ->
(plot != sideA && plot != sideB) || (plot == sideA && plot == sideB && plot != corner)
}
}
}
private fun Grid2d<Char>.mapRegions(): Set<Region> {
val regions = mutableSetOf<Region>()
val queue = ArrayDeque(points)
while (queue.isNotEmpty()) {
val current = queue.removeFirst()
val plots = getConnectedPlots(current)
queue.removeAll(plots)
regions.add(Region(this[current], plots))
}
return regions
}
private fun Grid2d<Char>.getConnectedPlots(plot: Point2d): Set<Point2d> {
val region = mutableSetOf<Point2d>()
val queue = ArrayDeque(setOf(plot))
while (queue.isNotEmpty()) {
val current = queue.removeFirst()
val neighbors =
neighborsOf(current)
.filter { neighbor -> this[plot] == this[neighbor] }
.filterNot { neighbor -> neighbor in region }
region.addAll(setOf(current) + neighbors)
queue.addAll(neighbors)
}
return region
}
}
}