Day 5
The input looks like:
[D]
[N] [C]
[Z] [M] [P]
1 2 3
move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2
The problem is moving the [X]
crates in column-based stacks according to the instructions below. A problem of stacks, basically.
First, we divide the input in two big lines: crates and instructions. Luckily, we can just divide at the empty line:
with open("ex_input.txt") as file:
input = file.readlines()
input = [line.strip('\n') for line in input]
# separates by empty line in two lists: crates, and move instructions
crates_instructions = [input[:input.index('')], input[input.index('')+1:]]
Getting the “columns” right for the crates input required a bit of tinkering, but ultimately it was simple. Basically I wanted this:
[['[]' '[D]' '[]']
['[N]' '[C]' '[]']
['[Z]' '[M]' '[P]']]
so that I could get this kind of input, where I could just use python’s pop()
to follow the instructions:
[['[Z]', '[N]'],
['[M]', '[C]', '[D]',
['[P]']]
In order to do that I used the following code:
# Create empty crates ("[]")
crates = [re.sub(" ", " [] ", row).strip() for row in crates]
# split by spaces, remove the last line with the numbers as I don't really need it
crates = [crate.split() for crate in crates][:-1]
# to array, for convenience:
crate_array = np.array(crates)
# transpose coordinates, reverse items in each row, end with a list of lists of different lengths
crate_array = crate_array.T
crate_array = np.flip(crate_array, axis= 1)
crates = crate_array.tolist()
# remove empty crates
# (I only needed them to flip the array comfortably)
for list_crates in crates:
list_crates[:] = [item for item in list_crates if item != "[]"]
Then I just need to follow instructions, remove the number of items required and append it to the required stack:
instructions = crates_instructions[1]
for instruction in instructions:
# takes instruction lines and picks relevant numbers
inst_list = instruction.split(" ")
ncrates = int(inst_list[1])
origin = int(inst_list[3])-1 # -1 because it'll be treated as an index
destiny = int(inst_list[5])-1 # idem
# for each required item to move
for i in range(1,ncrates+1):
# it pops it from the required stack
moving_crate = crates[origin].pop()
# and appends it elsewhere:
crates[destiny].append(moving_crate)
# the final output is just joining all the last items of each list in a string:
print(''.join([item[-1].strip('[]') for item in crates]))
Verbose, but not really hard once you figure out the input formatting.
Part two of the puzzle requires the same output, but keeping the order of the removed stack.
I modified the instructions block slightly to adjust to this, working with list slices rather than pop()
:
for instruction in instructions:
#same as above:
inst_list = instruction.split(" ")
ncrates = int(inst_list[1])
origin = int(inst_list[3])-1
destiny = int(inst_list[5])-1
moving_crates = crates[origin][-ncrates:]
crates[origin] = crates[origin][:-ncrates]
for single_crate in moving_crates:
crates[destiny].append(single_crate)
Aaand that’s it!