-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
62 changed files
with
668 additions
and
161 deletions.
There are no files selected for viewing
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
This file was deleted.
Oops, something went wrong.
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
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,61 @@ | ||
""" | ||
--- Day 21: Step Counter --- | ||
https://adventofcode.com/2023/day/21 | ||
""" | ||
import json | ||
import os | ||
from aocd import data | ||
from aoc_wim.search import BFS | ||
from aoc_wim.zgrid import manhattan_distance | ||
from aoc_wim.zgrid import ZGrid | ||
|
||
|
||
grid = ZGrid(data, on=".", off="#") | ||
z0 = grid.z("S") | ||
grid[z0] = "." | ||
plots = set(grid.bfs(z0=z0)) | ||
|
||
|
||
def step(n): | ||
parity = n % 2 | ||
reachable = far = 0 | ||
for z in plots: | ||
d = manhattan_distance(z, z0) | ||
if d > n: | ||
far += 1 | ||
else: | ||
reachable += d % 2 == parity | ||
return reachable, far | ||
|
||
|
||
def adj(state, h=grid.height, w=grid.width): | ||
z0, Z0 = state | ||
for z in grid.near(z0): | ||
if z in grid: | ||
Z = Z0 | ||
else: | ||
qy, ry = divmod(z.imag, h) | ||
qx, rx = divmod(z.real, w) | ||
z = complex(rx, ry) | ||
Z = Z0 + complex(qx, qy) | ||
if (z, Z) not in bfs.seen and grid[z] == ".": | ||
yield z, Z | ||
|
||
|
||
if "AOCD_EXTRA" not in os.environ: | ||
a, _ = step(64) | ||
print("answer_a:", a) | ||
N, rem = divmod(26501365, grid.width) | ||
r, f = step(rem) | ||
b = N*N*len(plots) + (2*N + 1)*r + N*f | ||
print("answer_b:", b) | ||
else: | ||
extra = json.loads(os.environ["AOCD_EXTRA"]) | ||
n_steps = extra["n_steps"] | ||
state0 = z0, 0 | ||
bfs = BFS(adj, max_depth=n_steps) | ||
bfs(state0) | ||
parity = n_steps % 2 | ||
a = b = sum(v % 2 == parity for v in bfs.seen.values()) | ||
print("answer_a:", a) | ||
print("answer_b:", b) |
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,112 @@ | ||
""" | ||
--- Day 22: Sand Slabs --- | ||
https://adventofcode.com/2023/day/22 | ||
""" | ||
from aocd import data | ||
from dataclasses import dataclass | ||
import operator as op | ||
|
||
|
||
@dataclass | ||
class Brick: | ||
x0: int | ||
y0: int | ||
z0: int | ||
x1: int | ||
y1: int | ||
z1: int | ||
id: int = None | ||
|
||
@classmethod | ||
def fromline(cls, line): | ||
return cls(*map(int, line.replace("~", ",").split(","))) | ||
|
||
def __post_init__(self): | ||
if self.x0 > self.x1 or self.y0 > self.y1 or self.z0 > self.z1: | ||
raise ValueError(f"Invalid brick {self}") | ||
|
||
def cells(self, dz=0): | ||
xs = range(self.x0, self.x1 + 1) | ||
ys = range(self.y0, self.y1 + 1) | ||
zs = range(self.z0, self.z1 + 1) | ||
return {(x, y, z + dz) for x in xs for y in ys for z in zs} | ||
|
||
def above(self): | ||
xs = range(self.x0, self.x1 + 1) | ||
ys = range(self.y0, self.y1 + 1) | ||
return {(x, y, self.z1 + 1) for x in xs for y in ys} | ||
|
||
def below(self): | ||
xs = range(self.x0, self.x1 + 1) | ||
ys = range(self.y0, self.y1 + 1) | ||
return {(x, y, self.z0 - 1) for x in xs for y in ys} | ||
|
||
def fall(self): | ||
self.z0 -= 1 | ||
self.z1 -= 1 | ||
|
||
|
||
tdata = """1,0,1~1,2,1 | ||
0,0,2~2,0,2 | ||
0,2,3~2,2,3 | ||
0,0,4~0,2,4 | ||
2,0,5~2,2,5 | ||
0,1,6~2,1,6 | ||
1,1,8~1,1,9""" | ||
# data = tdata | ||
|
||
bricks = [Brick.fromline(x) for x in data.splitlines()] | ||
bricks.sort(key=op.attrgetter("z0")) | ||
space = {} | ||
for i, brick in enumerate(bricks): | ||
brick.id = i | ||
xs = range(brick.x0, brick.x1 + 1) | ||
ys = range(brick.y0, brick.y1 + 1) | ||
zs = range(brick.z0, brick.z1 + 1) | ||
space.update(dict.fromkeys(brick.cells(), brick.id)) | ||
|
||
while True: | ||
mutated = False | ||
for brick in bricks: | ||
if brick.z0 == 1: | ||
continue | ||
if not space.keys() & brick.below(): | ||
for cell in brick.cells(): | ||
del space[cell] | ||
brick.fall() | ||
space.update() | ||
for cell in brick.cells(): | ||
space[cell] = brick.id | ||
mutated = True | ||
if not mutated: | ||
break | ||
|
||
bricks_below = [set() for b in bricks] | ||
bricks_above = [set() for b in bricks] | ||
for brick in bricks: | ||
for cell in brick.above(): | ||
if cell in space: | ||
bricks_above[brick.id].add(space[cell]) | ||
bricks_below[space[cell]].add(brick.id) | ||
|
||
supports = [set() for b in bricks] | ||
for brick in bricks: | ||
for brick_above in bricks_above[brick.id]: | ||
if len(bricks_below[brick_above]) == 1: | ||
supports[brick.id].add(brick_above) | ||
|
||
a = sum(not s for s in supports) | ||
print("answer_a:", a) | ||
|
||
b = 0 | ||
for brick in bricks: | ||
stack = list(supports[brick.id]) | ||
cumulative_support = set() | ||
while stack: | ||
b_id = stack.pop() | ||
cumulative_support.add(b_id) | ||
for brick_above in bricks_above[b_id]: | ||
if bricks_below[brick_above] <= cumulative_support: | ||
stack.append(brick_above) | ||
b += len(cumulative_support) | ||
print("answer_b:", b) |
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,58 @@ | ||
""" | ||
--- Day 23: A Long Walk --- | ||
https://adventofcode.com/2023/day/23 | ||
""" | ||
from aocd import data | ||
from aoc_wim.zgrid import ZGrid | ||
|
||
|
||
grid = ZGrid(data) | ||
start = 1 | ||
end = grid.bottom_right - 1 | ||
|
||
nodes = {} | ||
dzs = dict(zip("^>v<", [-1j, 1, 1j, -1])) | ||
for z, g in grid.items(): | ||
if g == "." and sum(grid.get(z + dz) in dzs for dz in dzs.values()) >= 2: | ||
nodes[z] = {} | ||
|
||
|
||
def find_next_node(z0, dz0): | ||
path = [z0, z0 + dz0] | ||
while path[-1] not in nodes: | ||
[z1] = [z for z in grid.near(path[-1]) if z != path[-2] and grid.get(z, "#") != "#"] | ||
path.append(z1) | ||
return path[-1], path[-2] - path[-1], len(path) - 1 | ||
|
||
|
||
nodes[start] = {1j: find_next_node(start, 1j)} | ||
nodes[end] = {-1j: find_next_node(end, -1j)} | ||
for z0, branches in nodes.items(): | ||
for dz0 in dzs.values(): | ||
g = grid.get(z0 + dz0) | ||
if g in dzs and dz0 not in branches: | ||
z1, dz1, dist = find_next_node(z0, dz0) | ||
branches[dz0] = z1, dist | ||
nodes[z1][dz1] = z0, dist | ||
|
||
|
||
def longest_path(part="a"): | ||
grid[start + 1j] = "v" | ||
paths = [] | ||
stack = [(start, 0)] | ||
while stack: | ||
path = stack.pop() | ||
z0, d0 = path[-2:] | ||
if z0 == end: | ||
paths.append(path) | ||
branches = nodes[z0] | ||
for g, dz in dzs.items(): | ||
if dz in branches and grid[z0 + dz] in ([g] if part == "a" else dzs): | ||
z1, dist = branches[dz] | ||
if z1 not in path: | ||
stack.append(path + (z1, d0 + dist)) | ||
return max(p[-1] for p in paths) | ||
|
||
|
||
print("answer_a:", longest_path(part="a")) | ||
print("answer_b:", longest_path(part="b")) |
Oops, something went wrong.