Skip to content

Commit 1b9e12a

Browse files
committed
refactor, rename, and add Day 16 start
1 parent 8ed8303 commit 1b9e12a

14 files changed

+188
-18
lines changed

.idea/Advent-of-Code.iml

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

AoC_2024/Days/14.py aoc_2024/Days/14.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
from tqdm import tqdm
1414

15-
from AoC_2024.utils import Grid, Point
15+
from aoc_2024.utils import Grid, Point
1616

1717

1818
DEMO_INPUT = """

aoc_2024/Days/16.py

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
"""
2+
--- Day 16: Reindeer Maze ---
3+
4+
Link:
5+
https://adventofcode.com/2024/day/16
6+
7+
"""
8+
import math
9+
from collections import defaultdict
10+
from enum import Enum, auto
11+
from pathlib import Path
12+
from sys import argv
13+
14+
from aoc_2024.maze import Maze
15+
from aoc_2024.utils import Grid, Point
16+
17+
18+
DEMO_INPUT = """
19+
###############
20+
#.......#....E#
21+
#.#.###.#.###.#
22+
#.....#.#...#.#
23+
#.###.#####.#.#
24+
#.#.#.......#.#
25+
#.#.#####.###.#
26+
#...........#.#
27+
###.#.#####.#.#
28+
#...#.....#.#.#
29+
#.#.#.###.#.#.#
30+
#.....#...#.#.#
31+
#.###.#.#.#.#.#
32+
#S..#.....#...#
33+
###############
34+
"""
35+
36+
37+
def remap(_map: str) -> Maze:
38+
"""
39+
Remap example list input provided in "Advent of Code"
40+
format.
41+
"""
42+
return Maze(_map)
43+
44+
45+
def part_1(maze: Maze):
46+
maze.visualize()
47+
48+
49+
def part_2(maze: Maze):
50+
...
51+
52+
53+
def solve(input_file=None):
54+
if input_file:
55+
demo = False
56+
default = ' '
57+
print(f"Solving with input file {input_file}")
58+
try:
59+
INPUT = open(input_file).read()
60+
except FileNotFoundError:
61+
print('File not found, using default ...')
62+
INPUT = open(Path(__file__).parent.parent / 'Inputs' / '14').read()
63+
_width = 101
64+
_height = 103
65+
66+
else:
67+
demo = True
68+
default = '.'
69+
INPUT = DEMO_INPUT
70+
71+
print("Solving Day 16 Problem! 🎄")
72+
73+
maze = remap(INPUT)
74+
75+
# Part 1
76+
_result = part_1(maze)
77+
print('Part 1:', _result)
78+
79+
# Part 2
80+
# _result = part_2(maze)
81+
# print('Part 2:', _result)
82+
83+
84+
if __name__ == '__main__':
85+
solve()
File renamed without changes.

aoc_2024/maze.py

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from enum import Enum, auto
2+
3+
import numpy as np
4+
import matplotlib.pyplot as plt
5+
6+
from .utils import Grid, Point
7+
8+
9+
class State(Enum):
10+
WALL = auto()
11+
PATH = auto()
12+
DEAD_END = auto()
13+
START = auto()
14+
END = auto()
15+
16+
17+
class Maze(Grid):
18+
19+
def __init__(self, _map: str):
20+
grid_array: list = _map.strip().split('\n')
21+
super().__init__(grid_array)
22+
23+
point_to_state = {}
24+
for y, row in enumerate(self.rows):
25+
for x, value in enumerate(row):
26+
p = Point(x, y)
27+
if value == '#':
28+
point_to_state[p] = State.WALL
29+
elif value == '.':
30+
point_to_state[p] = State.PATH
31+
elif value == 'S':
32+
point_to_state[p] = State.START
33+
elif value == 'E':
34+
point_to_state[p] = State.END
35+
self.point_to_state = point_to_state
36+
37+
def visualize(self):
38+
"""Visualizes the maze using Matplotlib."""
39+
# Create a color mapping
40+
color_map = {
41+
State.WALL: (0, 0, 0), # Wall - black
42+
State.PATH: (1, 1, 1), # Path - white
43+
State.START: (0, 1, 0), # Start - green
44+
State.END: (1, 0, 0), # End - red
45+
}
46+
47+
# Convert the maze into a NumPy array of colors
48+
height, width, pt_to_state = self.height, self.width, self.point_to_state
49+
colored_maze = np.zeros((height, width, 3)) # 3 channels for RGB
50+
51+
for y, row in enumerate(self._array):
52+
for x, cell in enumerate(row):
53+
state = pt_to_state[Point(x, y)]
54+
colored_maze[y, x] = color_map[state]
55+
56+
# Plot the maze
57+
plt.figure(figsize=(8, 8))
58+
plt.imshow(colored_maze, interpolation="nearest")
59+
plt.axis("off") # Turn off the axes
60+
plt.show()

AoC_2024/run.py aoc_2024/run.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ def main():
88

99
# Try to import the corresponding day module dynamically
1010
try:
11-
# Dynamically import the day script (e.g., AoC_2024.Days.day_14)
12-
day_module = import_module(f"AoC_2024.Days.{day_number}")
11+
# Dynamically import the day script (e.g., aoc_2024.Days.day_14)
12+
day_module = import_module(f"aoc_2024.Days.{day_number}")
1313
# Call the solution function if it exists in the module
1414
if hasattr(day_module, "solve"):
1515
day_module.solve(input_file)

AoC_2024/utils.py aoc_2024/utils.py

+29-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,35 @@
1-
from dataclasses import asdict
1+
from dataclasses import asdict, dataclass
22
from enum import Enum
3-
from numbers import Number
4-
from typing import NamedTuple
5-
3+
from typing import NamedTuple, TYPE_CHECKING
64

75
#################################################################
86
# POINTS, VECTORS AND GRIDS
97
#################################################################
108

11-
Point = NamedTuple("Point", [("x", Number), ("y", Number)])
129

13-
Point.__add__ = lambda self, other: Point(self.x + other.x, self.y + other.y)
14-
Point.__sub__ = lambda self, other: Point(self.x - other.x, self.y - other.y)
15-
Point.__mul__ = lambda self, scalar: Point(self.x * scalar, self.y * scalar)
16-
Point.__rmul__ = lambda self, scalar: self * scalar # for when int comes first
10+
if TYPE_CHECKING:
11+
class Point:
12+
# noinspection PyUnusedLocal
13+
def __init__(self, x: int, y: int): ...
14+
15+
16+
# noinspection PyRedeclaration
17+
class Point(NamedTuple):
18+
x: int
19+
y: int
20+
21+
def __add__(self, other):
22+
return Point(self.x + other.x, self.y + other.y)
23+
24+
def __sub__(self, other):
25+
return Point(self.x - other.x, self.y - other.y)
26+
27+
def __mul__(self, scalar):
28+
return Point(self.x * scalar, self.y * scalar)
29+
30+
def __rmul__(self, scalar):
31+
return self * scalar # for when int comes first
32+
1733

1834
def yield_neighbours(self, include_diagonals=True, include_self=False):
1935
""" Generator to yield neighbouring Points """
@@ -105,6 +121,10 @@ def cols(self):
105121
""" Return the grid as columns """
106122
return list(zip(*self._array))
107123

124+
@property
125+
def rows(self):
126+
return self._array
127+
108128
def rows_as_str(self):
109129
""" Return the grid """
110130
return ["".join(str(char) for char in row) for row in self._array]

pyproject.toml

+10-5
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,31 @@ readme = "README.md"
1414
keywords = ["advent of code", "python", "2024", "challenges"]
1515
classifiers = [
1616
"Programming Language :: Python :: 3",
17+
"Programming Language :: Python :: 3.9",
18+
"Programming Language :: Python :: 3.10",
19+
"Programming Language :: Python :: 3.11",
20+
"Programming Language :: Python :: 3.12",
1721
"Programming Language :: Python :: 3.13",
1822
"License :: OSI Approved :: MIT License",
1923
"Operating System :: OS Independent",
2024
]
2125

2226
[tool.hatch.version]
23-
path = "AoC_2024/__init__.py"
27+
path = "aoc_2024/__init__.py"
2428

2529
[tool.hatch.packages]
26-
include = ["AoC_2024", "AoC_2024.Days"]
30+
include = ["aoc_2024", "aoc_2024.Days"]
2731

2832
[tool.hatch.build.targets.wheel]
29-
packages = ["AoC_2024"]
33+
packages = ["aoc_2024"]
3034

3135
[project]
3236
name = "Advent-of-Code"
3337
dynamic = ["version"]
3438
dependencies = [
35-
"tqdm",
39+
"tqdm",
40+
"matplotlib",
3641
]
3742

3843
[project.scripts]
39-
aoc = "AoC_2024.run:main"
44+
aoc = "aoc_2024.run:main"

0 commit comments

Comments
 (0)