-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10 from tyler-hoffman/day-06
Day 06
- Loading branch information
Showing
10 changed files
with
220 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
from dataclasses import dataclass | ||
from functools import cached_property | ||
from aoc_2024.day_06.parser import Parser | ||
from aoc_2024.utils.point import Point | ||
|
||
DIRECTIONS = [Point(0, -1), Point(1, 0), Point(0, 1), Point(-1, 0)] | ||
|
||
|
||
@dataclass | ||
class Day06PartASolver: | ||
grid: list[list[str]] | ||
|
||
@property | ||
def solution(self) -> int: | ||
visited = set[Point]() | ||
direction_index = 0 | ||
pos = self.start | ||
while pos.x >= 0 and pos.y >= 0 and pos.x < self.width and pos.y < self.height: | ||
visited.add(pos) | ||
next_pos = pos.add(DIRECTIONS[direction_index]) | ||
if next_pos in self.obstacles: | ||
direction_index = (direction_index + 1) % 4 | ||
else: | ||
pos = next_pos | ||
return len(visited) | ||
|
||
@cached_property | ||
def width(self) -> int: | ||
return len(self.grid[0]) | ||
|
||
@cached_property | ||
def height(self) -> int: | ||
return len(self.grid) | ||
|
||
@cached_property | ||
def obstacles(self) -> set[Point]: | ||
output = set[Point]() | ||
for y, line in enumerate(self.grid): | ||
for x, char in enumerate(line): | ||
if char == "#": | ||
output.add(Point(x, y)) | ||
return output | ||
|
||
@cached_property | ||
def start(self) -> Point: | ||
for y, line in enumerate(self.grid): | ||
for x, char in enumerate(line): | ||
if char == "^": | ||
return Point(x, y) | ||
assert False, "How'd we get here?" | ||
|
||
|
||
def solve(input: str) -> int: | ||
data = Parser.parse(input) | ||
solver = Day06PartASolver(data) | ||
|
||
return solver.solution | ||
|
||
|
||
def get_solution() -> int: | ||
with open("aoc_2024/day_06/input.txt", "r") as f: | ||
input = f.read() | ||
return solve(input) | ||
|
||
|
||
if __name__ == "__main__": | ||
print(get_solution()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
from dataclasses import dataclass | ||
from functools import cached_property | ||
from aoc_2024.day_06.parser import Parser | ||
from aoc_2024.utils.point import Point | ||
|
||
DIRECTIONS = [Point(0, -1), Point(1, 0), Point(0, 1), Point(-1, 0)] | ||
|
||
|
||
@dataclass | ||
class Day06PartBSolver: | ||
grid: list[list[str]] | ||
|
||
@property | ||
def solution(self) -> int: | ||
output = 0 | ||
for extra_obstacle in self.to_check: | ||
if self.has_loop(self.obstacles | {extra_obstacle}): | ||
output += 1 | ||
return output | ||
|
||
def has_loop(self, obstacles: set[Point]) -> bool: | ||
visited = set[tuple[Point, int]]() | ||
direction_index = 0 | ||
pos = self.start | ||
while pos.x >= 0 and pos.y >= 0 and pos.x < self.width and pos.y < self.height: | ||
key = (pos, direction_index) | ||
if key in visited: | ||
return True | ||
else: | ||
visited.add(key) | ||
next_pos = pos.add(DIRECTIONS[direction_index]) | ||
if next_pos in obstacles: | ||
direction_index = (direction_index + 1) % 4 | ||
else: | ||
pos = next_pos | ||
return False | ||
|
||
@cached_property | ||
def to_check(self) -> set[Point]: | ||
points = set[Point]() | ||
direction_index = 0 | ||
pos = self.start | ||
while pos.x >= 0 and pos.y >= 0 and pos.x < self.width and pos.y < self.height: | ||
points.add(pos) | ||
next_pos = pos.add(DIRECTIONS[direction_index]) | ||
if next_pos in self.obstacles: | ||
direction_index = (direction_index + 1) % 4 | ||
else: | ||
pos = next_pos | ||
return points - {self.start} | ||
|
||
@cached_property | ||
def width(self) -> int: | ||
return len(self.grid[0]) | ||
|
||
@cached_property | ||
def height(self) -> int: | ||
return len(self.grid) | ||
|
||
@cached_property | ||
def obstacles(self) -> set[Point]: | ||
output = set[Point]() | ||
for y, line in enumerate(self.grid): | ||
for x, char in enumerate(line): | ||
if char == "#": | ||
output.add(Point(x, y)) | ||
return output | ||
|
||
@cached_property | ||
def start(self) -> Point: | ||
for y, line in enumerate(self.grid): | ||
for x, char in enumerate(line): | ||
if char == "^": | ||
return Point(x, y) | ||
assert False, "How'd we get here?" | ||
|
||
|
||
def solve(input: str) -> int: | ||
data = Parser.parse(input) | ||
solver = Day06PartBSolver(data) | ||
|
||
return solver.solution | ||
|
||
|
||
def get_solution() -> int: | ||
with open("aoc_2024/day_06/input.txt", "r") as f: | ||
input = f.read() | ||
return solve(input) | ||
|
||
|
||
if __name__ == "__main__": | ||
print(get_solution()) |
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
class Parser: | ||
@staticmethod | ||
def parse(input: str) -> list[list[str]]: | ||
lines = input.strip().splitlines() | ||
return [list(line) for line in lines] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
from __future__ import annotations | ||
from dataclasses import dataclass | ||
|
||
|
||
@dataclass(frozen=True) | ||
class Point: | ||
x: int | ||
y: int | ||
|
||
@property | ||
def unit(self) -> Point: | ||
x = 0 if self.x == 0 else self.x // abs(self.x) | ||
y = 0 if self.y == 0 else self.y // abs(self.y) | ||
|
||
return Point(x, y) | ||
|
||
def add(self, other: Point) -> Point: | ||
return Point(self.x + other.x, self.y + other.y) | ||
|
||
def subtract(self, other: Point) -> Point: | ||
return Point(self.x - other.x, self.y - other.y) | ||
|
||
def multiply(self, amt: int) -> Point: | ||
return Point(self.x * amt, self.y * amt) | ||
|
||
def dist(self, other: Point) -> int: | ||
return abs(self.x - other.x) + abs(self.y - other.y) | ||
|
||
@property | ||
def neighbors(self) -> set[Point]: | ||
return { | ||
Point(self.x, self.y - 1), | ||
Point(self.x + 1, self.y), | ||
Point(self.x, self.y + 1), | ||
Point(self.x - 1, self.y), | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from aoc_2024.day_06.a import get_solution, solve | ||
from aoc_2024.day_06.from_prompt import SAMPLE_DATA, SAMPLE_SOLUTION_A, SOLUTION_A | ||
|
||
|
||
def test_solve(): | ||
assert solve(SAMPLE_DATA) == SAMPLE_SOLUTION_A | ||
|
||
|
||
def test_my_solution(): | ||
assert get_solution() == SOLUTION_A |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from aoc_2024.day_06.b import get_solution, solve | ||
from aoc_2024.day_06.from_prompt import SAMPLE_DATA, SAMPLE_SOLUTION_B, SOLUTION_B | ||
|
||
|
||
def test_solve(): | ||
assert solve(SAMPLE_DATA) == SAMPLE_SOLUTION_B | ||
|
||
|
||
def test_my_solution(): | ||
assert get_solution() == SOLUTION_B |