165 lines
5.0 KiB
Python
165 lines
5.0 KiB
Python
# --- Day 5: Hydrothermal Venture ---
|
|
|
|
# You come across a field of hydrothermal vents on the ocean floor! These vents
|
|
# constantly produce large, opaque clouds, so it would be best to avoid them if
|
|
# possible.
|
|
|
|
# They tend to form in lines; the submarine helpfully produces a list of nearby
|
|
# lines of vents (your puzzle input) for you to review. For example:
|
|
|
|
# 0,9 -> 5,9
|
|
# 8,0 -> 0,8
|
|
# 9,4 -> 3,4
|
|
# 2,2 -> 2,1
|
|
# 7,0 -> 7,4
|
|
# 6,4 -> 2,0
|
|
# 0,9 -> 2,9
|
|
# 3,4 -> 1,4
|
|
# 0,0 -> 8,8
|
|
# 5,5 -> 8,2
|
|
|
|
# Each line of vents is given as a line segment in the format x1,y1 -> x2,y2
|
|
# where x1,y1 are the coordinates of one end the line segment and x2,y2 are the
|
|
# coordinates of the other end. These line segments include the points at both
|
|
# ends. In other words:
|
|
|
|
# An entry like 1,1 -> 1,3 covers points 1,1, 1,2, and 1,3.
|
|
# An entry like 9,7 -> 7,7 covers points 9,7, 8,7, and 7,7.
|
|
|
|
# For now, only consider horizontal and vertical lines: lines where either
|
|
# x1 = x2 or y1 = y2.
|
|
|
|
# So, the horizontal and vertical lines from the above list would produce the
|
|
# following diagram:
|
|
|
|
# .......1..
|
|
# ..1....1..
|
|
# ..1....1..
|
|
# .......1..
|
|
# .112111211
|
|
# ..........
|
|
# ..........
|
|
# ..........
|
|
# ..........
|
|
# 222111....
|
|
|
|
# In this diagram, the top left corner is 0,0 and the bottom right corner is
|
|
# 9,9. Each position is shown as the number of lines which cover that point or
|
|
# . if no line covers that point. The top-left pair of 1s, for example, comes
|
|
# from 2,2 -> 2,1; the very bottom row is formed by the overlapping lines 0,9
|
|
# -> 5,9 and 0,9 -> 2,9.
|
|
|
|
# To avoid the most dangerous areas, you need to determine the number of points
|
|
# where at least two lines overlap. In the above example, this is anywhere in
|
|
# the diagram with a 2 or larger - a total of 5 points.
|
|
|
|
# Consider only horizontal and vertical lines. At how many points do at least
|
|
# two lines overlap?
|
|
|
|
from collections import defaultdict
|
|
from typing import DefaultDict, Tuple
|
|
|
|
with open("files/P5.txt") as f:
|
|
points = [
|
|
points
|
|
for line in f.read().strip().split("\n")
|
|
for points in line.split(" -> ")
|
|
]
|
|
|
|
|
|
point_1 = points[::2]
|
|
x1y1 = [int(val) for p in point_1 for val in p.split(",")]
|
|
x_1 = x1y1[::2]
|
|
y_1 = x1y1[1::2]
|
|
|
|
point_2 = points[1::2]
|
|
x2y2 = [int(val) for p in point_2 for val in p.split(",")]
|
|
x_2 = x2y2[::2]
|
|
y_2 = x2y2[1::2]
|
|
|
|
|
|
def get_range(p1: int, p2: int) -> Tuple[int, int, int]:
|
|
if p1 > p2:
|
|
step = -1
|
|
p2 -= 1
|
|
else:
|
|
step = 1
|
|
p2 += 1
|
|
return p1, p2, step
|
|
|
|
|
|
def part_1() -> None:
|
|
grid: DefaultDict[Tuple[int, int], int] = defaultdict(int)
|
|
for idx in range(len(points) // 2):
|
|
if x_1[idx] == x_2[idx]:
|
|
start, stop, step = get_range(y_1[idx], y_2[idx])
|
|
for pos in range(start, stop, step):
|
|
grid[x_1[idx], pos] += 1
|
|
elif y_1[idx] == y_2[idx]:
|
|
start, stop, step = get_range(x_1[idx], x_2[idx])
|
|
for pos in range(start, stop, step):
|
|
grid[pos, y_1[idx]] += 1
|
|
|
|
print(sum(1 for key in grid.values() if key > 1))
|
|
|
|
|
|
# --- Part Two ---
|
|
|
|
# Unfortunately, considering only horizontal and vertical lines doesn't give
|
|
# you the full picture; you need to also consider diagonal lines.
|
|
|
|
# Because of the limits of the hydrothermal vent mapping system, the lines in
|
|
# your list will only ever be horizontal, vertical, or a diagonal line at
|
|
# exactly 45 degrees. In other words:
|
|
|
|
# An entry like 1,1 -> 3,3 covers points 1,1, 2,2, and 3,3.
|
|
# An entry like 9,7 -> 7,9 covers points 9,7, 8,8, and 7,9.
|
|
|
|
# Considering all lines from the above example would now produce the following
|
|
# diagram:
|
|
|
|
# 1.1....11.
|
|
# .111...2..
|
|
# ..2.1.111.
|
|
# ...1.2.2..
|
|
# .112313211
|
|
# ...1.2....
|
|
# ..1...1...
|
|
# .1.....1..
|
|
# 1.......1.
|
|
# 222111....
|
|
|
|
# You still need to determine the number of points where at least two lines
|
|
# overlap. In the above example, this is still anywhere in the diagram with a 2
|
|
# or larger - now a total of 12 points.
|
|
|
|
# Consider all of the lines. At how many points do at least two lines overlap?
|
|
|
|
|
|
def part_2() -> None:
|
|
grid: DefaultDict[Tuple[int, int], int] = defaultdict(int)
|
|
for idx in range(len(points) // 2):
|
|
# print(idx)
|
|
if x_1[idx] == x_2[idx]:
|
|
start, stop, step = get_range(y_1[idx], y_2[idx])
|
|
for pos in range(start, stop, step):
|
|
grid[x_1[idx], pos] += 1
|
|
elif y_1[idx] == y_2[idx]:
|
|
start, stop, step = get_range(x_1[idx], x_2[idx])
|
|
for pos in range(start, stop, step):
|
|
grid[pos, y_1[idx]] += 1
|
|
elif abs(x_1[idx] - x_2[idx]) == abs(y_1[idx] - y_2[idx]):
|
|
start_x, stop_x, step_x = get_range(x_1[idx], x_2[idx])
|
|
start_y, stop_y, step_y = get_range(y_1[idx], y_2[idx])
|
|
pos_x = [pos_x for pos_x in range(start_x, stop_x, step_x)]
|
|
pos_y = [pos_y for pos_y in range(start_y, stop_y, step_y)]
|
|
for px, py in zip(pos_x, pos_y):
|
|
grid[px, py] += 1
|
|
|
|
print(sum(1 for key in grid.values() if key > 1))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
part_1()
|
|
part_2()
|