Watch
1
0
Fork
You've already forked advent-of-code
0
advent-of-code/2017/day03.py

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))