Solution to problem 8 in Python
This commit is contained in:
parent
8120f461d6
commit
0f41d9426f
148
src/Year_2023/Day08.py
Normal file
148
src/Year_2023/Day08.py
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
# --- Day 8: Haunted Wasteland ---
|
||||||
|
|
||||||
|
# You're still riding a camel across Desert Island when you spot a sandstorm
|
||||||
|
# quickly approaching. When you turn to warn the Elf, she disappears before your
|
||||||
|
# eyes! To be fair, she had just finished warning you about ghosts a few minutes
|
||||||
|
# ago.
|
||||||
|
|
||||||
|
# One of the camel's pouches is labeled "maps" - sure enough, it's full of
|
||||||
|
# documents (your puzzle input) about how to navigate the desert. At least,
|
||||||
|
# you're pretty sure that's what they are; one of the documents contains a list
|
||||||
|
# of left/right instructions, and the rest of the documents seem to describe
|
||||||
|
# some kind of network of labeled nodes.
|
||||||
|
|
||||||
|
# It seems like you're meant to use the left/right instructions to navigate the
|
||||||
|
# network. Perhaps if you have the camel follow the same instructions, you can
|
||||||
|
# escape the haunted wasteland!
|
||||||
|
|
||||||
|
# After examining the maps for a bit, two nodes stick out: AAA and ZZZ. You feel
|
||||||
|
# like AAA is where you are now, and you have to follow the left/right
|
||||||
|
# instructions until you reach ZZZ.
|
||||||
|
|
||||||
|
# This format defines each node of the network individually. For example:
|
||||||
|
|
||||||
|
# RL
|
||||||
|
|
||||||
|
# AAA = (BBB, CCC)
|
||||||
|
# BBB = (DDD, EEE)
|
||||||
|
# CCC = (ZZZ, GGG)
|
||||||
|
# DDD = (DDD, DDD)
|
||||||
|
# EEE = (EEE, EEE)
|
||||||
|
# GGG = (GGG, GGG)
|
||||||
|
# ZZZ = (ZZZ, ZZZ)
|
||||||
|
|
||||||
|
# Starting with AAA, you need to look up the next element based on the next
|
||||||
|
# left/right instruction in your input. In this example, start with AAA and go
|
||||||
|
# right (R) by choosing the right element of AAA, CCC. Then, L means to choose
|
||||||
|
# the left element of CCC, ZZZ. By following the left/right instructions, you
|
||||||
|
# reach ZZZ in 2 steps.
|
||||||
|
|
||||||
|
# Of course, you might not find ZZZ right away. If you run out of left/right
|
||||||
|
# instructions, repeat the whole sequence of instructions as necessary: RL
|
||||||
|
# really means RLRLRLRLRLRLRLRL... and so on. For example, here is a situation
|
||||||
|
# that takes 6 steps to reach ZZZ:
|
||||||
|
|
||||||
|
# LLR
|
||||||
|
|
||||||
|
# AAA = (BBB, BBB)
|
||||||
|
# BBB = (AAA, ZZZ)
|
||||||
|
# ZZZ = (ZZZ, ZZZ)
|
||||||
|
|
||||||
|
# Starting at AAA, follow the left/right instructions. How many steps are
|
||||||
|
# required to reach ZZZ?
|
||||||
|
|
||||||
|
with open("files/P8.txt") as f:
|
||||||
|
instructions, _nodes = [line for line in f.read().strip().split("\n\n")]
|
||||||
|
|
||||||
|
nodes = {}
|
||||||
|
for node in _nodes.split("\n"):
|
||||||
|
start = node.split(" = ")[0]
|
||||||
|
left, right = node.split(" = ")[1][1:-1].split(", ")
|
||||||
|
nodes[start] = left, right
|
||||||
|
|
||||||
|
|
||||||
|
def part1(start, end):
|
||||||
|
i, total = 0, 0
|
||||||
|
while start != end:
|
||||||
|
# we are already there
|
||||||
|
if i == len(instructions):
|
||||||
|
i = 0
|
||||||
|
start = nodes[start][0 if instructions[i] == "L" else 1]
|
||||||
|
total += 1
|
||||||
|
i += 1
|
||||||
|
print(f"There are {total} steps required")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Part Two ---
|
||||||
|
|
||||||
|
# The sandstorm is upon you and you aren't any closer to escaping the wasteland.
|
||||||
|
# You had the camel follow the instructions, but you've barely left your
|
||||||
|
# starting position. It's going to take significantly more steps to escape!
|
||||||
|
|
||||||
|
# What if the map isn't for people - what if the map is for ghosts? Are ghosts
|
||||||
|
# even bound by the laws of spacetime? Only one way to find out.
|
||||||
|
|
||||||
|
# After examining the maps a bit longer, your attention is drawn to a curious
|
||||||
|
# fact: the number of nodes with names ending in A is equal to the number ending
|
||||||
|
# in Z! If you were a ghost, you'd probably just start at every node that ends
|
||||||
|
# with A and follow all of the paths at the same time until they all
|
||||||
|
# simultaneously end up at nodes that end with Z.
|
||||||
|
|
||||||
|
# For example:
|
||||||
|
|
||||||
|
# LR
|
||||||
|
|
||||||
|
# 11A = (11B, XXX)
|
||||||
|
# 11B = (XXX, 11Z)
|
||||||
|
# 11Z = (11B, XXX)
|
||||||
|
# 22A = (22B, XXX)
|
||||||
|
# 22B = (22C, 22C)
|
||||||
|
# 22C = (22Z, 22Z)
|
||||||
|
# 22Z = (22B, 22B)
|
||||||
|
# XXX = (XXX, XXX)
|
||||||
|
|
||||||
|
# Here, there are two starting nodes, 11A and 22A (because they both end with
|
||||||
|
# A). As you follow each left/right instruction, use that instruction to
|
||||||
|
# simultaneously navigate away from both nodes you're currently on. Repeat this
|
||||||
|
# process until all of the nodes you're currently on end with Z. (If only some
|
||||||
|
# of the nodes you're on end with Z, they act like any other node and you
|
||||||
|
# continue as normal.) In this example, you would proceed as follows:
|
||||||
|
|
||||||
|
# Step 0: You are at 11A and 22A.
|
||||||
|
# Step 1: You choose all of the left paths, leading you to 11B and 22B.
|
||||||
|
# Step 2: You choose all of the right paths, leading you to 11Z and 22C.
|
||||||
|
# Step 3: You choose all of the left paths, leading you to 11B and 22Z.
|
||||||
|
# Step 4: You choose all of the right paths, leading you to 11Z and 22B.
|
||||||
|
# Step 5: You choose all of the left paths, leading you to 11B and 22C.
|
||||||
|
# Step 6: You choose all of the right paths, leading you to 11Z and 22Z.
|
||||||
|
|
||||||
|
# So, in this example, you end up entirely on nodes that end in Z after 6 steps.
|
||||||
|
|
||||||
|
# Simultaneously start on every node that ends with A. How many steps does it
|
||||||
|
# take before you're only on nodes that end with Z?
|
||||||
|
|
||||||
|
|
||||||
|
from math import lcm
|
||||||
|
|
||||||
|
|
||||||
|
def part2(start):
|
||||||
|
i, total = 0, 0
|
||||||
|
while not start.endswith("Z"):
|
||||||
|
# we are already there
|
||||||
|
if i == len(instructions):
|
||||||
|
i = 0
|
||||||
|
start = nodes[start][0 if instructions[i] == "L" else 1]
|
||||||
|
total += 1
|
||||||
|
i += 1
|
||||||
|
return total
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
start, end = "AAA", "ZZZ"
|
||||||
|
part1(start, end)
|
||||||
|
|
||||||
|
total = 1
|
||||||
|
for start in nodes:
|
||||||
|
if start.endswith("A"):
|
||||||
|
total = lcm(total, part2(start))
|
||||||
|
print(f"There are {total} steps required")
|
Loading…
x
Reference in New Issue
Block a user