So this time we're confronted with a spiral of numbers and we're asked to compute the Manhattan distance to the center of the grid from 361527 where 1 is the center.
I don't think we actually need to do any real programming here but I suspect that if we recreate this grid it will help for part 2 let's just try and be tricky with math to figure this one out. What's the biggest square less than our target? This will overshoot by one:
import pandas as pd
import numpy as np
target = 361527
x = 1
while x ** 2 < target:
x += 2
square_width = x - 2
So we're on the 601st ring around the center. Now it starts one position up from the bottom right corner. We have this much leftover to trace of the total:
leftovers = target - square_width ** 2
Now this is less than the distance from the top so the vertical distance from the bottom right corner of this ring is 1 + leftovers
vertical_d = leftovers + 1 - (square_width // 2 + 1)
horizontal_d = square_width // 2
d = vertical_d + horizontal_d
d
That's a bit of a cheap shot.
Okay part two looks quite tricky. We are asked to create a grid in a way that the values are summed from all the adjacent values that have been filled in yet... I'd rather not program this in a way that is too specific to the puzzle input but not quite sure how to make this work otherwise...
I highly doubt this will even take one quarter the number of rows of the target. Let's use zero to denote an unfilled row:
mat_size = target // 100
zero_vec = []
for i in range(mat_size):
zero_vec.append(0)
matr = []
for i in range(mat_size):
matr.append(zero_vec)
matr = np.array(matr)
Function to move the x and y
def move_dir(direction):
global x
global y
if(direction == 0):
x += 1
elif(direction == 1):
y -= 1
elif(direction == 2):
x -= 1
else:
y += 1
Now let's write a function to fill in the values in the way they're supposed to for the puzzle
def cell_sum(y, x):
total = 0
for row in list(range(-1, 2)):
total += sum(matr[y + row][(x - 1):(x + 2)])
return(total)
# Set initial x, y, and matrix value
x = y = mat_size // 2
matr[y, x] = 1
# counter will record which step we're on
counter = 1
#dist will record how many steps we need to move on that side
dist = 1
# flipper will record whether we're on the first or second go of that distance
flipper = 0
# direction 0, 1, 2, 3 --> right, up, left, down
direction = 0
# and if we've met the goal:
met_goal = 0
Run it:
while counter < (mat_size - 2) ** 2:
# now loop through the particular side we're filling in:
for j in range(dist):
# move
move_dir(direction)
# fill next
counter += 1
new_val = cell_sum(y, x)
if new_val > target:
met_goal = 1
break
matr[y, x] = new_val
# change direction:
direction = (direction + 1) % 4
# increment the flipper and change dist if needed
flipper += 1
if flipper % 2 == 0:
dist += 1
if met_goal == 1:
break
print(new_val)