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