Solution to problem 13 in Python
This commit is contained in:
parent
3ad989a0cb
commit
ef40eb1932
341
src/Year_2018/P13.py
Normal file
341
src/Year_2018/P13.py
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
# --- Day 13: Mine Cart Madness ---
|
||||||
|
|
||||||
|
# A crop of this size requires significant logistics to transport produce, soil,
|
||||||
|
# fertilizer, and so on. The Elves are very busy pushing things around in carts
|
||||||
|
# on some kind of rudimentary system of tracks they've come up with.
|
||||||
|
|
||||||
|
# Seeing as how cart-and-track systems don't appear in recorded history for
|
||||||
|
# another 1000 years, the Elves seem to be making this up as they go along.
|
||||||
|
# They haven't even figured out how to avoid collisions yet.
|
||||||
|
|
||||||
|
# You map out the tracks (your puzzle input) and see where you can help.
|
||||||
|
|
||||||
|
# Tracks consist of straight paths (| and -), curves (/ and \), and
|
||||||
|
# intersections (+). Curves connect exactly two perpendicular pieces of track;
|
||||||
|
# for example, this is a closed loop:
|
||||||
|
|
||||||
|
# /----\
|
||||||
|
# | |
|
||||||
|
# | |
|
||||||
|
# \----/
|
||||||
|
|
||||||
|
# Intersections occur when two perpendicular paths cross. At an intersection,
|
||||||
|
# a cart is capable of turning left, turning right, or continuing straight.
|
||||||
|
# Here are two loops connected by two intersections:
|
||||||
|
|
||||||
|
# /-----\
|
||||||
|
# | |
|
||||||
|
# | /--+--\
|
||||||
|
# | | | |
|
||||||
|
# \--+--/ |
|
||||||
|
# | |
|
||||||
|
# \-----/
|
||||||
|
|
||||||
|
# Several carts are also on the tracks. Carts always face either up (^), down
|
||||||
|
# (v), left (<), or right (>). (On your initial map, the track under each cart
|
||||||
|
# is a straight path matching the direction the cart is facing.)
|
||||||
|
|
||||||
|
# Each time a cart has the option to turn (by arriving at any intersection), it
|
||||||
|
# turns left the first time, goes straight the second time, turns right the
|
||||||
|
# third time, and then repeats those directions starting again with left the
|
||||||
|
# fourth time, straight the fifth time, and so on. This process is independent
|
||||||
|
# of the particular intersection at which the cart has arrived - that is, the
|
||||||
|
# cart has no per-intersection memory.
|
||||||
|
|
||||||
|
# Carts all move at the same speed; they take turns moving a single step at a
|
||||||
|
# time. They do this based on their current location: carts on the top row move
|
||||||
|
# first (acting from left to right), then carts on the second row move (again
|
||||||
|
# from left to right), then carts on the third row, and so on. Once each cart
|
||||||
|
# has moved one step, the process repeats; each of these loops is called a tick.
|
||||||
|
|
||||||
|
# For example, suppose there are two carts on a straight track:
|
||||||
|
|
||||||
|
# | | | | |
|
||||||
|
# v | | | |
|
||||||
|
# | v v | |
|
||||||
|
# | | | v X
|
||||||
|
# | | ^ ^ |
|
||||||
|
# ^ ^ | | |
|
||||||
|
# | | | | |
|
||||||
|
|
||||||
|
# First, the top cart moves. It is facing down (v), so it moves down one square.
|
||||||
|
# Second, the bottom cart moves. It is facing up (^), so it moves up one square.
|
||||||
|
# Because all carts have moved, the first tick ends. Then, the process repeats,
|
||||||
|
# starting with the first cart. The first cart moves down, then the second cart
|
||||||
|
# moves up - right into the first cart, colliding with it! (The location of the
|
||||||
|
# crash is marked with an X.) This ends the second and last tick.
|
||||||
|
|
||||||
|
# Here is a longer example:
|
||||||
|
|
||||||
|
# /->-\
|
||||||
|
# | | /----\
|
||||||
|
# | /-+--+-\ |
|
||||||
|
# | | | | v |
|
||||||
|
# \-+-/ \-+--/
|
||||||
|
# \------/
|
||||||
|
|
||||||
|
# /-->\
|
||||||
|
# | | /----\
|
||||||
|
# | /-+--+-\ |
|
||||||
|
# | | | | | |
|
||||||
|
# \-+-/ \->--/
|
||||||
|
# \------/
|
||||||
|
|
||||||
|
# /---v
|
||||||
|
# | | /----\
|
||||||
|
# | /-+--+-\ |
|
||||||
|
# | | | | | |
|
||||||
|
# \-+-/ \-+>-/
|
||||||
|
# \------/
|
||||||
|
|
||||||
|
# /---\
|
||||||
|
# | v /----\
|
||||||
|
# | /-+--+-\ |
|
||||||
|
# | | | | | |
|
||||||
|
# \-+-/ \-+->/
|
||||||
|
# \------/
|
||||||
|
|
||||||
|
# /---\
|
||||||
|
# | | /----\
|
||||||
|
# | /->--+-\ |
|
||||||
|
# | | | | | |
|
||||||
|
# \-+-/ \-+--^
|
||||||
|
# \------/
|
||||||
|
|
||||||
|
# /---\
|
||||||
|
# | | /----\
|
||||||
|
# | /-+>-+-\ |
|
||||||
|
# | | | | | ^
|
||||||
|
# \-+-/ \-+--/
|
||||||
|
# \------/
|
||||||
|
|
||||||
|
# /---\
|
||||||
|
# | | /----\
|
||||||
|
# | /-+->+-\ ^
|
||||||
|
# | | | | | |
|
||||||
|
# \-+-/ \-+--/
|
||||||
|
# \------/
|
||||||
|
|
||||||
|
# /---\
|
||||||
|
# | | /----<
|
||||||
|
# | /-+-->-\ |
|
||||||
|
# | | | | | |
|
||||||
|
# \-+-/ \-+--/
|
||||||
|
# \------/
|
||||||
|
|
||||||
|
# /---\
|
||||||
|
# | | /---<\
|
||||||
|
# | /-+--+>\ |
|
||||||
|
# | | | | | |
|
||||||
|
# \-+-/ \-+--/
|
||||||
|
# \------/
|
||||||
|
|
||||||
|
# /---\
|
||||||
|
# | | /--<-\
|
||||||
|
# | /-+--+-v |
|
||||||
|
# | | | | | |
|
||||||
|
# \-+-/ \-+--/
|
||||||
|
# \------/
|
||||||
|
|
||||||
|
# /---\
|
||||||
|
# | | /-<--\
|
||||||
|
# | /-+--+-\ |
|
||||||
|
# | | | | v |
|
||||||
|
# \-+-/ \-+--/
|
||||||
|
# \------/
|
||||||
|
|
||||||
|
# /---\
|
||||||
|
# | | /<---\
|
||||||
|
# | /-+--+-\ |
|
||||||
|
# | | | | | |
|
||||||
|
# \-+-/ \-<--/
|
||||||
|
# \------/
|
||||||
|
|
||||||
|
# /---\
|
||||||
|
# | | v----\
|
||||||
|
# | /-+--+-\ |
|
||||||
|
# | | | | | |
|
||||||
|
# \-+-/ \<+--/
|
||||||
|
# \------/
|
||||||
|
|
||||||
|
# /---\
|
||||||
|
# | | /----\
|
||||||
|
# | /-+--v-\ |
|
||||||
|
# | | | | | |
|
||||||
|
# \-+-/ ^-+--/
|
||||||
|
# \------/
|
||||||
|
|
||||||
|
# /---\
|
||||||
|
# | | /----\
|
||||||
|
# | /-+--+-\ |
|
||||||
|
# | | | X | |
|
||||||
|
# \-+-/ \-+--/
|
||||||
|
# \------/
|
||||||
|
|
||||||
|
# After following their respective paths for a while, the carts eventually
|
||||||
|
# crash. To help prevent crashes, you'd like to know the location of the first
|
||||||
|
# crash. Locations are given in X,Y coordinates, where the furthest left column
|
||||||
|
# is X=0 and the furthest top row is Y=0:
|
||||||
|
|
||||||
|
# 111
|
||||||
|
# 0123456789012
|
||||||
|
# 0/---\
|
||||||
|
# 1| | /----\
|
||||||
|
# 2| /-+--+-\ |
|
||||||
|
# 3| | | X | |
|
||||||
|
# 4\-+-/ \-+--/
|
||||||
|
# 5 \------/
|
||||||
|
|
||||||
|
# In this example, the location of the first crash is 7,3.
|
||||||
|
|
||||||
|
directions = {">": [1, 0], "v": [0, 1], "<": [-1, 0], "^": [0, -1]}
|
||||||
|
|
||||||
|
map = []
|
||||||
|
carts = []
|
||||||
|
with open("files/P13.txt") as f:
|
||||||
|
for y, line in enumerate(f):
|
||||||
|
line = line.strip("\n")
|
||||||
|
for x, pos in enumerate(line):
|
||||||
|
if pos in directions:
|
||||||
|
dx, dy = directions[pos]
|
||||||
|
carts.append(
|
||||||
|
{
|
||||||
|
"x": x,
|
||||||
|
"y": y,
|
||||||
|
"dx": dx,
|
||||||
|
"dy": dy,
|
||||||
|
"turn_index": 0,
|
||||||
|
"deleted": False,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
map.append(pos)
|
||||||
|
cols = len(line)
|
||||||
|
|
||||||
|
|
||||||
|
def move_cart(cart):
|
||||||
|
cart["x"] += cart["dx"]
|
||||||
|
cart["y"] += cart["dy"]
|
||||||
|
|
||||||
|
|
||||||
|
def rotate_cart(cart, current):
|
||||||
|
if current in {"/", "\\", "+"}:
|
||||||
|
if current == "/":
|
||||||
|
cart["dx"], cart["dy"] = -cart["dy"], -cart["dx"]
|
||||||
|
elif current == "\\":
|
||||||
|
cart["dx"], cart["dy"] = cart["dy"], cart["dx"]
|
||||||
|
elif current == "+":
|
||||||
|
if cart["turn_index"] == 0:
|
||||||
|
cart["dx"], cart["dy"] = cart["dy"], -cart["dx"]
|
||||||
|
elif cart["turn_index"] == 2:
|
||||||
|
cart["dx"], cart["dy"] = -cart["dy"], cart["dx"]
|
||||||
|
cart["turn_index"] = (cart["turn_index"] + 1) % 3
|
||||||
|
|
||||||
|
|
||||||
|
def part_1():
|
||||||
|
is_collision = False
|
||||||
|
counter = 0
|
||||||
|
|
||||||
|
while not is_collision:
|
||||||
|
counter += 1
|
||||||
|
carts.sort(key=lambda s: (s["y"], s["x"]))
|
||||||
|
for cart in carts:
|
||||||
|
pos = cart["y"] * cols + cart["x"]
|
||||||
|
current = map[pos]
|
||||||
|
if current in {"/", "\\", "+"}:
|
||||||
|
rotate_cart(cart, current)
|
||||||
|
move_cart(cart)
|
||||||
|
|
||||||
|
coords = set()
|
||||||
|
for cart in carts:
|
||||||
|
pos = cart["x"], cart["y"]
|
||||||
|
if pos in coords:
|
||||||
|
is_collision = True
|
||||||
|
crash = pos
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
coords.add(pos)
|
||||||
|
|
||||||
|
print(f"The first crash is located at {crash}")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Part Two ---
|
||||||
|
|
||||||
|
# There isn't much you can do to prevent crashes in this ridiculous system.
|
||||||
|
# However, by predicting the crashes, the Elves know where to be in advance and
|
||||||
|
# instantly remove the two crashing carts the moment any crash occurs.
|
||||||
|
|
||||||
|
# They can proceed like this for a while, but eventually, they're going to run
|
||||||
|
# out of carts. It could be useful to figure out where the last cart that
|
||||||
|
# hasn't crashed will end up.
|
||||||
|
|
||||||
|
# For example:
|
||||||
|
|
||||||
|
# />-<\
|
||||||
|
# | |
|
||||||
|
# | /<+-\
|
||||||
|
# | | | v
|
||||||
|
# \>+</ |
|
||||||
|
# | ^
|
||||||
|
# \<->/
|
||||||
|
|
||||||
|
# /---\
|
||||||
|
# | |
|
||||||
|
# | v-+-\
|
||||||
|
# | | | |
|
||||||
|
# \-+-/ |
|
||||||
|
# | |
|
||||||
|
# ^---^
|
||||||
|
|
||||||
|
# /---\
|
||||||
|
# | |
|
||||||
|
# | /-+-\
|
||||||
|
# | v | |
|
||||||
|
# \-+-/ |
|
||||||
|
# ^ ^
|
||||||
|
# \---/
|
||||||
|
|
||||||
|
# /---\
|
||||||
|
# | |
|
||||||
|
# | /-+-\
|
||||||
|
# | | | |
|
||||||
|
# \-+-/ ^
|
||||||
|
# | |
|
||||||
|
# \---/
|
||||||
|
|
||||||
|
# After four very expensive crashes, a tick ends with only one cart remaining;
|
||||||
|
# its final location is 6,4.
|
||||||
|
|
||||||
|
# What is the location of the last cart at the end of the first tick where it is
|
||||||
|
# the only cart left?
|
||||||
|
|
||||||
|
|
||||||
|
def part_2():
|
||||||
|
global map, carts
|
||||||
|
counter = 0
|
||||||
|
while len(carts) > 1:
|
||||||
|
counter += 1
|
||||||
|
carts.sort(key=lambda s: (s["y"], s["x"]))
|
||||||
|
for cart in carts:
|
||||||
|
pos = cart["y"] * cols + cart["x"]
|
||||||
|
current = map[pos]
|
||||||
|
if current in {"/", "\\", "+"}:
|
||||||
|
rotate_cart(cart, current)
|
||||||
|
move_cart(cart)
|
||||||
|
|
||||||
|
coords = {}
|
||||||
|
for n, cart in enumerate(carts):
|
||||||
|
pos = cart["x"], cart["y"]
|
||||||
|
if pos not in coords:
|
||||||
|
coords[pos] = n
|
||||||
|
else:
|
||||||
|
cart["deleted"] = True
|
||||||
|
carts[coords[pos]]["deleted"] = True
|
||||||
|
carts = [cart for cart in carts if not cart["deleted"]]
|
||||||
|
last_cart_pos = (carts[0]["x"], carts[0]["y"])
|
||||||
|
|
||||||
|
print(f"The last cart is located at {last_cart_pos}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
part_1()
|
||||||
|
part_2()
|
Loading…
Reference in New Issue
Block a user