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): Int { val grid = CharGrid(input) var sum = 0 for (p in grid.generateGridPos()) { val c = grid[p] if (c != '.') { val areaPos = HashSet() val fence = HashSet() var newPos = setOf(p) while (newPos.isNotEmpty()) { val newSeeds = HashSet() 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): 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() var newPos = setOf(p) while (newPos.isNotEmpty()) { val newSeeds = HashSet() 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() }