Skip to content

Commit ea91164

Browse files
committed
chore: wip on 2024 day 18b
1 parent 4b44b4c commit ea91164

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed

2024/18b.py

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

0 commit comments

Comments
 (0)