My advent of code solutions
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

139 lines
3.6 KiB

"""
Advent of Code 2021 - Day 05
Run with:
python puzzles/day05.py inputs/day05.txt
"""
import pathlib
import sys
from typing import Dict, List, Tuple
from collections import defaultdict
from dataclasses import dataclass
@dataclass
class Location:
x: int = 0
y: int = 0
def __post_init__(self):
self.x = int(self.x)
self.y = int(self.y)
@dataclass
class VolcanicVent:
start: Location
end: Location
def __post_init__(self):
if self.start.x == self.end.x:
self.direction = "vertical"
elif self.start.y == self.end.y:
self.direction = "horizontal"
else:
self.direction = "diagnal"
class Chart:
chart: Dict = None
vents: List = None
def __init__(self, vents: List[VolcanicVent], diagnals: bool = True) -> None:
self.vents = vents
self._generate_chart(diagnals=diagnals)
def _generate_chart(self, diagnals: bool = True) -> None:
"""
.......1..
..1....1..
..1....1..
.......1..
.112111211
..........
..........
..........
..........
222111.... 0,9 -> 5,9 0,9 -> 2,9
"""
self.chart = defaultdict(int)
for vent in self.vents:
if vent.direction != "diagnal":
self._chart_line_horiz_vert(vent.start, vent.end)
elif diagnals:
self._chart_line_diagnal(vent.start, vent.end)
def _chart_line_diagnal(self, start: Location, end: Location) -> None:
if end.x > start.x: # direction: left
x_range = range(start.x, end.x + 1)
else: # direction: right
x_range = range(start.x, end.x - 1, -1) # reverse range
if end.y > start.y: # direction: down
y_range = range(start.y, end.y + 1)
else: # direction: up
y_range = range(start.y, end.y - 1, -1) # reverse range
for x, y in zip(x_range, y_range):
self.chart[x, y] += 1
def _chart_line_horiz_vert(self, start: Location, end: Location) -> None:
min_x = min(start.x, end.x)
max_x = max(start.x, end.x)
min_y = min(start.y, end.y)
max_y = max(start.y, end.y)
for x in range(min_x, max_x + 1):
for y in range(min_y, max_y + 1):
self.chart[x, y] += 1
def calculate_overlaps(self, max_depth: int = 1) -> int:
return sum(depth_count > max_depth for depth_count in self.chart.values())
def part1(inputs: List[int]) -> int:
c = Chart(inputs, diagnals=False)
return c.calculate_overlaps()
def part2(inputs: List[int]) -> int:
c = Chart(inputs)
return c.calculate_overlaps()
def parse(inputs: str) -> List[int]:
"""Parse the input string"""
results = []
for line in inputs.split("\n"):
start_end = line.split(" -> ")
results.append(
VolcanicVent(
start=Location(*start_end[0].split(",")),
end=Location(*start_end[1].split(",")),
)
)
return results
def solve(path: str) -> Tuple[int, int]:
"""Solve the puzzle"""
puzzle_input = parse(pathlib.Path(path).read_text().strip())
part1_result = part1(puzzle_input)
part2_result = part2(puzzle_input)
return part1_result, part2_result
def main() -> None:
for path in sys.argv[1:]:
print(f"Input File: {path}")
part1_result, part2_result = solve(path)
print(f"Part 1 Result: {part1_result}")
print(f"Part 2 Result: {part2_result}")
if __name__ == "__main__":
main()