advent-of-code/2024/06/main.py

90 lines
2.0 KiB
Python
Raw Permalink Normal View History

2024-12-08 20:36:04 +00:00
from typing import List, Union, Tuple, Set, Self
from dataclasses import dataclass
type Point = Tuple[int, int]
TURN = {
# (-1,0) > (0, 1) -> (1, 0) -> (0, -1)
(-1, 0): (0, 1),
(0, 1): (1, 0),
(1, 0): (0, -1),
(0, -1): (-1, 0),
}
@dataclass
class Map:
fields: List[List[bool]]
position: Point
direction: Point
max_y: int = 0
max_x: int = 0
def __post_init__(self):
self.max_y = len(self.fields)
self.max_x = len(self.fields[0])
def next_step(self):
return (
self.position[0] + self.direction[0],
self.position[1] + self.direction[1],
)
def get(self, point: Point) -> Union[bool, None]:
y, x = point
try:
return self.fields[y][x]
except IndexError:
return None
def walk(self):
visited: Set[Point] = set()
while True:
visited.add(self.position)
next_step = self.next_step()
content = self.get(next_step)
if content is None:
# Exited map
break
if content:
# Turn
self.direction = TURN[self.direction]
next_step = self.next_step()
self.position = next_step
return len(visited)
@staticmethod
def parse(raw: str) -> Self:
fields = [[f == "#" for f in line] for line in raw.splitlines()]
# Find init
position = (0, 0)
direction = (-1, 0) # Up
for y, line in enumerate(raw.splitlines()):
for x, f in enumerate(line):
if f == "^":
position = (y, x)
return Map(fields, position, direction)
def solve(raw: str) -> int:
# Part 1
part1 = 0
part2 = 0
m = Map.parse(raw)
part1 = m.walk()
return (part1, part2)
# Test
with open("./2024/06/test.txt", "r") as f:
result = solve(f.read().strip())
print(result)
# Input
with open("./2024/06/input.txt", "r") as f:
result = solve(f.read().strip())
print(result)