From 318bdf96614cc3cc792758818ccd14100fb8a6a6 Mon Sep 17 00:00:00 2001 From: Nettika Date: Tue, 12 Dec 2023 11:00:44 -0800 Subject: [PATCH] Solve day 5 --- 05/__main__.py | 14 +++ 05/almanac.py | 263 ++++++++++++++++++++++++++++++++++++++++++++++ 05/puzzle.py | 82 +++++++++++++++ 05/puzzle_test.py | 75 +++++++++++++ 4 files changed, 434 insertions(+) create mode 100644 05/__main__.py create mode 100644 05/almanac.py create mode 100644 05/puzzle.py create mode 100644 05/puzzle_test.py diff --git a/05/__main__.py b/05/__main__.py new file mode 100644 index 0000000..d095243 --- /dev/null +++ b/05/__main__.py @@ -0,0 +1,14 @@ +from pathlib import Path + +from almanac import maps, seeds +from puzzle import solve_pt_1, solve_pt_2 + + +def main(): + print("Lowest Location Numbers:") + print("Part 1 -", solve_pt_1(seeds, maps)) + print("Part 2 -", solve_pt_2(seeds, maps), " " * 30) + + +if __name__ == "__main__": + main() diff --git a/05/almanac.py b/05/almanac.py new file mode 100644 index 0000000..3fd9488 --- /dev/null +++ b/05/almanac.py @@ -0,0 +1,263 @@ +from puzzle import RangeConversion + +seeds = [ + 1187290020, + 247767461, + 40283135, + 64738286, + 2044483296, + 66221787, + 1777809491, + 103070898, + 108732160, + 261552692, + 3810626561, + 257826205, + 3045614911, + 65672948, + 744199732, + 300163578, + 3438684365, + 82800966, + 2808575117, + 229295075, +] + +maps = [ + [ + RangeConversion(1716002126, 3982609232, 32819234), + RangeConversion(527777042, 1448723593, 108905538), + RangeConversion(3097613512, 2185535945, 24556299), + RangeConversion(3351444381, 4015428466, 144436121), + RangeConversion(3331711186, 3196645623, 19733195), + RangeConversion(169931418, 1078390710, 353970858), + RangeConversion(1621489177, 1746859318, 67938624), + RangeConversion(1904740745, 2514777285, 180582308), + RangeConversion(2435282992, 2210092244, 85514440), + RangeConversion(1398165946, 286288423, 41146536), + RangeConversion(523902276, 1432361568, 3874766), + RangeConversion(1903021413, 3980889900, 1719332), + RangeConversion(1689427801, 2875575735, 26574325), + RangeConversion(2085323053, 2092073852, 27802380), + RangeConversion(1244196171, 922461291, 37612770), + RangeConversion(3834107486, 3846963083, 28702903), + RangeConversion(636682580, 327434959, 595026332), + RangeConversion(3207795548, 2695359593, 118500381), + RangeConversion(3035897751, 2813859974, 61715761), + RangeConversion(3326295929, 3875665986, 5415257), + RangeConversion(3122169811, 4209341559, 85625737), + RangeConversion(3954618410, 1867878056, 11806468), + RangeConversion(3027897115, 3881081243, 8000636), + RangeConversion(74621536, 159718198, 10213220), + RangeConversion(4091795019, 1879684524, 56951870), + RangeConversion(4148746889, 1995330417, 96743435), + RangeConversion(84834756, 0, 85096662), + RangeConversion(3800092500, 2331115565, 34014986), + RangeConversion(1281808941, 169931418, 116357005), + RangeConversion(4245490324, 4159864587, 49476972), + RangeConversion(2609257929, 3467510702, 57294822), + RangeConversion(2113125433, 3524805524, 322157559), + RangeConversion(2520797432, 1936636394, 58694023), + RangeConversion(3495880502, 1814797942, 53080114), + RangeConversion(1748821360, 2119876232, 65659713), + RangeConversion(0, 85096662, 74621536), + RangeConversion(3548960616, 3216378818, 251131884), + RangeConversion(2931281840, 2418162010, 96615275), + RangeConversion(1439312482, 960074061, 118316649), + RangeConversion(2674851505, 2910448814, 256430335), + RangeConversion(2666552751, 2902150060, 8298754), + RangeConversion(3966424878, 1621489177, 125370141), + RangeConversion(1231708912, 1436236334, 12487259), + RangeConversion(3862810389, 3889081879, 91808021), + RangeConversion(2579491455, 3166879149, 29766474), + RangeConversion(1867512532, 2295606684, 35508881), + RangeConversion(1814481073, 2365130551, 53031459), + ], + [ + RangeConversion(900001914, 416463108, 281254528), + RangeConversion(0, 126604924, 281385177), + RangeConversion(281385177, 1157253669, 618616737), + RangeConversion(1885448579, 1775870406, 139515090), + RangeConversion(3016033145, 2662884952, 103067725), + RangeConversion(1189729449, 1110523399, 46730270), + RangeConversion(2123796167, 0, 126604924), + RangeConversion(2809716281, 3293179505, 206316864), + RangeConversion(3394722305, 3499496369, 373018163), + RangeConversion(2250401091, 1915385496, 17843034), + RangeConversion(2387263517, 3872514532, 299008639), + RangeConversion(1181256442, 407990101, 8473007), + RangeConversion(2686272156, 4171523171, 123444125), + RangeConversion(3767740468, 2765952677, 527226828), + RangeConversion(1236459719, 1933228530, 335015595), + RangeConversion(1571475314, 697717636, 313973265), + RangeConversion(2024963669, 1011690901, 98832498), + RangeConversion(3119100870, 2387263517, 275621435), + ], + [ + RangeConversion(2043262733, 3156005317, 240398158), + RangeConversion(740161853, 3396403475, 396633652), + RangeConversion(2283660891, 728762031, 158542508), + RangeConversion(338820086, 530011363, 198750668), + RangeConversion(2442203399, 1391771783, 889292891), + RangeConversion(3734522375, 237378927, 58514752), + RangeConversion(3331496290, 988745698, 403026085), + RangeConversion(1136795505, 2814613159, 341392158), + RangeConversion(1809145049, 295893679, 234117684), + RangeConversion(537570754, 2281064674, 202591099), + RangeConversion(1478187663, 2483655773, 330957386), + RangeConversion(237378927, 887304539, 101441159), + ], + [ + RangeConversion(3659569782, 1525449239, 315716712), + RangeConversion(3476299666, 1083068766, 183270116), + RangeConversion(3231355346, 2188139141, 105510824), + RangeConversion(4174005670, 3640676221, 26006855), + RangeConversion(2033660875, 1999740193, 45748640), + RangeConversion(4057070245, 1972906150, 26834043), + RangeConversion(972390863, 634517173, 12741770), + RangeConversion(2909470443, 3992972439, 35114066), + RangeConversion(3371367762, 3517719799, 18082344), + RangeConversion(1577969948, 2765252679, 71346084), + RangeConversion(1355403194, 769026051, 222566754), + RangeConversion(1025652593, 3705699048, 26412059), + RangeConversion(3389450106, 2756144754, 7720673), + RangeConversion(519325900, 2956875516, 263858379), + RangeConversion(3176461571, 2056589398, 54893775), + RangeConversion(1649316032, 3732111107, 254481047), + RangeConversion(4005461865, 3535802143, 40507815), + RangeConversion(868266049, 3220733895, 65108842), + RangeConversion(2323504821, 1300840474, 47494425), + RangeConversion(4045969680, 2045488833, 11100565), + RangeConversion(4083904288, 2939503515, 17372001), + RangeConversion(933374891, 3666683076, 39015972), + RangeConversion(2944584509, 3285842737, 231877062), + RangeConversion(2603233578, 442821495, 41827275), + RangeConversion(3403912268, 4028086505, 49362804), + RangeConversion(860498512, 2763865427, 1387252), + RangeConversion(4200012525, 347866724, 94954771), + RangeConversion(387585701, 1841165951, 131740199), + RangeConversion(2435365509, 2293649965, 167868069), + RangeConversion(2170885476, 733737763, 35288288), + RangeConversion(2645060853, 484648770, 149868403), + RangeConversion(1903797079, 1509336552, 16112687), + RangeConversion(3453275072, 2733120160, 23024594), + RangeConversion(2370999246, 3576309958, 64366263), + RangeConversion(3975286494, 2909328144, 30175371), + RangeConversion(2206173764, 2615789103, 117331057), + RangeConversion(226584048, 1348334899, 161001653), + RangeConversion(3397170779, 226584048, 6741489), + RangeConversion(2079409515, 991592805, 91475961), + RangeConversion(3336866170, 1266338882, 34501592), + RangeConversion(4101276289, 2836598763, 72729381), + RangeConversion(1919909766, 2502037994, 113751109), + RangeConversion(1268924374, 647258943, 86478820), + RangeConversion(861885764, 3986592154, 6380285), + RangeConversion(783842544, 2111483173, 76655968), + RangeConversion(1052064652, 4077449309, 216859722), + RangeConversion(783184279, 4294309031, 658265), + RangeConversion(985132633, 2461518034, 40519960), + RangeConversion(2794929256, 233325537, 114541187), + ], + [ + RangeConversion(3539333023, 2561430684, 132087009), + RangeConversion(3698501184, 4084205096, 109385247), + RangeConversion(3378310404, 4253495312, 1341714), + RangeConversion(3379652118, 4281918178, 4529732), + RangeConversion(3384181850, 2314593178, 64260938), + RangeConversion(2785407303, 2874819838, 586422865), + RangeConversion(25112293, 160761603, 162822339), + RangeConversion(770938901, 1968882287, 168925624), + RangeConversion(2705922239, 2697964303, 79485064), + RangeConversion(512617614, 0, 160761603), + RangeConversion(3671420032, 4254837026, 27081152), + RangeConversion(673379217, 387568324, 33575302), + RangeConversion(706954519, 323583942, 63984382), + RangeConversion(1047197914, 1580976419, 38110593), + RangeConversion(0, 1619087012, 25112293), + RangeConversion(2297003964, 4193590343, 8717958), + RangeConversion(187934632, 1644199305, 324682982), + RangeConversion(4277378082, 2297003964, 17589214), + RangeConversion(4227273431, 2511326033, 50104651), + RangeConversion(939864525, 1133158202, 107333389), + RangeConversion(2692956243, 4286447910, 8519386), + RangeConversion(3448442788, 2777449367, 90890235), + RangeConversion(1085308507, 1240491591, 340484828), + RangeConversion(1425793335, 421143626, 712014576), + RangeConversion(3371830168, 2868339602, 6480236), + RangeConversion(2701475629, 2693517693, 4446610), + RangeConversion(2305721922, 4202308301, 51187011), + RangeConversion(3807886431, 2378854116, 132471917), + RangeConversion(3940358348, 3797290013, 286915083), + RangeConversion(2356908933, 3461242703, 336047310), + ], + [ + RangeConversion(4269649447, 2393649810, 25317849), + RangeConversion(2624622018, 1500892381, 293269560), + RangeConversion(3784916401, 3939293015, 342497756), + RangeConversion(2265977332, 3395782296, 159502803), + RangeConversion(1831892433, 2656443697, 262271473), + RangeConversion(3165592569, 2418967659, 50349192), + RangeConversion(2917891578, 2918715170, 32249137), + RangeConversion(3152416044, 4281790771, 13176525), + RangeConversion(2425480135, 3196640413, 199141883), + RangeConversion(0, 541439970, 311711929), + RangeConversion(1823766565, 1492766513, 8125868), + RangeConversion(990491492, 84547230, 456892740), + RangeConversion(311711929, 0, 84547230), + RangeConversion(2950140715, 2469316851, 187126846), + RangeConversion(4127414157, 2950964307, 142235290), + RangeConversion(396259159, 853151899, 594232333), + RangeConversion(3215941761, 3555285099, 21604105), + RangeConversion(2094163906, 2206687901, 171813426), + RangeConversion(3703390493, 2125161993, 81525908), + RangeConversion(3340986682, 3576889204, 362403811), + RangeConversion(3137267561, 2378501327, 15148483), + RangeConversion(3237545866, 3093199597, 103440816), + RangeConversion(1492766513, 1794161941, 331000052), + ], + [ + RangeConversion(697523568, 606382276, 38912139), + RangeConversion(3022503077, 2608306075, 46906919), + RangeConversion(3230895262, 2302415707, 63420952), + RangeConversion(736435707, 183964832, 131646187), + RangeConversion(3507404317, 3731540503, 41469688), + RangeConversion(1013393252, 490470958, 115911318), + RangeConversion(270068585, 0, 183964832), + RangeConversion(3316292469, 3480652736, 191111848), + RangeConversion(3800980345, 2893452190, 286098783), + RangeConversion(2373021543, 3773010191, 190266), + RangeConversion(3548874005, 3993865558, 91972017), + RangeConversion(0, 645294415, 270068585), + RangeConversion(2373211809, 4094117141, 87252238), + RangeConversion(2856512732, 2695675634, 165990345), + RangeConversion(2460464047, 4085837575, 8279566), + RangeConversion(619680743, 351018435, 72089891), + RangeConversion(3069409996, 2365836659, 129699055), + RangeConversion(3640846022, 3813115875, 53385677), + RangeConversion(2729080766, 2240595460, 61820247), + RangeConversion(1554011298, 1459823647, 179489523), + RangeConversion(1884012518, 2495535714, 112770361), + RangeConversion(2468743613, 3363193697, 35293527), + RangeConversion(3199109051, 2861665979, 31786211), + RangeConversion(454033417, 1031019876, 98284694), + RangeConversion(1733500821, 1302115255, 150511697), + RangeConversion(1431930368, 3773200457, 39915418), + RangeConversion(691770634, 930855093, 5752934), + RangeConversion(3694231699, 3671764584, 59775919), + RangeConversion(1302115255, 2655212994, 40462640), + RangeConversion(868081894, 936608027, 94411849), + RangeConversion(4087079128, 4181369379, 113597917), + RangeConversion(1471845786, 3398487224, 82165512), + RangeConversion(997901159, 915363000, 15492093), + RangeConversion(2504037140, 2015551834, 225043626), + RangeConversion(3761204313, 3866501552, 39776032), + RangeConversion(552318111, 423108326, 67362632), + RangeConversion(2790901013, 3906277584, 65611719), + RangeConversion(3294316214, 3971889303, 21976255), + RangeConversion(962493743, 315611019, 35407416), + RangeConversion(4200677045, 3268903446, 94290251), + RangeConversion(3754007618, 1452626952, 7196695), + RangeConversion(1996782879, 1639313170, 376238664), + RangeConversion(1342577895, 3179550973, 89352473), + ], +] diff --git a/05/puzzle.py b/05/puzzle.py new file mode 100644 index 0000000..b2b9b56 --- /dev/null +++ b/05/puzzle.py @@ -0,0 +1,82 @@ +from itertools import count +from math import inf +from typing import Iterable, NamedTuple + + +class RangeConversion(NamedTuple): + destination_start: int + source_start: int + range_length: int + + def resolve(self, source: int) -> int | None: + if self.source_start <= source < self.source_start + self.range_length: + return self.destination_start + source - self.source_start + return None + + def reverse_resolve(self, destination: int) -> int | None: + if ( + self.destination_start + <= destination + < self.destination_start + self.range_length + ): + return self.source_start + destination - self.destination_start + return None + + +class SeedRange(NamedTuple): + start: int + length: int + + def includes(self, seed: int): + return self.start <= seed < self.start + self.length + + +def resolve_destination(source: int, map: list[RangeConversion]) -> int: + for range_conversion in map: + if destination := range_conversion.resolve(source): + return destination + return source + + +def resolve_source(destination: int, map: list[RangeConversion]) -> int: + for range_conversion in map: + if source := range_conversion.reverse_resolve(destination): + return source + return destination + + +def solve_pt_1(seeds: list[int], maps: list[list[RangeConversion]]) -> int: + minimum_location = 9_999_999_999_999 + for seed in seeds: + result = seed + for map in maps: + result = resolve_destination(result, map) + minimum_location = min(minimum_location, result) + return minimum_location + + +def solve_pt_2(seeds: list[int], maps: list[list[RangeConversion]]) -> int: + seed_ranges = [ + SeedRange(start, length) for start, length in zip(seeds[::2], seeds[1::2]) + ] + + for location in count(): + if location % 100_000 == 0: + print( + f"Part 2 - [checking {location:,} through {location + 99_999:,}]", + end="\r", + ) + + result = location + for map in reversed(maps): + result = resolve_source(result, map) + + seed_candidate = result + for map in maps: + result = resolve_destination(result, map) + + for seed_range in seed_ranges: + if seed_range.includes(seed_candidate): + return location + + raise NotImplementedError() diff --git a/05/puzzle_test.py b/05/puzzle_test.py new file mode 100644 index 0000000..835dc5f --- /dev/null +++ b/05/puzzle_test.py @@ -0,0 +1,75 @@ +from puzzle import (RangeConversion, resolve_destination, resolve_source, + solve_pt_1, solve_pt_2) + +mock_seeds = [79, 14, 55, 13] +mock_destinations = [81, 14, 57, 13] +mock_maps = [ + [ + RangeConversion(50, 98, 2), + RangeConversion(52, 50, 48), + ], + [ + RangeConversion(0, 15, 37), + RangeConversion(37, 52, 2), + RangeConversion(39, 0, 15), + ], + [ + RangeConversion(49, 53, 8), + RangeConversion(0, 11, 42), + RangeConversion(42, 0, 7), + RangeConversion(57, 7, 4), + ], + [ + RangeConversion(88, 18, 7), + RangeConversion(18, 25, 70), + ], + [ + RangeConversion(45, 77, 23), + RangeConversion(81, 45, 19), + RangeConversion(68, 64, 13), + ], + [ + RangeConversion(0, 69, 1), + RangeConversion(1, 0, 69), + ], + [ + RangeConversion(60, 56, 37), + RangeConversion(56, 93, 4), + ], +] + + +def test_range_convevrsion_resolve(): + r = mock_maps[0][0] + assert r.resolve(97) is None + assert r.resolve(98) == 50 + assert r.resolve(99) == 51 + assert r.resolve(100) is None + + +def test_range_conversion_reverse_resolve(): + r = mock_maps[0][0] + assert r.reverse_resolve(49) is None + assert r.reverse_resolve(50) == 98 + assert r.reverse_resolve(51) == 99 + assert r.reverse_resolve(52) is None + + +def test_resolve_destination(): + assert [ + resolve_destination(seed, mock_maps[0]) for seed in mock_seeds + ] == mock_destinations + + +def test_resolve_source(): + assert [ + resolve_source(dest, mock_maps[0]) for dest in mock_destinations + ] == mock_seeds + + +def test_solve_1(): + assert solve_pt_1(mock_seeds, mock_maps) == 35 + + +def test_solve_2(): + assert solve_pt_2(mock_seeds, mock_maps) == 46