AOC: solve 5th task
This commit is contained in:
parent
4acdaa1deb
commit
ecaf90adb4
2 changed files with 75 additions and 90 deletions
|
@ -45,103 +45,91 @@ class Solution05(lines: List<String>) {
|
||||||
|
|
||||||
// Part 2.
|
// Part 2.
|
||||||
fun getLowestLocationNumberForRangeOfSeeds(): Long {
|
fun getLowestLocationNumberForRangeOfSeeds(): Long {
|
||||||
var ranges = mutableListOf<RangeWithFirstSeed>()
|
var ranges = mutableListOf<LongRange>()
|
||||||
|
|
||||||
for (i in seeds.indices step 2) {
|
for (i in seeds.indices step 2) {
|
||||||
ranges.add(
|
ranges.add(LongRange(seeds[i], seeds[i] + seeds[i+1] - 1))
|
||||||
RangeWithFirstSeed(
|
|
||||||
LongRange(seeds[i], seeds[i] + seeds[i+1] - 1),
|
|
||||||
seeds[i],
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (map in maps) {
|
for (map in maps) {
|
||||||
val newList = mutableListOf<RangeWithFirstSeed>()
|
var minCheckedValue = Long.MIN_VALUE
|
||||||
|
val newList = mutableListOf<LongRange>()
|
||||||
|
|
||||||
for (mapper in map.mappers) {
|
for (mapper in map.mappers.sortedBy{it.sourceRangeStart}) {
|
||||||
for (rng in ranges) {
|
//
|
||||||
val maxStart = max(mapper.sourceRangeStart, rng.range.first)
|
val mapperEnd = mapper.sourceRangeStart + mapper.rangeLength - 1
|
||||||
val minEndExcl = min(mapper.sourceRangeStart + mapper.rangeLength, rng.range.last + 1)
|
val diff = mapper.destRangeStart - mapper.sourceRangeStart
|
||||||
|
|
||||||
val len = minEndExcl - maxStart
|
// find all values before this range.
|
||||||
if (len > 0L) {
|
val unmatchedValues = ranges
|
||||||
|
.filter{it.first < mapper.sourceRangeStart}
|
||||||
|
.map{LongRange(max(minCheckedValue, it.first), min(mapper.sourceRangeStart - 1, it.last))}
|
||||||
|
.filter{it.first <= it.last}
|
||||||
|
newList.addAll(unmatchedValues)
|
||||||
|
|
||||||
val destStart = mapper.destRangeStart + (maxStart - mapper.sourceRangeStart)
|
// map values
|
||||||
newList.add(
|
val overlappingLeftValues = ranges
|
||||||
RangeWithFirstSeed(
|
.filter{it.first < mapper.sourceRangeStart && it.last >= mapper.sourceRangeStart && it.last <= mapperEnd}
|
||||||
LongRange(destStart, destStart + len - 1),
|
.map{
|
||||||
rng.firstSeedInRange
|
LongRange(
|
||||||
)
|
max(mapper.sourceRangeStart, it.first) + diff,
|
||||||
|
it.last + diff,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
.filter{it.first <= it.last}
|
||||||
}
|
newList.addAll(overlappingLeftValues)
|
||||||
|
|
||||||
// понять, какие диапазоны значений остались неиспользованными,
|
val overlappingMiddleValues = ranges
|
||||||
// тоже добавить их в список.
|
.filter{it.first >= mapper.sourceRangeStart && it.last <= mapperEnd}
|
||||||
|
.map{
|
||||||
val mprs = ListOfRanges(map.mappers.map{LongRange(it.sourceRangeStart, it.sourceRangeStart + it.rangeLength - 1)}.toMutableList())
|
LongRange(
|
||||||
|
it.first + diff, it.last + diff
|
||||||
for (rng in ranges) {
|
|
||||||
var currentRange = rng.range
|
|
||||||
|
|
||||||
var intrs = mprs
|
|
||||||
.findIntersectingRanges(rng.range)
|
|
||||||
.sortedBy{it.first}
|
|
||||||
|
|
||||||
if (intrs.isEmpty()) {
|
|
||||||
newList.add(
|
|
||||||
rng
|
|
||||||
)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i in intrs.indices) {
|
|
||||||
if (intrs[i].start > currentRange.start) {
|
|
||||||
newList.add(
|
|
||||||
RangeWithFirstSeed(
|
|
||||||
LongRange(intrs[i].start, currentRange.start - 1),
|
|
||||||
rng.firstSeedInRange
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
.filter{it.first <= it.last}
|
||||||
|
newList.addAll(overlappingMiddleValues)
|
||||||
|
|
||||||
var end = intrs[i].last
|
val overlappingRightValues = ranges
|
||||||
|
.filter{it.first >= mapper.sourceRangeStart && it.first <= mapperEnd && it.last >= mapperEnd}
|
||||||
if (i < intrs.size - 1 && intrs[i].last < intrs[i+1].first - 1) {
|
.map{
|
||||||
end = intrs[i+1].first - 1
|
LongRange(
|
||||||
|
it.first + diff,
|
||||||
newList.add(
|
min(it.last, mapperEnd) + diff
|
||||||
RangeWithFirstSeed(
|
|
||||||
LongRange(intrs[i].last + 1, intrs[i+1].first - 1),
|
|
||||||
rng.firstSeedInRange,
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
.filter{it.first <= it.last}
|
||||||
|
newList.addAll(overlappingRightValues)
|
||||||
|
|
||||||
currentRange = LongRange(end + 1, currentRange.endInclusive)
|
val bigRanges = ranges
|
||||||
}
|
.filter{it.first < mapper.sourceRangeStart && it.last > mapperEnd}
|
||||||
|
.map{
|
||||||
if (!currentRange.isEmpty()) {
|
LongRange(
|
||||||
newList.add(
|
mapper.sourceRangeStart + diff, mapperEnd + diff
|
||||||
RangeWithFirstSeed(
|
|
||||||
currentRange,
|
|
||||||
rng.firstSeedInRange
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
.filter{it.first <= it.last}
|
||||||
|
newList.addAll(bigRanges)
|
||||||
|
|
||||||
|
minCheckedValue = mapperEnd + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newList.addAll(
|
||||||
|
ranges
|
||||||
|
.filter{it.last >= minCheckedValue}
|
||||||
|
.map{
|
||||||
|
LongRange(
|
||||||
|
max(it.first, minCheckedValue),
|
||||||
|
it.last,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
ranges = newList
|
ranges = newList
|
||||||
.map{
|
|
||||||
if (it.range.last >= it.range.first) it else RangeWithFirstSeed(LongRange(it.range.last, it.range.first), it.firstSeedInRange)
|
|
||||||
}
|
|
||||||
.toMutableList()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ranges
|
return ranges
|
||||||
.map{it.range.first}
|
.map{it.first}
|
||||||
.min()
|
.min()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,13 +165,3 @@ data class Mapper(val sourceRangeStart: Long, val destRangeStart: Long, val rang
|
||||||
return num >= sourceRangeStart && num < sourceRangeStart + rangeLength
|
return num >= sourceRangeStart && num < sourceRangeStart + rangeLength
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class RangeWithFirstSeed(val range: LongRange, val firstSeedInRange: Long) {
|
|
||||||
}
|
|
||||||
|
|
||||||
data class ListOfRanges(val ranges: MutableList<LongRange>) {
|
|
||||||
fun findIntersectingRanges(other: LongRange): List<LongRange> {
|
|
||||||
return ranges
|
|
||||||
.filter{it.last >= other.first && it.first <= other.last}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -20,13 +20,20 @@ class Solution05Test {
|
||||||
fun testGetLowestLocationForRangeOfSeeds() {
|
fun testGetLowestLocationForRangeOfSeeds() {
|
||||||
val text = ResourceReader().readFile("day-05/test.txt")
|
val text = ResourceReader().readFile("day-05/test.txt")
|
||||||
val res = Solution05(text).getLowestLocationNumberForRangeOfSeeds()
|
val res = Solution05(text).getLowestLocationNumberForRangeOfSeeds()
|
||||||
assertEquals(46L, res)
|
assertEquals(46, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun solvePart2() {
|
fun solvePart2() {
|
||||||
val text = ResourceReader().readFile("day-05/input.txt")
|
val text = ResourceReader().readFile("day-05/input.txt")
|
||||||
val res = Solution05(text).getLowestLocationNumberForRangeOfSeeds()
|
val res = Solution05(text).getLowestLocationNumberForRangeOfSeeds()
|
||||||
println(res)
|
println("Your answer: $res")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPart2() {
|
||||||
|
val text = ResourceReader().readFile("day-05/input.txt")
|
||||||
|
val res = Solution05(text).getLowestLocationNumberForRangeOfSeeds()
|
||||||
|
assertEquals(15880236, res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue