Skip to content

Commit

Permalink
Merge branch 'main' into 2024/17
Browse files Browse the repository at this point in the history
  • Loading branch information
wimglenn authored Dec 23, 2024
2 parents bfcfca1 + 15b6dcb commit e48139e
Show file tree
Hide file tree
Showing 62 changed files with 668 additions and 161 deletions.
67 changes: 62 additions & 5 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,71 @@
name: Upload to PyPI
name: Tag new versions

on:
push:
tags:
- "[0-9]+.[0-9]+"
branches: [main]
workflow_dispatch:

jobs:
version-check:
name: Check dynamic version
outputs:
v: ${{ steps.get_version.outputs.v }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true

- name: Install uv
uses: astral-sh/setup-uv@v3
with:
enable-cache: true
cache-dependency-glob: pyproject.toml

- name: Install Python 3.13
run: uv python install 3.13

- name: Get version string
id: get_version
run: |
uv run --no-project - <<EOF
import os
import subprocess
from pathlib import Path
from aoc_wim import __version__
rc = subprocess.run(["git", "tag", "-l", __version__], check=True, capture_output=True)
if rc.stdout:
print(f"version {__version__} is already tagged")
else:
print(f"version {__version__} is new")
path = Path(os.environ["GITHUB_OUTPUT"])
path.write_text(f"v={__version__}\n")
EOF
version-tag:
name: Tag new versions
runs-on: ubuntu-latest
needs: version-check
if: needs.version-check.outputs.v
steps:
- name: Create tag ${{ needs.version-check.outputs.v }}
uses: actions/github-script@v5
with:
script: |
github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: 'refs/tags/${{ needs.version-check.outputs.v }}',
sha: context.sha
})
pypi-publish:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
name: Upload release to PyPI
runs-on: ubuntu-latest
needs: version-tag
if: needs.version-check.outputs.v
environment:
name: pypi
url: https://pypi.org/p/advent-of-code-wim
Expand All @@ -30,7 +87,7 @@ jobs:
run: |
uv venv
uv pip install build
pyproject-build
.venv/bin/pyproject-build
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
62 changes: 0 additions & 62 deletions .github/workflows/tag.yml

This file was deleted.

6 changes: 3 additions & 3 deletions aoc_wim/aoc2018/q22.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,6 @@ def adjacent(self, state):

state0 = (grid.pos, "🔦")
target = (grid.target, "🔦")
a_star = Q22AStar(state0=state0, target=target, grid=grid)
a_star.run()
print("answer_b:", a_star.gscore[target])
astar = Q22AStar(state0=state0, target=target, grid=grid)
astar.run()
print("answer_b:", astar.gscore[target])
61 changes: 61 additions & 0 deletions aoc_wim/aoc2023/q21.py
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)
112 changes: 112 additions & 0 deletions aoc_wim/aoc2023/q22.py
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)
58 changes: 58 additions & 0 deletions aoc_wim/aoc2023/q23.py
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"))
Loading

0 comments on commit e48139e

Please sign in to comment.