Skip to content

Instantly share code, notes, and snippets.

@jaymecd
Created December 5, 2021 16:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jaymecd/5ad2fcb70ec984f7ee4eb8ef21b01c7f to your computer and use it in GitHub Desktop.
Save jaymecd/5ad2fcb70ec984f7ee4eb8ef21b01c7f to your computer and use it in GitHub Desktop.
adventofcode 2021 05
#!/usr/bin/env python3
from __future__ import annotations
import sys
from collections import Counter
from pathlib import Path
from typing import List, Mapping, NamedTuple, Sequence
import enum
class Point(NamedTuple):
x: int
y: int
@classmethod
def create(cls, raw: str) -> Point:
return cls(*map(int, raw.split(",")))
class Board(NamedTuple):
points: List[Point]
@property
def overlapped_points(self) -> Mapping[Point, int]:
return dict(Counter(self.points))
def overlapped_points_by_level(self, min_level: int):
return {k: v for k, v in self.overlapped_points.items() if v >= min_level}
class LineType(enum.Enum):
HORIZONTAL = enum.auto()
VERTICAL = enum.auto()
DIAGONAL = enum.auto()
COMPLEX = enum.auto()
class Line(NamedTuple):
p1: Point
p2: Point
@classmethod
def create(cls, raw: str) -> Line:
return cls(*map(Point.create, raw.split(" -> ")))
@property
def type(self) -> LineType:
if self.p1.y == self.p2.y:
return LineType.HORIZONTAL
if self.p1.x == self.p2.x:
return LineType.VERTICAL
if abs(self.p2.x - self.p1.x) == abs(self.p2.y - self.p1.y):
return LineType.DIAGONAL
return LineType.COMPLEX
@property
def supported(self) -> bool:
return self.horizontal or self.vertical or self.diagonal
@property
def horizontal(self) -> bool:
return self.type is LineType.HORIZONTAL
@property
def vertical(self) -> bool:
return self.type is LineType.VERTICAL
@property
def diagonal(self) -> bool:
return self.type is LineType.DIAGONAL
@property
def points(self) -> Sequence[Point]:
step_x = 1 if self.p2.x >= self.p1.x else -1
step_y = 1 if self.p2.y >= self.p1.y else -1
if self.horizontal:
return [
Point(x, self.p1.y)
for x in range(self.p1.x, self.p2.x + step_x, step_x)
]
if self.vertical:
return [
Point(self.p1.x, y)
for y in range(self.p1.y, self.p2.y + step_y, step_y)
]
if self.diagonal:
return [
Point(self.p1.x + step_x * i, self.p1.y + step_y * i)
for i in range(abs(self.p2.x - self.p1.x) + 1)
]
raise NotImplementedError()
def parse_payload(file: Path) -> Sequence[Line]:
with file.open("r") as fp:
lines = fp.read().splitlines(False)
return [Line.create(line) for line in lines]
def render_board(board: Board, size: int):
overlapped_points = board.overlapped_points
print()
for row in range(size + 1):
for col in range(size + 1):
p = Point(col, row)
if p in overlapped_points:
print(overlapped_points[p], end="")
continue
print(".", end="")
print()
print()
def main():
lines = parse_payload(Path(__file__).with_name("data.txt"))
lines = list(filter(lambda x: x.supported, lines))
for line in lines:
print(f"{line} {line.type.name=}")
print(f"{len(lines)=}", file=sys.stderr)
size = max(
max(line.p2.x for line in lines),
max(line.p2.y for line in lines),
)
points = [point for line in lines for point in line.points]
print(f"{len(points)=}", file=sys.stderr)
board = Board(points)
# render_board(board, size)
dangerous_points = board.overlapped_points_by_level(2)
# print('dangerous_points:')
# pprint(dangerous_points)
print(f"{len(dangerous_points)=}", file=sys.stderr)
if __name__ == "__main__":
main()
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment