2020-12-03 17:02:39 +01:00
|
|
|
"""Generic 2D grid with a few helpers."""
|
|
|
|
|
|
|
|
from collections import defaultdict
|
|
|
|
|
|
|
|
|
2020-12-11 19:24:09 +01:00
|
|
|
def near(p):
|
|
|
|
"""Return a tuple of neighbor positions (up, left, down, right)."""
|
|
|
|
return (
|
|
|
|
(p[0] , p[1] - 1),
|
|
|
|
(p[0] + 1, p[1] ),
|
|
|
|
(p[0] , p[1] + 1),
|
|
|
|
(p[0] - 1, p[1] ),
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def near8(p):
|
|
|
|
"""Return a tuple of neighbor positions, including diagonals."""
|
|
|
|
return (
|
|
|
|
(p[0] - 1, p[1] - 1),
|
|
|
|
(p[0] , p[1] - 1),
|
|
|
|
(p[0] + 1, p[1] - 1),
|
|
|
|
(p[0] - 1, p[1] ),
|
|
|
|
(p[0] + 1, p[1] ),
|
|
|
|
(p[0] - 1, p[1] + 1),
|
|
|
|
(p[0] , p[1] + 1),
|
|
|
|
(p[0] + 1, p[1] + 1),
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2020-12-03 17:02:39 +01:00
|
|
|
class Grid:
|
|
|
|
|
|
|
|
def __init__(self, value_factory=int, lines=None):
|
|
|
|
self.g = defaultdict(lambda: defaultdict(value_factory))
|
|
|
|
if lines:
|
|
|
|
self.load(lines)
|
|
|
|
|
2020-12-11 19:24:09 +01:00
|
|
|
def hasv(self, x, y):
|
|
|
|
return y in self.g and x in self.g[y]
|
|
|
|
|
2020-12-03 17:02:39 +01:00
|
|
|
def getv(self, x, y):
|
|
|
|
return self.g[y][x]
|
|
|
|
|
|
|
|
def setv(self, x, y, value):
|
|
|
|
self.g[y][x] = value
|
|
|
|
|
|
|
|
def load(self, lines, f=lambda v: v):
|
|
|
|
for y, line in enumerate(lines):
|
|
|
|
for x, c in enumerate(line.rstrip()):
|
|
|
|
self.g[y][x] = f(c)
|
|
|
|
|
|
|
|
def values_gen(self):
|
|
|
|
for y, row in self.g.items():
|
|
|
|
for x, v in row.items():
|
|
|
|
yield (x, y, v)
|
|
|
|
|
2020-12-11 19:24:09 +01:00
|
|
|
def near_objects(self, p, near_f=near):
|
|
|
|
return {
|
|
|
|
q: self.getv(q[0], q[1])
|
|
|
|
for q in near_f(p)
|
|
|
|
if self.hasv(q[0], q[1]) # do not create entries.
|
|
|
|
}
|
2020-12-03 17:02:39 +01:00
|
|
|
|
|
|
|
def dumb_print(self, f=lambda v: v):
|
|
|
|
for row in self.g.values():
|
|
|
|
for x in row.values():
|
|
|
|
print(f(x), end="")
|
|
|
|
print()
|
|
|
|
|
|
|
|
def print_near(self, p, view_size=2):
|
|
|
|
for dy in range(-view_size, view_size + 1):
|
|
|
|
print("".join([
|
|
|
|
self.g[p[1] + dy][p[0] + dx]
|
|
|
|
for dx in range(-view_size, view_size + 1)
|
|
|
|
]))
|