-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay03GearRatios.kt
68 lines (58 loc) · 2.43 KB
/
Day03GearRatios.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
package adventofcode.year2023
import adventofcode.Puzzle
import adventofcode.PuzzleInput
import adventofcode.common.neighbors
import adventofcode.common.product
class Day03GearRatios(customInput: PuzzleInput? = null) : Puzzle(customInput) {
override fun partOne() =
input
.parsePartNumbers()
.filter { partNumber -> partNumber.isValidPartNumber(input.parseGrid()) }
.sumOf(PartNumber::value)
override fun partTwo() =
input
.parsePartNumbers()
.asSequence()
.map { partNumber -> partNumber.getAdjacentGears(input.parseGrid()) to partNumber.value }
.filter { (gears, _) -> gears.isNotEmpty() }
.groupBy { (gears, _) -> gears }
.map { (_, adjacentParts) -> adjacentParts.map { (_, adjacentPartNumber) -> adjacentPartNumber } }
.filter { adjacentPartNumbers -> adjacentPartNumbers.size == 2 }
.sumOf(List<Int>::product)
companion object {
private val PART_NUMBER_REGEX = """(\d+)""".toRegex()
private data class PartNumber(
val value: Int,
val location: Pair<IntRange, Int>,
) {
fun isValidPartNumber(grid: List<List<Char>>) =
neighbors(grid)
.map { (x, y) -> grid[y][x] }
.filterNot { value -> value == '.' }
.isNotEmpty()
fun getAdjacentGears(grid: List<List<Char>>) =
neighbors(grid)
.filter { (x, y) -> grid[y][x] == '*' }
.toSet()
private fun neighbors(grid: List<List<Char>>): Set<Pair<Int, Int>> {
val coordinates =
location
.first
.map { x -> x to location.second }
.toSet()
return coordinates
.flatMap { (x, y) -> grid.neighbors(x, y, includeDiagonals = true) }
.toSet()
.minus(coordinates)
}
}
private fun String.parseGrid(): List<List<Char>> = lines().map(String::toList)
private fun String.parsePartNumbers(): List<PartNumber> =
lines()
.flatMapIndexed { y, line ->
PART_NUMBER_REGEX
.findAll(line)
.map { PartNumber(it.value.toInt(), it.range to y) }
}
}
}