day5: Fix integer overflow bug

This commit is contained in:
Tristan Daniël Maat 2023-12-06 05:01:15 +01:00
parent 713bc2b47d
commit 13454b3f18
Signed by: tlater
GPG key ID: 49670FD774E43268

View file

@ -1,6 +1,6 @@
import java.io.File import java.io.File
typealias Map = Pair<UIntRange, UIntRange> typealias Map = Pair<LongRange, LongRange>
fun main() { fun main() {
val input = File("input") val input = File("input")
@ -13,11 +13,11 @@ fun main() {
println(part2(seedRanges, maps)) println(part2(seedRanges, maps))
} }
fun part1(seeds: List<UInt>, maps: List<List<Map>>): UInt { fun part1(seeds: List<Long>, maps: List<List<Map>>): Long {
return seeds.map { seed -> maps.fold(seed) { toFind, map -> findMapping(toFind, map) } }.min() return seeds.map { seed -> maps.fold(seed) { toFind, map -> findMapping(toFind, map) } }.min()
} }
fun findMapping(toFind: UInt, maps: List<Map>): UInt { fun findMapping(toFind: Long, maps: List<Map>): Long {
for (map in maps) { for (map in maps) {
if (toFind >= map.first.first && toFind <= map.first.last) { if (toFind >= map.first.first && toFind <= map.first.last) {
val index = toFind - map.first.first val index = toFind - map.first.first
@ -34,50 +34,24 @@ fun findMapping(toFind: UInt, maps: List<Map>): UInt {
return toFind return toFind
} }
fun part2(seedRanges: List<UIntRange>, maps: List<List<Map>>): UInt { fun part2(seedRanges: List<LongRange>, maps: List<List<Map>>): Long {
return seedRanges return seedRanges
.map { range -> .map { range ->
maps maps
.fold(listOf(range)) { toReduce, map -> findReduction(toReduce, map) } .fold(listOf(range)) { toReduce, map -> findReduction(toReduce, map) }
.filter {
// TODO(tlater): Remove this cursed filter
//
// Sometimes the source and range match up
// perfectly, and the destination starts
// with 0.
//
// Maybe this is a bug in the puzzle (?!),
// or whenever this happens my logic
// breaks down and the resulting
// translated range always ends up in the
// result.
//
// Nonetheless, filtering these 0s out
// gives the right answer.
//
// More likely it's a booby trap for
// *exactly* the logical fallacy I'm
// committing?
//
// That, *or* it's just unlikely any one
// range is the lowest in the end, and
// these don't happen to contribute, while
// the rest is computed correctly.
it.first != 0u
}
.map { it.first } .map { it.first }
.min() .min()
} }
.min() .min()
} }
fun findReduction(toReduce: List<UIntRange>, maps: List<Map>): List<UIntRange> { fun findReduction(toReduce: List<LongRange>, maps: List<Map>): List<LongRange> {
var result: MutableList<UIntRange> = mutableListOf() var result: MutableList<LongRange> = mutableListOf()
var reducing: MutableList<UIntRange> = mutableListOf() var reducing: MutableList<LongRange> = mutableListOf()
reducing.addAll(toReduce) reducing.addAll(toReduce)
for (map in maps) { for (map in maps) {
var next: MutableList<UIntRange> = mutableListOf() var next: MutableList<LongRange> = mutableListOf()
val source = map.first val source = map.first
val destination = map.second val destination = map.second
@ -96,17 +70,17 @@ fun findReduction(toReduce: List<UIntRange>, maps: List<Map>): List<UIntRange> {
} }
fun getDestinationForOverlap( fun getDestinationForOverlap(
overlap: UIntRange, overlap: LongRange,
source: UIntRange, source: LongRange,
destination: UIntRange destination: LongRange
): UIntRange { ): LongRange {
val startDiff = overlap.first - source.first val startDiff = overlap.first - source.first
val endDiff = source.last - overlap.last val endDiff = source.last - overlap.last
return destination.first + startDiff..destination.last - endDiff return destination.first + startDiff..destination.last - endDiff
} }
fun getOverlap(range1: UIntRange, range2: UIntRange): Pair<UIntRange?, List<UIntRange>> { fun getOverlap(range1: LongRange, range2: LongRange): Pair<LongRange?, List<LongRange>> {
val start = val start =
when { when {
range1.first <= range2.first -> range2.first range1.first <= range2.first -> range2.first
@ -124,24 +98,24 @@ fun getOverlap(range1: UIntRange, range2: UIntRange): Pair<UIntRange?, List<UInt
if (start > end) { if (start > end) {
return Pair(null, listOf(range1)) return Pair(null, listOf(range1))
} else { } else {
val excess: MutableList<UIntRange> = mutableListOf() val excess: MutableList<LongRange> = mutableListOf()
if (start > range1.first) { if (start > range1.first) {
excess.add(range1.first ..< start) excess.add(range1.first ..< start)
} }
if (range1.last > end) { if (range1.last > end) {
excess.add(end + 1u..range1.last) excess.add(end + 1L..range1.last)
} }
return Pair(start..end, excess) return Pair(start..end, excess)
} }
} }
fun parseInput(input: File): Pair<List<UInt>, List<List<Map>>> { fun parseInput(input: File): Pair<List<Long>, List<List<Map>>> {
val text = input.bufferedReader() val text = input.bufferedReader()
val seeds = text.readLine().split(": ")[1].split(" ").map { it.toUInt() } val seeds = text.readLine().split(": ")[1].split(" ").map { it.toLong() }
text.readLine() text.readLine()
var line = text.readLine() var line = text.readLine()
@ -152,7 +126,7 @@ fun parseInput(input: File): Pair<List<UInt>, List<List<Map>>> {
line == "" -> Unit // Skip empty lines line == "" -> Unit // Skip empty lines
line.endsWith(':') -> maps.add(mutableListOf()) line.endsWith(':') -> maps.add(mutableListOf())
else -> { else -> {
val (destination, source, length) = line.split(" ").map { it.toUInt() } val (destination, source, length) = line.split(" ").map { it.toLong() }
maps.last() maps.last()
.add(Pair(source ..< source + length, destination ..< destination + length)) .add(Pair(source ..< source + length, destination ..< destination + length))
} }