Skip to content

Commit 1d65cf3

Browse files
committedDec 25, 2024
feat: 2024 day 18
1 parent ea91164 commit 1d65cf3

File tree

3 files changed

+147
-32
lines changed

3 files changed

+147
-32
lines changed
 

‎2024/18a.py

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
from aoc import *
2+
from itertools import product
3+
from collections import namedtuple, deque, UserList
4+
from heapq import *
5+
import itertools
6+
7+
8+
# Priority queue implementation from
9+
# https://docs.python.org/3.3/library/heapq.html#priority-queue-implementation-notes
10+
class PriorityQueue(UserList):
11+
def __init__(self):
12+
self.entry_finder = {} # mapping of tasks to entries
13+
self.REMOVED = '<removed-task>' # placeholder for a removed task
14+
self.counter = itertools.count() # unique sequence count
15+
UserList.__init__(self)
16+
17+
def add_task(self, task, priority=0):
18+
'Add a new task or update the priority of an existing task'
19+
if task in self.entry_finder:
20+
self.remove_task(task)
21+
count = next(self.counter)
22+
entry = [priority, count, task]
23+
self.entry_finder[task] = entry
24+
heappush(self.data, entry)
25+
26+
def remove_task(self, task):
27+
'Mark an existing task as REMOVED. Raise KeyError if not found.'
28+
entry = self.entry_finder.pop(task)
29+
entry[-1] = self.REMOVED
30+
31+
def pop_task(self):
32+
'Remove and return the lowest priority task. Raise KeyError if empty.'
33+
while self.data:
34+
priority, count, task = heappop(self.data)
35+
if task is not self.REMOVED:
36+
del self.entry_finder[task]
37+
return task
38+
raise KeyError('pop from an empty priority queue')
39+
40+
41+
# Dijkstra from https://rosettacode.org/wiki/Dijkstra%27s_algorithm#Python
42+
inf = float('inf')
43+
Edge = namedtuple('Edge', ['start', 'end', 'cost'])
44+
45+
46+
class Graph:
47+
def __init__(self, edges):
48+
self.edges = [Edge(*edge) for edge in edges]
49+
# print(dir(self.edges[0]))
50+
self.vertices = {e.start for e in self.edges} | {
51+
e.end for e in self.edges
52+
}
53+
54+
def dijkstra(self, source, dest):
55+
assert source in self.vertices
56+
57+
dist = {vertex: inf for vertex in self.vertices}
58+
dist[source] = 0
59+
previous = {vertex: None for vertex in self.vertices}
60+
61+
q = PriorityQueue()
62+
[q.add_task(v, dist[v]) for v in self.vertices]
63+
64+
neighbours = {vertex: set() for vertex in self.vertices}
65+
for start, end, cost in self.edges:
66+
neighbours[start].add((end, cost))
67+
68+
while q:
69+
u = q.pop_task()
70+
if dist[u] == inf or u == dest:
71+
break
72+
for v, cost in neighbours[u]:
73+
alt = dist[u] + cost
74+
if alt < dist[v]: # Relax (u,v,a)
75+
dist[v] = alt
76+
previous[v] = u
77+
q.add_task(v, alt)
78+
s, u = deque(), dest
79+
while previous[u]:
80+
s.appendleft(u)
81+
u = previous[u]
82+
s.appendleft(u)
83+
return s, dist[dest]
84+
85+
86+
DIRS = ((-1, 0), (0, 1), (1, 0), (0, -1))
87+
88+
89+
def main(infi: str):
90+
inp = lines_stripped(infi)
91+
coords = set()
92+
for b in range(1025, len(inp)):
93+
for x in inp[:b]:
94+
nums = x.split(',')
95+
coords.add((int(nums[0]), int(nums[1])))
96+
maxi = 71
97+
# maxi = 7 # for test input
98+
maxj = maxi
99+
edges = []
100+
for i, j in product(range(maxi), range(maxj)):
101+
for d in DIRS:
102+
if (
103+
(i, j) not in coords
104+
and 0 <= i + d[0] < maxi
105+
and 0 <= j + d[1] < maxj
106+
and (i + d[0], j + d[1]) not in coords
107+
):
108+
edges.append(((i, j), (i + d[0], j + d[1]), 1))
109+
edges.append(((i + d[0], j + d[1]), (i, j), 1))
110+
g = Graph(edges)
111+
path, shortest_length = g.dijkstra((0, 0), (maxi - 1, maxj - 1))
112+
return shortest_length
113+
114+
115+
DAY = 18
116+
FILE_TEST = f"{DAY}_testa.txt"
117+
# FILE_TEST = f"{DAY}_testb.txt"
118+
FILE_EXP = f"{DAY}_exp.txt"
119+
FILE = f"{DAY}.txt"
120+
# test_and_submit(main, FILE_TEST, FILE_EXP, FILE, DAY)
121+
# print(main(FILE_TEST))
122+
print(main(FILE))

‎2024/18b.py

+24-32
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,18 @@
11
from aoc import *
2-
from itertools import pairwise, combinations, repeat, product, accumulate, permutations, cycle, combinations_with_replacement
3-
from more_itertools import first_true, flatten, ncycles, first_true, zip_broadcast, windowed, chunked, take, peekable
4-
import re
5-
from blessed import BlessedList
6-
from collections import namedtuple, defaultdict, OrderedDict, Counter, deque, UserList
7-
import operator
8-
from operator import itemgetter
9-
from bisect import *
10-
from functools import reduce, cache, cmp_to_key
11-
import math
12-
from copy import deepcopy
13-
from math import ceil
2+
from itertools import product
3+
from collections import namedtuple, deque, UserList
144
from heapq import *
155
import sys
16-
from pprint import pprint as pp
17-
from statistics import mode
18-
from string import ascii_uppercase
196
import itertools
207

218

229
# Priority queue implementation from
2310
# https://docs.python.org/3.3/library/heapq.html#priority-queue-implementation-notes
2411
class PriorityQueue(UserList):
2512
def __init__(self):
26-
self.entry_finder = {} # mapping of tasks to entries
27-
self.REMOVED = '<removed-task>' # placeholder for a removed task
28-
self.counter = itertools.count() # unique sequence count
13+
self.entry_finder = {} # mapping of tasks to entries
14+
self.REMOVED = '<removed-task>' # placeholder for a removed task
15+
self.counter = itertools.count() # unique sequence count
2916
UserList.__init__(self)
3017

3118
def add_task(self, task, priority=0):
@@ -51,19 +38,19 @@ def pop_task(self):
5138
return task
5239
raise KeyError('pop from an empty priority queue')
5340

41+
5442
# Dijkstra from https://rosettacode.org/wiki/Dijkstra%27s_algorithm#Python
5543
inf = float('inf')
5644
Edge = namedtuple('Edge', ['start', 'end', 'cost'])
5745

58-
class Graph():
46+
47+
class Graph:
5948
def __init__(self, edges):
6049
self.edges = [Edge(*edge) for edge in edges]
6150
# print(dir(self.edges[0]))
62-
self.vertices = {e.start for e in self.edges} | {e.end for e in self.edges}
63-
64-
def add_edge(self, edge)
65-
self.edges.append(Edge(*edge))
66-
self.vertices.extend({edges[0], edges[1]})
51+
self.vertices = {e.start for e in self.edges} | {
52+
e.end for e in self.edges
53+
}
6754

6855
def dijkstra(self, source, dest):
6956
assert source in self.vertices
@@ -85,7 +72,7 @@ def dijkstra(self, source, dest):
8572
break
8673
for v, cost in neighbours[u]:
8774
alt = dist[u] + cost
88-
if alt < dist[v]: # Relax (u,v,a)
75+
if alt < dist[v]: # Relax (u,v,a)
8976
dist[v] = alt
9077
previous[v] = u
9178
q.add_task(v, alt)
@@ -99,11 +86,13 @@ def dijkstra(self, source, dest):
9986

10087
DIRS = ((-1, 0), (0, 1), (1, 0), (0, -1))
10188

89+
10290
def main(infi: str):
10391
inp = lines_stripped(infi)
10492
coords = set()
105-
# for b in range(2966, len(inp)):
106-
for b in range(len(inp)):
93+
# The start of the range was raised manually. TODO: binary search, or a
94+
# better implementation of graph search.
95+
for b in range(2900, len(inp)):
10796
for x in inp[:b]:
10897
nums = x.split(',')
10998
coords.add((int(nums[0]), int(nums[1])))
@@ -113,13 +102,18 @@ def main(infi: str):
113102
edges = []
114103
for i, j in product(range(maxi), range(maxj)):
115104
for d in DIRS:
116-
if (i, j) not in coords and 0 <= i + d[0] < maxi and 0 <= j + d[1] < maxj and (i + d[0], j + d[1]) not in coords:
105+
if (
106+
(i, j) not in coords
107+
and 0 <= i + d[0] < maxi
108+
and 0 <= j + d[1] < maxj
109+
and (i + d[0], j + d[1]) not in coords
110+
):
117111
edges.append(((i, j), (i + d[0], j + d[1]), 1))
118112
edges.append(((i + d[0], j + d[1]), (i, j), 1))
119113
g = Graph(edges)
120-
path, shortest_length = g.dijkstra((0, 0), (maxi-1, maxj-1))
114+
path, shortest_length = g.dijkstra((0, 0), (maxi - 1, maxj - 1))
121115
if shortest_length == inf:
122-
return inp[b-1]
116+
return inp[b - 1]
123117
# print(b, inp[b-1], shortest_length, path[-1])
124118

125119

@@ -131,5 +125,3 @@ def main(infi: str):
131125
# test_and_submit(main, FILE_TEST, FILE_EXP, FILE, DAY)
132126
# print(main(FILE_TEST))
133127
print(main(FILE))
134-
135-
# 140 bad

‎README.org

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
| 21 | >24h | 15115 | 0 | >24h | 11364 | 0 |
1212
| 20 | 02:16:45 | 5713 | 0 | >24h | 20970 | 0 |
1313
| 19 | 01:44:22 | 6641 | 0 | 01:50:06 | 5444 | 0 |
14+
| 18 | 00:23:32 | 2771 | 0 | 00:29:19 | 2300 | 0 |
1415
| 17 | 00:27:08 | 1748 | 0 | 07:06:10 | 5688 | 0 |
1516
| 15 | 00:32:17 | 2397 | 0 | 02:59:49 | 4379 | 0 |
1617
| 14 | 00:19:09 | 1902 | 0 | 01:13:46 | 3551 | 0 |

0 commit comments

Comments
 (0)
Please sign in to comment.