So we've received a set of instructions that tell us which container to change, by how much, and under what condition. This seems like it would be a good chance to use the eval()
funciton in R as you could just evaluate whether the statement is true or not and then procede with the instructions. As for python.... we'll see what we come up with.
# load the puzzle input, It seems like I want to put everything into a DataFrame but I guess that's how my work goes
import pandas as pd
import numpy as np
initial = open('/Users/Sven/py_files/aoc_2017/d8_input.txt')
initial = initial.readlines()
initial[:5]
# I guess we'll do something very similar to last time to format the input
def fmt_block(txt):
txt = txt.replace('\n', '')
# split on spaces and then take pieces
splits = txt.split()
name = splits[0]
direction = splits[1]
ammt = int(splits[2])
# now get the condition
splits2 = txt.split('if ')[1].split()
cond = splits2[1] + splits2[2]
cond_var = splits2[0]
# return the data frame:
dat = pd.DataFrame({'name' : [name], 'direction' : [direction], 'ammt' : [ammt], 'cond_var' : [cond_var], 'cond' : [cond]})
return(dat)
fmt_block(initial[0])
Again, loop through the list of strings, turn into data frames, and bind together
frames = [fmt_block(x) for x in initial]
instructions = pd.concat(frames).reset_index(drop = True)
So this increasing decreasing thing is kinda silly, let's just turn them all into increases
def flipper(x):
if x == 'inc':
return(1)
else:
return(-1)
instructions['flipper'] = [flipper(x) for x in instructions.direction]
instructions['ammt2'] = instructions.flipper*instructions.ammt
display(instructions[:5])
I think it will be less cumbersome to keep track of the values as a dictionary, rather than additional columns within the instructions. I guess I'll not assume that the unique values in name are the only ones that could appear in the conditions so let's concatenate these.
labels = instructions.name.unique().tolist()
labels2 = instructions.cond_var.unique().tolist()
labels.sort()
labels2.sort()
print(labels == labels2)
# Okay I guess I didn't need to do that but whatever
zeroes = [0 for i in range(len(labels))]
containers = {key : value for (key, value) in zip(labels, zeroes)}
containers
Okay that was easier than expected. Now comes the hard part of figuring out how to evaluate these character strings within the data set. We'll have to do some kind of for loop downward through the rows because the validity of the statements will depend on the current state. I guess we'll just go back to our trick of making a function that works for a single case and iterate. This time I'm going to try and not work with global variables within the function though as it's not kosher.
def eval_cond(dictionary, i):
# first get information from the instructions
inst_cond = instructions.cond.iloc[i]
inst_cond_var = instructions.cond_var.iloc[i]
inst_name = instructions.name.iloc[i]
inst_ammt = instructions.ammt2.iloc[i]
# Now get the value from the dictionary we just received
dict_cond_var = dictionary[inst_cond_var]
# evaluate the condition and modify dict if true
check = str(dict_cond_var) + inst_cond
if eval(check):
dictionary[inst_name] += inst_ammt
return(dictionary)
Now we jsut run this through the length of the instructions
containers_copy = containers.copy()
for i in range(len(instructions)):
containers_copy = eval_cond(containers_copy, i)
max(list(containers_copy.values()))
We're given a slight wrinkle on the problem where we want to know the maximum value ever reached during the process. I think this should be pretty simple by just computing the max value after each function call.
m = 0
containers_copy2 = containers.copy()
for i in range(len(instructions)):
containers_copy2 = eval_cond(containers_copy2, i)
new_max = max(list(containers_copy2.values()))
m = max([m, new_max])
m