224 lines
5.4 KiB
Python
224 lines
5.4 KiB
Python
import re
|
||
from math import inf
|
||
|
||
# Directions/Adjacents for 2D matrices, in the order UP, RIGHT, DOWN, LEFT
|
||
D = [
|
||
(-1, 0),
|
||
(0, 1),
|
||
(1, 0),
|
||
(0, -1),
|
||
]
|
||
|
||
Di = [
|
||
(-1, -1),
|
||
(-1, 1),
|
||
(1, -1),
|
||
(1, 1),
|
||
]
|
||
|
||
# Directions for 2D matrices, as a dict with keys U, R, D, L
|
||
DD = {
|
||
"U": (-1, 0),
|
||
"R": (0, 1),
|
||
"D": (1, 0),
|
||
"L": (0, -1),
|
||
}
|
||
|
||
DDa = {
|
||
"^": (-1, 0),
|
||
">": (0, 1),
|
||
"v": (1, 0),
|
||
"<": (0, -1),
|
||
}
|
||
|
||
# Adjacent relative positions including diagonals for 2D matrices, in the order NW, N, NE, W, E, SW, S, SE
|
||
ADJ = [
|
||
(-1, -1),
|
||
(-1, 0),
|
||
(1, -1),
|
||
(0, -1),
|
||
(0, 1),
|
||
(1, 1),
|
||
(1, 0),
|
||
(1, -1),
|
||
]
|
||
|
||
|
||
def ints(s):
|
||
"""Extract all integers from a string"""
|
||
return [int(n) for n in re.findall(r"\d+", s)]
|
||
|
||
|
||
def sints(s):
|
||
"""Extract all signed integers from a string"""
|
||
return [int(n) for n in re.findall(r"-?\d+", s)]
|
||
|
||
|
||
def mhd(a, b):
|
||
"""Calculates the Manhattan distance between 2 positions in the format (y, x) or (x, y)"""
|
||
ar, ac = a
|
||
br, bc = b
|
||
return abs(ar - br) + abs(ac - bc)
|
||
|
||
|
||
def grid(d, o="#"):
|
||
"""Transform a string into an iterable matrix. Returns the matrix, row count and col count"""
|
||
m = [tuple(r) for r in d.split()]
|
||
return set([(r, c) for c in range(len(m[0])) for r in range(len(m)) if m[r][c] == o])
|
||
|
||
|
||
def matrix(d):
|
||
"""Transform a string into an iterable matrix. Returns the matrix, row count and col count"""
|
||
m = [tuple(r) for r in d.split()]
|
||
return m, len(m), len(m[0])
|
||
|
||
|
||
def mdbg(m):
|
||
"""Print-debug a matrix"""
|
||
for r in m:
|
||
print("".join(r))
|
||
|
||
|
||
def vdbg(seen, mask=("#", "."), M=None):
|
||
"""Print-debug visited positions of a matrix"""
|
||
t = inf
|
||
l = inf
|
||
b = 0
|
||
r = 0
|
||
for y, x in seen:
|
||
t = min(t, y)
|
||
r = max(r, x)
|
||
b = max(b, y)
|
||
l = min(l, x)
|
||
H = b - t + 1
|
||
W = r - l + 1
|
||
osr = t
|
||
osc = l
|
||
C, Z = mask
|
||
def _m(r, c):
|
||
return M[r][c] if M else Z
|
||
for r in range(H):
|
||
print("".join([C if (r + osr, c + osc) in seen else _m(r, c) for c in range(W)]))
|
||
|
||
|
||
def vvdbg(seen, h, w):
|
||
"""Print-debug visited positions of a matrix, with values"""
|
||
for r in range(h):
|
||
print("".join([seen[(r, c)] if (r, c) in seen else "." for c in range(w)]))
|
||
|
||
|
||
def cw(y, x):
|
||
"""Flip a (y, x) direction counterwise: U->R, R->D, D->L, L->U.
|
||
|
||
>>> cw(-1, 0)
|
||
(0, 1)
|
||
>>> cw(0, 1)
|
||
(1, 0)
|
||
>>> cw(1, 0)
|
||
(0, -1)
|
||
>>> cw(0, -1)
|
||
(-1, 0)
|
||
"""
|
||
return (x, y) if y == 0 else (x, -y)
|
||
|
||
|
||
def ccw(y, x):
|
||
"""Flip a (y, x) direction counterwise: U->L, L->D, D->R, R->U.
|
||
|
||
>>> ccw(-1, 0)
|
||
(0, -1)
|
||
>>> ccw(0, -1)
|
||
(1, 0)
|
||
>>> ccw(1, 0)
|
||
(0, 1)
|
||
>>> ccw(0, 1)
|
||
(-1, 0)
|
||
"""
|
||
return (x, y) if x == 0 else (-x, y)
|
||
|
||
|
||
def bfs(S, E=None):
|
||
"""BFS algorithm, equal weighted nodes"""
|
||
seen = set()
|
||
q = [(S, 0)]
|
||
g = {} # graph, required to be provided at some point
|
||
while q:
|
||
m, w = q.pop(0)
|
||
if m in seen:
|
||
continue
|
||
seen.add(m)
|
||
# investigate here
|
||
for s in g[m]:
|
||
q.append((s, w + 1))
|
||
# return insights
|
||
|
||
|
||
def mhd_search(r, c, R=20):
|
||
"""returns all coords that are within R manhattan distance from (r,c)"""
|
||
p = set()
|
||
for d in range(1, R + 1):
|
||
p.add((r, c + d))
|
||
p.add((r, c - d))
|
||
p.add((r + d, c))
|
||
p.add((r - d, c))
|
||
for dd in range(d):
|
||
p.add((r - dd, c - d + dd))
|
||
p.add((r + dd, c - d + dd))
|
||
p.add((r - dd, c - dd + d))
|
||
p.add((r + dd, c - dd + d))
|
||
return p
|
||
|
||
|
||
def dijkstras(grid, start, target):
|
||
"""
|
||
1. Create an array that holds the distance of each vertex from the starting
|
||
vertex. Initially, set this distance to infinity for all vertices except
|
||
the starting vertex which should be set to 0.
|
||
2. Create a priority queue (heap) and insert the starting vertex with its
|
||
distance of 0.
|
||
3. While there are still vertices left in the priority queue, select the vertex
|
||
with the smallest recorded distance from the starting vertex and visit its
|
||
neighboring vertices.
|
||
4. For each neighboring vertex, check if it is visited already or not. If it
|
||
isn’t visited yet, calculate its tentative distance by adding its weight
|
||
to the smallest distance found so far for its parent/previous node
|
||
(starting vertex in case of first-level vertices).
|
||
5. If this tentative distance is smaller than previously recorded value
|
||
(if any), update it in our ‘distances’ array.
|
||
6. Finally, add this visited vertex with its updated distance to our priority
|
||
queue and repeat step-3 until we have reached our destination or exhausted
|
||
all nodes.
|
||
"""
|
||
import heapq
|
||
|
||
target = max(grid)
|
||
seen = set()
|
||
queue = [(start, 0)]
|
||
while queue:
|
||
cost, pos, direction, steps = heapq.heappop(queue)
|
||
y, x = pos
|
||
dy, dx = direction
|
||
|
||
if pos == target:
|
||
return cost
|
||
|
||
if ((pos, "and stuff")) in seen:
|
||
continue
|
||
|
||
seen.add((pos, "and stuff"))
|
||
|
||
neighbors = []
|
||
for n in neighbors:
|
||
heapq.heappush(queue, ("stuffs"))
|
||
|
||
return -1
|
||
|
||
|
||
def bk(graph, p, r=set(), x=set()):
|
||
"""Bron-Kerbosch algoritm, no pivot: https://en.wikipedia.org/wiki/Bron%E2%80%93Kerbosch_algorithm"""
|
||
if not p and not x:
|
||
yield r
|
||
while p:
|
||
v = p.pop()
|
||
yield from bk(graph, p & set(graph[v]), r | {v}, x & graph[v])
|
||
x.add(v)
|