Skip to content

Instantly share code, notes, and snippets.

@skifli
Last active December 7, 2024 11:37
Show Gist options
  • Select an option

  • Save skifli/f2534f51009f39ff0e27d1897b1054f0 to your computer and use it in GitHub Desktop.

Select an option

Save skifli/f2534f51009f39ff0e27d1897b1054f0 to your computer and use it in GitHub Desktop.
Advent of Code 2024 Day 6

Wasn't doing AOC this year, but did this day specifically for some friends. Hacked together and written without execution speed in mind - instead, I wanted to get working code as quickly as possible.

@skifli ➜ /workspaces/bruty (main) $ time python day_06.py
Part 1: 4656
Part 2: 1575

real    0m5.520s
user    0m5.369s
sys     0m0.017s
import functools
import itertools
import os
import typing
def get_new_coords(guard: dict, inp_map: list) -> typing.Optional[tuple]:
dx, dy = DIRECTIONS[guard["dir"]]["x"], DIRECTIONS[guard["dir"]]["y"]
new_x, new_y = guard["x"] + dx, guard["y"] + dy
if 0 <= new_x < COL_COUNT and 0 <= new_y < ROW_COUNT:
return new_x, new_y
return None # Out of bounds
@functools.lru_cache
def rotate_direction(current_dir: str) -> str:
return POSSIBLE_DIRECTIONS[(POSSIBLE_DIRECTIONS.index(current_dir) + 1) % POSSIBLE_DIRECTIONS_LEN]
def part1(inp_map: list, guard: dict) -> int:
distinct_positions = {(guard["x"], guard["y"])} # Use tuple directly for coordinates
guard = guard.copy()
while True:
new_coords = get_new_coords(guard, inp_map)
if new_coords is None: # Out of bounds
break
x, y = new_coords
if inp_map[y][x] == "#":
guard["dir"] = rotate_direction(guard["dir"])
else:
guard["x"], guard["y"] = x, y
distinct_positions.add((x, y))
return distinct_positions
def part2(obstacle_positions: set, inp_map: list, guard: dict) -> int:
matches = 0
for x, y in obstacle_positions:
if inp_map[y][x] not in DIRECTIONS and inp_map[y][x] != "#":
# Modify map in-place for obstruction and restore after
original_char = inp_map[y][x]
inp_map[y][x] = "#"
current_guard = {
"x": guard["x"],
"y": guard["y"],
"dir": guard["dir"],
}
distinct_states = set()
while True:
new_coords = get_new_coords(current_guard, inp_map)
if new_coords is None: # Out of bounds
break
cx, cy = new_coords
if inp_map[cy][cx] == "#":
current_guard["dir"] = rotate_direction(current_guard["dir"])
if (current_guard["x"], current_guard["y"], current_guard["dir"]) in distinct_states:
matches += 1
break
distinct_states.add((current_guard["x"], current_guard["y"], current_guard["dir"]))
else:
current_guard["x"], current_guard["y"] = cx, cy
# Restore map to original state
inp_map[y][x] = original_char
return matches
DIRECTIONS: typing.Final[dict] = { # Directions in order of rotation
"^": {"x": 0, "y": -1},
">": {"x": 1, "y": 0},
"v": {"x": 0, "y": 1},
"<": {"x": -1, "y": 0},
}
POSSIBLE_DIRECTIONS = list(DIRECTIONS.keys())
POSSIBLE_DIRECTIONS_LEN = len(POSSIBLE_DIRECTIONS)
path = os.path.split(__file__)[0]
with open(f"{path}/input.txt", "r") as f:
inp_raw = f.read()
inp_map = [list(line) for line in inp_raw.split("\n")]
guard = None
ROW_COUNT = len(inp_map)
COL_COUNT = len(inp_map[0])
for y, line in enumerate(inp_map):
for x, char in enumerate(line):
if char in DIRECTIONS:
guard = {"x": x, "y": y, "dir": char}
break
part_1_data = part1(inp_map, guard)
print(f"Part 1: {len(part_1_data)}")
part_2_data = part2(part_1_data, inp_map, guard)
print(f"Part 2: {part_2_data}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment