[Day 5] If You Give A Seed A Fertilizer// Advent of Code 2023 (Python)
Solving Advent of Code 2023 Day 5 in Python: mapping seeds on demand, then range intersections that beat a 34 minute brute force for seed ranges.

If You Give A Seed A Fertilizer (via DALL-E 3)
Advent of Code
You take the boat and find the gardener right where you were told he would be: managing a giant “garden” that looks…adventofcode.com
Part One
You take the boat and find the gardener right where you were told he would be: managing a giant “garden” that looks more to you like a farm.
“A water source? Island Island is the water source!” You point out that Snow Island isn’t receiving any water.
“Oh, we had to stop the water because we ran out of sand to filter it with! Can’t make snow with dirty water. Don’t worry, I’m sure we’ll get more sand soon; we only turned off the water a few days… weeks… oh no.” His face sinks into a look of horrified realization.
“I’ve been so busy making sure everyone here has food that I completely forgot to check why we stopped getting more sand! There’s a ferry leaving soon that is headed over in that direction — it’s much faster than your boat. Could you please go check it out?”
You barely have time to agree to this request when he brings up another. “While you wait for the ferry, maybe you can help us with our food production problem. The latest Island Island Almanac just arrived and we’re having trouble making sense of it.”
The almanac (your puzzle input) lists all of the seeds that need to be planted. It also lists what type of soil to use with each kind of seed, what type of fertilizer to use with each kind of soil, what type of water to use with each kind of fertilizer, and so on. Every type of seed, soil, fertilizer and so on is identified with a number, but numbers are reused by each category — that is, soil
123and fertilizer123aren’t necessarily related to each other.For example:
seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4water-to-light map:
88 18 7
18 25 70light-to-temperature map:
45 77 23
81 45 19
68 64 13temperature-to-humidity map:
0 69 1
1 0 69humidity-to-location map:
60 56 37
56 93 4The almanac starts by listing which seeds need to be planted: seeds
79,14,55, and13.The rest of the almanac contains a list of maps which describe how to convert numbers from a source category into numbers in a destination category. That is, the section that starts with
seed-to-soil map:describes how to convert a seed number (the source) to a soil number (the destination). This lets the gardener and his team know which soil to use with which seeds, which water to use with which fertilizer, and so on.Rather than list every source number and its corresponding destination number one by one, the maps describe entire ranges of numbers that can be converted. Each line within a map contains three numbers: the destination range start, the source range start, and the range length.
Consider again the example
seed-to-soil map:50 98 2
52 50 48The first line has a destination range start of
50, a source range start of98, and a range length of2. This line means that the source range starts at98and contains two values:98and99. The destination range is the same length, but it starts at50, so its two values are50and51. With this information, you know that seed number98corresponds to soil number50and that seed number99corresponds to soil number51.The second line means that the source range starts at
50and contains48values:50,51, …,96,97. This corresponds to a destination range starting at52and also containing48values:52,53, …,98,99. So, seed number53corresponds to soil number55.Any source numbers that aren’t mapped correspond to the same destination number. So, seed number
10corresponds to soil number10.So, the entire list of seed numbers and their corresponding soil numbers looks like this:
seed soil
0 0
1 1
… …
48 48
49 49
50 52
51 53
… …
96 98
97 99
98 50
99 51With this map, you can look up the soil number required for each initial seed number:
Seed number
79corresponds to soil number81.Seed number
14corresponds to soil number14.Seed number
55corresponds to soil number57.Seed number
13corresponds to soil number13.The gardener and his team want to get started as soon as possible, so they’d like to know the closest location that needs a seed. Using these maps, find the lowest location number that corresponds to any of the initial seeds. To do this, you’ll need to convert each seed number through other categories until you can find its corresponding location number. In this example, the corresponding types are:
Seed
79, soil81, fertilizer81, water81, light74, temperature78, humidity78, location82.Seed
14, soil14, fertilizer53, water49, light42, temperature42, humidity43, location43.Seed
55, soil57, fertilizer57, water53, light46, temperature82, humidity82, location86.Seed
13, soil13, fertilizer52, water41, light34, temperature34, humidity35, location35.So, the lowest location number in this example is
35.What is the lowest location number that corresponds to any of the initial seed numbers?
Phew! That was a big read! But often bigger problems have the most trivial solutions.
💭 On a closer observation, we can clearly make out that this is the standard map of map of map... problem where you ned to traverse across multiple maps almost in a pipe | like fashion where:
location = map1[map2[map3[map4[map5[map6[seed]]]]]]
where map1...N are being built in realtime while parsing the puzzle input!
So, as always, let’s first write a test case as given in the question, so we can start to structure our code and validate that with base case:
def test_find_lowest_location_number():
almanac = """seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4
"""
answer = find_lowest_location_number(almanac)
assert answer == 35, f"Tst failed: Expected 35, got {answer}"
print("All tests passed succesfully!")
Now, it’s time to whip out a quick terminal to do some string operations, and as with the case with last few challenges, it seems like our good’ol friend split() will have to once again do some heavy lifting!


💡 Might be good to start looking into regex
refor these usecases as well, but since the puzzle input is predictable and well structured, we can get away by using methods likedata.split("\n\n")[0].split(":")[0]. In real life aka production code, this will not fly, but then again, the amount of such hacky code I have seen in production, only if I had ₹1 for every time, I would be a rich person!
Once, we know how we can parse the input, let’s try to implement our find_lowest_location_number() function. I can envision based on experience that our map building logic can be common here as we need to generate a dict based on destination, source, range_length as shared in base test case above!

💡 We don’t really need to worry about any source numbers that aren’t mapped, as we can just assume
source == destinationwhich becomes quite trivial in python withdict.get(key, default_value)where default value will just be thekeyitself.
So, I was able to write a simple loop which will basically call each and every map chained to one another and will store the final location in seed_location_map and from there we could just return min(seed_location_map.values()) for the answers.
💡 Edge case: We need to ensure that we maintain the order of maps as we are parsing the input, as if we mess up the order, the pipe
|approach as we discussed above wouldn’t work. I am using acollections.dequeobject to ensure we reach from seed to the seed-to-soil > soil-to-fertilizer > fertilizer-to-water > water-to-light > light-to-temperature > temperature-to-humidity > humidity-to-location location.

So, with a lot of hit and trial and basically after living in the debugger, we can see that we are able to build our queue_of_dicts properly, where it is maintaining the correct order of dicts as parsed! (Hint: keeping a track of dict_name in queue_of_dicts does help a lot here).
# --- Day 5: If You Give A Seed A Fertilizer ---
## --- Part One ---
from collections import deque
def dict_builder(raw_map):
raw_map = raw_map.strip("\n")
dict_name, mappings = raw_map.split(':')
dict_name = dict_name.split()[0]
mappings = mappings.strip("\n").split("\n")
dict_data = {}
for row in mappings:
dest, src, range_length = [int(num) for num in row.split()]
for i in range(range_length):
dict_data[src+i] = dest+i
return dict_name, dict_data
def find_lowest_location_number(almanac):
almanac = almanac.split("\n\n")
# extract out seeds? assuming it's always first in the puzzle input
seeds = [int(seed) for seed in almanac[0].split(":")[1].strip().split(" ")]
queue_of_dicts = deque()
for raw_map in almanac[1:]:
tmp_name, tmp_data = dict_builder(raw_map)
queue_of_dicts.append((tmp_name, tmp_data))
# print(queue_of_dicts)
seed_location_map = {}
for seed in seeds:
final_val = seed
for _, tmp_map in queue_of_dicts:
final_val = tmp_map.get(final_val, final_val) # update if found, else keep it same as key
seed_location_map[seed]=final_val
print("Seed location map:", seed_location_map)
return min(seed_location_map.values())
def part_1():
with open("day_5/input.txt", "r") as f:
almanac = f.read()
answer = find_lowest_location_number(almanac)
print("Lowest location number:", answer)
def test_find_lowest_location_number():
almanac = """seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4
"""
answer = find_lowest_location_number(almanac)
assert answer == 35, f"Tst failed: Expected 35, got {answer}"
print("All tests passed succesfully!")
if __name__ == "__main__":
test_find_lowest_location_number()
❯ /Users/jmalik/.pyenv/versions/3.11.0rc2/bin/python /Users/jmalik/github/advent-of-code-2023/day_5/if_you_give_a_seed_a_fertilizer.py
Seed location map: {79: 82, 14: 43, 55: 86, 13: 35}
All tests passed succesfully!
Let’s load up the puzzle input…

And let’s run it against our function here!
Well….after 1 minute we were still waiting for it to finish…

Look at that CPU% 📈
And after 2 minutes of processing on my 10 core M1 Macbook, I was sure this is not really close to being optimal to solve it and… ‼️

And we hit the motherload!
So, let’s quit the program using Ctrl+C to break! Let’s see why?
If we observe the puzzle input v/s base test case, it will evident what is the bottleneck:

A chunk of puzzle input
The numbers are just too damn high ⏫, and our approach of building full blown hashmaps (despite optimising for missing numbers in map by just returning the key, see 💡 above) using dict_builder() seems to waste a lot of CPU cycles especially when we see that the number of seeds are just 20!
seeds: 950527520 85181200 546703948 123777711 63627802 279111951 1141059215 246466925 1655973293 98210926 3948361820 92804510 2424412143 247735408 4140139679 82572647 2009732824 325159757 3575518161 370114248
Surely, there should be a way for us to avoid all of the preprocessing and just do it on demand?
💡 Instead of creating a complete mapping for each step, we can write a function that, given a number and a map range, computes the corresponding number dynamically. This way, we avoid holding large maps in memory!
In this updated code, find_mapped_number function dynamically calculates the mapped number for a given input number and a single mapping range.

It works by iterating through a list of mapping rules and, for each rule, checks if the given number falls within the specified source range. If it does, the function calculates the mapped number by adding the difference between the given number and the source range start to the destination range start.
This function is used within find_lowest_location_number to process each seed number through the series of mappings without storing the entire range of mappings in memory. This should resolve the memory issue and allow the program to handle large input data efficiently 🤞
Our base test case is working as intended!
❯ /Users/jmalik/.pyenv/versions/3.11.0rc2/bin/python /Users/jmalik/github/advent-of-code-2023/day_5/if_you_give_a_seed_a_fertilizer.py
All tests passed succesfully!
Let’s try to run this again for input.txt and let’s see how quick it is, this time?
[Running] python3 "/Users/jmalik/github/advent-of-code-2023/day_5/if_you_give_a_seed_a_fertilizer.py"
The lowest location number is: xxxxxx
[Done] exited with code=0 in 0.05 seconds
Got the answer in 0.05 seconds! Isn’t that crazy how we were struggling with OutOfMemoryError just a while back, and with a small change, we are able to solve the same problem in just 0.05 seconds!
💭 Kids, this is why DSA is very important! You can save so much $$$ in production code wrt your compute and data cost if you write your code efficiently!
Let’s put our answer into the box and…

🎉🎉
Here’s our pythonic code till now! Encapsulating the logic within a class allows better organization and readability!
# --- Day 5: If You Give A Seed A Fertilizer ---
class AlmanacProcessor:
def __init__(self, almanac):
self.almanac = almanac
self.seeds, self.mappings = self._parse_input(almanac)
def find_lowest_location_number(self):
"""Finds the lowest location number based on the almanac's rules."""
seed_locations = {}
for seed in self.seeds:
current_number = seed
for map_data in self.mappings:
current_number = self._find_mapped_number(current_number, map_data)
seed_locations[seed] = current_number # location of seed in last map
return min(seed_locations.values())
def _parse_input(self, input_data):
"""Parses the input data into seeds and mappings."""
sections = input_data.strip().split('\n\n')
seeds = list(map(int, sections[0].split(': ')[1].split()))
mappings = [section.split(':\n')[1].split('\n') for section in sections[1:]]
return seeds, mappings
def _find_mapped_number(self, number, map_data):
"""Finds the corresponding mapped number based on the mapping rules."""
for line in map_data:
if line.strip():
dest_start, src_start, length = map(int, line.split())
if src_start <= number < src_start + length:
return dest_start + (number - src_start)
return number
def part_1():
with open("day_5/input.txt", "r") as f:
almanac = f.read()
processor = AlmanacProcessor(almanac)
lowest_location = processor.find_lowest_location_number()
print("The lowest location number is:", lowest_location)
def test_find_lowest_location_number():
almanac = """seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4
"""
processor = AlmanacProcessor(almanac)
lowest_location = processor.find_lowest_location_number()
assert lowest_location == 35, f"Tst failed: Expected 35, got {lowest_location}"
print("All tests passed succesfully!")
if __name__ == "__main__":
# Uncomment the line below to run the test
# test_find_lowest_location_number()
part_1()
Part Two
Everyone will starve if you only plant such a small number of seeds. Re-reading the almanac, it looks like the
seeds:line actually describes ranges of seed numbers.The values on the initial
seeds:line come in pairs. Within each pair, the first value is the start of the range and the second value is the length of the range. So, in the first line of the example above:seeds: 79 14 55 13
This line describes two ranges of seed numbers to be planted in the garden. The first range starts with seed number
79and contains14values:79,80, …,91,92. The second range starts with seed number55and contains13values:55,56, …,66,67.Now, rather than considering four seed numbers, you need to consider a total of 27 seed numbers.
In the above example, the lowest location number can be obtained from seed number
82, which corresponds to soil84, fertilizer84, water84, light77, temperature45, humidity46, and location46. So, the lowest location number is46.Consider all of the initial seed numbers listed in the ranges on the first line of the almanac. What is the lowest location number that corresponds to any of the initial seed numbers?
So, reading the Part Two of the problem…
💭 It’s evident that we have more number of seeds that we initially thought and it will require us to implement as similar range logic for
seedsas we did for themappings.
Let’s play a bit in ipython3 do build the logic to expand seeds:

And now let’s update our code to generate out seeds list correctly:

And it seems like base test case is working as we get: 46 as the answer.
[Running] python3 "/Users/jmalik/github/advent-of-code-2023/day_5/if_you_give_a_seed_a_fertilizer.py"
All tests passed succesfully!
Here’s our code:
# --- Day 5: If You Give A Seed A Fertilizer ---
class AlmanacProcessor:
def __init__(self, almanac):
self.almanac = almanac
self.seeds, self.mappings = self._parse_input(almanac)
def find_lowest_location_number(self):
"""Finds the lowest location number based on the almanac's rules."""
seed_locations = {}
for seed in self.seeds:
current_number = seed
for map_data in self.mappings:
current_number = self._find_mapped_number(current_number, map_data)
seed_locations[seed] = current_number # location of seed in last map
return min(seed_locations.values())
def _parse_input(self, input_data):
"""Parses the input data into seeds and mappings."""
sections = input_data.strip().split('\n\n')
# part One assumes seeds to be given as a list of integers
# seeds = list(map(int, sections[0].split(': ')[1].split()))
# part Two explains seeds to be given as a list of ranges as a pair
seed_ranges = sections[0].split(': ')[1].split()
seeds = self._generate_seed_list(seed_ranges)
mappings = [section.split(':\n')[1].split('\n') for section in sections[1:]]
return seeds, mappings
def _generate_seed_list(self, seed_ranges):
"""Generates a list of seeds based on the ranges provided in pairs"""
seeds = []
for i in range(0, len(seed_ranges), 2):
start = int(seed_ranges[i])
length = int(seed_ranges[i + 1])
seeds.extend(range(start, start + length))
return seeds
def _find_mapped_number(self, number, map_data):
"""Finds the corresponding mapped number based on the mapping rules."""
for line in map_data:
if line.strip():
dest_start, src_start, length = map(int, line.split())
if src_start <= number < src_start + length:
return dest_start + (number - src_start)
return number
def main():
with open("day_5/input.txt", "r") as f:
almanac = f.read()
processor = AlmanacProcessor(almanac)
lowest_location = processor.find_lowest_location_number()
print("The lowest location number is:", lowest_location)
def test_find_lowest_location_number():
almanac = """seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4
"""
processor = AlmanacProcessor(almanac)
lowest_location = processor.find_lowest_location_number()
# assert lowest_location == 35, f"Tst failed: Expected 35, got {lowest_location}" # As per part 1 logic for seeds
assert lowest_location == 46, f"Tst failed: Expected 35, got {lowest_location}" # As per part 2 logic for seeds
print("All tests passed succesfully!")
if __name__ == "__main__":
# Uncomment the line below to run the test
test_find_lowest_location_number()
main()
Let’s run for input.txt I don’t have a good feeling about this as the number of seeds is now too damn high!

Yep, process running from 1:58 mins 😅

Lost my patience after waiting for 4:22 minutes!
Let’s exit it and take another look at the bottleneck now. Clearly, it’s the insanely high number of seeds in the puzzle input:
seeds: 950527520 85181200 546703948 123777711 63627802 279111951 1141059215 246466925 1655973293 98210926 3948361820 92804510 2424412143 247735408 4140139679 82572647 2009732824 325159757 3575518161 370114248
which basically translates to the huge numbers of seeds we need as per:
seed_start, till_range
950527520, 85181200
546703948, 123777711
63627802, 279111951
1141059215, 246466925
1655973293, 98210926
3948361820, 92804510
2424412143, 247735408
4140139679, 82572647
2009732824, 325159757
3575518161, 370114248
💡 One of the bottlenecks I can see is where I am trying to store
seed_locationsdict for all seeds and then later running amin(seed_locations.values())to get the lowest location. Maybe we can just keep the minimum value and compare on each iteration within the loop?!

This should save some time?
Let’s run it again? 🤞

Well, not much help!
I think we need to deep dive further into reducing our reliance on memory and computation and try to reduce the number of calculations somehow! 🤔
💡 We need to optimise our mapping to preprocess into a dict and avoid generating all seeds and storing them in memory, instead we can just do everything on the fly? We can take a seed, go through the maps to find the location and just check as per
lowest_location = min(lowest_location, current_number)to continously update the lowerst location.That should help a lot in fixing the performance of this code!
NOPE!
💡I also wondered if there is any overlap in seed numbers leading to duplicate calculation and hence ended up using excel to just create seed number ranges available to us:
6,36,27,802 to 34,27,39,753
54,67,03,948 to 67,04,81,659
95,05,27,520 to 1,03,57,08,720
1,14,10,59,215 to 1,38,75,26,140
1,65,59,73,293 to 1,75,41,84,219
2,33,48,92,581 to 2,33,48,92,581
2,42,44,12,143 to 2,67,21,47,551
3,57,55,18,161 to 3,94,56,32,409
3,94,83,61,820 to 4,04,11,66,330
4,14,01,39,679 to 4,22,27,12,326
Turns out there is no overlap. So, keeping a track of processed_seeds will also not help! 🤦♂️
I think now the only solution I can think off is to parallelize the seed -> location lookup and just find the lowest seed in each range and then compare at the end?
❯ /Users/jmalik/.pyenv/versions/3.11.0rc2/bin/python /Users/jmalik/github/advent-of-code-2023/day_5/if_you_give_a_seed_a_fertilizer.py
Starting a thread for seed range: 950527520 1035708720
Starting a thread for seed range: 546703948 670481659
Starting a thread for seed range: 63627802 342739753
Starting a thread for seed range: 1141059215 1387526140
Starting a thread for seed range: 1655973293 1754184219
Starting a thread for seed range: 3948361820 4041166330
Starting a thread for seed range: 2424412143 2672147551
Starting a thread for seed range: 4140139679 4222712326
Starting a thread for seed range: 2009732824 2334892581
Starting a thread for seed range: 3575518161 3945632409

It did spawn 10 proccesss, 1 for each range but..
I think we need MOAR processes! Need to divide and conquer further!
Let’s do some subprocesses in batches of 1000?

Wait! I am making it too complex!! While I did get the correct answer from brute force in 34 minutes while my laptop ran 🔥, there has to be a simpler way!
Let’s go back to drawing board!
💡 The essence of part 2 solution lies in handling of the mappings as ranges instead of individual values which are well over in ~4Bn+.
During the conversion process, we can iterate over each mapping, determining the intersection between the current value ranges (starting with seeds) and the conversion ranges specified in the (subsequent) maps.
If a mapping applies to a particular range, we can transform it accordingly; otherwise, the range remains unchanged.
💡 This approach efficiently reduces the computational load by avoiding the need to process each individual value, instead working with batches of values encapsulated within ranges.
After processing all the mappings, we can get a final set of location ranges, post which we can find the lowest possible location number by selecting the minimum lower bound from these final location ranges.
Here’s the final code:
# --- Day 5: If You Give A Seed A Fertilizer ---
# --- Part Two ---
class AlmanacProcessor:
def __init__(self, almanac):
self.seeds = []
self.maps = []
self._parse_input(almanac)
def _parse_input(self, almanac):
"""Parses the input sections into seeds and maps."""
self.sections = [block.splitlines() for block in almanac.strip().split("\n\n")]
self.seeds = [int(i) for i in self.sections[0][0].split()[1:]]
self.maps = [[list(map(int, line.split())) for line in block[1:]] for block in self.sections[1:]]
def process_maps(self):
"""Processes each map to convert the ranges according to the almanac."""
# this will store the lower and upper bounds of each range
values = [(self.seeds[i], self.seeds[i] + self.seeds[i + 1]) for i in range(0, len(self.seeds), 2)]
for map in self.maps:
next_map = []
for dest_start, src_start, length in map:
next_range = []
for val_low, val_high in values:
sorted_bounds = sorted([val_low, val_high, src_start, src_start + length])
for low, high in zip(sorted_bounds, sorted_bounds[1:]):
if val_low <= low < high <= val_high:
if src_start <= low < high <= src_start + length:
next_map.append((low - src_start + dest_start, high - src_start + dest_start))
else:
next_range.append((low, high))
values = next_range
values += next_map
return values
def find_minimum_location(self, values):
"""Finds the minimum location value."""
return min(low for low, high in values)
def test_find_lowest_location_number():
almanac = """seeds: 79 14 55 13
seed-to-soil map:
50 98 2
52 50 48
soil-to-fertilizer map:
0 15 37
37 52 2
39 0 15
fertilizer-to-water map:
49 53 8
0 11 42
42 0 7
57 7 4
water-to-light map:
88 18 7
18 25 70
light-to-temperature map:
45 77 23
81 45 19
68 64 13
temperature-to-humidity map:
0 69 1
1 0 69
humidity-to-location map:
60 56 37
56 93 4
"""
processor = AlmanacProcessor(almanac)
values = processor.process_maps()
lowest_location = processor.find_minimum_location(values)
assert lowest_location == 46, f"Tst failed: Expected 35, got {lowest_location}" # As per part 2 logic for seeds
print("All tests passed succesfully!")
def main():
with open("day_5/input.txt", "r") as f:
almanac = f.read()
processor = AlmanacProcessor(almanac)
values = processor.process_maps()
min_location = processor.find_minimum_location(values)
print(f"Minimum location number: {min_location}")
if __name__ == "__main__":
test_find_lowest_location_number()
main()
Let’s run this one! 🤞
[Running] python3 "/Users/jmalik/github/advent-of-code-2023/day_5/if_you_give_a_seed_a_fertilizer_take2.py"
All tests passed succesfully!
Minimum location number: xxxxxx
[Done] exited with code=0 in 0.06 seconds
And we get an answer in just 0.06 seconds a much much faster result than 34 minutes of brutal brute force! 🧐
Let’s input that in our answer box and…

🥁
This one was just pure madness, I absolutely loved it! 🙌
On to the next one!
p.s: I am deliberating not adding answers here so you can actually spend some time trying to understand how we solved the problem!
Feel free to checkout code on my Github repo and try to set it up and run on your machine 👇
GitHub - jatinkrmalik/advent-of-code-2023: Advent of Code is an Advent calendar of small…
Advent of Code is an Advent calendar of small programming puzzles for a variety of skill sets and skill levels that can…github.com
Keep reading
🎄Solve Advent of Code 2024 With Me!
Announcing a spoiler-free YouTube video series for Advent of Code 2024 that focuses on how to analyze and approach each puzzle, not just the answers.
The Redis Paradox: my DelhiFOSS 2.0 talk at IIT Delhi, written up
The written version of my DelhiFOSS 2.0 talk on Redis beyond caching: a short history of caches, live driver matching with GEO commands, and Pub/Sub.
Interview prep, senior edition: a system design checklist, one backtracking template and what loops grade on
My 2022 prep notes for senior and staff interviews: a system design checklist, one Python DFS for seven backtracking problems, rubrics and a STAR story bank.
Leave a comment