-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day05.kt
66 lines (54 loc) · 2.23 KB
/
Day05.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
package io.dmitrijs.aoc2023
import kotlin.math.max
import kotlin.math.min
class Day05(input: String) {
private val seeds = input
.substringBefore("\n\n")
.substringAfter(": ")
.split(" ")
.map(String::toLong)
private val rangesMap = hashMapOf<String, Pair<String, List<MappingRange>>>().apply {
input.split("\n\n").drop(1).forEach { block ->
val lines = block.trimEnd().split("\n")
val (source, _, target) = lines.first().substringBefore(" ").split("-")
val ranges = lines.drop(1).map { MappingRange.of(it) }.sortedBy { it.first }
this[source] = target to ranges
}
}
fun puzzle1() = seeds.minOf { n ->
mapRange(n..n).minOf { it.first }
}
fun puzzle2() = seeds.chunked(2).minOf { (n, l) ->
mapRange(n..<n + l).minOf { it.first }
}
private fun mapRange(input: LongRange, phase: String = "seed"): List<LongRange> {
if (phase == "location") return listOf(input)
val (target, mappings) = rangesMap.getValue(phase)
val overallMin = mappings.first().first
val overallMax = mappings.last().last
return mappings
.mapNotNull { mappingRange -> mappingRange.remap(input) }
.toMutableList()
.apply {
if (input.first < overallMin) add(input.first..min(overallMin - 1, input.last))
if (input.last > overallMax) add(max(overallMax + 1, input.first)..input.last)
if (isEmpty()) add(input) // Do I have broken input?
}
.flatMap { range -> mapRange(range, target) }
}
private data class MappingRange(private val range: LongRange, private val delta: Long) {
val first get() = range.first
val last get() = range.last
fun remap(other: LongRange): LongRange? {
val min = max(first, other.first) + delta
val max = min(last, other.last) + delta
return if (min <= max) min..max else null
}
companion object {
fun of(line: String) = line
.split(" ")
.map(String::toLong)
.let { (to, from, len) -> MappingRange(from..<from + len, to - from) }
}
}
}