Solution to problem 12 in Python
This commit is contained in:
parent
69e541e250
commit
b34578de33
203
src/Year_2018/P12.py
Normal file
203
src/Year_2018/P12.py
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
# --- Day 12: Subterranean Sustainability ---
|
||||||
|
|
||||||
|
# The year 518 is significantly more underground than your history books
|
||||||
|
# implied. Either that, or you've arrived in a vast cavern network under the
|
||||||
|
# North Pole.
|
||||||
|
|
||||||
|
# After exploring a little, you discover a long tunnel that contains a row of
|
||||||
|
# small pots as far as you can see to your left and right. A few of them
|
||||||
|
# contain plants - someone is trying to grow things in these
|
||||||
|
# geothermally-heated caves.
|
||||||
|
|
||||||
|
# The pots are numbered, with 0 in front of you. To the left, the pots are
|
||||||
|
# numbered -1, -2, -3, and so on; to the right, 1, 2, 3.... Your puzzle input
|
||||||
|
# contains a list of pots from 0 to the right and whether they do (#) or do not
|
||||||
|
# (.) currently contain a plant, the initial state. (No other pots currently
|
||||||
|
# contain plants.) For example, an initial state of #..##.... indicates that
|
||||||
|
# pots 0, 3, and 4 currently contain plants.
|
||||||
|
|
||||||
|
# Your puzzle input also contains some notes you find on a nearby table:
|
||||||
|
# someone has been trying to figure out how these plants spread to nearby pots.
|
||||||
|
# Based on the notes, for each generation of plants, a given pot has or does
|
||||||
|
# not have a plant based on whether that pot (and the two pots on either side
|
||||||
|
# of it) had a plant in the last generation. These are written as LLCRR => N,
|
||||||
|
# where L are pots to the left, C is the current pot being considered, R are
|
||||||
|
# the pots to the right, and N is whether the current pot will have a plant in
|
||||||
|
# the next generation. For example:
|
||||||
|
|
||||||
|
# A note like ..#.. => . means that a pot that contains a plant but with no
|
||||||
|
# plants within two pots of it will not have a plant in it during the next
|
||||||
|
# generation.
|
||||||
|
# A note like ##.## => . means that an empty pot with two plants on each
|
||||||
|
# side of it will remain empty in the next generation.
|
||||||
|
# A note like .##.# => # means that a pot has a plant in a given generation
|
||||||
|
# if, in the previous generation, there were plants in that pot, the one
|
||||||
|
# immediately to the left, and the one two pots to the right, but not in the
|
||||||
|
# ones immediately to the right and two to the left.
|
||||||
|
|
||||||
|
# It's not clear what these plants are for, but you're sure it's important, so
|
||||||
|
# you'd like to make sure the current configuration of plants is sustainable by
|
||||||
|
# determining what will happen after 20 generations.
|
||||||
|
|
||||||
|
# For example, given the following input:
|
||||||
|
|
||||||
|
# initial state: #..#.#..##......###...###
|
||||||
|
|
||||||
|
# ...## => #
|
||||||
|
# ..#.. => #
|
||||||
|
# .#... => #
|
||||||
|
# .#.#. => #
|
||||||
|
# .#.## => #
|
||||||
|
# .##.. => #
|
||||||
|
# .#### => #
|
||||||
|
# #.#.# => #
|
||||||
|
# #.### => #
|
||||||
|
# ##.#. => #
|
||||||
|
# ##.## => #
|
||||||
|
# ###.. => #
|
||||||
|
# ###.# => #
|
||||||
|
# ####. => #
|
||||||
|
|
||||||
|
# For brevity, in this example, only the combinations which do produce a plant
|
||||||
|
# are listed. (Your input includes all possible combinations.) Then, the next
|
||||||
|
# 20 generations will look like this:
|
||||||
|
|
||||||
|
# 1 2 3
|
||||||
|
# 0 0 0 0
|
||||||
|
# 0: ...#..#.#..##......###...###...........
|
||||||
|
# 1: ...#...#....#.....#..#..#..#...........
|
||||||
|
# 2: ...##..##...##....#..#..#..##..........
|
||||||
|
# 3: ..#.#...#..#.#....#..#..#...#..........
|
||||||
|
# 4: ...#.#..#...#.#...#..#..##..##.........
|
||||||
|
# 5: ....#...##...#.#..#..#...#...#.........
|
||||||
|
# 6: ....##.#.#....#...#..##..##..##........
|
||||||
|
# 7: ...#..###.#...##..#...#...#...#........
|
||||||
|
# 8: ...#....##.#.#.#..##..##..##..##.......
|
||||||
|
# 9: ...##..#..#####....#...#...#...#.......
|
||||||
|
# 10: ..#.#..#...#.##....##..##..##..##......
|
||||||
|
# 11: ...#...##...#.#...#.#...#...#...#......
|
||||||
|
# 12: ...##.#.#....#.#...#.#..##..##..##.....
|
||||||
|
# 13: ..#..###.#....#.#...#....#...#...#.....
|
||||||
|
# 14: ..#....##.#....#.#..##...##..##..##....
|
||||||
|
# 15: ..##..#..#.#....#....#..#.#...#...#....
|
||||||
|
# 16: .#.#..#...#.#...##...#...#.#..##..##...
|
||||||
|
# 17: ..#...##...#.#.#.#...##...#....#...#...
|
||||||
|
# 18: ..##.#.#....#####.#.#.#...##...##..##..
|
||||||
|
# 19: .#..###.#..#.#.#######.#.#.#..#.#...#..
|
||||||
|
# 20: .#....##....#####...#######....#.#..##.
|
||||||
|
|
||||||
|
# The generation is shown along the left, where 0 is the initial state. The pot
|
||||||
|
# numbers are shown along the top, where 0 labels the center pot,
|
||||||
|
# negative-numbered pots extend to the left, and positive pots extend toward
|
||||||
|
# the right. Remember, the initial state begins at pot 0, which is not the
|
||||||
|
# leftmost pot used in this example.
|
||||||
|
|
||||||
|
# After one generation, only seven plants remain. The one in pot 0 matched the
|
||||||
|
# rule looking for ..#.., the one in pot 4 matched the rule looking for .#.#.,
|
||||||
|
# pot 9 matched .##.., and so on.
|
||||||
|
|
||||||
|
# In this example, after 20 generations, the pots shown as # contain plants,
|
||||||
|
# the furthest left of which is pot -2, and the furthest right of which is pot
|
||||||
|
# 34. Adding up all the numbers of plant-containing pots after the 20th
|
||||||
|
# generation produces 325.
|
||||||
|
|
||||||
|
# After 20 generations, what is the sum of the numbers of all pots which
|
||||||
|
# contain a plant?
|
||||||
|
|
||||||
|
with open("files/P12.txt") as f:
|
||||||
|
raw = [line for line in f.read().strip().split("\n")]
|
||||||
|
|
||||||
|
|
||||||
|
def parse_data() -> tuple[str, dict[str, str]]:
|
||||||
|
rules = {}
|
||||||
|
for line in raw:
|
||||||
|
if "initial state" in line:
|
||||||
|
initial_state = line[15:]
|
||||||
|
else:
|
||||||
|
rules[line[:5]] = line[9:10]
|
||||||
|
|
||||||
|
return initial_state, rules
|
||||||
|
|
||||||
|
|
||||||
|
def part_1() -> None:
|
||||||
|
initial_state, rules = parse_data()
|
||||||
|
current = dict(
|
||||||
|
(idx, char) for idx, char in enumerate(initial_state) if char == "#"
|
||||||
|
)
|
||||||
|
_sum, difference = 0, {}
|
||||||
|
for gen in range(20):
|
||||||
|
# notes are given for a given pot plus two on each side
|
||||||
|
left_side, right_side = min(current) - 2, max(current) + 2
|
||||||
|
next_gen = {}
|
||||||
|
for char in range(left_side, right_side + 1):
|
||||||
|
pattern = ""
|
||||||
|
for idx in range(char - 2, char + 3):
|
||||||
|
if idx in current:
|
||||||
|
pattern += current[idx]
|
||||||
|
else:
|
||||||
|
pattern += "."
|
||||||
|
next_gen[char] = rules[pattern]
|
||||||
|
current = dict(
|
||||||
|
(idx, next_gen[idx]) for idx in next_gen if next_gen[idx] == "#"
|
||||||
|
)
|
||||||
|
diff = sum(current) - _sum
|
||||||
|
if diff not in difference:
|
||||||
|
difference[diff] = 1
|
||||||
|
else:
|
||||||
|
difference[diff] += 1
|
||||||
|
_sum = sum(current)
|
||||||
|
print(
|
||||||
|
f"After 20 generations, there will be {sum(current)} pots containing plants"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# --- Part Two ---
|
||||||
|
|
||||||
|
# You realize that 20 generations aren't enough. After all, these plants will
|
||||||
|
# need to last another 1500 years to even reach your timeline, not to mention
|
||||||
|
# your future.
|
||||||
|
|
||||||
|
# After fifty billion (50000000000) generations, what is the sum of the numbers
|
||||||
|
# of all pots which contain a plant?
|
||||||
|
|
||||||
|
|
||||||
|
def part_2() -> None:
|
||||||
|
generations = 50_000_000_000
|
||||||
|
initial_state, rules = parse_data()
|
||||||
|
current = dict(
|
||||||
|
(idx, char) for idx, char in enumerate(initial_state) if char == "#"
|
||||||
|
)
|
||||||
|
_sum, difference = 0, {}
|
||||||
|
for gen in range(generations):
|
||||||
|
# notes are given for a given pot plus two on each side
|
||||||
|
left_side, right_side = min(current) - 2, max(current) + 2
|
||||||
|
next_gen = {}
|
||||||
|
for char in range(left_side, right_side + 1):
|
||||||
|
pattern = ""
|
||||||
|
for idx in range(char - 2, char + 3):
|
||||||
|
if idx in current:
|
||||||
|
pattern += current[idx]
|
||||||
|
else:
|
||||||
|
pattern += "."
|
||||||
|
next_gen[char] = rules[pattern]
|
||||||
|
current = dict(
|
||||||
|
(idx, next_gen[idx]) for idx in next_gen if next_gen[idx] == "#"
|
||||||
|
)
|
||||||
|
diff = sum(current) - _sum
|
||||||
|
if diff not in difference:
|
||||||
|
difference[diff] = 1
|
||||||
|
else:
|
||||||
|
difference[diff] += 1
|
||||||
|
_sum = sum(current)
|
||||||
|
# it is a periodic result, so skip most of the calculations
|
||||||
|
if diff in difference and difference[diff] > 1000:
|
||||||
|
res = sum(current) + (generations - gen - 1) * diff
|
||||||
|
print(
|
||||||
|
f"After 5e10 generations, there will be {res} pots containing plants"
|
||||||
|
)
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
part_1()
|
||||||
|
part_2()
|
Loading…
Reference in New Issue
Block a user