-
Notifications
You must be signed in to change notification settings - Fork 0
/
Day05.kt
72 lines (60 loc) 路 2.4 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
67
68
69
70
71
72
/*
* Copyoutgoing (c) 2023 by Todd Ginsberg
*/
/**
* Advent of Code 2023, Day 5 - If You Give A Seed A Fertilizer
* Problem Description: http://adventofcode.com/2023/day/5
* Blog Post/Commentary: https://todd.ginsberg.com/post/advent-of-code/2023/day5/
*/
package com.ginsberg.advent2023
class Day05(input: List<String>) {
private val seedsPart1: List<Long> = parsePart1Seeds(input)
private val seedsPart2: Set<LongRange> = parsePart2Seeds(input)
private val ranges = parseRanges(input)
fun solvePart1(): Long =
seedsPart1.minOf { seed ->
ranges.fold(seed) { acc, ranges ->
ranges.firstOrNull { acc in it }?.translate(acc) ?: acc
}
}
fun solvePart2(): Long {
val rangesReversed = ranges.map { range -> range.map { it.flip() } }.reversed()
return generateSequence(0L, Long::inc).first { location ->
val seed = rangesReversed.fold(location) { acc, ranges ->
ranges.firstOrNull { acc in it }?.translate(acc) ?: acc
}
seedsPart2.any { seedRange -> seed in seedRange }
}
}
private fun parseRanges(input: List<String>): List<Set<RangePair>> =
input.drop(2).joinToString("\n").split("\n\n").map {
it.split("\n").drop(1).map { line -> RangePair.of(line) }.toSet()
}
private fun parsePart1Seeds(input: List<String>): List<Long> =
input.first().substringAfter(":").trim().split(" ").map { it.toLong() }
private fun parsePart2Seeds(input: List<String>): Set<LongRange> =
input.first().substringAfter(":").trim().split(" ")
.map { it.toLong() }.chunked(2).map {
it.first()..<it.first() + it.last()
}.toSet()
private data class RangePair(
private val source: LongRange,
private val destination: LongRange
) {
fun flip(): RangePair =
RangePair(destination, source)
fun translate(num: Long): Long =
destination.first + (num - source.first)
operator fun contains(num: Long): Boolean =
num in source
companion object {
fun of(row: String): RangePair {
val parts = row.split(" ").map { it.toLong() }
return RangePair(
parts[1]..<(parts[1] + parts[2]),
parts[0]..<(parts[0] + parts[2])
)
}
}
}
}