Update solution

This commit is contained in:
Ivan R. 2024-02-03 16:27:17 +05:00
parent 36dc294e98
commit 4acdaa1deb
Signed by: lumin
GPG key ID: 927D3132247BDE4E
2 changed files with 113 additions and 32 deletions

View file

@ -1,11 +1,14 @@
import kotlin.math.min
import kotlin.math.max
class Solution05(lines: List<String>) { class Solution05(lines: List<String>) {
private var seeds: MutableList<ULong> = mutableListOf() private var seeds: MutableList<Long> = mutableListOf()
private var maps: MutableList<MapList> = mutableListOf() private var maps: MutableList<MapList> = mutableListOf()
init { init {
// Parse seeds // Parse seeds
val (_, seedsStr) = lines[0].split(": ") val (_, seedsStr) = lines[0].split(": ")
seeds.addAll(seedsStr.split(" ").map{it.toULong()}) seeds.addAll(seedsStr.split(" ").map{it.toLong()})
// Parse all maps // Parse all maps
for (line in lines.subList(2, lines.size)) { for (line in lines.subList(2, lines.size)) {
@ -18,15 +21,15 @@ class Solution05(lines: List<String>) {
val (destRangeStart, srcRangeStart, rangeLength) = line.split(" ") val (destRangeStart, srcRangeStart, rangeLength) = line.split(" ")
maps.last().addRange( maps.last().addRange(
srcRangeStart.toULong(), srcRangeStart.toLong(),
destRangeStart.toULong(), destRangeStart.toLong(),
rangeLength.toULong(), rangeLength.toLong(),
) )
} }
} }
// Part 1. // Part 1.
fun getLowestLocationNumber(): ULong { fun getLowestLocationNumber(): Long {
return seeds return seeds
.map{ .map{
var num = it var num = it
@ -41,30 +44,105 @@ class Solution05(lines: List<String>) {
} }
// Part 2. // Part 2.
fun getLowestLocationNumberForRangeOfSeeds(): ULong { fun getLowestLocationNumberForRangeOfSeeds(): Long {
// Available location numbers. var ranges = mutableListOf<RangeWithFirstSeed>()
var currentRanges = maps
.last()
.mappers
.map{RangeFromLoc(it.destRangeStart, it.rangeLength, it.destRangeStart)}
for (map in maps.reversed()) { for (i in seeds.indices step 2) {
val newList: MutableList<RangeFromLoc> = mutableListOf() ranges.add(
RangeWithFirstSeed(
LongRange(seeds[i], seeds[i] + seeds[i+1] - 1),
seeds[i],
)
)
}
for (map in maps) {
val newList = mutableListOf<RangeWithFirstSeed>()
for (mapper in map.mappers) { for (mapper in map.mappers) {
// Find intersections for (rng in ranges) {
currentRanges val maxStart = max(mapper.sourceRangeStart, rng.range.first)
val minEndExcl = min(mapper.sourceRangeStart + mapper.rangeLength, rng.range.last + 1)
val len = minEndExcl - maxStart
if (len > 0L) {
for (rng in currentRanges) { val destStart = mapper.destRangeStart + (maxStart - mapper.sourceRangeStart)
newList.add(
RangeWithFirstSeed(
LongRange(destStart, destStart + len - 1),
rng.firstSeedInRange
)
)
}
} }
} }
currentRanges = newList // понять, какие диапазоны значений остались неиспользованными,
// тоже добавить их в список.
val mprs = ListOfRanges(map.mappers.map{LongRange(it.sourceRangeStart, it.sourceRangeStart + it.rangeLength - 1)}.toMutableList())
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
)
)
}
var end = intrs[i].last
if (i < intrs.size - 1 && intrs[i].last < intrs[i+1].first - 1) {
end = intrs[i+1].first - 1
newList.add(
RangeWithFirstSeed(
LongRange(intrs[i].last + 1, intrs[i+1].first - 1),
rng.firstSeedInRange,
)
)
}
currentRange = LongRange(end + 1, currentRange.endInclusive)
}
if (!currentRange.isEmpty()) {
newList.add(
RangeWithFirstSeed(
currentRange,
rng.firstSeedInRange
)
)
}
}
ranges = newList
.map{
if (it.range.last >= it.range.first) it else RangeWithFirstSeed(LongRange(it.range.last, it.range.first), it.firstSeedInRange)
}
.toMutableList()
} }
return 0UL return ranges
.map{it.range.first}
.min()
} }
} }
@ -72,13 +150,13 @@ class Solution05(lines: List<String>) {
class MapList() { class MapList() {
val mappers: MutableList<Mapper> = mutableListOf() val mappers: MutableList<Mapper> = mutableListOf()
fun addRange(sourceRangeStart: ULong, destRangeStart: ULong, rangeLength: ULong) { fun addRange(sourceRangeStart: Long, destRangeStart: Long, rangeLength: Long) {
mappers.add( mappers.add(
Mapper(sourceRangeStart, destRangeStart, rangeLength), Mapper(sourceRangeStart, destRangeStart, rangeLength),
) )
} }
fun mapSrcNumberToDest(src: ULong): ULong { fun mapSrcNumberToDest(src: Long): Long {
for (range in mappers) { for (range in mappers) {
if (range.isNumberInSrcRange(src)) { if (range.isNumberInSrcRange(src)) {
return range.srcValueToDest(src) return range.srcValueToDest(src)
@ -90,19 +168,22 @@ class MapList() {
} }
// Mapper contains one line of map. // Mapper contains one line of map.
data class Mapper(val sourceRangeStart: ULong, val destRangeStart: ULong, val rangeLength: ULong) { data class Mapper(val sourceRangeStart: Long, val destRangeStart: Long, val rangeLength: Long) {
fun srcValueToDest(v: ULong): ULong { fun srcValueToDest(v: Long): Long {
return destRangeStart + v - sourceRangeStart return destRangeStart + v - sourceRangeStart
} }
fun isNumberInSrcRange(num: ULong): Boolean { fun isNumberInSrcRange(num: Long): Boolean {
return num >= sourceRangeStart && num < sourceRangeStart + rangeLength return num >= sourceRangeStart && num < sourceRangeStart + rangeLength
} }
} }
// Range of numbers with the first number of corresponding location. data class RangeWithFirstSeed(val range: LongRange, val firstSeedInRange: Long) {
data class RangeFromLoc(val rangeStart: ULong, val rangeLength: ULong, val locationStart: ULong) { }
fun getIntersection(newRangeStart: ULong, newRangeLength: ULong): RangeFromLoc {
return RangeFromLoc(rangeStart, rangeLength, locationStart) data class ListOfRanges(val ranges: MutableList<LongRange>) {
fun findIntersectingRanges(other: LongRange): List<LongRange> {
return ranges
.filter{it.last >= other.first && it.first <= other.last}
} }
} }

View file

@ -6,21 +6,21 @@ class Solution05Test {
fun testGetLowestLocation() { fun testGetLowestLocation() {
val text = ResourceReader().readFile("day-05/test.txt") val text = ResourceReader().readFile("day-05/test.txt")
val res = Solution05(text).getLowestLocationNumber() val res = Solution05(text).getLowestLocationNumber()
assertEquals(35UL, res) assertEquals(35L, res)
} }
@Test @Test
fun solvePart1() { fun solvePart1() {
val text = ResourceReader().readFile("day-05/input.txt") val text = ResourceReader().readFile("day-05/input.txt")
val res = Solution05(text).getLowestLocationNumber() val res = Solution05(text).getLowestLocationNumber()
assertEquals(621354867UL, res) assertEquals(621354867L, res)
} }
@Test @Test
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(46UL, res) assertEquals(46L, res)
} }
@Test @Test