Update solution
This commit is contained in:
parent
36dc294e98
commit
4acdaa1deb
2 changed files with 113 additions and 32 deletions
|
@ -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}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue