From b636dd4c43dc5784eaf49e71a1eee72a2b642853 Mon Sep 17 00:00:00 2001 From: Ivan Date: Thu, 11 Jan 2024 18:05:07 +0500 Subject: [PATCH 1/5] Add partial solution for the 5th day of AoC --- .../src/main/kotlin/Solution05.kt | 89 +++++++ .../src/main/resources/day-05/input.txt | 252 ++++++++++++++++++ .../src/main/resources/day-05/test.txt | 33 +++ .../src/test/kotlin/Solution05Test.kt | 32 +++ 4 files changed, 406 insertions(+) create mode 100644 advent-of-code-2023/src/main/kotlin/Solution05.kt create mode 100644 advent-of-code-2023/src/main/resources/day-05/input.txt create mode 100644 advent-of-code-2023/src/main/resources/day-05/test.txt create mode 100644 advent-of-code-2023/src/test/kotlin/Solution05Test.kt diff --git a/advent-of-code-2023/src/main/kotlin/Solution05.kt b/advent-of-code-2023/src/main/kotlin/Solution05.kt new file mode 100644 index 0000000..55b4c43 --- /dev/null +++ b/advent-of-code-2023/src/main/kotlin/Solution05.kt @@ -0,0 +1,89 @@ +class Solution05(lines: List) { + private var seeds: MutableList = mutableListOf() + private var maps: MutableMap = mutableMapOf() + + init { + // Parse seeds + val (_, seedsStr) = lines[0].split(": ") + seeds.addAll(seedsStr.split(" ").map{it.toULong()}) + + // Parse all maps + var currentSrc = "" + for (line in lines.subList(2, lines.size)) { + if (line.isEmpty()) continue + + if (line.contains(" map:")) { + val (mapTitle, _) = line.split(" ") + val (src, dest) = mapTitle.split("-to-") + currentSrc = src + + if (!maps.containsKey(currentSrc)) { + maps[currentSrc] = Ranges(dest) + } + + continue + } + + val (destRangeStart, srcRangeStart, rangeLength) = line.split(" ") + maps[currentSrc]?.addRange( + srcRangeStart.toULong(), + destRangeStart.toULong(), + rangeLength.toULong(), + ) + } + } + + fun getLowestLocationNumber(): ULong { + return seeds + .map{convertSeedNumber(it, "location")} + .min() + } + + fun getLowestLocationNumberForRangeOfSeeds(): ULong { + val allSeeds: MutableSet = mutableSetOf() + + for (i in 0.. = mutableListOf() + + fun addRange(sourceRangeStart: ULong, destRangeStart: ULong, rangeLength: ULong) { + ranges.add(Range(sourceRangeStart, destRangeStart, rangeLength)) + } + + fun mapNumber(src: ULong): ULong { + for (range in ranges) { + if (src >= range.sourceRangeStart && src < range.sourceRangeStart + range.rangeLength) { + return range.destRangeStart + src - range.sourceRangeStart + } + } + + return src + } +} + +data class Range(val sourceRangeStart: ULong, val destRangeStart: ULong, val rangeLength: ULong) diff --git a/advent-of-code-2023/src/main/resources/day-05/input.txt b/advent-of-code-2023/src/main/resources/day-05/input.txt new file mode 100644 index 0000000..3d50c1c --- /dev/null +++ b/advent-of-code-2023/src/main/resources/day-05/input.txt @@ -0,0 +1,252 @@ +seeds: 432986705 28073546 1364097901 88338513 2733524843 234912494 3151642679 224376393 485709676 344068331 1560394266 911616092 3819746175 87998136 892394515 435690182 4218056486 23868437 848725444 8940450 + +seed-to-soil map: +748585809 2125564114 88980459 +1317392128 775565564 217595062 +1218610825 676784261 98781303 +954230685 2235762425 141777617 +2920242079 4081180892 51765553 +2972007632 3159586797 16102841 +0 2377540042 17565155 +2834452876 3712797875 58062179 +2892515055 2917079842 6424918 +3327351062 3175689638 162608005 +673338549 647264576 29519685 +1197392973 2214544573 21217852 +738232750 116664417 10353059 +2988110473 2429807442 71556277 +17565155 334379348 277510712 +1700771639 228674051 105705297 +3059666750 4132946445 162020851 +1806476936 993160626 588628261 +1096008302 127289380 101384671 +622123656 1908836676 50942989 +3221687601 3338297643 28028532 +2408505336 3770860054 310320838 +4175210607 3039830108 119756689 +3326652416 3039131462 698646 +2898939973 2408505336 21302106 +673066645 127017476 271904 +3489959067 3382623558 330174317 +702858234 611890060 35374516 +4086270124 2562002619 88940483 +837566268 0 116664417 +1534987190 1959779665 165784449 +2718826174 2923504760 115626702 +3249716133 3366326175 16297383 +3820133384 2650943102 266136740 +3266013516 2501363719 60638900 +295075867 1581788887 327047789 + +soil-to-fertilizer map: +2018515973 2192795257 82329405 +3722326327 3015971185 249665840 +3046459770 3689390318 25519185 +3971992167 3265637025 40217941 +3071978955 3453653215 203407731 +0 443504340 17965088 +584437096 1722124969 470670288 +1055107384 744431503 164966659 +1489299099 461469428 282962075 +2321848831 2380372526 153650776 +2100845378 269225056 174279284 +3487660258 2648616968 234666069 +3275386686 3305854966 147798249 +1772261174 1172578553 246254799 +4012210108 2883283037 132688148 +3423184935 4138946628 64475323 +4144898256 2321848831 58523695 +538253726 1418833352 46183370 +1220074043 0 269225056 +17965088 909398162 263180391 +2590093273 3657060946 32329372 +281145479 1465016722 257108247 +2622422645 3714909503 424037125 +2475499607 2534023302 114593666 + +fertilizer-to-water map: +3731805434 353192162 37567806 +926873139 889685769 255250442 +3170336676 695153543 194532226 +679924479 451681440 193671776 +3009343704 3081959489 160992972 +1242360754 3579359343 278026518 +1861131448 2500688596 20068354 +4028837903 4006213119 266129393 +1182123581 3242952461 60237173 +3877550443 645353216 49800327 +2223776164 1371077033 341527178 +3364868902 2566566565 36440100 +1773121333 0 76664401 +264823995 2444756861 55931735 +3929841219 3857385861 27802851 +2166799431 1712604211 56976733 +873596255 1769580944 53276884 +645696746 3047731756 34227733 +3927350770 3955153621 2490449 +3769373240 177937131 108177203 +0 3314535348 264823995 +1942121274 3885188712 69964909 +1881199802 390759968 60921472 +1849785734 3303189634 11345714 +3401309002 2855740726 104355610 +2079164011 2960096336 87635420 +544424016 76664401 101272730 +2565303342 2520756950 45809615 +1520387272 2603006665 252734061 +2012086183 286114334 67077828 +2611112957 1822857828 398230747 +320755730 2221088575 223668286 +3505664612 1144936211 226140822 +4006213119 4272342512 22624784 + +water-to-light map: +62780592 544346201 30115959 +2740764032 1352944740 34082945 +377487729 807592920 35446631 +1316419610 1454554942 34907962 +986581913 756881718 50711202 +4167758628 3240047125 127208668 +818809239 1222506283 58684750 +3649838514 2036598113 6212644 +127663629 0 10715051 +3023280854 1435387310 19167632 +663070842 10715051 124076893 +2774846977 2422700597 37614763 +1812617371 2460315360 5121443 +1640337506 1864318248 172279865 +2986755724 1316419610 36525130 +2023334670 2467203928 540327060 +1159184084 248462172 14557802 +1037293115 152894449 95567723 +0 134791944 18102505 +18102505 712203631 44678087 +465375803 972369801 197695039 +2576394916 3007530988 65274194 +92896551 1281191033 34767078 +3656051158 4289142647 5824649 +412934360 1170064840 52441443 +3417303830 3873138614 84580361 +787147735 263019974 31661504 +1817738814 2042810757 205595856 +1285160111 843039551 30798000 +2563661730 3123136764 12733186 +138378680 305237152 239109049 +3648071389 2465436803 1767125 +1132860838 574462160 26323246 +888049663 873837551 98532250 +3626039273 3072805182 22032116 +3530183657 4193287031 95855616 +1404769450 3957718975 235568056 +3042448486 1489462904 374855344 +2641669110 1387027685 48359625 +877493989 294681478 10555674 +3501884191 3094837298 28299466 +1351327572 3186605247 53441878 +2690028735 3135869950 50735297 +2812461740 2248406613 174293984 +3661875807 3367255793 505882821 +1173741886 600785406 111418225 + +light-to-temperature map: +964570004 989608620 226759942 +2204148775 2545437438 20646474 +233260112 338444213 39032265 +958191857 332066066 6378147 +2318799855 914518254 75090366 +4247140372 3146297568 47826924 +2224795249 1216368562 94004606 +2871022952 1310373168 80313918 +1400254919 233260112 98805954 +445493256 487550555 149554087 +2576473348 3962746668 294549604 +3535295748 2775008885 371288683 +1499060873 377476478 110074077 +272292377 2215619580 173200879 +3347481948 1867953550 157067409 +4161267146 3794452372 85873226 +3504549357 2184873189 30746391 +1759636962 1780717197 87236353 +2951336870 2388820459 6114967 +1191329946 2566083912 208924973 +1884544339 3880325598 82421070 +595047343 3431307858 363144514 +2393890221 731935127 182583127 +4001414916 2025020959 159852230 +2957451837 1390687086 390030111 +1846873315 4257296272 37671024 +1966965409 3194124492 237183366 +1609134950 2394935426 150502012 +3906584431 637104642 94830485 + +temperature-to-humidity map: +1406768592 2335526312 13344484 +666958498 1862550129 472976183 +558853371 843618476 74696086 +1168798622 129171378 168640618 +1713291209 297811996 183431863 +1993628008 635748116 152317885 +2560263686 2849350774 11516524 +32266442 1212766321 287276323 +2571780210 3319898101 11192927 +375095240 995599149 183758131 +2661986290 2353962919 50829838 +3252020768 4280298713 14668583 +1337439240 1793220777 69329352 +3419718116 3502299739 574454544 +2353962919 2650392505 198958269 +633549457 1179357280 33409041 +2582973137 4076754283 50515665 +319542765 788066001 55552475 +1896723072 32266442 96904936 +1420113076 1500042644 293178133 +3006421020 2404792757 245599748 +2842554807 3331091028 163866213 +2633488802 2990605977 28497488 +2300450150 947178503 48420646 +3266689351 4127269948 153028765 +2145945893 481243859 154504257 +3994172660 3019103465 300794636 +1139934681 918314562 28863941 +2712816128 2860867298 129738679 +2552921188 3494957241 7342498 + +humidity-to-location map: +897459980 3171885613 268595078 +506368722 1864971513 13322696 +1166055058 2803961444 53745388 +2572095034 667166679 114420176 +687118932 1725187165 139784348 +2478398695 0 14138781 +3427672233 370325921 251085897 +3888215738 3612891343 82449665 +1674720770 1530101168 79955344 +3970665403 925512154 2812137 +519691418 2452425610 167427514 +3884704963 3168374838 3510775 +826903280 2381868910 70556700 +2399774019 349568762 20757159 +2972099388 3465151802 147739541 +1754676114 131614075 217954687 +2865104023 3440480691 24671111 +2206760431 932309368 77882935 +2284643366 1610056512 115130653 +2492537476 14138781 35151040 +2527688516 3695341008 44406518 +3119838929 781586855 143925299 +2732270071 2857706832 132833952 +1599442846 2728683520 75277924 +3263764228 3995626854 27783181 +0 2990540784 177834054 +2686515210 621411818 45754861 +2420531178 2670816003 57867517 +1219800446 1010192303 191374197 +3678758130 3789680021 205946833 +3973477540 3739747526 49932495 +1972630801 2014419033 234129630 +3291547409 1878294209 136124824 +2889775134 49289821 82324254 +1411174643 2619853124 50962879 +1466122599 2248548663 133320247 +177834054 1201566500 328534668 +1462137522 928324291 3985077 diff --git a/advent-of-code-2023/src/main/resources/day-05/test.txt b/advent-of-code-2023/src/main/resources/day-05/test.txt new file mode 100644 index 0000000..f756727 --- /dev/null +++ b/advent-of-code-2023/src/main/resources/day-05/test.txt @@ -0,0 +1,33 @@ +seeds: 79 14 55 13 + +seed-to-soil map: +50 98 2 +52 50 48 + +soil-to-fertilizer map: +0 15 37 +37 52 2 +39 0 15 + +fertilizer-to-water map: +49 53 8 +0 11 42 +42 0 7 +57 7 4 + +water-to-light map: +88 18 7 +18 25 70 + +light-to-temperature map: +45 77 23 +81 45 19 +68 64 13 + +temperature-to-humidity map: +0 69 1 +1 0 69 + +humidity-to-location map: +60 56 37 +56 93 4 diff --git a/advent-of-code-2023/src/test/kotlin/Solution05Test.kt b/advent-of-code-2023/src/test/kotlin/Solution05Test.kt new file mode 100644 index 0000000..a5878af --- /dev/null +++ b/advent-of-code-2023/src/test/kotlin/Solution05Test.kt @@ -0,0 +1,32 @@ +import kotlin.test.Test +import kotlin.test.assertEquals + +class Solution05Test { + @Test + fun testGetLowestLocation() { + val text = ResourceReader().readFile("day-05/test.txt") + val res = Solution05(text).getLowestLocationNumber() + assertEquals(35UL, res) + } + + @Test + fun solvePart1() { + val text = ResourceReader().readFile("day-05/input.txt") + val res = Solution05(text).getLowestLocationNumber() + println(res) + } + + @Test + fun testGetLowestLocationForRangeOfSeeds() { + val text = ResourceReader().readFile("day-05/test.txt") + val res = Solution05(text).getLowestLocationNumberForRangeOfSeeds() + assertEquals(46UL, res) + } + + @Test + fun solvePart2() { + val text = ResourceReader().readFile("day-05/input.txt") + val res = Solution05(text).getLowestLocationNumberForRangeOfSeeds() + println(res) + } +} From 36dc294e980b706991b6d670ee664aa4f2b09818 Mon Sep 17 00:00:00 2001 From: Ivan Date: Fri, 26 Jan 2024 17:42:55 +0500 Subject: [PATCH 2/5] Update solution --- .../src/main/kotlin/Solution05.kt | 97 +++++++++++-------- .../src/test/kotlin/Solution05Test.kt | 2 +- 2 files changed, 59 insertions(+), 40 deletions(-) diff --git a/advent-of-code-2023/src/main/kotlin/Solution05.kt b/advent-of-code-2023/src/main/kotlin/Solution05.kt index 55b4c43..3d4da94 100644 --- a/advent-of-code-2023/src/main/kotlin/Solution05.kt +++ b/advent-of-code-2023/src/main/kotlin/Solution05.kt @@ -1,6 +1,6 @@ class Solution05(lines: List) { private var seeds: MutableList = mutableListOf() - private var maps: MutableMap = mutableMapOf() + private var maps: MutableList = mutableListOf() init { // Parse seeds @@ -8,24 +8,16 @@ class Solution05(lines: List) { seeds.addAll(seedsStr.split(" ").map{it.toULong()}) // Parse all maps - var currentSrc = "" for (line in lines.subList(2, lines.size)) { if (line.isEmpty()) continue if (line.contains(" map:")) { - val (mapTitle, _) = line.split(" ") - val (src, dest) = mapTitle.split("-to-") - currentSrc = src - - if (!maps.containsKey(currentSrc)) { - maps[currentSrc] = Ranges(dest) - } - + maps.add(MapList()) continue } val (destRangeStart, srcRangeStart, rangeLength) = line.split(" ") - maps[currentSrc]?.addRange( + maps.last().addRange( srcRangeStart.toULong(), destRangeStart.toULong(), rangeLength.toULong(), @@ -33,52 +25,63 @@ class Solution05(lines: List) { } } + // Part 1. fun getLowestLocationNumber(): ULong { return seeds - .map{convertSeedNumber(it, "location")} - .min() - } + .map{ + var num = it - fun getLowestLocationNumberForRangeOfSeeds(): ULong { - val allSeeds: MutableSet = mutableSetOf() + for (map in maps) { + num = map.mapSrcNumberToDest(num) + } - for (i in 0.. = mutableListOf() - while (dest != target) { - val ranges = maps[dest]!! - dest = ranges.destName - num = ranges.mapNumber(num) + for (mapper in map.mappers) { + // Find intersections + currentRanges + + + for (rng in currentRanges) { + + } + } + + currentRanges = newList } - return num + return 0UL } } -data class Ranges(val destName: String) { - val ranges: MutableList = mutableListOf() +// Map stores the rules for matching one number to another. +class MapList() { + val mappers: MutableList = mutableListOf() fun addRange(sourceRangeStart: ULong, destRangeStart: ULong, rangeLength: ULong) { - ranges.add(Range(sourceRangeStart, destRangeStart, rangeLength)) + mappers.add( + Mapper(sourceRangeStart, destRangeStart, rangeLength), + ) } - fun mapNumber(src: ULong): ULong { - for (range in ranges) { - if (src >= range.sourceRangeStart && src < range.sourceRangeStart + range.rangeLength) { - return range.destRangeStart + src - range.sourceRangeStart + fun mapSrcNumberToDest(src: ULong): ULong { + for (range in mappers) { + if (range.isNumberInSrcRange(src)) { + return range.srcValueToDest(src) } } @@ -86,4 +89,20 @@ data class Ranges(val destName: String) { } } -data class Range(val sourceRangeStart: ULong, val destRangeStart: ULong, val rangeLength: ULong) +// Mapper contains one line of map. +data class Mapper(val sourceRangeStart: ULong, val destRangeStart: ULong, val rangeLength: ULong) { + fun srcValueToDest(v: ULong): ULong { + return destRangeStart + v - sourceRangeStart + } + + fun isNumberInSrcRange(num: ULong): 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) + } +} diff --git a/advent-of-code-2023/src/test/kotlin/Solution05Test.kt b/advent-of-code-2023/src/test/kotlin/Solution05Test.kt index a5878af..11387fb 100644 --- a/advent-of-code-2023/src/test/kotlin/Solution05Test.kt +++ b/advent-of-code-2023/src/test/kotlin/Solution05Test.kt @@ -13,7 +13,7 @@ class Solution05Test { fun solvePart1() { val text = ResourceReader().readFile("day-05/input.txt") val res = Solution05(text).getLowestLocationNumber() - println(res) + assertEquals(621354867UL, res) } @Test From 4acdaa1deb85444dd8d2071199f6715c9a637b17 Mon Sep 17 00:00:00 2001 From: Ivan Date: Sat, 3 Feb 2024 16:27:17 +0500 Subject: [PATCH 3/5] 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 From ecaf90adb4cbcabbf5beb4c2a062e4f7a0f26c27 Mon Sep 17 00:00:00 2001 From: Ivan Reshetnikov Date: Mon, 5 Feb 2024 00:27:57 +0500 Subject: [PATCH 4/5] AOC: solve 5th task --- .../src/main/kotlin/Solution05.kt | 154 ++++++++---------- .../src/test/kotlin/Solution05Test.kt | 11 +- 2 files changed, 75 insertions(+), 90 deletions(-) diff --git a/advent-of-code-2023/src/main/kotlin/Solution05.kt b/advent-of-code-2023/src/main/kotlin/Solution05.kt index 7b441cd..a2e06c3 100644 --- a/advent-of-code-2023/src/main/kotlin/Solution05.kt +++ b/advent-of-code-2023/src/main/kotlin/Solution05.kt @@ -45,103 +45,91 @@ class Solution05(lines: List) { // Part 2. fun getLowestLocationNumberForRangeOfSeeds(): Long { - var ranges = mutableListOf() + var ranges = mutableListOf() for (i in seeds.indices step 2) { - ranges.add( - RangeWithFirstSeed( - LongRange(seeds[i], seeds[i] + seeds[i+1] - 1), - seeds[i], - ) - ) + ranges.add(LongRange(seeds[i], seeds[i] + seeds[i+1] - 1)) } + for (map in maps) { - val newList = mutableListOf() + var minCheckedValue = Long.MIN_VALUE + val newList = mutableListOf() - for (mapper in map.mappers) { - for (rng in ranges) { - val maxStart = max(mapper.sourceRangeStart, rng.range.first) - val minEndExcl = min(mapper.sourceRangeStart + mapper.rangeLength, rng.range.last + 1) + for (mapper in map.mappers.sortedBy{it.sourceRangeStart}) { + // + val mapperEnd = mapper.sourceRangeStart + mapper.rangeLength - 1 + val diff = mapper.destRangeStart - mapper.sourceRangeStart - val len = minEndExcl - maxStart - if (len > 0L) { + // find all values before this range. + 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) - newList.add( - RangeWithFirstSeed( - LongRange(destStart, destStart + len - 1), - rng.firstSeedInRange - ) + // map values + val overlappingLeftValues = ranges + .filter{it.first < mapper.sourceRangeStart && it.last >= mapper.sourceRangeStart && it.last <= mapperEnd} + .map{ + 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{ + LongRange( + it.first + diff, it.last + diff + ) + } + .filter{it.first <= it.last} + newList.addAll(overlappingMiddleValues) + + val overlappingRightValues = ranges + .filter{it.first >= mapper.sourceRangeStart && it.first <= mapperEnd && it.last >= mapperEnd} + .map{ + LongRange( + it.first + diff, + min(it.last, mapperEnd) + diff + ) + } + .filter{it.first <= it.last} + newList.addAll(overlappingRightValues) + + val bigRanges = ranges + .filter{it.first < mapper.sourceRangeStart && it.last > mapperEnd} + .map{ + LongRange( + mapper.sourceRangeStart + diff, mapperEnd + diff + ) + } + .filter{it.first <= it.last} + newList.addAll(bigRanges) + + minCheckedValue = mapperEnd + 1 } - // понять, какие диапазоны значений остались неиспользованными, - // тоже добавить их в список. - - 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 - ) + newList.addAll( + ranges + .filter{it.last >= minCheckedValue} + .map{ + LongRange( + max(it.first, minCheckedValue), + it.last, ) } - - 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 ranges - .map{it.range.first} + .map{it.first} .min() } } @@ -177,13 +165,3 @@ data class Mapper(val sourceRangeStart: Long, val destRangeStart: Long, val rang return num >= sourceRangeStart && num < sourceRangeStart + rangeLength } } - -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 6eb58de..6a4edbd 100644 --- a/advent-of-code-2023/src/test/kotlin/Solution05Test.kt +++ b/advent-of-code-2023/src/test/kotlin/Solution05Test.kt @@ -20,13 +20,20 @@ class Solution05Test { fun testGetLowestLocationForRangeOfSeeds() { val text = ResourceReader().readFile("day-05/test.txt") val res = Solution05(text).getLowestLocationNumberForRangeOfSeeds() - assertEquals(46L, res) + assertEquals(46, res) } @Test fun solvePart2() { val text = ResourceReader().readFile("day-05/input.txt") 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) } } From 8d2d26c503e5cc74cbaf200a036acefd27fae202 Mon Sep 17 00:00:00 2001 From: Ivan Reshetnikov Date: Mon, 5 Feb 2024 00:32:44 +0500 Subject: [PATCH 5/5] refactor: simplify the solution for the 5th day of AOC --- .../src/main/kotlin/Solution05.kt | 61 +++++-------------- 1 file changed, 16 insertions(+), 45 deletions(-) diff --git a/advent-of-code-2023/src/main/kotlin/Solution05.kt b/advent-of-code-2023/src/main/kotlin/Solution05.kt index a2e06c3..c0eb4ec 100644 --- a/advent-of-code-2023/src/main/kotlin/Solution05.kt +++ b/advent-of-code-2023/src/main/kotlin/Solution05.kt @@ -51,65 +51,36 @@ class Solution05(lines: List) { ranges.add(LongRange(seeds[i], seeds[i] + seeds[i+1] - 1)) } - for (map in maps) { var minCheckedValue = Long.MIN_VALUE val newList = mutableListOf() for (mapper in map.mappers.sortedBy{it.sourceRangeStart}) { - // val mapperEnd = mapper.sourceRangeStart + mapper.rangeLength - 1 val diff = mapper.destRangeStart - mapper.sourceRangeStart // find all values before this range. val unmatchedValues = ranges - .filter{it.first < mapper.sourceRangeStart} - .map{LongRange(max(minCheckedValue, it.first), min(mapper.sourceRangeStart - 1, it.last))} + .map{ + LongRange( + max(minCheckedValue, it.first), + min(mapper.sourceRangeStart - 1, it.last), + ) + } .filter{it.first <= it.last} newList.addAll(unmatchedValues) // map values - val overlappingLeftValues = ranges - .filter{it.first < mapper.sourceRangeStart && it.last >= mapper.sourceRangeStart && it.last <= mapperEnd} - .map{ - 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{ - LongRange( - it.first + diff, it.last + diff - ) - } - .filter{it.first <= it.last} - newList.addAll(overlappingMiddleValues) - - val overlappingRightValues = ranges - .filter{it.first >= mapper.sourceRangeStart && it.first <= mapperEnd && it.last >= mapperEnd} - .map{ - LongRange( - it.first + diff, - min(it.last, mapperEnd) + diff - ) - } - .filter{it.first <= it.last} - newList.addAll(overlappingRightValues) - - val bigRanges = ranges - .filter{it.first < mapper.sourceRangeStart && it.last > mapperEnd} - .map{ - LongRange( - mapper.sourceRangeStart + diff, mapperEnd + diff - ) - } - .filter{it.first <= it.last} - newList.addAll(bigRanges) + newList.addAll( + ranges + .map{ + LongRange( + max(mapper.sourceRangeStart, it.first) + diff, + min(mapperEnd, it.last) + diff, + ) + } + .filter{it.first <= it.last} + ) minCheckedValue = mapperEnd + 1 }