generated from kotlin-hands-on/advent-of-code-kotlin-template
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9d55b16
commit 1582c56
Showing
2 changed files
with
149 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package aoc.year2024 | ||
|
||
import aoc.library.Direction | ||
import aoc.library.Point | ||
import aoc.library.Puzzle | ||
import aoc.library.move | ||
|
||
object Day12 : Puzzle<Int, Int>(12) { | ||
|
||
override fun solvePart2(input: String): Int = solve(input, ::perimeterV2) | ||
|
||
override fun solvePart1(input: String): Int = solve(input, ::perimeterV1) | ||
|
||
private fun solve( | ||
input: String, | ||
perimeter: (Set<Point>) -> Int, | ||
): Int { | ||
val garden = parse(input) | ||
return clusterByRegions(garden).sumOf { | ||
val pointsInRegion = it.points | ||
perimeter(pointsInRegion) * pointsInRegion.size | ||
} | ||
} | ||
|
||
private fun clusterByRegions(garden: Map<Point, Char>): List<Region> { | ||
val regions = mutableListOf<Region>() | ||
val visited = mutableSetOf<Point>() | ||
garden.keys.forEach { start -> | ||
if (start !in visited) { | ||
val groupChar = garden.getValue(start) | ||
val group = mutableSetOf<Point>() | ||
fun visit(point: Point) { | ||
if (!group.add(point)) return | ||
point.adjacentOrthogonal() | ||
.forEach { adjacent -> | ||
val char = garden[adjacent] | ||
if (char == groupChar) { | ||
visit(adjacent) | ||
} | ||
} | ||
} | ||
visit(start) | ||
regions += Region(groupChar, group) | ||
visited.addAll(group) | ||
} | ||
} | ||
return regions | ||
} | ||
|
||
private fun parse(input: String): Map<Point, Char> = input.lines().flatMapIndexed { y, line -> | ||
line.mapIndexed { x, char -> | ||
Point(x, y) to char | ||
} | ||
}.toMap() | ||
|
||
private fun perimeterV1(points: Set<Point>): Int = points.sumOf { point -> | ||
point.adjacentOrthogonal().count { it !in points } | ||
} | ||
|
||
private fun perimeterV2(points: Set<Point>): Int { | ||
fun Point.hasFence(direction: Direction): Boolean = this in points && move(direction) !in points | ||
return points.sumOf { point -> | ||
Direction.entries.count { direction -> | ||
point.hasFence(direction) && !point.move(direction.clockwise()).hasFence(direction) | ||
} | ||
} | ||
} | ||
|
||
private data class Region(val char: Char, val points: Set<Point>) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package aoc.year2024 | ||
|
||
import aoc.library.solvePart1 | ||
import aoc.library.solvePart2 | ||
import io.kotest.matchers.ints.shouldBeExactly | ||
import org.junit.jupiter.api.Test | ||
|
||
class Day12Test { | ||
|
||
@Test | ||
fun part1TestInput() { | ||
Day12.solvePart1( | ||
""" | ||
AAAA | ||
BBCD | ||
BBCC | ||
EEEC | ||
""".trimIndent(), | ||
) shouldBeExactly 140 | ||
} | ||
|
||
@Test | ||
fun part1TestInput2() { | ||
Day12.solvePart1( | ||
""" | ||
RRRRIICCFF | ||
RRRRIICCCF | ||
VVRRRCCFFF | ||
VVRCCCJFFF | ||
VVVVCJJCFE | ||
VVIVCCJJEE | ||
VVIIICJJEE | ||
MIIIIIJJEE | ||
MIIISIJEEE | ||
MMMISSJEEE | ||
""".trimIndent(), | ||
) shouldBeExactly 1930 | ||
} | ||
|
||
@Test | ||
fun part1() { | ||
Day12.solvePart1() shouldBeExactly 1434856 | ||
} | ||
|
||
@Test | ||
fun part2TestInput() { | ||
Day12.solvePart2( | ||
""" | ||
AAAA | ||
BBCD | ||
BBCC | ||
EEEC | ||
""".trimIndent(), | ||
) shouldBeExactly 80 | ||
} | ||
|
||
@Test | ||
fun part2TestInput2() { | ||
Day12.solvePart2( | ||
""" | ||
RRRRIICCFF | ||
RRRRIICCCF | ||
VVRRRCCFFF | ||
VVRCCCJFFF | ||
VVVVCJJCFE | ||
VVIVCCJJEE | ||
VVIIICJJEE | ||
MIIIIIJJEE | ||
MIIISIJEEE | ||
MMMISSJEEE | ||
""".trimIndent(), | ||
) shouldBeExactly 1206 | ||
} | ||
|
||
@Test | ||
fun part2() { | ||
Day12.solvePart2() shouldBeExactly 891106 | ||
} | ||
} |