99 lines
3.2 KiB
Kotlin
99 lines
3.2 KiB
Kotlin
package aoc2024
|
|
|
|
import CharGrid
|
|
import RelPos
|
|
import println
|
|
import readInput
|
|
|
|
/*
|
|
--- Day 12: Garden Groups ---
|
|
https://adventofcode.com/2024/day/12
|
|
*/
|
|
fun main() {
|
|
|
|
val inlineTestInput = """
|
|
RRRRIICCFF
|
|
RRRRIICCCF
|
|
VVRRRCCFFF
|
|
VVRCCCJFFF
|
|
VVVVCJJCFE
|
|
VVIVCCJJEE
|
|
VVIIICJJEE
|
|
MIIIIIJJEE
|
|
MIIISIJEEE
|
|
MMMISSJEEE
|
|
"""
|
|
|
|
fun part1(input: List<String>): Int {
|
|
val grid = CharGrid(input)
|
|
var sum = 0
|
|
for (p in grid.generateGridPos()) {
|
|
val c = grid[p]
|
|
if (c != '.') {
|
|
val areaPos = HashSet<RelPos>()
|
|
val fence = HashSet<RelPos>()
|
|
var newPos = setOf(p)
|
|
while (newPos.isNotEmpty()) {
|
|
val newSeeds = HashSet<RelPos>()
|
|
for (np in newPos) {
|
|
areaPos.add(np)
|
|
grid[np] = c.lowercaseChar()
|
|
newSeeds.addAll(grid.matchAbsoluteRelPos(np, CharGrid.PLUS_POS) { it == c })
|
|
fence.addAll(grid.matchRelative(np.dc, np.dr, CharGrid.PLUS_POS) { it.uppercaseChar() != c }
|
|
.map { RelPos(np.dc * 2 + it.dc, np.dr * 2 + it.dr) })
|
|
}
|
|
newPos = newSeeds
|
|
}
|
|
areaPos.forEach { grid[it] = '.' }
|
|
sum += areaPos.size * fence.size
|
|
}
|
|
}
|
|
return sum
|
|
}
|
|
|
|
fun part2(input: List<String>): Int {
|
|
val grid = CharGrid(input)
|
|
var sum = 0
|
|
val magic = listOf(3, 5, 10, 12)
|
|
val star = CharGrid.PLUS_POS.plus(CharGrid.CROSS_POS)
|
|
for (p in grid.generateGridPos()) {
|
|
val c = grid[p]
|
|
if (c != '.') {
|
|
val areaPos = HashSet<RelPos>()
|
|
var newPos = setOf(p)
|
|
while (newPos.isNotEmpty()) {
|
|
val newSeeds = HashSet<RelPos>()
|
|
for (np in newPos) {
|
|
areaPos.add(np)
|
|
grid[np] = '.'
|
|
newSeeds.addAll(grid.matchAbsoluteRelPos(np, CharGrid.PLUS_POS) { it == c })
|
|
}
|
|
newPos = newSeeds
|
|
}
|
|
val corners = areaPos.sumOf {
|
|
val b = star.mapIndexed { i, rp -> if (areaPos.contains(it.translate(rp))) 1 shl i else 0 }.sum()
|
|
val outer = magic.count { b and it == 0 }
|
|
val inner = magic.filterIndexed { i, m -> (b and m == m) && (b and (16 shl i) == 0) }.count()
|
|
outer + inner
|
|
}
|
|
sum += areaPos.size * corners
|
|
}
|
|
}
|
|
return sum
|
|
}
|
|
|
|
// test if implementation meets criteria from the description, like:
|
|
val testInput = inlineTestInput.trim().reader().readLines()
|
|
//val testInput = readInput("aoc2024/Day12_test")
|
|
val testInputPart1Result = part1(testInput)
|
|
println("Part 1 Test: $testInputPart1Result")
|
|
val testInputPart2Result = part2(testInput)
|
|
println("Part 2 Test: $testInputPart2Result")
|
|
check(testInputPart1Result == 1930)
|
|
check(testInputPart2Result == 1206)
|
|
|
|
val input = readInput("aoc2024/Day12")
|
|
part1(input).println()
|
|
part2(input).println()
|
|
}
|