Day 3

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:

In [1]:
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:

In [2]:
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

In [3]:
vertical_d = leftovers + 1 - (square_width // 2 + 1)
horizontal_d = square_width // 2
d = vertical_d + horizontal_d
d
Out[3]:
326

That's a bit of a cheap shot.

Part 2

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:

In [4]:
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

In [5]:
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

In [6]:
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:

In [7]:
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)    
363010