-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day03.kt
92 lines (79 loc) · 3.07 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
package aoc.years.year2023
import aoc.Day
@Year2023
class Day03 : Day() {
override fun solvePart1(input: List<String>): Any {
return Engine(input)
.getPartNumbers()
.sum()
}
override fun solvePart2(input: List<String>): Any {
return Engine(input)
.getTotalGearRatio()
}
}
class Engine(private val schematic: List<String>) {
fun getPartNumbers(): List<Int> {
return schematic.mapIndexed { x, line ->
val partNumbers = mutableListOf<Int>()
var currentPartNumber = ""
var isCurrentPartEnginePart = false
for ((y, char) in line.withIndex()) {
if (char.isDigit()) {
currentPartNumber += char
if (adjacentPositions(x, y).any { this.schematic[it.first][it.second].isSymbol() }) {
isCurrentPartEnginePart = true
}
} else {
if (isCurrentPartEnginePart) {
partNumbers.add(currentPartNumber.toInt())
}
currentPartNumber = ""
isCurrentPartEnginePart = false
}
}
if (isCurrentPartEnginePart) {
partNumbers.add(currentPartNumber.toInt())
}
return@mapIndexed partNumbers
}.flatten()
}
fun getTotalGearRatio(): Int {
return schematic.mapIndexed { x, line ->
line.mapIndexed { y, char -> if (char == '*') getGearRatio(x, y) else 0 }.sum()
}.sum()
}
private fun Char.isSymbol(): Boolean {
return !this.isDigit() && this != '.'
}
private fun getGearRatio(x: Int, y: Int): Int {
val adjacentParts = adjacentPositions(x, y)
.map { getPartNumber(it.first, it.second) }
.filter { it != -1 }
.distinct()
return if (adjacentParts.size == 2) adjacentParts[0] * adjacentParts[1] else 0
}
private fun getPartNumber(x: Int, y: Int): Int {
if (this.schematic[x][y].isDigit()) {
val leftPart = ((y - 1) downTo 0)
.takeWhile { this.schematic[x][it].isDigit() }
.map { this.schematic[x][it] }
.reversed()
.fold("") { leftPart, char -> leftPart.plus(char) }
val rightPart = ((y + 1)..(this.schematic.first().length - 1))
.takeWhile { this.schematic[x][it].isDigit() }
.map { this.schematic[x][it] }
.fold("") { rightPart, char -> rightPart.plus(char) }
return (leftPart + this.schematic[x][y] + rightPart).toInt()
} else {
return -1
}
}
private fun adjacentPositions(x: Int, y: Int): List<Pair<Int, Int>> {
return listOf(
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),
).filter { it.first in this.schematic.indices && it.second in this.schematic.first().indices }
}
}