/
Day03.kt
108 lines (91 loc) · 3.05 KB
/
Day03.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
data class SchematicNumber(
val y: Int,
val x: List<Int>,
val n: Int,
) {
fun occupies(x: Int, y: Int): Boolean {
return y == this.y && this.x.contains(x)
}
}
class Schematic(schematicLines: List<String>) {
var symbols = mutableMapOf<Pair<Int, Int>, Char>()
var numbers = mutableListOf<SchematicNumber>()
init {
schematicLines.forEachIndexed { y, line ->
var numberInProgress = ""
val numberCoordinates = mutableListOf<Int>()
fun resetNumber() {
if (numberInProgress.isNotEmpty()) {
numbers.add(SchematicNumber(y, numberCoordinates.toList(), numberInProgress.toInt()))
}
numberInProgress = ""
numberCoordinates.clear()
}
line.forEachIndexed { x, c ->
if (c == '.' || c.isWhitespace()) {
resetNumber()
} else if (c.isDigit()) {
numberInProgress += c
numberCoordinates.add(x)
} else {
symbols[Pair(x, y)] = c
resetNumber()
}
}
resetNumber()
}
}
fun isPartNumber(n: SchematicNumber): Boolean {
val symbolCoordinates = symbols.keys.toSet()
val y = n.y
n.x.forEach { x ->
val neighbors = neighborCoordinates(x, y)
if (neighbors.intersect(symbolCoordinates).isNotEmpty()) {
return true
}
}
return false
}
private fun neighborCoordinates(x: Int, y: Int) = setOf(
Pair(x - 1, y - 1),
Pair(x - 1, y),
Pair(x - 1, y + 1),
Pair(x, y - 1),
Pair(x, y + 1),
Pair(x + 1, y - 1),
Pair(x + 1, y),
Pair(x + 1, y + 1),
)
val gears: List<Int> get() {
val gears = mutableListOf<Int>()
val stars = symbols.filter { it.value == '*' }.map { it.key }
stars.forEach { star ->
val neighbors = mutableSetOf<SchematicNumber>()
neighborCoordinates(star.first, star.second).forEach { coordinate ->
neighbors += numbers.filter { it.occupies(coordinate.first, coordinate.second) }
}
if (neighbors.size == 2) {
gears.add(neighbors.first().n * neighbors.last().n)
}
}
return gears
}
}
class Day03: BasePuzzle<Schematic, Int, Int>() {
override fun getPuzzleInput(): Schematic {
return Schematic(readLines("day03.txt"))
}
override fun part1(input: Schematic): Int {
return input.numbers.filter { input.isPartNumber(it) }.sumOf { it.n }
}
override fun part2(input: Schematic): Int {
return input.gears.sum()
}
companion object {
@JvmStatic fun main(args: Array<String>) {
val dayClass = this::class.java.declaringClass.getDeclaredConstructor()
val day = dayClass.newInstance() as BasePuzzle<*, *, *>
day.main()
}
}
}