From 4acdaa1deb85444dd8d2071199f6715c9a637b17 Mon Sep 17 00:00:00 2001 From: Ivan Date: Sat, 3 Feb 2024 16:27:17 +0500 Subject: [PATCH] Update solution --- .../src/main/kotlin/Solution05.kt | 139 ++++++++++++++---- .../src/test/kotlin/Solution05Test.kt | 6 +- 2 files changed, 113 insertions(+), 32 deletions(-) diff --git a/advent-of-code-2023/src/main/kotlin/Solution05.kt b/advent-of-code-2023/src/main/kotlin/Solution05.kt index 3d4da94..7b441cd 100644 --- a/advent-of-code-2023/src/main/kotlin/Solution05.kt +++ b/advent-of-code-2023/src/main/kotlin/Solution05.kt @@ -1,11 +1,14 @@ +import kotlin.math.min +import kotlin.math.max + class Solution05(lines: List) { - private var seeds: MutableList = mutableListOf() + private var seeds: MutableList = mutableListOf() private var maps: MutableList = mutableListOf() init { // Parse seeds val (_, seedsStr) = lines[0].split(": ") - seeds.addAll(seedsStr.split(" ").map{it.toULong()}) + seeds.addAll(seedsStr.split(" ").map{it.toLong()}) // Parse all maps for (line in lines.subList(2, lines.size)) { @@ -18,15 +21,15 @@ class Solution05(lines: List) { val (destRangeStart, srcRangeStart, rangeLength) = line.split(" ") maps.last().addRange( - srcRangeStart.toULong(), - destRangeStart.toULong(), - rangeLength.toULong(), + srcRangeStart.toLong(), + destRangeStart.toLong(), + rangeLength.toLong(), ) } } // Part 1. - fun getLowestLocationNumber(): ULong { + fun getLowestLocationNumber(): Long { return seeds .map{ var num = it @@ -41,30 +44,105 @@ class Solution05(lines: List) { } // Part 2. - fun getLowestLocationNumberForRangeOfSeeds(): ULong { - // Available location numbers. - var currentRanges = maps - .last() - .mappers - .map{RangeFromLoc(it.destRangeStart, it.rangeLength, it.destRangeStart)} + fun getLowestLocationNumberForRangeOfSeeds(): Long { + var ranges = mutableListOf() - for (map in maps.reversed()) { - val newList: MutableList = mutableListOf() + for (i in seeds.indices step 2) { + ranges.add( + RangeWithFirstSeed( + LongRange(seeds[i], seeds[i] + seeds[i+1] - 1), + seeds[i], + ) + ) + } + + for (map in maps) { + val newList = mutableListOf() for (mapper in map.mappers) { - // Find intersections - currentRanges + for (rng in ranges) { + 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) { class MapList() { val mappers: MutableList = mutableListOf() - fun addRange(sourceRangeStart: ULong, destRangeStart: ULong, rangeLength: ULong) { + fun addRange(sourceRangeStart: Long, destRangeStart: Long, rangeLength: Long) { mappers.add( Mapper(sourceRangeStart, destRangeStart, rangeLength), ) } - fun mapSrcNumberToDest(src: ULong): ULong { + fun mapSrcNumberToDest(src: Long): Long { for (range in mappers) { if (range.isNumberInSrcRange(src)) { return range.srcValueToDest(src) @@ -90,19 +168,22 @@ class MapList() { } // Mapper contains one line of map. -data class Mapper(val sourceRangeStart: ULong, val destRangeStart: ULong, val rangeLength: ULong) { - fun srcValueToDest(v: ULong): ULong { +data class Mapper(val sourceRangeStart: Long, val destRangeStart: Long, val rangeLength: Long) { + fun srcValueToDest(v: Long): Long { return destRangeStart + v - sourceRangeStart } - fun isNumberInSrcRange(num: ULong): Boolean { + fun isNumberInSrcRange(num: Long): Boolean { return num >= sourceRangeStart && num < sourceRangeStart + rangeLength } } -// Range of numbers with the first number of corresponding location. -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 RangeWithFirstSeed(val range: LongRange, val firstSeedInRange: Long) { +} + +data class ListOfRanges(val ranges: MutableList) { + fun findIntersectingRanges(other: LongRange): List { + return ranges + .filter{it.last >= other.first && it.first <= other.last} } } diff --git a/advent-of-code-2023/src/test/kotlin/Solution05Test.kt b/advent-of-code-2023/src/test/kotlin/Solution05Test.kt index 11387fb..6eb58de 100644 --- a/advent-of-code-2023/src/test/kotlin/Solution05Test.kt +++ b/advent-of-code-2023/src/test/kotlin/Solution05Test.kt @@ -6,21 +6,21 @@ class Solution05Test { fun testGetLowestLocation() { val text = ResourceReader().readFile("day-05/test.txt") val res = Solution05(text).getLowestLocationNumber() - assertEquals(35UL, res) + assertEquals(35L, res) } @Test fun solvePart1() { val text = ResourceReader().readFile("day-05/input.txt") val res = Solution05(text).getLowestLocationNumber() - assertEquals(621354867UL, res) + assertEquals(621354867L, res) } @Test fun testGetLowestLocationForRangeOfSeeds() { val text = ResourceReader().readFile("day-05/test.txt") val res = Solution05(text).getLowestLocationNumberForRangeOfSeeds() - assertEquals(46UL, res) + assertEquals(46L, res) } @Test