Solution to problem 5 in Python
This commit is contained in:
parent
47eb4890b0
commit
67bfd066ba
258
src/Year_2023/Day05.py
Normal file
258
src/Year_2023/Day05.py
Normal file
@ -0,0 +1,258 @@
|
||||
# --- Day 5: If You Give A Seed A Fertilizer ---
|
||||
|
||||
# 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 123 and fertilizer 123 aren't necessarily related to each
|
||||
# other.
|
||||
|
||||
# For example:
|
||||
|
||||
# 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
|
||||
|
||||
# The almanac starts by listing which seeds need to be planted: seeds 79, 14,
|
||||
# 55, and 13.
|
||||
|
||||
# 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 48
|
||||
|
||||
# The first line has a destination range start of 50, a source range start of
|
||||
# 98, and a range length of 2. This line means that the source range starts at
|
||||
# 98 and contains two values: 98 and 99. The destination range is the same
|
||||
# length, but it starts at 50, so its two values are 50 and 51. With this
|
||||
# information, you know that seed number 98 corresponds to soil number 50 and
|
||||
# that seed number 99 corresponds to soil number 51.
|
||||
|
||||
# The second line means that the source range starts at 50 and contains 48
|
||||
# values: 50, 51, ..., 96, 97. This corresponds to a destination range starting
|
||||
# at 52 and also containing 48 values: 52, 53, ..., 98, 99. So, seed number 53
|
||||
# corresponds to soil number 55.
|
||||
|
||||
# Any source numbers that aren't mapped correspond to the same destination
|
||||
# number. So, seed number 10 corresponds to soil number 10.
|
||||
|
||||
# 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 51
|
||||
|
||||
# With this map, you can look up the soil number required for each initial seed
|
||||
# number:
|
||||
|
||||
# Seed number 79 corresponds to soil number 81.
|
||||
# Seed number 14 corresponds to soil number 14.
|
||||
# Seed number 55 corresponds to soil number 57.
|
||||
# Seed number 13 corresponds to soil number 13.
|
||||
|
||||
# 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, soil 81, fertilizer 81, water 81, light 74, temperature 78,
|
||||
# humidity 78, location 82.
|
||||
# Seed 14, soil 14, fertilizer 53, water 49, light 42, temperature 42,
|
||||
# humidity 43, location 43.
|
||||
# Seed 55, soil 57, fertilizer 57, water 53, light 46, temperature 82,
|
||||
# humidity 82, location 86.
|
||||
# Seed 13, soil 13, fertilizer 52, water 41, light 34, temperature 34,
|
||||
# humidity 35, location 35.
|
||||
|
||||
# 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?
|
||||
|
||||
with open("files/P5.txt") as f:
|
||||
almanac = [line for line in f.read().strip().split("\n\n")]
|
||||
|
||||
seed, *maps = almanac
|
||||
seeds = [int(s) for s in seed.split(":")[1].split()]
|
||||
mappings = [
|
||||
[[int(i) for i in line.split()] for line in m.splitlines()[1:]]
|
||||
for m in maps
|
||||
]
|
||||
|
||||
|
||||
def part1():
|
||||
locations = seeds
|
||||
for mapping in mappings:
|
||||
new_locations = []
|
||||
for location in locations:
|
||||
new_val = location
|
||||
for destination, start, size in mapping:
|
||||
if start <= location < start + size:
|
||||
new_val = location - start + destination
|
||||
break
|
||||
new_locations.append(new_val)
|
||||
locations = new_locations
|
||||
|
||||
print(f"The lowest location is {min(locations)}")
|
||||
|
||||
|
||||
# --- 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 79 and contains 14 values: 79, 80,
|
||||
# ..., 91, 92. The second range starts with seed number 55 and contains 13
|
||||
# values: 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 soil 84, fertilizer 84, water 84, light 77,
|
||||
# temperature 45, humidity 46, and location 46. So, the lowest location number
|
||||
# is 46.
|
||||
|
||||
# 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?
|
||||
|
||||
|
||||
def get_ranges(span_start, span_end, map_start, map_end):
|
||||
if span_start < map_start and map_end < span_end:
|
||||
return [(map_start, map_end)], [
|
||||
(span_start, map_start - 1),
|
||||
(map_end + 1, span_end),
|
||||
]
|
||||
elif map_start <= span_start and span_end <= map_end:
|
||||
return [(span_start, span_end)], []
|
||||
elif span_start < map_start <= span_end:
|
||||
return [(map_start, span_end)], [(span_start, map_start - 1)]
|
||||
elif span_start <= map_end < span_end:
|
||||
return [(span_start, map_end)], [(map_end + 1, span_end)]
|
||||
else:
|
||||
return [], [(span_start, span_end)]
|
||||
|
||||
|
||||
new_mappings = [
|
||||
[
|
||||
[destination - start, start, start + size - 1]
|
||||
for destination, start, size in m
|
||||
]
|
||||
for m in mappings
|
||||
]
|
||||
|
||||
|
||||
def part2():
|
||||
ranges = [
|
||||
(seeds[i], seeds[i] + seeds[i + 1] - 1)
|
||||
for i in range(0, len(seeds), 2)
|
||||
]
|
||||
|
||||
for mapping in new_mappings:
|
||||
new_ranges = []
|
||||
for seed_span in ranges:
|
||||
unprocessed = [seed_span]
|
||||
for offset, map_start, map_end in mapping:
|
||||
new_unprocessed = []
|
||||
for span_start, span_end in unprocessed:
|
||||
map1, map2 = get_ranges(
|
||||
span_start, span_end, map_start, map_end
|
||||
)
|
||||
new_unprocessed += map2
|
||||
new_ranges += [(a + offset, b + offset) for a, b in map1]
|
||||
unprocessed = new_unprocessed
|
||||
new_ranges += unprocessed
|
||||
ranges = new_ranges
|
||||
|
||||
print(f"The lowest location is {min(idx for idx, _ in ranges)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
part1()
|
||||
part2()
|
Loading…
Reference in New Issue
Block a user