This problem involves a virus that has a particular movement pattern through a grid. The grid is composed of infected and non-infected tiles. The virus's behavior is:
We're asked how many times the virus changes a cell to being infected over 10,000 iterations.
from math import ceil
import numpy as np
# K we gotta do some work to get these into nice arrays
grid = open('/Users/Sven/py_files/aoc_2017/d22_input.txt').readlines()
grid = [cell.replace('\n', '') for cell in grid]
grid[:5]
The virus starts in the very middle of the grid so here's it's position as though this were a matrix.
start_row = ceil(len(grid)/2) - 1
start_col = ceil(len(grid[1])/2) - 1
start_loc = (start_row, start_col)
print(start_loc)
Okay so because this is an infinite grid, I think we're going to be better off not trying to make a grid. Instead we can just keep track of 1x2 np.array
s and a dictionary. We'll add to this dictionary when needed.
Let's start by getting the dictionary set up. We know this is a 25x25 grid to start with so:
flattened_land = [val for row in grid for val in row]
# I suddenly understand the nested list comprehension.
# for some reason seeing it this way:
# [val (for row in grid: for val in row)]
# makes it a lot clearer to me why it's phrased this way
# I think -1 and 1 will be nicer than # and .
flattened_land = [-1 if x == '#' else 1 for x in flattened_land]
print(flattened_land[:5])
# now we make the associated tuples.
grid_size = 25
grid_locs = [(row, col) for row in range(grid_size) for col in range(grid_size)]
print(grid_locs[:5])
# ez
location_dict = dict(zip(grid_locs, flattened_land))
location_dict[(0,0)]
Okay that seems like an easy way to record this. Now we need to establish the directions. I guess we can use 0-3 as NESW:
start_dir = 0
def turn(direction, left = True):
return((direction + (-1) ** left) % 4)
print(turn(start_dir))
print(turn(start_dir, False))
And a function to move:
move_dirs = dict(zip([0, 1, 2, 3], [(-1, 0), (0, 1), (1, 0), (0, -1)]))
def move(location, direction):
new_loc = np.array(location) + np.array(move_dirs[direction])
return(tuple(new_loc))
move(start_loc, 0)
Okay I think we're good to go here...
curr_loc = start_loc
curr_dir = start_dir
counter = 0
for i in range(10000):
# Find the value we've got:
if curr_loc in location_dict.keys():
curr_cell = location_dict[curr_loc]
else:
curr_cell = 1
# if infected, turn left
if curr_cell == -1:
curr_dir = turn(curr_dir, left = False)
else:
curr_dir = turn(curr_dir, left = True)
counter += 1
# update the cell:
location_dict[curr_loc] = -curr_cell
# move
curr_loc = move(curr_loc, curr_dir)
counter
The second part of this is only a slight modification from the original. We now have 4 states that each cell can be in and the virus cycles through them. It also has different turning instructions based on those four states. I think this shouldn't be too hard because we just have to modify the turns and states.
# let's copy this setup stuff again and this time use the values 0-3 for the states clean, weakened, infected, flagged
flattened_land = [val for row in grid for val in row]
flattened_land = [2 if x == '#' else 0 for x in flattened_land]
# now we make the associated tuples.
grid_size = 25
grid_locs = [(row, col) for row in range(grid_size) for col in range(grid_size)]
location_dict = dict(zip(grid_locs, flattened_land))
Now let's make a modification on our turn function:
def turn2(direction, cell):
if cell == 0:
direction -= 1
elif cell == 2:
direction += 1
elif cell == 3:
direction += 2
return(direction % 4)
Next loop:
curr_loc = start_loc
curr_dir = start_dir
counter = 0
for i in range(10000000):
# Find the value we've got:
if curr_loc in location_dict.keys():
curr_cell = location_dict[curr_loc]
else:
# set this as zero since that's cleaned
curr_cell = 0
# Turn the appropriate direction
curr_dir = turn2(curr_dir, curr_cell)
# update the cell:
curr_cell = (curr_cell + 1) % 4
location_dict[curr_loc] = curr_cell
# update counter
if curr_cell == 2:
counter += 1
# move
curr_loc = move(curr_loc, curr_dir)
counter