diff options
-rw-r--r-- | src/Day05.kt | 120 |
1 files changed, 35 insertions, 85 deletions
diff --git a/src/Day05.kt b/src/Day05.kt index fece98e..7c93896 100644 --- a/src/Day05.kt +++ b/src/Day05.kt @@ -1,105 +1,55 @@ import kotlin.math.absoluteValue +import kotlin.math.max import kotlin.math.sign -class Line(val start: Pair<Int, Int>, val end: Pair<Int, Int>) { +data class Pos(val x: Int, val y: Int) + +data class Line(val start: Pos, val end: Pos) { companion object { fun fromString(input: String): Line { - val parts = input.split(" -> ").map { part -> - val coordinates = part.split(",").map { it.toInt() } - coordinates[0] to coordinates[1] + val (start, end) = input.split(" -> ").map { coordinateString -> + val (x, y) = coordinateString.split(",").map { it.toInt() } + Pos(x, y) } - return Line(parts[0], parts[1]) + return Line(start, end) } } -} - -fun main() { - fun part1(input: List<String>): Int { - val lines = input.map(Line::fromString) - val positions = mutableMapOf<Pair<Int, Int>, Int>() - lines.forEach { - when { - it.start.first == it.end.first -> { - if (it.start.second <= it.end.second) { - for (y in it.start.second..it.end.second) { - positions[it.start.first to y] = 1 + positions.getOrDefault(it.start.first to y, 0) - } - } else { - for (y in it.end.second..it.start.second) { - positions[it.start.first to y] = 1 + positions.getOrDefault(it.start.first to y, 0) - } - } - } - it.start.second == it.end.second -> { - if (it.start.first<= it.end.first) { - for (x in it.start.first..it.end.first) { - positions[x to it.start.second] = 1 + positions.getOrDefault(x to it.start.second, 0) - } - } else { - for (x in it.end.first..it.start.first) { - positions[x to it.start.second] = 1 + positions.getOrDefault(x to it.start.second, 0) - } - } - } + val isHorizontalOrVertical: Boolean + get() = start.x == end.x || start.y == end.y - } - } - - return positions.values.count { it >= 2 } - } + val isDiagonal: Boolean + get() = (end.x - start.x).absoluteValue == (end.y - start.y).absoluteValue + val pointSequence: Sequence<Pos> + get() = sequence { + val xOffset = end.x - start.x + val yOffset = end.y - start.y - fun part2(input: List<String>): Int { - val lines = input.map(Line::fromString) + for (s in 0..max(xOffset.absoluteValue, yOffset.absoluteValue)) { + val x = start.x + s * xOffset.sign + val y = start.y + s * yOffset.sign - val positions = mutableMapOf<Pair<Int, Int>, Int>() - lines.forEach { - when { - it.start.first == it.end.first -> { - if (it.start.second <= it.end.second) { - for (y in it.start.second..it.end.second) { - positions[it.start.first to y] = 1 + positions.getOrDefault(it.start.first to y, 0) - } - } else { - for (y in it.end.second..it.start.second) { - positions[it.start.first to y] = 1 + positions.getOrDefault(it.start.first to y, 0) - } - } - } - it.start.second == it.end.second -> { - if (it.start.first<= it.end.first) { - for (x in it.start.first..it.end.first) { - positions[x to it.start.second] = 1 + positions.getOrDefault(x to it.start.second, 0) - } - } else { - for (x in it.end.first..it.start.first) { - positions[x to it.start.second] = 1 + positions.getOrDefault(x to it.start.second, 0) - } - } - } - (it.end.first - it.start.first).absoluteValue == (it.end.second - it.start.second).absoluteValue -> { - val xOffset = it.end.first - it.start.first - val yOffset = it.end.second - it.start.second - - val xSign = xOffset.sign - val ySign = yOffset.sign - - val length = xOffset.absoluteValue - - for (i in 0..length) { - val x = it.start.first + xSign * i - val y = it.start.second + ySign * i - positions[x to y] = 1 + positions.getOrDefault(x to y, 0) - } - - } + yield(Pos(x, y)) } } +} - return positions.values.count { it >= 2 } - } +fun main() { + fun helper(input: List<String>, linePredicate: (line: Line) -> Boolean) = input + .asSequence() + .map(Line::fromString) + .filter(linePredicate) + .flatMap(Line::pointSequence) + .groupingBy { it } + .eachCount() + .values + .count { it >= 2 } + + fun part1(input: List<String>): Int = helper(input, Line::isHorizontalOrVertical) + + fun part2(input: List<String>): Int = helper(input) { it.isHorizontalOrVertical || it.isDiagonal } val testInput = readInputAsLines("Day05_test") check(part1(testInput) == 5) |