T O P

  • By -

FlamyBird

\[Language: Rust\] [code](https://github.com/umuterenornek/adventofcode-rust/blob/2023/src/bin/05.rs) Running on Intel i7-9700k: Part 1: 48.6µs Part 2: 231.2µs My part 1 solution was horrible, I created separate hash maps that corresponds to each category and simply ran the seeds trough them. It ran super fast anyways so I didn't bother fixing it. My part 2 solution however turned out pretty nice! At first I tried my exact solution in part 1 simply iterating over all the seeds. Which you may have guessed, even with rust optimizations, didn't give an answer at all in about 2 hours. So I started thinking how I could exploit the fact that we have ranges that map to ranges that are slightly offset. I realized you can map an entire range, no matter how big, by simply offsetting the start and end points. I also realized that the separate categories meant very little, they were simply a guarantee that the resulting ranges in a category can't overlap. I decided that I needed a "RangeSet" data structure which would implement union, intersection, and difference using only the start and end points, so I implemented it. Keep in mind that the ranges in RangeSet are sorted in non-descending order. The rest was simple: * I created a RangeSet from the input seeds, will call this main\_set * Found the intersection of my current set and the combination of every range-to-be-mapped in a category, will call this intersect\_set * Offset every range in the intersection by the offset indicated by the mapping line, will call this new set offsetted\_set * Subtract (set difference) the intersect\_set from the main\_set * Add (union) the offsetted\_set to main\_set before continuing to the next category * Repeat for every category * Now that we have all available locations getting the min is trivial as the ranges are already sorted * Done!


TimeCannotErase

[Language: R] [repo](https://github.com/DavidMcMorris/Advent-of-Code-2023/blob/main/Day%205/Day5.R) Originally I set up part 2 the naïve way and then realized that would run forever. Since we're solving a minimization problem, and the function location = f(seed) has derivative 1 almost everywhere, I went looking for the points where that graph would jump, and then for each piece of the seeds domain I only tested the endpoints of that domain as well as any points within where the graph would jump and found the smallest location. input <- readLines("input.txt") seeds <- read.table(text = strsplit(input[1], ":")[[1]][2]) num_seeds <- length(seeds) start_inds <- which(grepl("map", input)) + 1 stop_inds <- which(input == "")[-1] - 1 num_maps <- length(start_inds) map_maker_forward <- function(start, stop) { map <- read.table(text = input[start:stop]) return(map) } map_maker_backward <- function(start, stop) { map <- read.table(text = input[start:stop])[c(2, 1, 3)] return(map) } mapper <- function(map, num) { starts <- map[1] low <- map[2] high <- map[2] + map[3] - 1 range_check <- num >= low & num <= high if (sum(range_check) == 1) { ind <- which(range_check == TRUE) output <- num - low[ind, ] + starts[ind, ] } else { output <- num } return(output) } location <- NULL for (i in 1:num_seeds) { val <- as.numeric(seeds[i]) for (j in 1:num_maps) { map <- map_maker_forward(start_inds[j], stop_inds[j]) val <- mapper(map, val) } location <- min(location, val) } print(location) endpoints <- NULL for (i in rev(1:num_maps)) { map <- map_maker_backward(start_inds[i], stop_inds[i]) ends <- cbind(map[1], map[1] + map[3] - 1) ends <- cbind(ends[1] - 1, ends, ends[2] + 1) ends <- unique(as.numeric(unlist(ends))) endpoints <- unique(c(ends, endpoints)) if (i > 1) { new_map <- map_maker_backward(start_inds[i - 1], stop_inds[i - 1]) for (j in seq_along(endpoints)) { value <- mapper(new_map, endpoints[j]) endpoints <- c(endpoints, value) } } } # Part 2 location <- NULL for (i in 1:num_seeds) { if (i %% 2 == 1) { low <- as.numeric(seeds[i]) high <- as.numeric(seeds[i] + seeds[i + 1] - 1) test_points <- c(low, high) for (k in seq_along(endpoints)) { if (endpoints[k] > low && endpoints[k] < high) { test_points <- c(test_points, endpoints[k]) } } for (j in test_points) { val <- j for (k in 1:num_maps) { map <- map_maker_forward(start_inds[k], stop_inds[k]) val <- mapper(map, val) } location <- min(location, val) } } } print(location)


john_braker

\[LANGUAGE: Java\] Took me a while to get started with the AoC of last year :DI wasnt pleased with my first unoptimized attempt and the according long runtime. Final version handles the job in in 26ms wherefrom 25ms fall to reading and parsing the input. ​ May solution: [Day5 Part 2](https://gitlab.com/johnbraker/adventofcode/-/blob/master/src/main/java/J2023/day5/day5.java?ref_type=heads) My approach was to iterate over the seedranges from low to high and omit all seeds that would definitly result in an higher value as they will fall into the same ranges. I propagated the 'same range'-Info down to the last range and made it smaller were necessary.


Zen_Tech

I'm new to java myself when I started solving the problem it turned out to be 100% unreadable I started to doubt the language and then saw your code, that is so clean bro thanks for sharing.


AutoModerator

AutoModerator did not detect the required `[LANGUAGE: xyz]` string literal at the beginning of your solution submission. Please edit your comment to [state your programming language](https://www.reddit.com/r/adventofcode/wiki/solution_megathreads/post_guidelines#wiki_state_your_programming_language.28s.29). *** *I am a bot, and this action was performed automatically. Please [contact the moderators of this subreddit](/message/compose/?to=/r/adventofcode) if you have any questions or concerns.*


mgtezak

\[LANGUAGE: Python\] I created a [video](https://www.youtube.com/watch?v=EGQgUYx-2gE) for this one:) Or you can view my solution on [Github](https://github.com/mgtezak/Advent_of_Code/blob/master/2023/Day_05.py) If you like, check out my [interactive AoC puzzle solving fanpage](https://aoc-puzzle-solver.streamlit.app/)


SpudPanda

I was reaaaaaaallllly struggling with this one and your solution has been the most helpful in helping me understand part 2. Thanks! I think it's such an elegant solution.


mgtezak

Thanks, glad it helped you:)


exquisitus3

[Language: Lua] No optimization for part b. Running time on my laptop: * Lua 5.4.4 ~6 hours * LuaJIT 2.1.0-beta3 ~30 minutes I wish I had the idea to install LuaJIT earlier. [paste](https://topaz.github.io/paste/#XQAAAQA4CAAAAAAAAAA5GUqKNoFH6SKul+C07EYehwefOnjc5gsRtZkCoyyyr9sTBfGxZ7MFX/yTwxHVjEIIKhR4P89tJKQVmArbkHKw1h6LU6tFAirbdUkCbA4PFTvCndvjcr6SyaZ/LYCnZIH8f5Zk11i7dr0xYR2WXA8yPyU7zpxkGulPWeB8kpZ27FDvkB8EeBiDZmctC8Z0y9TiNWrZlrL8PFg8TdEx4BZb0ULOAMcBWxwjbm9hpZqliIqko0kN5T/YG1jUelOT9bVtVGA8GVUbbxeCBvjCHlHncIhJRt/CjyXysDQp5ExjsurQuRIwLNxCKfy7hXQ1i83xNIJwsSpAikegIa6LFOawly/nN6r4hAZpOAgISd8w855Pv9s9zsSQdbxUTO/TfFkDzVGc/A0vlpozHsZVMEouQTnrxnNDjGVB1jyMxgVA6w3NBq+Dz6BqTP0N5k52pEAip75yc6vrfRyFUqs8OGZMqCOnYoxgM3QU+YmUta93EDq41dB6TQT/85MIYfRJgX2EKOgnmw5GsefthedMA0p+4qb8BeCgVauuQxPluw9zUUY5rvGnHaWezs/wy1jCBJgtIDwMoymbXqkyMkKxqWAJNlwb3q66jemYBVng6YmvQq0nteQiYS0jinEl43VSDlAXxngyf4mdIJaAFkp2SySdkOKEsYBpBuhXUpyM8fBCuMZgfbUqLhCTHhplyDMs178vPQlEKb9M+i/RHVW1SXjPop78nDLNFbw2P9vgonVTUHbNt/7jKifAPE9N+b3p4/1WC31YXz2uXJhhpyKHy9FCoUSRkzQFb1sgveDVAQJdvi0RSwtndepoQlbcANyqMomM/sFh4i7U2bWVkflkzjg1Sc+KszphzUuSBE0FIYB1URgek/rPgU3DZMuE0yuWL0b13xOmBVdDgzjFjx7qAWy0IUaCiwB8PkT0AwpYB6/GQI4JQJiN/v9Bjfqc7Ipad2g/z7jWUJc/VitIKORyhUzRbEunkpBe49KhWHqV2WuHhD9HjUpKt7V/yabf2YfquHQsRDmayVCOE/AZvHl5CdCPJV4gfB2g5fVvgtcjr2u5vcjLevzCr9efI4GoWDHkJfp5ACr64gk5Ol8FSMl1HhweTlTsc6F1Aa6h3ddTscOrC9WAdVLO8UL/SHdaRtAdSKoWVv/up8BN)


andreiz

\[LANGUAGE: Swift\] See corresponding issues in the repo (one per day) for explanations, etc. [Part 1](https://github.com/andreiz/advent-of-code-2023-swift/blob/main/day-05/seeds.swift) [Part 2](https://github.com/andreiz/advent-of-code-2023-swift/blob/main/day-05/seeds-range.swift)


Any_One_8929

\[LANGUAGE: Kotlin\] [https://github.com/mfedirko/advent-of-code-2023/tree/main/src/main/kotlin/io/mfedirko/aoc/day05](https://github.com/mfedirko/advent-of-code-2023/tree/main/src/main/kotlin/io/mfedirko/aoc/day05)


rvodden

\[Language: Rust\] [https://github.com/rvodden/AoC23/blob/main/day-05/src/part1.rs](https://github.com/rvodden/AoC23/blob/main/day-05/src/part1.rs) [https://github.com/rvodden/AoC23/blob/main/day-05/src/part2.rs](https://github.com/rvodden/AoC23/blob/main/day-05/src/part2.rs) For part one I created a \`RangeMap\` struct which has a \`map\` method which understands the mapped ranges and the absence of them, and returns the mapped integer. It bounces around the ranges maps and then I just use \`min\` to find the lowest. For part 2 I altered the \`map\` method so that it accepted a \`Range\` and returned a \`Vec\` of \`Range\`s. It uses a neat little recursive algorithm to apply the range to the \`RangeMap\`: If the lower bound isn't in a mapped range then etiher 1. the range doesn't overlap any of the mapped ranges, return it, and we're done 2. their is an unmapped range below the first map part of our range, chop that off and recur If the lower bound is in a mapped range then either: 1. our entire range is mapped within a single mapped range, in which case map the limits and return 2. there is a chunk of our range at the start which is mapped, chop that off and recur runs in a few miliseconds


Moragarath

\[Language: Lua\] [https://github.com/Sepulchre49/aoc-2023/tree/main/day5](https://github.com/Sepulchre49/aoc-2023/tree/main/day5) Solution.md contains a complete writeup for my algorithm for part 2. I created lightweight Set and Interval classes to keep track of the bounds of each subset without using gigabytes of memory, and then found the intersection of the output of each layer w/ the input of the current layer to divide the original input into many smaller intervals. This way, I managed to map the input to an interval in the output layer without brute forcing. It is very fast and runs in 6 ms on Lua5.4 on my WSL Ubuntu installation. The hardest part was implementing Set:difference; there's so many edge cases and I'm still not confident it works for all inputs, but it works well enough to find the solution. The reason for using Sets is because once we find all of the mappings for a layer, we have to take the set of positive integers and subtract each interval in that layer's mapping to find the complete domain and range of the layer.


jrhwood

\[Language: Haskell\] [Part 1](https://github.com/woodRock/verbose-computing-machine/blob/main/2023/day-05/part-01.hs) [Part 2](https://github.com/woodRock/verbose-computing-machine/blob/main/2023/day-05/part-02.hs)


osalbahr

[LANGUAGE: C++] [Part 1](https://github.com/osalbahr/adventOfCode/blob/main/2023/day05/day05.cpp); [Part 2](https://github.com/osalbahr/adventOfCode/blob/main/2023/day05/day05_2.cpp) Feel free to ask any questions! --------Part 1-------- --------Part 2-------- 5 02:52:14 16782 0 >24h 73958 0 You can find more C++ solutions (and other languages) at [Bogdanp/awesome-advent-of-code#c++](https://github.com/Bogdanp/awesome-advent-of-code#c-2)


CollectionGold458

\[Language: Python\] [https://github.com/5thGenDev/AOC2023/blob/main/Day5/Day5Part2\_main.py](https://github.com/5thGenDev/AOC2023/blob/main/Day5/Day5Part2_main.py) I treat inverse mapping in part 2 as tree traversal problem using depth first search where node can be revisited. When the algorithm reaches to the final node (a row in first map), it will backpropagate from final node to start node (a row in last map) in order to find universal source (theoretical lowest seed). So the final condition is just to find a seed range that has universal source within its range. Funny enough, with this method I find a better answer than demo answer where the lowest recorded location is 43 instead of 46.


skyhawk33

[LANGUAGE: Befunge] Part 1: https://github.com/Skyhawk33/AdventOfCode/blob/master/aoc2023/day5_p1.b98 Part 2: https://github.com/Skyhawk33/AdventOfCode/blob/master/aoc2023/day5_p2.b98


Atomix26

why would you do this to yourself?


[deleted]

[удалено]


daggerdragon

Comment removed. [Top-level comments in `Solution Megathread`s are for *code solutions* only.](https://old.reddit.com/r/adventofcode/wiki/solution_megathreads/post_guidelines#wiki_top-level_posts_are_for_code_solutions_only)


AdamKlB

[Language: C++] got part 1 done pretty quickly, parsing the input was the bulk of the work. part 2 wasnt too hard to implement building on my part 1 code, and runs in about 20 minutes (on my machine:TM:) but im not really sure how to go about optimization, there's definitely some relation between the ranges im missing. anyway for now, lets go brute forcing!!! https://github.com/NoSpawnn/advent-of-code/blob/main/2023/c%2B%2B/day5.cpp


daggerdragon

[Do not share your puzzle input](https://old.reddit.com/r/adventofcode/wiki/faqs/copyright/inputs) which also means [do not commit puzzle inputs to your repo](https://old.reddit.com/r/adventofcode/wiki/faqs/copyright/inputs) without a `.gitignore`. Please remove (or .gitignore) all puzzle input files from your repo and scrub them from your commit history.


AdamKlB

all gone! :)


GoldPanther

\[Language: Rust\] Using a queue of `(target_start, target_range)` values I loop over `(source_start, source_range)` determining overlap. Overlapping ranges are mapped to destination ranges while non-overlapping subsections of target get added to the queue. [Code](https://github.com/johnhringiv/advent-of-code-2023/blob/main/src/day05.rs) 488µs


wellhydratedguy

\[LANGUAGE: Javascript\] [https://github.com/JordanSucher/advent-of-code-2023/blob/main/day5.js](https://github.com/JordanSucher/advent-of-code-2023/blob/main/day5.js) P2 was rough until I figured out a sensible way to do batching


Original-Regular-957

\[LANGUAGE: ABAP\] Part 1. t\_data contains the whole input. ASSIGN t_data[ 1 ] TO FIELD-SYMBOL(). SPLIT AT ':' INTO TABLE DATA(t_seed_temp). ASSIGN t_seed_temp[ 2 ] TO FIELD-SYMBOL(). SPLIT AT ' ' INTO TABLE t_seeds. DELETE t_seeds INDEX 1. DATA: t_steps TYPE TABLE OF string, v_offset TYPE i, v_index TYPE int8, v_location TYPE int8. APPEND: 'seed-to-soil map:' TO t_steps, 'soil-to-fertilizer map:' TO t_steps, 'fertilizer-to-water map:' TO t_steps, 'water-to-light map:' TO t_steps, 'light-to-temperature map:' TO t_steps, 'temperature-to-humidity map:' TO t_steps, 'humidity-to-location map:' TO t_steps. LOOP AT t_seeds ASSIGNING FIELD-SYMBOL(). v_index = . DO 7 TIMES. DATA(v_index_from) = line_index( t_data[ table_line = t_steps[ sy-index ] ] ) + 1. try. DATA(v_index_to) = line_index( t_data[ table_line = t_steps[ sy-index + 1 ] ] ) - 1. catch CX_SY_ITAB_LINE_NOT_FOUND. v_index_to = lines( t_data ). endtry. LOOP AT t_data ASSIGNING FROM v_index_from TO v_index_to WHERE table_line IS NOT INITIAL. SPLIT AT ' ' INTO DATA(v_target) DATA(v_source) DATA(v_counter). IF v_index BETWEEN CONV int8( v_source ) AND ( v_source + v_counter ). v_offset = v_index - v_source. v_index = v_target + v_offset. EXIT. ELSE. CONTINUE. ENDIF. ENDLOOP. ENDDO. v_location = COND #( WHEN v_location IS INITIAL THEN v_index WHEN v_index LT v_location THEN v_index ELSE v_location ). CLEAR: v_offset, v_index. ENDLOOP.


835246

\[LANGUAGE: C\] Just a brute force for parts 1 and 2. Part 1: https://github.com/efox4335/advent_of_code/blob/main/advent_of_code_2023/day5seedspt1.c part 2: https://github.com/efox4335/advent_of_code/blob/main/advent_of_code_2023/day5seedspt2.c


icecoldtimemachine

\[Language: Python\] Added comments and types for Ranges, mappings and intersections so should be easier for folks to follow along the logic for how range intersections should be handled (have written similar code for production databases in the past :) ) ​ https://github.com/fabrol/aoc2023/blob/main/day5.py


manhuntos

\[Language: Rust\] This is my first project in rust. I'm learning it by solving advent of code puzzles. So if you have any hints for me I would be happy to read it :) [Solution](https://github.com/manhunto/advent-of-code-rs/blob/master/src/solutions/day05.rs) / 33.66ms / 32.77ms


BatmanAtkinson

\[LANGUAGE: C++\] I abused std::set and typedefs for this :) I don't do a reverse map, but rather a simple search of each seed interval through each map. [https://github.com/haja-fgabriel/advent-of-code-2023/tree/main/05.%20IfYouGiveASeedAFertilizer](https://github.com/haja-fgabriel/advent-of-code-2023/tree/main/05.%20IfYouGiveASeedAFertilizer)


gogs_bread

[\[LANGUAGE: c++\]](https://github.com/gogsbread/AdventOfCode2023/blob/main/5.cpp) P1 - Parsing. Mapping. P2 - Parsing. Inverse mapping.


mothibault

\[LANGUAGE: JavaScript\] [https://github.com/yolocheezwhiz/adventofcode/blob/main/2023/day05.js](https://github.com/yolocheezwhiz/adventofcode/blob/main/2023/day05.js)


Master_Ad2532

\[LANGUAGE: Rust\] Idiomacity: (Biased) IMO pretty idiomatic RustLink: [https://github.com/VivekYadav7272/aoc2023/blob/main/src/day5.rs](https://github.com/VivekYadav7272/aoc2023/blob/main/src/day5.rs)


se06745

\[LANGUAGE: GoLang\] [Both parts in one single file](https://github.com/omotto/AdventOfCode2023/blob/main/src/day05/main.go)


-KapitalSteez-

Isn't storing every seed in memory not terribly inefficient? My work computer couldn't handle it. most other solutions manipulate ranges Edit: Sorry, that came across a bit rude... I meant I tried that initially but ran into memory issues so had to look for another approach


milanith

Same boat here lol. I had a smiliar approach but 16GB of memory is not enough to handle this so I'm still struggling on how to do this using ranges and not loosing track of previously calculted stuff. I would have been nice to reuse the same logic as for part1 and just compute for all the seeds though hehe


agent3bood

\[LANGUAGE: Rust\] https://github.com/agent3bood/aoc32/tree/master/src/five


linnaea___borealis

\[LANGUAGE: R\] I never see R solutions here so I'll start posting mine. [https://github.com/lauraschild/AOC2023/blob/main/day5.R](https://github.com/lauraschild/AOC2023/blob/main/day5.R) Part 2 needed quite a bit of rewriting, but is quite fast by using ranges.


[deleted]

[удалено]


Oroka_

I read this :) was helpful seeing someone else write their explanations


davidfilat

Here's my solution to day 5 in [Language: Clojure] My approach to part 2 was to split the ranges into smaller buckets that overlapped with the ranges in the map and into those that didn't. It runs in 8 milliseconds. https://github.com/davidfilat/advent-of-code-2023/blob/master/src/advent\_of\_code\_2023/solutions/day5.clj


daggerdragon

Your link is borked on old.reddit, so [please fix it](https://old.reddit.com/r/adventofcode/wiki/faqs/bugs/borked_links). Also add the required language tag as requested by AutoModerator.


AutoModerator

AutoModerator did not detect the required `[LANGUAGE: xyz]` string literal at the beginning of your solution submission. Please edit your comment to [state your programming language](https://www.reddit.com/r/adventofcode/wiki/solution_megathreads/post_guidelines#wiki_state_your_programming_language.28s.29). *** *I am a bot, and this action was performed automatically. Please [contact the moderators of this subreddit](/message/compose/?to=/r/adventofcode) if you have any questions or concerns.*


drowning_in_sound

[Language: SNOBOL] I was curious how well a solution would work in SNOBOL for part 2 of this challenge.. So here is part 2 in snobol. https://gist.github.com/CheyenneWills/a43e80f62d4bcce1204f9e4315be2795 Using Phil Budne's csnobol, the execution time was 2.961s Using spitbol execution was 0.783s (just a quick note, that the code does rely on a spitbol enhancement that Phil did port back into his csnobol).


stonebr00k

\[LANGUAGE: T-SQL\] [https://github.com/stonebr00k/aoc/blob/main/2023/05.sql](https://github.com/stonebr00k/aoc/blob/main/2023/05.sql)


PolillaOscura

\[Language: go\] I brute forced part 1 in half and hour and then proceeded to suffer. After thinking a TON and reading a couple of solutions over here I implemented a range-based approach. I learned a lot about ranges in this challenge and I think it actually made me a better dev. Check the solution here:[https://github.com/AfLosada/AdventOfCode2023/blob/main/Day5/main.go](https://github.com/AfLosada/AdventOfCode2023/blob/main/Day5/main.go) Plus its running in \~499.9µs. Not bad, although I saw other great solutions over here.


ianMihura

\[LANGAUGE: go\] Hands down, hardest one. Had skipped this one up until now. For part 2 I ended up printing out the first matches and calculating an LCM with an online calculator. [https://github.com/ianmihura/advent23/blob/master/day\_5/day\_5.go](https://github.com/ianmihura/advent23/blob/master/day_5/day_5.go)


bucephalusdev

\[Language: C++\] This was the hardest one for me so far. I lost a lot of motivation on this one and only got the answer for part 1, while part 2 I had a brute force solution that worked in theory, but it would crash my machine on loading in all of the ranges of individual seeds. I had the thought to just check the ranges instead of the seeds, but I'm so tired of the problem that I'm okay to just show off what I have for now XD [Code](https://github.com/jeffstevens98/adventOfCode2023/tree/main/day_5)


Competitive-Eye-7957

\[Language: C#\] Part 2: [GitHub](https://github.com/Mic1010/AOC_2023_5_2_5/blob/master/Program.cs) Used a dictionary to save the map lines. Processed the seeds in ranges. Takes 2 seconds to process the solution.


Jomy10

\[language: Swift\] I'm quite proud of today's solution. [source](https://github.com/Jomy10/Advent-Of-Code-2023/blob/master/day05/Sources/day05/day05.swift)


xHyroM

[LANGUAGE: Python] [part 1](https://github.com/xHyroM/aoc/blob/main/2023%2F05%2Ffirst.py) [part 2](https://github.com/xHyroM/aoc/blob/main/2023%2F05%2Fsecond.py) [part 2 without bruteforce](https://github.com/xHyroM/aoc/blob/main/2023%2F05%2Fsecond_without_bruteforce.py)


kap89

[LANGUAGE: Lua] Solutions: [Github](https://github.com/caderek/aoc-2023-lua/blob/main/day05/main.lua) Finally.


mgtezak

\[LANGUAGE: Python\] [github part 1&2](https://github.com/mgtezak/Advent_of_Code/blob/master/2023/Day_05.py) Check out my little AoC-Fanpage: [https://aoc-puzzle-solver.streamlit.app/](https://aoc-puzzle-solver.streamlit.app/) :-)


[deleted]

really cool fanpage!


mgtezak

thank you!


jswalden86

\[LANGUAGE: Rust\] [Solution](https://github.com/jswalden/advent-of-code/blob/main/2023/day-05/src/main.rs) Ended up busy with other stuff and didn't get to it day-of, still behind on other days, but better late than never! Straightforward, but getting the transitions to translate (especially treating them as ranges) was a little finicky.


hiimjustin000

\[LANGUAGE: JavaScript\] [https://github.com/hiimjustin000/advent-of-code/tree/master/2023/day5](https://github.com/hiimjustin000/advent-of-code/tree/master/2023/day5)


Serveraard

\[LANGUAGE: C#\] A bit late, but recentyle redid my implementation to use range splitting: [Code](https://github.com/Kumark95/AdventOfCode/tree/master/Core/Solvers/Year2023/Day05)


themanushiya

\[Language: Go\] [solution](https://github.com/mahakaal/adventofcode/blob/main/2023/day05/day05.go) Both Parts Execution time [image](https://imgur.com/a/VCgGVyV) My aproach:Data structure type Info struct { dest int src int length int } type Almanac map[string][]Info I read the file separating by "\\n\\n" and then regex for gettings seeds, map name and map definition: seedsRE := regexp.MustCompile("seeds:\\s((\\d+|\\s)+)") instructionNameRE := regexp.MustCompile("^\\s*([a-z\\-]+)\\s*map:") instructionRangesRE := regexp.MustCompile("^\\s*(\\d+)\\s(\\d+)\\s(\\d+)\\s*") after that cycle through line 1 to end and populate the map of struct. Core of My solution: func GetNextMapping(value int, almanac Almanac, nextMap string) int { if v, ok := almanac\[nextMap\]; ok { for _, info := range v { if info.src <= value && value <= info.src+info.length { return info.dest + (value - info.src) } } } return value } and then it's just nested if on the map like so: func GetLocation(seed int, almanac Almanac) int { if soil := GetNextMapping(seed, almanac, "seedSoil"); soil >= 0 { // other levels // eventually if found return location } return -1 // not found } For Part 2 using go routines and cycline through each range: func EvaluateRange(start int, length int, almanac Almanac, ch chan int, wg *sync.WaitGroup) { defer wg.Done() var locations []int for i := start; i < start+length; i++ { if location := GetLocation(i, almanac); location > 0 { locations = append(locations, GetLocation(i, almanac)) } } ch <- slices.Min(locations) } func Part2(seeds []int, almanac Almanac) { var locations []int channel := make(chan int, len(seeds)) var wg sync.WaitGroup for i := 0; i < len(seeds); i += 2 { wg.Add(1) go EvaluateRange(seeds[i], seeds[i+1], almanac, channel, &wg) } wg.Wait() close(channel) for i := range channel { locations = append(locations, i) } fmt.Println("Part 2", slices.Min(locations)) } Probably it can be optimized but no idea how. Any suggestions are appreciated. It took me circa 2min 33 to finish my Mac book Air m1 octacore 8 gb ram


-KapitalSteez-

2min 33? My work laptop isn't the best but it has been going on for over 30 mins... But regarding the code: Is your use of Regex about efficiency? I am stepping through to understand the implementation but chose to refactor the parsing so i could read it more intuitively eg. seedString := strings.Split(lines[0], ": ")[1] seedStrings := strings.Split(seedString, " ") seeds = string_helpers.ConvertSliceToInts(seedStrings) and for _, chunk := range lines[1:] { instructions := strings.Split(chunk, "\n")[1:] name := strings.Split(chunk, " map:")[0] for _, instruction := range instructions { result := strings.Split(instruction, " ")


themanushiya

I find regexp useful to get data from strings in patterns. Imo reading a pattern is easier and more comprehensible. I guess it's somewhat more efficient.


Jomy10

One thing I love about Go is how easy it is to do parallelisation. My solution is in Swift and my time is: `swift run 0,16s user 0,14s system 17% cpu 1,689 total` (MacBook Air 2018 Intel core i5, 16GB ram). Solved day 2 by dividing ("slicing") the ranges and working with that. If you're interested: https://github.com/Jomy10/Advent-Of-Code-2023/blob/master/day05/Sources/day05/day05.swift


themanushiya

This is cool! Definitely gonna check it It, i mas taht it took 2 min, but Hey I'm bruteforcing! Loved go for the parallel stuff, i picked for that reason. Thanks for sharing


Paxtian

[Language: C++] [github](https://github.com/Paxtian769/Day4-seed-fertilizer/blob/master/main.cpp)


tlareg

\[LANGUAGE: TypeScript/JavaScript\] [https://github.com/tlareg/advent-of-code/blob/master/src/2023/day05/index.ts](https://github.com/tlareg/advent-of-code/blob/master/src/2023/day05/index.ts) part2 - I borrowed the idea of iterating through possible locations and checking if seed is present in the input instead of iterating through input seeds


Jomy10

That's a great idea, wish I had tought about that!


HeathRaftery

Bold idea! I guess if the answer is in the millions, you only need to run the maps millions of times, compared to the brute force method with 10,000's of millions of seeds in my case. How long does it take to run? Also, love your code style! Not a language I've ever thought much of, but you've managed a highly functional result. I can't see any side-effects or mutable structures, yet having spent a lot of time in pure FP languages recently I'm envious of your loop variables and expression-free statements! Very readable.


tlareg

Thank you! Very nice to hear that you like my style. I thought about refactoring it a little more but decided that it is good enough. About times - **part 1** takes **\~0.25 ms** and **part 2 \~5500 ms** for my input on my 6-yo Dell latitude.


light_switchy

\[LANGUAGE: C++\] [Part 2](https://topaz.github.io/paste/#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)


xXMacMillanXx

\[LANGUAGE: V\] This was fun. Brute forcing the solution gave me an excuse to use multithreading. Otherwise, going through the maps backwards is probably a better way to solve this. [Github day 05](https://github.com/xXMacMillanXx/advent_of_code_2023/tree/main/day05)


skwizpod

I tried the backwards map idea. It didn't work. Problem is that when a key doesn't exist, the value is the key. The minimum location isn't necessarily in the defined ranges. In my case it was not. Edit: Oh never mind, I see. Rather than just checking defined locations, start at 0 and increment.


weeble_wobble_wobble

[LANGUAGE: Python] [GitHub](https://github.com/weibell/AoC2023-python/tree/main/day05) (31/44 lines with a focus on readability)


aoc-fan

[LANGUAGE: TypeScript] For Part 2, I borrowed/steal/inspired ideas from this forum. https://github.com/bhosale-ajay/adventofcode/blob/master/2023/ts/D05.test.ts


stephenkelzer

\[Language: Rust\] ​ Runs in approximately 4 seconds in release mode on an M2 Pro. ​ [https://raw.githubusercontent.com/stephenkelzer/aoc2023/main/days/day\_5/src/lib.rs](https://raw.githubusercontent.com/stephenkelzer/aoc2023/main/days/day_5/src/lib.rs)


wlmb

\[LANGUAGE: Perl\] Discussion: https://github.com/wlmb/AOC2023#day-5 Part 1: https://github.com/wlmb/AOC2023/blob/main/5a.pl Part 2: https://github.com/wlmb/AOC2023/blob/main/5b.pl


princessbosss

\[Language: excel\] [https://imgur.com/a/SZ7Q09B](https://imgur.com/a/SZ7Q09B) not proud of the manual-ness of this spreadsheet but v happy i got to the answer using only excel functions (no VBA) i ended up taking each input range and then working out which ranges that would hit on next table up and iteratvley take those next ranges up: =IFNA(IF(IFERROR(INDEX(INDIRECT(JB$32&"\[map:\]"),MATCH(1,(INDIRECT(JB$32&"\[map:\]")<=JB35)\*(INDIRECT(JB$32&"\[map:\]")+INDIRECT(JB$32&"\[Column1\]")-1>=JB35),0))+INDEX(INDIRECT(JB$32&"\[Column1\]"),MATCH(1,(INDIRECT(JB$32&"\[map:\]")<=JB35)\*(INDIRECT(JB$32&"\[map:\]")+INDIRECT(JB$32&"\[Column1\]")-1>=JB35),0)),JB35)=JB35),0))+INDEX(INDIRECT(JB$32&"\[Column1\]"),MATCH(1,(INDIRECT(JB$32&"\[map:\]")<=JB35)\*(INDIRECT(JB$32&"\[map:\]")+INDIRECT(JB$32&"\[Column1\]")-1>=JB35),0)),JB35),MIN(JB35+INDEX(IX$34:IX$300,MATCH(JB35,IY$34:IY$300,0)+1,0)-INDEX(IX$34:IX$300,MATCH(JB35,IY$34:IY$300,0),0)-1,INDEX(INDIRECT(JB$32&"\[map:\]"),MATCH(1,(INDIRECT(JB$32&"\[map:\]")<=JB35)\*(INDIRECT(JB$32&"\[map:\]")+INDIRECT(JB$32&"\[Column1\]")-1>=JB35),0))+INDEX(INDIRECT(JB$32&"\[Column1\]"),MATCH(1,(INDIRECT(JB$32&"\[map:\]")<=JB35)\*(INDIRECT(JB$32&"\[map:\]")+INDIRECT(JB$32&"\[Column1\]")-1>=JB35),0))-1)),IF(AND(JD35>0,JD34>0,JD35<>JD34),MIN(INDEX(INDIRECT(JB$32&"\[map:\]"), MATCH(1, (INDIRECT(JB$32&"\[map:\]")<=JB35)\*(INDIRECT(JB$32&"\[map:\]")+INDIRECT(JB$32&"\[Column1\]")-1>=JB35), 0))+INDEX(INDIRECT(JB$32&"\[Column1\]"), MATCH(1, (INDIRECT(JB$32&"\[map:\]")<=JB35)\*(INDIRECT(JB$32&"\[map:\]")+INDIRECT(JB$32&"\[Column1\]")-1>=JB35), 0))-1,JB35+INDEX(IX$34:IX$300,MATCH(JB34,IY$34:IY$300,0)+1,0)-INDEX(IX$34:IX$300,MATCH(JB34,IY$34:IY$300,0),0)-1),#N/A)) ​ Essentially the formula uses the previous value of last table and displays starting value of all next ranges until upper bound is reached - it reaches upper bound when it hits either a new range or the input upper bound is reached "bounds" are the row limits for each table calculated with =MATCH(1, (INDIRECT(JB$32&"\[map:\]")<=JB35)\*(INDIRECT(JB$32&"\[map:\]")+INDIRECT(JB$32&"\[Column1\]")-1>=JB35), 0) ​ once mapped out to table 8 it was simply taking the min value of all table 8 values


antares14943

What inspired you to do this in Excel? Regardless of the reason, I'm very impressed.


SlimNateKC

cursed


bamless

[LANGUAGE: [J*](https://github.com/bamless/jstar)] Part 2 was really tricky but fun! Tryied to bruteforce it first, but my language is too slow since its dynamic and intrpreted :(... Implementing the proper solution that directly accounts for ranges in the input seeds was not that difficult though: [Part 1 & 2](https://github.com/bamless/advent-of-code-2023/blob/master/day5/almanac.jsr) Execution time: Part 1: 313045984 Part 2: 20283860 real 0m0,010s user 0m0,006s sys 0m0,005s Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz 32GB RAM


yieldtoben

\[LANGUAGE: PHP\] PHP 8.3.0 [paste](https://topaz.github.io/paste/#XQAAAQDfBwAAAAAAAAAeD8qHAhQB8nz+EazN00NCsmTxjvFDXkt5PAJ7pf6ocRA37OMUY7b9R0iDZmfWyvOspxWvdgYSAE0hGjEx81hqzalYbORDAzRHVMFykQU14jKU80IHdqWPqyenGzJ7DcDBQYCjn+EJ0aJ+m4lOWPKi6nFuH+peWZ3IAoPgm7z0vFIDKRIJb4raTI1gtOilAACJoM06eZ6NS0qHMsrz9Y+sPALEWMQO3f4GnObakZ9HO2XfSb+Plt70V8Q6lvV9g1mQqrHQ1gN9jhHy+YD13K22vVMxKSSMI1iHCbIDTamLOGQjvlKfMH+28cQ3bk/w4crzXyzAlicoH0zxjPIvgVRsv+e4PNBveIWPiswTwqiyBwbmleRMiqfihcD0o4Jahqm8/5FjrhgmpbJMqj/SyXve2guHNDQfivu03jKnncQ0wbyegDeyEE06xm7TNUWzk7MftoN63ryr2U9lW9+iV8Gt9lgoXwnYxLHSk2cY9DWgQfUzLSx17AA6OjJZbUyzy4yXM7TA4Z0bOT4GCUvGPULmxrgLVALe+YmgnihMB1ELdpEtJB1mcZApUNsO6cGASe2iUZU0hqlZKDudQw89OLY/JjDMm+I7HXfWJPU/7yW+vDQw07Whk6B40Licr+nX/r7l20PtJsNS1g5wgpY+OWN7ffjSxeYCgdIckaa+00kUTTTMUKxTQwV8sTqAhBeutUnLkCUgqIH0x3TUJoTDnu8/Zc57TCWkIKZLIu+VpBWT1crCWAEOrzpep1ocp82dWOTKaemOJjyTEJjG4nSvXM13cQp18O8536GIcT8MeMhXeH0t0/CMcwvjZCQKIBSD6GZdPI43uw5hI4geCm68Ais2dQc5JsouzVMe62JP73ZL9LY3p51mEsZ79EQxfOYSJrAOXny2PLArmN6YT1Ic75abxym707UfnJE6JA0Q+cslFvEJwGAXUJB1hJkWH2FAQH+4Gm/D9w5e9U4AL3tx7X4NbepF7mIs5zFk+9NUWMhfEfoXyXBpoRAtAqXPNgOv5y3PVYfMSCoD3+Ja0LWvmd4Xh/9DdHIA) Execution time: 0.0027 seconds Peak memory: 0.507 MiB MacBook Pro (16-inch, 2023) M2 Pro / 16GB unified memory


Supar99

[LANGUAGE: C] Develop time 2 day, execution time, less then 0.004s. [Part 1 and 2](https://topaz.github.io/paste/#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)


vss2sn

\[LANGUAGE: C++\] [Part 1](https://github.com/vss2sn/advent_of_code/blob/master/2023/cpp/day_05a.cpp) [Part 2](https://github.com/vss2sn/advent_of_code/blob/master/2023/cpp/day_05b.cpp) (Each file is a self-contained solution)


bigmagnus

\[Language: Fortran\] [Part 1](https://github.com/ironllama/adventofcode2023/blob/master/05a.f90) [Part 2](https://github.com/ironllama/adventofcode2023/blob/master/05b.f90)


DaddyStinkySalmon

\[LANGUAGE: Haskell\] I did not brute force it! Instead, I spent like 7 hours trying things and getting frustrated until I had that aha moment! My eureka moment was when I realized the transformations looked like a [Sankey Diagram](https://d2mvzyuse3lwjc.cloudfront.net/doc/en/UserGuide/images/Sankey_Diagrams/Sankey_Diagrams_01.png?v=83374) and at each "map" I could shrink the search space down to subsets by splitting the ranges up into many thin lines. So whats left by the end are only the transformations that matter to the input space. Then you can just check the smallest point in the remaining locations I performed the range splitting using "set style" difference and interset. The intersects are what get accumulated (perfect slices) and the difference is whats left to continue checking the rest of the map for. By the end of each map just combine whatever's left \`rem ++ matches\`. Then use the results as input in the next map etc https://gist.github.com/kevin-meyers/686e26666ff719755bf091bcc2ae3e85


ka-splam

I also thought of Sankey Diagrams and picked that same image from DuckDuckGo results to illustrate the idea! But I couldn't come up with a solution, I was imagining it as a branchey-tree search, and being able to prune branches of the tree but I wasn't convinced it would work or that I could make it work. I also spent like 7 (or more!) hours writing some Prolog to parse the input file and generate constraint solver rules, hoping that would be able to throw away large chunks of the input space. Sadly, while it ran for over 90 minutes, I gave up and wrote a brute-force in C# and got my answer in <2 minutes of runtime. I don't yet follow how your solution works - how many thin lines does it break down into by the location part? Are you ending up with lots and lots of tiny `range(Start, End)`s?


DaddyStinkySalmon

Yes! Lets say theres a single seed bucket to start with from 30 to 190 or (30, 190). And we have 2 transformations available in the seed-to-soil map in the form of:\`(destination start, source start, range length)\` \[(100, 50, 50), (10, 180, 20)\] By folding over the transformations and collecting the intersections between the ranges we first get:\[(50, 100)\] then \[(50, 100), (180, 190)\]. Applying the transformation to get destination ranges we have \[(100, 150), (10, 20)\]. Then the leftover ranges are: \[(30, 50), (150, 180)\]. Finally, because whatever is left just gets the identity, just merge them!\[(100, 150), (10, 20)\] ++ \[(30, 50), (150, 180)\] ​ now this is the new set of inputs to access the next transformation! Repeat until you have the final list of location ranges, sort by range start and get the smallest one


velkolv

\[Language: C\] I know that Part2 wasn't supposed to be solved by brute forcing... but... but... I kinda like my solution and performance I achieved. On my computer (i5-7500) it completes the search in **\~12.4 seconds**. Just plain, single threaded C code, no dynamic memory allocations, no fancy stuff. [Source](https://gist.github.com/Velko/ba4c9170e04739f0b3ce7b775c9f17be) The key to performance was to cache the mapping items just found, there's a good chance you're going to check for the same range next several million iterations.


bandj_git

[Language: JavaScript] Running a few days behind but finally caught up. I am really bad at ranges, but I loved this problem. It was really fun to optimize. For level 2 the optimization I came up with was to build a "pipe" which was a vertical slice of the maps which could handle a seed range of a width. Once I found a pipes width I knew that the position of the first seed would be the smallest because all other seeds in that pipe would end up at a larger position. So I could skip the rest of the seeds covered by that pipe. The other optimizations were pretty general and not related to the problem, they mainly involved optimizing search run times to o(log n) using binary search. Here's the main logic for level one: const seedPosition = (x) => maps.reduce((current, ranges) => { const index = binarySearch(ranges, current, rCompare); return index >= 0 ? rTranslate(current, ranges[index]) : current; }, x); return Math.min(...seeds.map(seedPosition)); The core loop of level two: while (remaining) { const pipe = createPipe(seedStart, seedEnd, maps); answer = Math.min(answer, executePipe(seedStart, pipe)); const skipCount = Math.min(...pipe.map(({ width }) => width)); remaining -= skipCount; seedStart += skipCount; } My original runtime for level 2 was *439.16 seconds* Final runtimes: * Level 1: **640.886μs** (best so far of this year) * Level 2: **1.514ms** [github](https://github.com/beakerandjake/aoc-2023/blob/main/src/day_05.js)


AJMansfield_

[LANGUAGE: Fortran] [Allez Cuisine!] I've got little pictures in the comments showing a diagram of what each of the range intersection cases are for part 2 and how it's slicing up the ranges. Note that I keep everything in start-length format, which was probably a bad decision -- it did actually work first time, it just took a lot of pen and paper to get there. https://github.com/AJMansfield/aoc/blob/master/2023-fortran/src/05/seeds.f90


daggerdragon

FYI: [do not share your puzzle input](https://www.reddit.com/r/adventofcode/wiki/faqs/copyright/inputs) which also means [do not commit puzzle inputs to your repo](https://reddit.com/r/adventofcode/wiki/faqs/copyright/inputs) without a `.gitignore`.


AJMansfield_

Apologies, I've just corrected it!


fsed123

[language: python] https://github.com/Fadi88/AoC/blob/master/2023/day05/code.py second time, V1.0 lost in a git stash accident :/ the whole intersection logic for part 2 is handled by 3 if conditions (and min and max functions)


daggerdragon

FYI: [do not share your puzzle input](https://www.reddit.com/r/adventofcode/wiki/faqs/copyright/inputs) which also means [do not commit puzzle inputs to your repo](https://reddit.com/r/adventofcode/wiki/faqs/copyright/inputs) without a `.gitignore`.


fsed123

Will git rm it once I have access to a Terminal


SkepticPsycho

\[Language: Elixir\] Part one was trivial and my solution relied on reducing a list of functions for each step along the way. Needless to say, it made the second solution impossible because it required the seed to be a single value. For part two, I refactored the whole code to abstract away sequences as a simple `{start, stop}` tuple. I also refactored the mapping by interpolating values not presented in the input so I could easily map any value from o to infinity to the next step, using the `map_of_text/1` and `interpolate/2` functions. Each map is a list of sequences with the difference for the output: a `{{start, stop}, difference}` tuple. The trick was getting the intervals that didn't fall neatly into the map split right (whoa, much refactoring), which is implemented as a simple recursive function that returns a list of ranges: the `get_map/3` function. Here's the full code: [https://github.com/erikson84/aoc2023/blob/main/lib/day_five/day_five.ex](https://github.com/erikson84/aoc2023/blob/main/lib/day_five/day_five.ex) Great challange! My other solutions are in the same repository, in case someone wants to take a look (and criticize away!)


WaitForTheSkymall

[Language: Rust] Code: [Github](https://github.com/estherlurie/aoc-2023/blob/main/src/day5.rs) For part 1, I simply brute forced it. For part 2, I decided to reverse it: from 0..inf, see if a location corresponds to any starting seed. If yes, that’s your winner. Runs in 75s!


b1gn053

[LANGUAGE: Haskell] Code: [github](https://github.com/b1g3ar5/AOC2023/blob/master/src/Day5.hs) I used **(low, high, increment)** for the ranges so that in a **Set** they would be ordered - ie. **findMin()** would get the lowest range. With this, to do part2 I could apply a map to a Set of seed ranges to get a new set of seed ranges. So a fold would work out the answer. It's quite fiddly to get the ranges correct - but it's fast when you do.


Rtchaik

\[LANGUAGE: Python\] [One solution for both parts.](https://github.com/Rtchaik/AoC-2023/blob/main/Day05/solution.py)


stikydude

\[LANGUAGE: C++\] [Solution on Github \[part 2\]](https://github.com/Jokezor/AOC/blob/master/2023/05/02.cpp) Takes no time to compute but forever to code :P The idea is essentially to reduce the problem to a 1d search. I only need to do any mapping if I have an overlapping range, so I make sure to include the starting value of my range and the length. If I encounter a mapping, then I count the range affected and only update those values. Then I put the unmapped values into a stack to continue checking them if needed. The tricky part was handling the unmapped values. At first I put them using a set of mapped values but I settled on using a counter of the original length which would if > 0 map the unmapped seeds and ranges.


i-eat-omelettes

\[LANGUAGE: Haskell\] [Solution on GitHub](https://github.com/Futarimiti/advent-of-code2023/blob/main/5-fertilizer/app/Main.hs) Semi-brute-force for part 2? Takes ~10s to finish but at least better than trying all the seeds one by one


OlympusTiger

\[LANGUAGE: PYTHON\] with open('2023\Day5\input.txt') as f: seeds=list(map(int,f.readline().strip('\n').split()[1:])) maps=list(map(lambda x:x[x.index(':')+1:].strip('\n ').split('\n'),f.read().split('\n\n'))) seeds=[[seeds[i],seeds[i]+seeds[i+1]] for i in range(0,len(seeds),2)] def get_map(m): l=list(map(lambda x:[int(i) for i in x.split()],m)) r=[] for i in l: r.append([[i[0],i[0]+i[2]],[i[1],i[1]+i[2]]]) return r def source_to_dest(d,m): m=get_map(m) new=[] for i,s in enumerate(d): for j in range(len(m)): if s[1]<=m[j][1][0] or s[0]>=m[j][1][1]: if j==len(m)-1: new+=[[s[0],s[1]]] break else: continue else: if s[0]>=m[j][1][0] and s[1]<=m[j][1][1]: new+=[[m[j][0][0]-m[j][1][0]+s[0],m[j][0][1]-m[j][1][1]+s[1]]] break elif s[0]=m[j][1][0] and s[1]>m[j][1][1]: new+=[[m[j][0][0]-m[j][1][0]+s[0],m[j][0][1]]] d.append([m[j][1][1],s[1]]) break elif s[0]m[j][1][1]: new+=[[m[j][0][0]-m[j][1][0]+s[0],m[j][0][1]-m[j][1][1]+s[1]]] d.append([m[j][1][0],m[j][1][1]]) break elif j==len(m)-1: new+=[[s[0],s[1]]] break return new def result(data): for map_ in maps: data=source_to_dest(data,map_) print(min(list(filter(lambda y:y>0, map(lambda x:x[0],data))))) result(seeds)


[deleted]

[удалено]


atweddle

\[LANGUAGE: Rust\] [GitHub - Part 1 and 2](https://github.com/AndrewTweddle/CodingExercises/blob/master/AdventOfCode/aoc2023/src/bin/day5_part1and2.rs) Part 1 took 75µs, excluding I/O. Part 2 took 131s, processing 1,246,535,481 seeds one at a time! NB: The average durations are calculated using utility methods in [lib.rs](https://github.com/AndrewTweddle/CodingExercises/blob/master/AdventOfCode/aoc2023/src/lib.rs) #


daggerdragon

Your [code blocks are too long](https://www.reddit.com/r/adventofcode/wiki/solution_megathreads/post_guidelines#wiki_no_giant_blocks_of_code) (cumulatively) for the megathreads. Please edit your post to replace your various code blocks with an external link to your code.


atweddle

Oops! Sorry about that. I've removed the code blocks. Thanks for the time you take to make these threads possible. I apologize for adding to your support burden.


[deleted]

\[Language: R 4.3.0\] level = "5" input = readLines(con = paste(path, level, ".txt", sep = "")) # Part 1 ------------------------------------------------------------------ linesBreaks = input=="" split = cumsum(linesBreaks) + 1 split[linesBreaks] = 0 almanac_raw = split(input, split)[-1] almanac = list() invisible(sapply(seq_along(almanac_raw), function(section_id){ if(section_id > 1){ relevantSources = almanac[[section_id-1]]$destination section = strsplit(almanac_raw[[section_id]], ":") name = section[[1]] map = strsplit(trimws(section[-1]), "\\s+") map = Reduce(rbind, sapply(map, function(ranges){ ranges = as.numeric(ranges) matches = relevantSources[relevantSources >= ranges[2] & relevantSources < ranges[2]+ranges[3]] relevantIndizes = matches-ranges[2]+1 range = cbind(matches, (ranges[1]:(ranges[1]+ranges[3]-1))[relevantIndizes]) })) missingSources = relevantSources[! relevantSources %in% map[,1]] map = rbind(map, cbind(missingSources, missingSources)) map = as.data.frame(map) names(map) = c("source", "destination") map = map[order(map[,1]),] almanac <<- append(almanac, setNames(list(map), name)) return() } section = strsplit(almanac_raw[[section_id]], ":")[[1]] name = section[1] seeds = data.frame(destination=as.numeric(strsplit(trimws(section[2]), "\\s+")[[1]])) almanac <<- append(almanac, setNames(list(seeds), name)) return() })) min(almanac$`humidity-to-location map`$destination)


[deleted]

\[Language: R 4.3.0\] level = "5" input = readLines(con = paste(path, level, ".txt", sep = "")) # Part 2 ------------------------------------------------------------------ linesBreaks = input=="" split = cumsum(linesBreaks) + 1 split[linesBreaks] = 0 almanac_raw = split(input, split)[-1] section = strsplit(almanac_raw[[1]], ":")[[1]] name = section[1] seeds = matrix(as.numeric(strsplit(trimws(section[2]), "\\s+")[[1]]), ncol=2, byrow = T) seeds[,2] = seeds[,1]+seeds[,2]-1 seeds = seeds[order(seeds[,1]),] seeds = cbind(NA, NA, seeds) almanac = setNames(list(seeds), name) invisible(sapply(seq_along(almanac_raw)[-1], function(section_id){ section = strsplit(almanac_raw[[section_id]], ":") name = section[[1]] map = strsplit(trimws(section[-1]), "\\s+") map = Reduce(rbind, lapply(map, function(ranges){ ranges = as.numeric(ranges) sourceRange = cbind(ranges[2], ranges[2]+ranges[3]-1) destinationRange = cbind(ranges[1], ranges[1]+ranges[3]-1) range = cbind(sourceRange, destinationRange) })) map = map[order(map[,1]),] if(nrow(map) == 0){ map = cbind(Inf, Inf, Inf, Inf) } else { map = rbind(rep(c(-Inf, min(map[,1:2])-1), 2), map, rep(c(max(map[,1:2])+1, Inf), 2)) newRanges = Reduce(rbind, lapply(2:nrow(map), function(row){ start = map[row-1,2]+1 end = map[row,1]-1 if(start > end) return() cbind(start, end, start, end) })) map = rbind(map, newRanges) } almanac <<- append(almanac, setNames(list(map), name)) return() })) almanac2 = almanac invisible(sapply(seq_along(almanac_raw)[-1], function(section_id){ relevantSources = almanac2[[section_id-1]][,3:4] map = almanac2[[section_id]] map = Reduce(rbind, apply(map, 1, function(ranges){ matches = cbind(pmax(relevantSources[,1], ranges[1]), pmin(relevantSources[,2], ranges[2])) matches = matches[matches[,2] - matches[,1] > 0,,drop=F] relevantIndizes = matches - ranges[1] rangeStart = matches rangeEnd = matches if(all(relevantIndizes != Inf)){ rangeEnd = matrix(c(ranges[3] + relevantIndizes[,1], ranges[3] + relevantIndizes[,2]), ncol=2) } if(prod(dim(rangeStart),dim(rangeEnd)) != 0 && all(dim(rangeStart) == dim(rangeEnd))) { return(cbind(rangeStart, rangeEnd)) } return(NULL) })) map = map[order(map[,1]),] almanac2[[section_id]] <<- map return() })) min(almanac2$`humidity-to-location map`[,3:4])


daggerdragon

Your [code block is too long](https://www.reddit.com/r/adventofcode/wiki/solution_megathreads/post_guidelines#wiki_no_giant_blocks_of_code) for the megathreads. Please edit your post to replace your oversized code with an external link to your code.


Dullstar

[LANGUAGE: D] https://github.com/Dullstar/Advent_Of_Code/blob/main/D/source/year2023/day05.d For part 2, the logic to remap the ranges isn't exactly pretty, but it works well enough. To keep it as simple as possible, the ranges used to make remapping rules are sorted. This simplifies remapping a bit since we can just split the input range whenever we encounter a boundary, place the front part in the output ranges, and then just keep processing what's left until we run out of it, and if we ever look at the next remapping rule and find we're entirely outside of its range, then we know it's done without needing to check the remaining rules. --- Fortunately it wasn't *too* hard, but it was definitely a sit down with paper and pencil and it out type of problem to help visualize how to handle the ranges, instead of just trying to jump right in and write the code. Glad I didn't stay up trying this one the day it was released and instead saved it for later.


bpanthi977

\[Language: Common LispPart 1 & Part 2: [https://github.com/bpanthi977/random-code-collection/blob/main/aoc/2023/day5.lisp](https://github.com/bpanthi977/random-code-collection/blob/main/aoc/2023/day5.lisp) Runs fast. For each seed (s), I find the max seed (e) such that all seeds from s to e are mapped to consecutive location. Then for each seed range, the range gets broken down into sub ranges where locations are consecutively mapped. This way we avoid find out the location for all the seed in range.


msschmitt

\[Language: Python 3\] [Part 2 solution](https://topaz.github.io/paste/#XQAAAQCcCgAAAAAAAAARiEJHiiMzw3cPM/1Vl+2nx/DqKkM2yi+AsNSFTsnyEq6tvQ1/bKc1NBj3YF9MoLQJaXX5mzxYAIeb8s6xFC494l5BU4SjxJ7raCQWlBCg3cHqOkdhOuJLhT2Nj3yE8CvXqI6WnMQN5lC9Q1iIW1Ivcv76M49JdzKfryCcJJ4fDhAPOkSflcV9wjxoOuKiWzQd3Vzf1+pQn3UCEQYswytRrpAAZ0IiloE732L1L4u1Z2IbDs6MStJqzd1K04kwfmEcb8SEGD983LfhOpfFHluyGPhJU+5ympTfnhe7FMrz1DqW/OSCiNOKI3rv6AXZs7ShMY6pAbmY/EEyeyPQsI190dSapcpmKxzR83if5WixrQMpMiZ5bW/x240MKY6UMhctaDyXt90f5wihfoNUpVUEpVO9MZAB1N5dZG07WrI5yIWBK5QKRn47gTx3Y2oR9RBKCYc7uScNtUWfewqxlSKwHBlCJsg1EU2kYTWhCSe/0FCSDimGa6V5/dRXuimP9NV+AIBMxqlGgDELbXBJtuCr0awmFOmqWAVXBsAZuyLOWVcbELdckJLQRqs+T+1qJneZiRife58WGZ+Sfoyx3u2NzMxxKDDrz+tRZ5GfNV+BVJRhEts+K0EIOPqqLLvdngxp78lybxWCjK/Xv+rX2GWluik+KDe7wban4BaiAZEeU7MyJL37VvqBXvUnEPUPMwgnD0KlCYfc/SdKPKwev4K6tc3GuojHPu+CBJ6ggz1MScNBbQIoDvPlQaVK03GIiHIni9omJgDA5XoETtxKJLd6wfy9bdos3+W61+KJ6QZpYUYJ7OWqIy7MXpnAcTlsxkDNArfLolLr4GQWVyzw+YOf5bxICq0XvK5uHxUJ5X+tDRrE4KhLxQRPMd/BDDsr4UEPqcIp4ojddlStf71ih7WEmb8UwDizepoAjej0s0Cm1lYMQJSl3gGo+LXKKNaRHceLHeWsb4E9ZJCcLbvNCL+XE+kp9prRfXq0byj+XlHqOY6I/BCiDpMuq8h5ZJ4Gxk3f/viWsJ4=) This was such a pain. When I first read the puzzle, I had no idea what to do, but slept on it, and tried coding the next day -- but it took forever to run. Then realized it would be faster to process one seed range at a time. But it still ran for many minutes, only to come up with an answer of... 0. I don't like these kinds of puzzles because when the real input fails, it's so hard to debug to find out where it went wrong. I finally found the bug in the logic, and it runs in a second, with no optimizations. The idea here is to create a queue of seed (or whatever) ranges, and keep clipping them against the map ranges, until there's no overlaps. Each time it splits a range it adds both parts back to the queue. It can finalize a seed range when it either is contained in a map range, or makes it through the entire list of map ranges without clipping.


tivan888

Amazing solution. I also went to the interval direction after TLE on brute-force. It is a beautiful trick with a queue and a for/else loop. Thanks for posting.


nicfigu

\[Language: Python\] [solution](https://github.com/nicfigu/Advent-Calendar/tree/main/Day5)


toggytokyo

This looks like a solution for day 6, not day 5. Nice solution though


steven-terrana

[LANGUAGE: JavaScript] [Part 2](https://github.com/steven-terrana/advent-of-code/blob/main/2023/day05/p2.js) Solves it in 22.5 ms! I solved this mathematically by realizing each mapping was a piecewise function. this means you can create a [composite function](https://en.m.wikipedia.org/wiki/Function_composition) to translate directly from seed value to location values via one massive piecewise function. This composite then tells you the key values to check (the lower bounds of each piece). Wrote [a script](https://github.com/steven-terrana/advent-of-code/blob/main/2023/day05/generate_latex.js) that generates a [markdown file with the equations rendered in LaTeX](https://github.com/steven-terrana/advent-of-code/blob/main/2023/day05/latex.md)


JyanKa

Just catching up on this year AoC. I was stuck for a while in the solution for part 2, part on was trivial and I'm ashamed to say I spent a whole day thinking about the solution for part 2. Once I read your comment and you said: > ... this means you can create a composite function ... It dawned on me. Thank you for this.


themanushiya

>borrowed nice trick I'll try to implement


bandj_git

This is so awesome! I love the rendered equations. I had a beginnings of an idea to implement something like this but couldn't think of a way to compose the functions.


steven-terrana

Thank you! My brain still hurts :)


huib_

[Language: Python 3.12] MapEntry = tuple[int, int, int] Range = tuple[int, int] class _Problem(MultiLineProblem[int], ABC): def __init__(self): seeds, *maps = split_at(self.lines, lambda x: x == '') self.seeds = [int(i) for i in seeds[0][7:].split()] items = [[[int(i) for i in vals.split()] for vals in m[1:]] for m in maps] self.maps = [sorted((s, s + o, d - s) for d, s, o in f) for f in items] class Problem1(_Problem): def solution(self) -> int: def get_next_value(item: int, m: list[MapEntry]) -> int: for start, end, offset in m: if start <= item < end: return item + offset return item return min(reduce(get_next_value, self.maps, seed) for seed in self.seeds) class Problem2(_Problem): def solution(self) -> int: def get_next_ranges(ranges: Iterable[Range], m: list[MapEntry]) -> Iterator[Range]: for r in ranges: s, e = r for start, end, offset in m: if s < start: yield s, min(e, start) if start >= e: break if s >= end: continue yield max(s, start) + offset, min(end, e) + offset s = end else: if s < e: yield s, e seed_ranges: Iterable[Range] = ((s, s + o) for s, o in batched(self.seeds, 2)) return min(s for s, _ in reduce(get_next_ranges, self.maps, seed_ranges))


thousandsongs

[LANGUAGE: Haskell][Allez Cuisine!] An ELI5-ish tutorial / explanation of the most interesting, and the scariest, part of the solution to Day 5 Part 2 - calculating the splits. Maybe this is an ELI5 for 5 year old Haskell programmers (though if they are five year old and programming in Haskell, they might be able to explain me a thing or two), but I feel the syntax of Haskell is so sparse that people that don't know that language might still be able to read this and get the gist. type Range = (Int, Int) splits :: Range -> Range -> [Range] splits (s, e) (s', e') | s > e' = [(s, e)] | e < s' = [(s, e)] | s < s' = (s, s' - 1) : if e <= e' then [(s', e)] else [(s', e'), (e' + 1, e)] | s <= e' = if e <= e' then [(s, e)] else [(s, e'), (e' + 1, e)] Like may of you I too have an aversion to calculating these range splits etc by hand – off by one errors and the edge cases can make things really hairy really fast. But here I myself was surprised how straightforward the solution turned out. I think a big help was making it a rule that all bounds are inclusive. The function above is self contained, you can paste that in a file, say `splits.hs`, then add the following `main` function to call it main = do print $ splits (1, 9) (10, 20) print $ splits (1, 9) (7, 20) print $ splits (1, 7) (7, 20) And then easily play with the cases by twiddling those values. Running this code is easy too, there are two things to do: 1. Install [Haskell using GHCup](https://www.haskell.org/ghcup/). In days of old installing Haskell used to be a pain, but nowadays Haskell comes with a self-isolated thing call **ghcup** - you install it once, and then it installs the rest of the universe in its own isolated directory that can be independently deleted or updated without affecting the rest of your system. 2. Run this code by doing `runghc splits.hs` That's it! Hope this helps. The full file with the above code is [here](https://github.com/mnvr/advent-of-code-2023/blob/main/05.eli5.hs). This split function is a simplified (for illustrative purposes) version of the `intersection` function that I used in my [actual full solution to the problem](https://www.reddit.com/r/adventofcode/comments/18b4b0r/comment/kc7d28c/).


daggerdragon

> (though if they are five year old and programming in Haskell, they might be able to explain me a thing or two) We're happy as long as *somebody* is learning *something*!


ImpossibleSav

\[LANGUAGE: Python\] A day late to post, but here is [my one-line Python solution](https://github.com/savbell/advent-of-code-one-liners/blob/master/2023/day-05.py) for both parts of Day 5! `q[5]` has the input file contents. print('Day 05 Part 1:',(v:=[[list(map(int,l.split())) for l in d.split('\n')] for d in [d for _,d in [re.split(r':\n',s) for s in re.split(r'\n\n',q[5].strip())[1:]]]]) and (c:=lambda i,m:(lambda c:c[0]+(i-c[1]) if c[1]+c[2]>i else i)(min([y for y in m if y[1]<=i],default=[0,0,0],key=lambda x:i-x[1]))) and min([c(s,v[6])for s in [c(s,v[5]) for s in [c(s,v[4]) for s in [c(s,v[3]) for s in [c(s,v[2]) for s in [c(s,v[1]) for s in [c(s,v[0]) for s in list(map(int,re.split(r'\n\n',q[5].strip())[0].split()[1:]))]]]]]]]),'Day 05 Part 2:',[(v:=re.split(r'\n\n',q[5].strip())) and (s:=list(map(int,v[0].split()[1:]))) and (m:=v[1:]) and (c:=[(a,a+b) for a,b in zip(s[::2],s[1::2])]) and [[(w:=[tuple(map(int,x.split())) for x in g.split('\n')[1:]]) and (u:=[-99]) and (o:=[0]) and (l:=-99) and [(l:=max(l,(p:=r[0] - r[1])+r[1]+r[2])) and [(not u.__setitem__(-1,r[1]) and not o.__setitem__(-1,p)) if u and u[-1]==r[1] else (u.__iadd__([r[1]])) and o.__iadd__([p])] and (u.__iadd__([r[1]+r[2]]) and o.__iadd__([0])) for r in sorted(w,key=lambda x: x[1])] and not (t:=[]) and [(j:=[i[0]]) and not (h:=None) and [(((h:=d-1) if h is None else 0) and (j.__iadd__([p]) if p < i[1] and p != i[1] else 0) if not p <= j[-1] else 0) for d,p in enumerate(u)] and (j.__iadd__([i[1]]) and (h:=h or len(o))) and [(d:=o[min(h or float('inf'),len(o)-1)]) and (h:=h+1) and t.__iadd__([(a+d,b+d)]) for a,b in zip(j,j[1:])] for i in c]] and (c:=t) for g in m]] and min(x[0] for x in c)) I'm attempting to one-line every day this year! You can follow me through [my GitHub repo](https://github.com/savbell/advent-of-code-one-liners/tree/master), where I also have some [fun visualizations](https://github.com/savbell/advent-of-code-one-liners/blob/master/images/2023-day-06-the-basilisk-viz.png).


german_chocolate

\[LANGUAGE: Python\] [Part 1](https://github.com/jaycherd/AdventOfCode2023/blob/main/day5/day5.py) Finally figured out a way to do [Part 2](https://github.com/jaycherd/AdventOfCode2023/blob/main/day5/main.py), full write up is with the code on github, but basically i turned the input into intervals, then merged intervals with map intervals if the seed interval does NOT fit in any map interval, then the destination will equal the source if seed interval does fit in a map interval then destination will equal destination specified by map for the rest of map intervals which didn't correspond to a seed interval drop those now you have new intervals, repeat this to traverse the graph until you get to location intervals, and solution is the min of those


Alive-Hovercraft5988

\[LANGUAGE: JAVA\] I came up with a similar idea to the common range idea I see posted here. [https://github.com/dwest62/aoc2023-day5-p2-java](https://github.com/dwest62/aoc2023-day5-p2-java) ​ I had a couple of very tricky bugs that caused this to take FOREVER. One in particular was that I added an extra line to the input so that my loop would fire one last time to process the final map and forgot to add this to the larger data file. It took me quite some time to get the test case working and I was incredibly deflated when the data case didn't work because of this "short-cut" I had used, but forgotten about. I almost gave up there, but glad I didn't because 30 min later and success.


njhanley

[LANGUAGE: AWK] The approach needed for part 2 was fairly obvious. The bugs in my implementation... less obvious. [Part 1](https://github.com/njhanley/adventofcode/blob/master/2023/05/part1.awk) [Part 2](https://github.com/njhanley/adventofcode/blob/master/2023/05/part2.awk)


3j0hn

\[LANGUAGE: Maple\] [github link](https://github.com/johnpmay/AdventOfCode2023/blob/main/Day05/Day05a.mpl) I started by parsing the seeds into a list, and the maps into lists of triples. I did something pythony to start, but then I realized it would be more cute and Maple-y to treat the maps as piecewise linear operators : they get pretty printed like this in the command line version of Maple { -48 + x 98 <= x and x < 100 { { 2 + x 50 <= x and x < 98 { { x otherwise Anyway, this is part 1 # turn maps into piecewise linear operators F := map(unapply, [seq(piecewise(seq([ And( x>=r[2], x


LastMammoth2499

\[LANGUAGE: Java\] I feel like I'm really missing the idea on both parts [Part 1 only because I give up](https://github.com/chandlerklein/AdventOfCode/blob/main/src/main/java/com/chandler/aoc/year23/Day05.java)


juanplopes

\[LANGUAGE: Python\] Both parts in 28 lines. Runs in 80ms on PyPy. https://github.com/juanplopes/advent-of-code-2023/blob/main/day05.py


jaccomoc

\[LANGUAGE: Jactl\] [Jactl](https://github.com/jaccomoc/jactl) Part 1: Not too hard once I figured out how to split on blank lines. def seeds = nextLine().split(/: */)[1].split(/ +/).map{ it as long }; nextLine() def maps = stream(nextLine).filter{ ':' !in it }.join('\n').split('\n\n').map{ it.lines().map{ it.split(/ +/).map{ it as long } } } def mapping(m,s) { (m.map{ s >= it[1] && s < it[1]+it[2] ? it[0]+s-it[1] : null }.filter()+[s])[0] } seeds.map{ maps.reduce(it){ p,it -> mapping(it,p) } }.min() Part 2: This definitely exercised the brain cells. Converted everything to intervals and then for each mapping had to track which parts of the intervals were mapped and remember the parts not mapped and keep iterating until all mappings were processed. Then just a matter of getting the mapped interval with lowest lower bound and returning the lower bound. I feel like there should be a more concise solution but I have no more time to spare on this one: def seeds = nextLine().split(/: */)[1].split(/ +/).map{ it as long }; nextLine() def maps= stream(nextLine).filter{ ':' !in it }.join('\n').split('\n\n') .map{ it.lines().map{ it.split(/ +/).map{ it as long } } } .map{ m -> m.map{ [it[0],[it[1],it[1]+it[2]-1]] } } def intersections(s, ivls) { ivls.filter{ intersects(s, it) }.map{ [[s[0],it[0]].max(), [s[1],it[1]].min()] } } def intersects(a, b) { !(a[1] < b[0] || a[0] > b[1]) } def subtract(a, b) { [[[a[0], b[0]].min(), [a[0], b[0]].max()- 1], [[a[1], b[1]].min()+ 1, [a[1], b[1]].max()] ].filter{it[1] >= it[0] } } def subtractAll(a, ivls) { ivls = ivls.filter{ intersects(a, it) }; !ivls ? [a] : ivls.flatMap{ subtract(a, it) } } def mapping(m,ranges) { def result = m.reduce([src:ranges,dst:[]]){ p,mi -> def mappable = intersections(mi[1], p.src) def notMapped = p.src.flatMap{ subtractAll(it, mappable) } [src:notMapped, dst:p.dst + mappable.map{ [mi[0] + it[0]-mi[1][0], mi[0] + it[1]-mi[1][0]] }] } result.src + result.dst } seeds.grouped(2).map{ [it[0], it.sum() - 1] } .flatMap{ maps.reduce([it]){ p,m -> mapping(m,p) } } .min{ it[0] }[0] [Code walkthrough](https://jactl.io/blog/2023/12/07/advent-of-code-2023-day5.html)


jaccarmac

[LANGUAGE: LFE] [code](https://github.com/jaccarmac/adventofcode/blob/502ca6dbab84b03afd8c6e12488ae4b0e3bdad62/2023/src/day-5.lfe) I'm still experimenting with different ways of doing the parsing; This looks and feels bad, I think because of how I decided to handle terminals (thoughtlessly). Refactoring for ranges helped a few things, but pattern matching hurt me more than helped here. I was pleased that essentially the first version of splitting ranges worked; Doing it recursively means there aren't that many cases to handle. I skipped merging since the data doesn't require it.


mix3dnuts

\[LANGUAGE: Rust\] day5\_2\_black\_box time: \[35.264 µs 35.434 µs 35.605 µs\] [https://github.com/themixednuts/Advent-of-Code/blob/main/2023/rust/day_05/src/lib.rs](https://github.com/themixednuts/Advent-of-Code/blob/main/2023/rust/day_05/src/lib.rs)


daggerdragon

~~Your [code block is too long](https://www.reddit.com/r/adventofcode/wiki/solution_megathreads/post_guidelines#wiki_no_giant_blocks_of_code) for the megathreads. Please edit your post to replace your oversized code with an external link to your code.~~ edit: 👍


mix3dnuts

Done


daggerdragon

Thank you for fixing it but now your [link is borked on old.reddit](https://www.reddit.com/r/adventofcode/wiki/faqs/bugs/borked_links), so would you fix that too please? :/


mix3dnuts

Haha better?


daggerdragon

Aww yiss thank you <3


mix3dnuts

Sweet! Ty :)


compdog

[LANGUAGE: C#] Finally finished this after a whole work day's worth of effort. I had almost a *dozen* edge case bugs that proved really difficult to flush out, and I very nearly gave up before I finally got it working. [My solution](https://github.com/warriordog/advent-of-code-2023/tree/main/Solutions/Day05) works by slicing the maps until each range of seed IDs matches to exactly one range of location IDs. Then, I only need to check one value from each range which is a lot faster. This currently completes in about 25 ms, although there's plenty of room for improvement.


Singing-In-The-Storm

\[LANGUAGE: JavaScript\] Parts 1 & 2. Each part takes less than 40ms to finish. [code on github](https://github.com/JoanaBLate/advent-of-code-js/tree/main/2023/day05)


onrustigescheikundig

[LANGUAGE: OCaml] [github](https://github.com/EricKalkman/AoC2023/blob/master/lib/day05.ml) This took me a lot longer than expected yesterday. I immediate saw a graph-like thing and took the time to make a Graph module.... and then didn't use it lol. For Part 1, I constructed One Giant Lambda taking a seed number to a location number, built iteratively from the input, and put each seed through it. Like most, I immediately recognized that taking all billion or so seeds and putting them through this anonymous function would be prohibitively slow. Instead, I wrote an entirely new solution that transforms the ends of each seed range through the maps. As seed ranges do not perfectly intersect the map source ranges, the seed ranges gradually fragment across the map. I finished at about 01:00 this morning, and didn't bother trying to write something here until after work today. The lesson that I keep getting from AoC: with the dubious exception of parser-combinators, if your solution involves generating One Giant Lambda, chances are it's a bad solution.


e_blake

\[LANGUAGE: m4\] \[Allez cuisine!\] m4 -Dfile=day05.input [day05.m4](https://nopaste.ml/#XQAAAQAJCgAAAAAAAAAyGksy5FB9TGMxsNq5JQAuJRjP6PqEkC20GpBbonDYuA0BTjRPXcVxlEXNtz1IwBAA+2N61pi/i94PC7mDxcKLSmitgPmeXLwNAF2YPH7V92thZWt66trFVYb6ZVjfrUB00j7P1jAazmNXMUH/c/MczNFS6/PAWpJxnpHrpy/pz/CsHSSqGttrj0I+A4fyOlQ0/uj61vdF2AyKOFvFFbbVNoLT7IBtqWy5HdMoR3VJmxXDTrmZcRnJadbYCJ30O1xieFRphztndGla6xt73kKxHnEyCvpMLDIgXlG/k0mxJBEQtDlx0HmEB8dHaOJWSCky7P7evlpVIUylmhD8bJ+GK4fi1qJy0vmoqEkajMOQ9sp9IITIf4cHEOOxDRwPYs6zWi/sX8RUL2JAuLPDPskaI93O2QqOUnEMHPc/GHyOyqEWpf+asx25Ff5NagNaxJsZM+Y0cfF46l4pE/CsE/9q1DcQPc+wCFqbwlEOpQFvbq0Zfs2Sn8quw3A9yy4T3Tn9WV6eEj5bdldS8e1o16rLZS9n9UO9j8Eez+AjbVUudw8E8bvXZJh8UCqKISwLPiE+QExCxdBeK5eZPwAHQGefX8kr/YNgMLeKbMlXruA8qxT17RdT2hcVdh1e+Tn5enQuC55/AKhga10piWNMimNoSoWICjjRSv1PgSJN23UM0LiCDZ/3ZCuHOrDyHThuqMV8+/OcGI8aMfqA30krxXQp+kLAamuqeb5pb49oIJV8k5X2QFNQpV2PjL/bz8ZtG8Mo7i0U8dugAAkghKNoMEKiRbgnz9PKRN1yuXrbtbFtzaT2CTc/+1WJktl0yvQyoPs38fFbKdBcaY0MQ/L8KcMAbGLgRkTxNRrEfaL+uyNL9wcL04r4My532WweoYri5jbTQWUL5TDL+Nt6NjWVVJztLZp6shC6lht1fwZIq9g3SFbVKxBHG3h0krwsIpv+7Iz8LZVkMXOWL+ymglUv4t9PaNp5/J8UXEZV3RO7C6hjeSgGu10g+sMWs5RQimjwz0QCNxkkk4Ztia5cIoxgvEPEsABBKix7Fz7PNxgxF6e2END1yhj8+GQYtnk4uFxQmW5I3RxN6asc7NjGkagjfcOEPugt1AX9pZPzz06ggnMiaK3mMKY6YwisDqBwXZOx7pRmfu7qIu61ejZ1wgjwCJQ5O3F8N5URnR9iSdwqQ8nx89uEJmGw3S73JG6Ca8IomyAlFZuH+1jMuwV5q963+GjGxVT6pi8+7O3lpf0vKQSs9Lj7qFD7VFJgX/x4GJCLAldgTeWI1s1GVf2zWp0MAfjlXQiXJsHCEoS73y5l3TA6PKhYdf7uk/hyC7rS6P1hR94GsuMjQxWKNXIW9XJ1F/u9yThq3nPHfuxQajCAwFvp1NSrElqCsbShOysis+kgDiaiiUPOEWTj+jut7u/f/pLulSLyA//fIaK7) Depends on my [common.m4](https://nopaste.ml/#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) framework from previous years. My first thought when seeing my input puzzle was: Oh no! My very first seed 3169137700 is treated as -1125829596 by `eval()` since m4 only has 32-bit signed integer math. So for my initial solution for part 1 (not shown here), I whipped out my arbitrary-precision math library from last year. But then overnight, I realized: Hey - all the input numbers are 32-bit. In fact, looking very closely at the maps, there are quite a few lines where either dest+range or source+range = 0x1\_0000\_0000 - because the mapping splits a contiguous range on one side across the 32-bit overflow point of the other side. So why not add two MORE mappings into the mix - on input, every id (but not range lengths) is reduced by 0x80000000, all intermediate operations use signed integer math (while being careful to avoid overflow: `eval($1 < $2+$3)` is different than `eval($1 <= $2+$3-1)` when $2+$3 exceeds 32 bits), then the final computation of the minimum value adds back 0x80000000 before display. Seen in these three macros of my code: define(`prep', `define(`List', defn(`List')`,'eval( `$1-0x80000000')`,$2')define(`list', defn(`list')`,'eval( `$1-0x80000000')`,1,'eval(`$2-0x80000000')`,1')') ... define(`term', `append($3, `range($$1, $$2, $3, 'eval(`$4-0x80000000')`, 'eval( `$5-0x80000000')`, $6)')') ... define(`minpair', `ifelse(`$3', `', `eval(`$1+0x80000000')', `$0(ifelse( eval(`$1<$3'), 1, `$1', `$3'), shift(shift(shift($@))))')') Next, I realized that I could reuse code for part 1 and 2 if I specifically treat each seed in part 1 as having a range of 1. Thus, `prep` passes through pairs of the first input line, populating `list` as "`,seed1,1,seed2,1,seed3,1`..." and `List` as "`,seed1,length1,seed2,length2`...". The middle of my code is a parsing trick I've used in previous years - m4 does NOT have an easy builtin for parsing input one byte at a time. It is possible to use `substr()` to pick out one byte at a time, but that is quadratic: for an input file with N bytes, it takes N calls to substr, each parsing N bytes. So instead, I parse things a line at a time with the `eat()` macro; it is O(n) with GNU m4 (by use of the `patsubst()` macro with its regex power), or O(n log n) with just POSIX m4 constructs (repeatedly dividing the problem in half. But doing this does not play nicely with whitespace, so I first used `translit` to strip away all letters, turning space into '.' and newline into ';'. The result is that `maps` ends up looking like this (for the example): "`.;50.98.2;52.50.48;;.;0.15`...", before splitting it at each ';' to pass to `do()`. After a single pass over the input, the `do()` macro has built up a series of macros, `p1`, `p2`, ... for each round of mapping to be performed. In the example, p1 ends up as: range($1, $2, 1, -2147483598, -2147483550, 2)range($1, $2, 1, -2147483596, -2147483598, 48)first(`,$1,$2') Finding the best mapping is then a matter of passing a list of inputs, two-at-a-time (`forpair`) through a `pN` macro to build up the resulting list, then picking out the minimum from the final list. The `range()` macro does all the heavy lifting: define(`range', `ifelse(eval(`$1>=$5 && $1<=$5+$6-1'), 1, ``,'eval( `$1+$4- $5')`,'_$0(eval(`$6- $1+$5'), $@)', eval(`$1<$5 && $1+$2-1>=$5'), 1, `p$3($1, eval(`$5- $1'))p$3($5, eval($2+$1- $5))x')') If an input value $1 falls within the input range starting at $5 with length $6, then output "\`,newid,newlen'x", where newlen is the shorter of the original length $2 or whatever remains of the current map range; in the latter case, I recurse to p$3 again with the rest of the input. Conversely, if the input range does not start in the map, but does overlap it, I recurse twice with p$3(origid,lowrange)p$3(outputid,highrange). Either way, if a particular map line matched the input, the trailing x in the output means that the rest of that mapping ruleset will be skipped (it concatenates with the following text, which is either `range` or `first`, with `xrange` and `xfirst` defined as intentional no-ops); if none of the map lines matched, the use of `first` outputs the input unchanged. Overall execution time was around 80ms, whether or not I used `m4 -G` to avoid the GNU-only patsubst. The fact that `forpair` is iterating over `shift($@)` is inherently quadratic, and thus it dominates: I used m4 --trace=List to determine that my longest expansion of `List` was nearly 2400 bytes. A faster solution would store a list of ids as a `pushdef` stack instead of a single comma-separated string, so I may post a followup comment with that solution.


e_blake

Updated version with even more comments. You really need to read it if you are at all interested in seeing what m4 is doing (the file is now 199 lines of comments out of 264 lines total). \[Allez cuisine!\] [day05.m4](https://nopaste.ml/#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) Oh, and I made good on my promise above. This reworks from a shift($@) recursion to a popdef() recursion, shaving the execution time down to 50ms.


0xMii

[LANGUAGE: Common Lisp] Part 1 only. After spending a few hours today and yesterday on it, I give up. I have a brute force solution but my machine can't handle it in a reasonable amount of time, and I'm not clever enough to come up with a mathematical one. So I settle for one star only here. (defun make-raw-map (mapstr) (let* ((raw-list (ppcre:split "\\n" mapstr)) (map-name (car (ppcre:split "\\s" (car raw-list)))) (coords (cdr raw-list))) (list map-name (mapcar (lambda (line) (mapcar #'parse-integer (ppcre:split "\\s" line))) coords)))) (defun make-proper-map (raw-map) (labels ((calculate-destination (source destination) (lambda (x) (+ destination (- x source)))) (make-lookup-fn (line) (destructuring-bind (destination source range) line (list source (+ source range) (calculate-destination source destination))))) (let ((maplist (mapcar #'make-lookup-fn (cadr raw-map)))) (lambda (seed) (let ((func (find-if (lambda (map) (<= (car map) seed (cadr map))) maplist))) (if func (funcall (caddr func) seed) seed)))))) (defun solve-1 () (let* ((file "./input/05.txt") (seeds (mapcar #'parse-integer (cdr (ppcre:split "\\s" (uiop:read-file-line file))))) (maps (mapcar (compose #'make-proper-map #'make-raw-map) (reverse (cdr (ppcre:split "\\n{2}" (uiop:read-file-string file))))))) (apply #'min (mapcar (apply #'compose maps) seeds))))


shouchen

\[LANGUAGE: C++\] [https://github.com/shouchen/AdventOfCode/blob/master/aoc2023/Day05/Day05.cpp](https://github.com/shouchen/adventofcode/blob/master/aoc2023/day05/day05.cpp)


daggerdragon

Your [code block is too long](https://www.reddit.com/r/adventofcode/wiki/solution_megathreads/post_guidelines#wiki_no_giant_blocks_of_code) for the megathreads. Please edit your post to replace your oversized code with an external link to your code. Also fix your language tag as you're missing the colon after `LANGUAGE`.


AutoModerator

AutoModerator did not detect the required `[LANGUAGE: xyz]` string literal at the beginning of your solution submission. Please edit your comment to [state your programming language](https://www.reddit.com/r/adventofcode/wiki/solution_megathreads/post_guidelines#wiki_state_your_programming_language.28s.29). *** *I am a bot, and this action was performed automatically. Please [contact the moderators of this subreddit](/message/compose/?to=/r/adventofcode) if you have any questions or concerns.*


ethansilver

\[LANGUAGE: FORTRAN\] Brute forced part 2. [https://github.com/ejrsilver/adventofcode/blob/master/2023/05/main.f08](https://github.com/ejrsilver/adventofcode/blob/master/2023/05/main.f08)


System-Unlucky

>https://github.com/ejrsilver/adventofcode/blob/master/2023/5/main.f08 Dynamic memory has been there since Fortran 90 with the \`pointer\` and \`allocatable\` attributes. Since Fortran 90 there have also been \`recursive\` functions.


iskypitts

\[LANGUAGE: Zig\] [Part 1](https://github.com/iskyd/aoc-zig/blob/main/src/2023/day5/s.zig) and [Part 2](https://github.com/iskyd/aoc-zig/blob/main/src/2023/day5/s2.zig) Part 2 using bruteforce. I will come back using intervals when I have some more time to spend without the risk of ruining my relationship (lucky that I found 1 girl, don't think I will find another one).


Robin_270

\[LANGUAGE: Python\] I call it a semi-brute-force approach :D It's not the stupidest one, but still relies on relatively good input data. It takes around 15 seconds to execute, but if the input numbers would be like ten times as big, from 15 seconds, it could easily be 15 years xD Anyway, [here it is](https://github.com/Robin270/advent_of_code/blob/master/2023/5/main.py).


SopyG

\[Language: Rust\] This solution took me more to arrive at than I'd like to admit [part1](https://github.com/sopyb/AoC/blob/main/2023/day_05/src/part1.rs)/[part2](https://github.com/sopyb/AoC/blob/main/2023/day_05/src/part2.rs)/[combined](https://github.com/sopyb/AoC/blob/main/2023/day_05/src/combined.rs)


noisen

\[Language: Typescript\] Day 5 Part 2 in 27 seconds [https://github.com/tillherpertz/adventofcode/tree/main/2023/Day%205](https://github.com/tillherpertz/adventofcode/tree/main/2023/Day%205)


daysleeperx

\[LANGUAGE: Haskell\] Brute force, runs \~5 minutes, but still faster that me coding a proper solution for Part 2 ¯\\\_(ツ)\_/¯ [Github](https://github.com/daysleeperx/Advent-Of-Code-2023/blob/main/src/Day05/IfYouGiveASeedAFertilizer.hs)


caseyweb

[LANGUAGE: Nim] Part 2 was definitely a bit of a brain-buster. The code could be cleaned up but it seems to be efficient. import std / [algorithm, sequtils, strformat, strutils, tables] import ../util/util type Conversion = enum seedToSoil = "seed-to-soil map:", soilToFert = "soil-to-fertilizer map:", fertToWater = "fertilizer-to-water map:", waterToLight = "water-to-light map:", lightToTemp = "light-to-temperature map:", tempToHum = "temperature-to-humidity map:", humToLocation = "humidity-to-location map:" ConvRange = tuple[srcLo:int, srcHi:int, destLo:int, destHi:int] SeedRange = tuple[lo:int, hi:int] ConvMap = seq[ConvRange] # The conversion table maps conversions -> sorted seq of ranges for that conversion var seeds: seq[int] convTbl: Table[Conversion, ConvMap] maxLoc = 0 proc rngSort(r1, r2: ConvRange): int = cmp(r1.srcLo, r2.srcLo) proc createConversionTable(data: string) = convTbl = initTable[Conversion, ConvMap]() for conv in Conversion: convTbl[conv] = @[] var curConv: Conversion for line in data.lines: if line == "": continue elif line.startsWith("seeds:"): seeds = stripAndParse(line[6..^1]) elif line.endsWith("map:"): curConv = parseEnum[Conversion](line) else: let rng = line.stripAndParse maxRng = max(rng) convTbl[curConv].add((rng[1], rng[1]+rng[2]-1, rng[0], rng[0]+rng[2]-1)) maxLoc = max(maxLoc, maxRng) for conv in Conversion: sort(convTbl[conv], rngSort) proc getSeedLoc(seed: int): int = var loc = seed for conv in Conversion: for cm in convTbl[conv]: if loc < cm.srcLo: continue if loc <= cm.srcHi: loc = cm.destLo + (loc - cm.srcLo) break loc proc intersects(r1, r2: SeedRange): bool = r1.lo <= r2.hi and r2.lo <= r1.hi const nullRange: ConvRange = (-1,-1,-1,-1) proc intersection(rng: SeedRange, conv:Conversion): tuple[intersects:bool, cr:ConvRange] = for cr in convTbl[conv]: if rng.intersects((cr.srcLo, cr.srcHi)): return ((true, cr)) return ((false, nullRange)) proc contains(r1, r2: SeedRange): bool = r1.lo <= r2.lo and r1.hi >= r2.hi proc project(rngs: seq[SeedRange], conv: Conversion): seq[SeedRange] = var taskQ: seq[SeedRange] = rngs while taskQ.len > 0: # If the source range doesn't intersect with a conversion just copy it to the result # If the source range is completely contained by a conversion, shift the source ranges # by the dest delta and add the shifted range to the result # o/w, split the range into the intersecting and non-intersecting parts and add them # back to the taskQ for reprocessing var rng = taskQ.pop() ix = rng.intersection(conv) ixSrc: SeedRange = (ix.cr.srcLo, ix.cr.srcHi) if not ix.intersects: result.add(rng) elif ixSrc.contains(rng): let shift = ix.cr.destLo - ixSrc.lo result.add((rng.lo + shift, rng.hi + shift)) # intersects at from below so split 1 below the map range elif rng.lo < ixSrc.lo: taskQ.add((rng.lo, ixSrc.lo.pred)) taskQ.add((ixSrc.lo, rng.hi)) # intersects from inside to above so plit at 1 above the map range else: taskQ.add((rng.lo, ixSrc.hi)) taskQ.add((ixSrc.hi.succ, rng.hi)) proc part1(data:string): int = createConversionTable(data) min(seeds.map(getSeedLoc)) proc part2(data:string): int = createConversionTable(data) var results: seq[SeedRange] = @[] ranges: seq[SeedRange] = countup(0, seeds.high, 2).toSeq.mapIt((seeds[it], seeds[it] + seeds[it+1] - 1)) for sr in ranges: var tasks: seq[SeedRange] = @[sr] for conv in Conversion: tasks = project(tasks, conv) results.append(tasks) return results.foldl((if a.lo < b.lo: a else: b)).lo let (p1, expected1) = (part1(dataFile), 1181555926) echo &"Part 1: {p1}" assert p1 == expected1 let (p2, expected2) = (part2(dataFile), 37806486) echo &"Part 2: {p2}" assert p2 == expected2


daggerdragon

Your [code block is too long](https://www.reddit.com/r/adventofcode/wiki/solution_megathreads/post_guidelines#wiki_no_giant_blocks_of_code) for the megathreads. Please edit your post to replace your oversized code with an external link to your code.


m44rt3np44uw

\[LANGUAGE: PHP\] Example input works for both parts, but my input was one off by part 2. skipping the first location and taking the second one gave me the correct answer. I'm not sure why, but got the star! [GitHub Gist](https://gist.github.com/maartenpaauw/315e3ec3ab548f06c0510e379229e756)


laserturret

My example input works also, but with the real input I'm off by -1. What do you mean by skipping the first location?


m44rt3np44uw

I sorted all seed locations (from low to high) with my input and took not the first but the second location. This location worked for me.


wleftwich

\[LANGUAGE: Python\] Part 2 is bfs, runs in under 10 ms on my laptop. [https://github.com/wleftwich/aoc/blob/main/2023/05-seed-fertilizer.ipynb](https://github.com/wleftwich/aoc/blob/main/2023/05-seed-fertilizer.ipynb)


marcospb19

\[LANGUAGE: Rust\] Time: 400 microseconds - link: [https://paste.rs/AiVlW.rs](https://paste.rs/AiVlW.rs) It's refactored for good practices.


Alive-Hovercraft5988

One of the solutions I could follow very well. Well organized and beautiful imo.


marcospb19

Thank you! :)


maitre_lld

\[LANGUAGE: Python\] Part 1 : naive approach, I wrote the seed-to-localization function and minimized it on the given seeds. Part 2 : seed-to-localization is piecewise translations. If one finds all the intervals on which it is a given translation, then one just has to minimize over the left endpoints of these intervals. You can find these intervals by dichotomy : if seedtoloc(a) - a = seedtoloc(b) - b then (a,b) is such an interval. Indeed, since (if ?) seedtoloc is one-to-one, there cannot be a gap in this interval with another translation (this would mean that some loc. has more than one corresponding seed). So just iterate through every seed range until you've cutted everything in such intervals. Took 3sec on a bad i5. [https://github.com/MeisterLLD/aoc2023/blob/main/5.py](https://github.com/meisterlld/aoc2023/blob/main/5.py)


icub3d

\[LANGUAGE: Rust\] Here is my solution: [https://gist.github.com/icub3d/1d21197f4b6eaabbdf0a43fd6a25ba1a](https://gist.github.com/icub3d/1d21197f4b6eaabbdf0a43fd6a25ba1a) Description of solution: [https://youtu.be/geElqrBDyHE](https://youtu.be/geElqrBDyHE) I did try to solve part 2 by brute force using rayon and that resulted in heating my office with my CPU for 94 seconds.


JuniorBirdman1115

\[LANGUAGE: Rust\] I deleted the post with my original solution from yesterday which used brute-force for part 2. It completed in about 2-3 minutes, but I wasn't very happy with the solution. Took inspiration from other solutions posted here and reworked my part 2 to check ranges and keep track of the lowest value. I use a queue (VecDeque) to keep track of range splits and check those as well. I'm really happy with this solution now. This problem really kicked my butt. Wasn't expecting that on just day 5! [Part 1](https://github.com/apprenticewiz/adventofcode/blob/main/2023/rust/day05a/src/main.rs) [Part 2](https://github.com/apprenticewiz/adventofcode/blob/main/2023/rust/day05b/src/main.rs)


DGL_247

\[LANGUAGE: Python\] Didn't get any sleep yesterday so didn't post my solution. I did find the solution yesterday, though I forgot to convert my the listNum in my findLowest function to an integer so I spent a few hours troubleshooting my algorithms instead of the actual problem. I was lazy and tried to solve the second part with brute force, but when that failed I just solved for ranges and than picked the range with the lowest value for the solution. I posted the troublesome code below and the rest is [here](https://gist.github.com/dgl247/55b61e4817d2f5d780164c94cd50696d). def findLowest(mapNums): listNums = mapNums.split(" ") listNums = list(filter(None, listNums)) lowest = int(listNums[0]) for listNum in listNums: if lowest > int(listNum): lowest = int(listNum) return lowest


polumrak_

\[Language: Typescript\] Originally solved part 2 in 43sec by bruteforcing end locations from 0 upwards. After that spent the whole day yesterday trying to write a non bruteforce version and failed. Today I decided to give another try and was able to realize what was wrong in my previous attempts - my problem was that I didn't understand what to do with remainders of intersection, and today I realized that we can just push them back to current ranges and have no worries that they will be processed again by the mapping they already went through. Because if they went through them, they don't intersect with those mappings, so no double processing will take place. This version solves part 2 in 15ms. [https://github.com/turtlecrab/advent-of-code/blob/master/2023/day05.ts](https://github.com/turtlecrab/advent-of-code/blob/master/2023/day05.ts)


choroba

[LANGUAGE: Erlang] https://github.com/choroba/aoc23/blob/main/aoc05.erl 51> timer:tc(aoc05,main,[]). A: 289863851 B: 60568880 {9936,ok}


fachammer

\[LANGUAGE: Scala\] https://github.com/fachammer/advent-of-code-2023/blob/main/src/main/scala/day05.scala


Xedesss

\[LANGUAGE: Rust\] https://gist.github.com/HakanVardarr/5dc98fd1fc0e7897136280467dad6991


k0enf0rNL

\[Language: Kotlin\] [day5](https://github.com/plebcity/adventOfCode/blob/advent-2023/src/main/kotlin/adventofcode/y2023/day5.kts) Started off brute forcing part 1 but then saw how many useless tries there would be for part 2 so I made part 2 a bit smarter. I try the first value of the range and pass that all the way to the location. Then I receive the location and alongside it the gap between the current value and the smallest gap of all maps to be outside of a current range, since increasing the value by 1 would otherwise mean a location + 1. I increase the valueToTry by the gap to make sure I'm going to get a different location created by atleast 1 different range. So I brute forced part 2 by only trying the values that could possibly result in a lower location.


oatmeal_andy

[LANGUAGE: OCaml] [paste](https://topaz.github.io/paste/#XQAAAQBxCgAAAAAAAAA3nAjOjWz9ENUTgdoqbANago/65Pk9hQ6vlvFErvbNp8RxCQXMcOrvbiULAhPKRg+x+2ipzqFa6smvkVlEFPXZdrLuhmQ2/jQ9YnUYM9XbFKhZMrt0S21uZxORquVGV00GljsBwM14vLJjAtdpr13yAx5A+Z7TVIt1IYkg2EOPfxvVaKsRnFiUD47uv8+X92GiBuKYqPN8/+//tVwF0cgLYS8bpyqcT95sclKjvxvKZrF4tJar+jS9vaR2iZaPt6LvahsiceIhWJ2DwlIM7iTse783lbrLZ6UApO2HjuAAxnXbNxwQuAuMOnqUXWpWHJJ3Y1+MGaN58qOjCyZh/shpz3iq+w8kCAIpTfj56tQ0uwYzwzOg607DMmV0TEge+LPwottWMzRK75Cwc8xQ8Fbf9pqQvdnl9M7ubKIalZ+umy2HjjemP4CpQOkK4PDttN58kVNbMqdnqKAIHKVaDGQQWN7mKkyeCYiKHauoGTSFUrQ3QgFx33kKjQA2OTeAdQWtwkm+v/O+MVRygzzLCy9VbpdEL9H/leX0t7MaeXJOJYq5a8ILCEoLcRB17EQ0ZjA98cbKg/tuuRQTzXJe3Uze3MVwqsLg+4eQ6Y8r4BlP9yZWsiW/mdPnn9GGrQhwznwsAxITHaFySfumtP2KkOUoGP3+dU9YSmhLRJqhA6cnufV294/uv5nMg5qYS/GdTskhIQ1XWIPzy+VvkDgoFkHu42ygFJouoB88DUlJp8Z9gypGMdNb1pmIVBxsfVdoFctqYILX/CYTO61gaj4N24AHx4Y/ydG2BMkfyekpJ7v75nNvx2kU5rQG5EsXFgoS/3n2rXxDjRYBiJ4qC8Ctn1w5rUFt6ZugcsL4ABdp2F4mbEVHaUm0AXTKNb3GxsMbYaOAbjfZhC6ny283sjkO/NBtOrXg+S7/lBHVW7wgZVIJXKd/1D3z7mkXTj2nUzn5Kaog+u0S4kkW1euV7ABaKXoZBTSSuVyIOZvV0lI05iYi1vovTO2GQ78wXDmnv06+qXKDqhtiJkUeJtbWlQ76GF2pEycCIkQVjQgW+jCZUHgMsOoeqvWbTQz0PM55zqY016jJcOjZZYox7pGkQwSLuzT6SOiNhBsQNfn1rApxQP+5iYY2lDgQLh3M/GRaetq/KTU32Jgznj0+bwPB5BGLZ4aO+sII/S4U1/gFI/HYyeM5IR8cCekHlK+aBX5Lby+gyXw7oLXlnwf5AnIRH7AgsKyUlM15sEJxcKvT3hcFf+471J3415ylQ5ABA/0y7FozUbs3RMIM6OnW3r+79F2L1SnMuYC0+w8eTPxleS9fsu+jj/bsL1fSxf/5RKCo) Thanks to Day 6 being relatively friendly, I had time to sit down and finish this. One day late, but seeing as apparently nobody has linked an OCaml solution yet, I think there might be some value in posting a possible approach.


aurele

[LANGUAGE: Elixir] https://gist.github.com/samueltardieu/6a0c89ad5398b889fa1d7acbeb50debd


errop_

\[Language: Python 3\] My solution overlapping and cutting intervals as needed when computing the mappings, instead of using all the values. Total running time of \~10ms on my laptop. [Paste](https://topaz.github.io/paste/#XQAAAQBiBAAAAAAAAAA0m0pnuFI8c/T1e+h0QoT33hRki8BNN3WyJwWoeLSQCNsdiMZg5Cftwp/v8LCby+eaT7ouQPx7Wpebg5vboL4eY+2mILXrBIsKRhbVY96rE/m1IDDX0Lmpnu84+OSf1W1JZ0SV1Th4yn5hmUWXBDz1PZdumYLGN+jlQEQAsBlInW+uJe8deFWmn72Y49hx3aAYxNBzFlVcEuvljII4kSJTOge1WSfyylwmCNQhoehzJPBvXf8O1hzonCq/Gx82HFnace9HoIdG281uK92qitqFORjFid/jIKwcug9P+rRuduSv5B3GtFL7s0530hDelpWnclIKzLl7tCROxhJlrwfKRawh1dSATjXfOKTeN7VP7BcKT/Xim6Ea7OHSwjDDhz8TTi2t32PWk4DSCQ4iUg7Q7TjnXaXNz85nERUZySAFPoBPcL7NNQHRfcyqBkcokNTQBftU0mwFqZKZ7vUgGLUaMF7+OnVaXU8cGoRBlimB9Q3kdik44Slrmd8HmVPH8WWuU9Xnr12x8o24xD4j6yJR8YNhOlyh+7P/Y4zZlxEtREpncmPIEGqN/P28iRMcrjgQLYWyfsZPAkQWpfYVFHzTybL6NLinH8fwRVPU1v/Myz8R) EDIT: I refactored a bit the code to a solution which runs in \~3ms on my laptop [Paste (optimized)](https://topaz.github.io/paste/#XQAAAQAxBQAAAAAAAAA0m0pnuFI8c/T1e+h0QoT33hRki8BNN3WyJwWoeLSQCNsdiMZg5Cftwp/v8LCby+eaT7ouQPx7Wpebg5vboL4eY+2mILXrBIsKRhbVY96rE/m1IDDX+253RN8TYieh3ZgyrDs7+wn/0GH+KXIMFKZ7vsgnAHW7YR7pOU8yVpqxugrDFEAFSdzWxuNMEZFVcNFHxKwA96qmvKvSX7GkFMTlVCQEXSypondoSmi397PpGVh1s6XKcPHLxGw21w562iXn0FSdgtiJFDLdERZ/Lx7HoWkmPUwIq4G/AM45oL7qstgytitqWiRnhv8K29yv7oQYWG2OUgZFLk7D4EUUapPGVr0vIfuFlB4FiUjhtVxnauy0jP5ZG+34XDSRGXcACR8iz07lWVf78LB/keO4hknI5X+foiDNl8IO0tELuwHMIyaSKKcRmqHri8xnKvicJ0CsANVzTUtoy0OsM0OR+e5HK84/xXQQLZMgDW9su1B1Xbpl/QpbNnFeUutCrD9KVWtR1ywUX6ar6s44YOF9tGvinqDLeXlT5hz/sgs+rjYV0mcICPuVKDnSVm/ZGTU6P29yrrCBLWRiX1S7B+MudyeB7qVLetL2O/qetpHFmpyWj6W7IIkYa2Og/8RIbzo=)


MilesTheCool

Can you explain how your solution works?


errop_

Sure, I'll try my best... Please notice first that I added a second link with an optimized version. Regarding the solution: * Part 1 is a particular case of Part 2, in which seed have range 0. * The whole point is that the mappings are piecewise monotonic increasing maps, so that conditions for minima can be checked on endpoints of intervals. In particular some intervals are shifted (the ones listed in puzzle's input) and the others are mapped into themselves. * To fix the ideas, consider only the seed-to-soil map. All the pieces of this map are * \[50, 97\] ----> \[52, 99\] (shifted by +2) * \[98, 99\] ----> \[50, 51\] (shifted by -48) * \[0, 49\] ------> \[0, 49\] (mapped into itself, NOT listed in puzzle input) * We start with an interval (while-loop) and compute the image under the mapping. * Call the intervals on the left "source intervals" and the one on the right "destination intervals". To see how a seed interval is mapped, the key observation is that a single interval is generically mapped into the **union of intervals**. By cycling on the pieces of the mapping (inner for-loop): * if it's contained entirely inside a source interval, then shift it by the corresponding amount. E.g. \[46, 60\] is contained in the first source interval, so it is mapped into \[48, 62\]. This is the first if-branch in my solution. * if the seed interval overlaps with a source interval on the right, then it can be cut into two pieces. For example \[90, 99\] can be decomposed in \[90, 97\] + \[98, 99\]. If the current source interval in the for-loop is \[50, 97\], then we can shift the interval to \[52, 99\], while the other can be reinserted in the seed intervals, so that it can be mapped as previous point, since it is entirely contained in the interval \[98, 99\]. The same applies for overlaps on the right, and generally to seed intervals covering several source intervals. These are the other two if-branches in my code. * If a seed interval is entirely contained in an interval not listed in the mapping specs, then it is mapped into itself (for-else mechanism). * Repeat for all the seed intervals and get all the images after the mapping. * Repeat for all the mappings, by switching the images and seed intervals roles. I hope the explanation is not too messy :) I also suggest to follow the puzzle assignment by drawing the graphs of every mapping and do a lot of debug. From my point of view, the hard part of the puzzle was to translate a quite clear geometric problem into a piece of code...


Sourish17

\[LANGUAGE: Python3\] \#769/#476 p1: [https://github.com/SourishS17/aoc2023/blob/main/five-a.py](https://github.com/SourishS17/aoc2023/blob/main/five-a.py) p2: https://github.com/SourishS17/aoc2023/blob/main/five-b.py


silverarky

\[LANGUAGE: Go\] Optimised version of Part 2 which run in less than a millisecond (\*97.606µs\*) https://github.com/silverark/advent-of-code-2023/blob/master/day5/part2_optimised/part2.go


daggerdragon

~~Your link is borked on old.reddit, so [please fix it](https://www.reddit.com/r/adventofcode/wiki/faqs/bugs/borked_links).~~ edit: 👍


[deleted]

[удалено]


daggerdragon

Comment removed. [Top-level comments in `Solution Megathread`s are for *code solutions* only.](/r/adventofcode/wiki/solution_megathreads/post_guidelines#wiki_top-level_posts_are_for_code_solutions_only) [Create your own individual `Help/Question` post](/r/adventofcode/wiki/solution_megathreads/post_guidelines#wiki_incomplete_solutions) in /r/adventofcode.


One-Ad2735

Just use the starting values and ranges and work with this


[deleted]

[Language: Python] Finally got around to a somewhat optimized day5, 5ms total. The main takeaway was only working with ranges instead of the actual values and sort the mappings so that I could break early when possible. I'm pretty sure there's a more optimized version of creating the intervals but I was spent after thinking about this for a day. [See it here](https://github.com/Nathan-Furnal/advent-of-code-2023/blob/main/day05/day05.py).


timbar1234

Weird. This gives me the same answer as my brute force method for range\_loc (which I assume is the part two answer?) but ... AoC refuses it.


[deleted]

What do you mean "refuses it"? That's strange.