Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dijkstra not required in Adevent of Code 2024 Day 20, BFS is sufficient #138

Open
vismit2000 opened this issue Dec 28, 2024 · 1 comment

Comments

@vismit2000
Copy link

vismit2000 commented Dec 28, 2024

Thanks for really good concise solutions again this year. Maybe @norvig and Karpathy are the two people who know the expressive power of python the best. I come back to these solutions every year to not only check alternate approaches but to also learn writing better Python.

https://github.com/norvig/pytudes/blob/main/ipynb/Advent-2024.ipynb

Since the distances are same throughout (1 unit) in Race Condition problem (Day 20), Dijkstra is overkill here although it obviously works perfectly fine. So BFS can asymptotically improve the running time.

with open("input.txt", "r") as file:
    lines = file.read().strip().split("\n")
    graph = {i + j * 1j: c for i, r in enumerate(lines) for j, c in enumerate(r)}
    start = next(p for p in graph if graph[p] == "S")
    end = next(p for p in graph if graph[p] == "E")


def bfs(point, graph):
    dist = {}
    q = [(point, 0)]
    visited = {point}
    while q:
        p, d = q.pop(0)
        dist[p] = d
        for dir in (-1, 1j, 1, -1j):
            np = p + dir
            if graph.get(np, "#") != "#" and np not in visited:
                q.append((np, d + 1))
                visited.add(np)
    return dist


def neighborhood(point, radius):
    """All points within `radius` of `point` (using taxi distance)."""
    return [
        point + dx + dy * 1j
        for dx in range(-radius, radius + 1)
        for dy in range(-(radius - abs(dx)), radius - abs(dx) + 1)
    ]


def taxi_distance(p1, p2):
    return abs(p1.real - p2.real) + abs(p1.imag - p2.imag)


def cheats(racetrack, lower_bound=1, radius=20):
    """All ways of cheating by taking up to `radius` steps through walls and back to the track."""
    D = bfs(end, racetrack)
    return [
        (p1, p2, t)
        for p1 in D
        for p2 in neighborhood(p1, radius)
        if p2 in D and (t := D[p1] - D[p2] - taxi_distance(p1, p2)) >= lower_bound
    ]


print(len(cheats(graph, 100, 2)))
print(len(cheats(graph, 100, 20)))
@norvig
Copy link
Owner

norvig commented Jan 2, 2025 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants