94 lines
1.9 KiB
Python
94 lines
1.9 KiB
Python
puzzle_input = 0 # TODO
|
|
|
|
def cardinals(distance):
|
|
d = 0
|
|
distance[1] = d
|
|
yield 1
|
|
|
|
d += 1
|
|
distance[2] = d
|
|
yield 2
|
|
|
|
while True:
|
|
v = (2*d)**2 - (d-1)
|
|
distance[v] = d
|
|
yield v
|
|
|
|
v = (2*d)**2 + (d+1)
|
|
distance[v] = d
|
|
yield v
|
|
|
|
v = (2*d + 1)**2 - d
|
|
distance[v] = d
|
|
yield v
|
|
|
|
v = (2*d + 1)**2 + (d+1)
|
|
distance[v] = d + 1
|
|
yield v
|
|
|
|
d += 1
|
|
|
|
def closest_cardinals(n, distance):
|
|
cs = cardinals(distance)
|
|
lo = next(cs)
|
|
hi = next(cs)
|
|
while not lo <= n <= hi:
|
|
lo, hi = hi, next(cs)
|
|
return lo, hi
|
|
|
|
def manhattan_to_center(n):
|
|
distance = {}
|
|
best = sorted(closest_cardinals(n, distance), key=lambda x: abs(n - x))[0]
|
|
return distance[best] + abs(n - best)
|
|
|
|
for inp, expected in [
|
|
(1, 0),
|
|
(2, 1),
|
|
(12, 3),
|
|
(23, 2),
|
|
(1024, 31),
|
|
]:
|
|
actual = manhattan_to_center(inp)
|
|
assert actual == expected, f'Expected {expected} got {actual}'
|
|
|
|
print(manhattan_to_center(puzzle_input))
|
|
|
|
def walking_order():
|
|
start = (0, 0)
|
|
R, D, L, U = [(+1, 0), (0, -1), (-1, 0), (0, +1)]
|
|
|
|
yield R
|
|
yield U
|
|
|
|
count = 2
|
|
while True:
|
|
for deltas in [(L, D), (R, U)]:
|
|
for delta in deltas:
|
|
for _ in range(count):
|
|
yield delta
|
|
count += 1
|
|
|
|
def neighbors(cell):
|
|
x, y = cell
|
|
for dx in range(-1, 2):
|
|
for dy in range(-1, 2):
|
|
if dx == dy == 0: continue
|
|
yield (x+dx, y+dy)
|
|
|
|
def sum_neighbors_until(limit):
|
|
grid = {}
|
|
deltas = walking_order()
|
|
|
|
cell = (0, 0)
|
|
grid[cell] = 1
|
|
|
|
while True:
|
|
x, y = cell
|
|
dx, dy = next(deltas)
|
|
cell = (x+dx, y+dy)
|
|
value = sum(grid.get(n, 0) for n in neighbors(cell))
|
|
grid[cell] = value
|
|
if value > limit:
|
|
return value
|
|
|
|
print(sum_neighbors_until(puzzle_input))
|