-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day5.kt
116 lines (104 loc) · 4.02 KB
/
Day5.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
109
110
111
112
113
114
115
116
package aoc2023.day05
fun parse(lines: List<String>): Input {
val mappings = mutableMapOf<MapType, List<Range>>()
val seeds = mutableListOf<Long>()
for (line in lines) {
if (line.isEmpty()) {
continue
}
if (line.startsWith("seeds:")) {
seeds.addAll(line
.replace("seeds: ", "")
.split(" ")
.map { it.toLong() })
continue
}
val split = line.split(": ")
val numberGroups = split[1].split(" | ")
val ranges = numberGroups.map {
val group = it.split(" ").map { str -> str.toLong() }
Range(group[0], group[1], group[2])
}
when {
split[0].startsWith("seed-to-soil") -> {
mappings[MapType.SEED_TO_SOIL] = ranges
}
split[0].startsWith("soil-to-fertilizer") -> {
mappings[MapType.SOIL_TO_FERTILIZER] = ranges
}
split[0].startsWith("fertilizer-to-water") -> {
mappings[MapType.FERTILIZER_TO_WATER] = ranges
}
split[0].startsWith("water-to-light") -> {
mappings[MapType.WATER_TO_LIGHT] = ranges
}
split[0].startsWith("light-to-temperature") -> {
mappings[MapType.LIGHT_TO_TEMPERATURE] = ranges
}
split[0].startsWith("temperature-to-humidity") -> {
mappings[MapType.TEMPERATURE_TO_HUMIDITY] = ranges
}
split[0].startsWith("humidity-to-location") -> {
mappings[MapType.HUMIDITY_TO_LOCATION] = ranges
}
}
}
return Input(seeds, mappings)
}
fun part1(input: Input): Long {
val seedToLocation = mutableMapOf<Long, Long>()
input.seeds.forEach { seed ->
val location = mapSeedToLocation(seed, input)
seedToLocation[seed] = location
}
return seedToLocation.minOf { it.value }
}
fun part2(input: Input): Long {
var lowestLocation = Long.MAX_VALUE
val seeds = input.seeds.toList()
(seeds.indices step 2).forEach {i ->
(seeds[i] until seeds[i] + seeds[i + 1]).forEach { seed ->
val location = mapSeedToLocation(seed, input)
if (location < lowestLocation) {
lowestLocation = location
}
}
}
return lowestLocation
}
private fun mapSeedToLocation(seed: Long, input: Input): Long {
val soil = findMapping(seed, input.mappings[MapType.SEED_TO_SOIL]!!)
val fertilizer = findMapping(soil, input.mappings[MapType.SOIL_TO_FERTILIZER]!!)
val water = findMapping(fertilizer, input.mappings[MapType.FERTILIZER_TO_WATER]!!)
val light = findMapping(water, input.mappings[MapType.WATER_TO_LIGHT]!!)
val temperature = findMapping(light, input.mappings[MapType.LIGHT_TO_TEMPERATURE]!!)
val humidity = findMapping(temperature, input.mappings[MapType.TEMPERATURE_TO_HUMIDITY]!!)
val location = findMapping(humidity, input.mappings[MapType.HUMIDITY_TO_LOCATION]!!)
return location
}
fun findMapping(input: Long, ranges: List<Range>): Long {
for (range in ranges) {
if (range.sourceRangeStart <= input && input < range.sourceRangeStart + range.rangeLength) {
val step = input - range.sourceRangeStart
return range.destRangeStart + step
} else {
continue
}
}
return input
}
data class Range(val destRangeStart: Long, val sourceRangeStart: Long, val rangeLength: Long)
data class Input(val seeds: List<Long>, val mappings: Map<MapType, List<Range>>)
enum class MapType(val key: String) {
SEED_TO_SOIL("seed-to-soil"),
SOIL_TO_FERTILIZER("soil-to-fertilizer"),
FERTILIZER_TO_WATER("fertilizer-to-water"),
WATER_TO_LIGHT("water-to-light"),
LIGHT_TO_TEMPERATURE("light-to-temperature"),
TEMPERATURE_TO_HUMIDITY("temperature-to-humidity"),
HUMIDITY_TO_LOCATION("humidity-to-location");
companion object {
fun byKey(key: String): MapType? =
values().firstOrNull { key == it.key }
}
}