Robert Mion

Posted on

# Supply Stacks

## Part 1

1. Save for later
2. Manually re-creating the stack of crates
3. Programming the crane
4. Loop and adjust everything by 1
5. My algorithm in JavaScript

### Save for later

• I intend to build a simulator for today's puzzle
• To do that, I'll need to programmatically build the stack of crates
• I'm excited to build that algorithm
• But I'm more excited to attempt solving the puzzle for my own input

### Manually re-creating the stack of crates

To programmatically represent the example input:

``````    [D]
[N] [C]
[Z] [M] [P]
1   2   3
``````

I will use a nested list data structure:

``````[
['Z', 'N'],
['M', 'C', 'D'],
['P']
]
``````

### Programming the crane

After the crates are rearranged, the desired crates will be at the top of each stack.

There are four ways to adjust the amount of items in a list at either end:

• Insert at the end
• Insert at the beginning
• Remove from the end
• Remove from the beginning

It seems like this puzzle calls for these two:

• Remove from the end
• Insert at the end

In JavaScript, those are represented as:

• `pop()`
• `push()`

A command like `move 3` would perform the following operations:

``````pop()
push()
pop()
push()
pop()
push()
``````

### Loop and adjust everything by 1

Each command references stacks using 1-based indices:

``````move 3 from 1 to 3
``````

In pseudocode, I need to:

``````Do three times
pop() from stack 0
push() to stack 2
``````

### My algorithm in JavaScript

``````// stacks = [ [...], [...], [...] ]

input
.split('\n\n')[1]
.split('\n')
.forEach(cmd => {
let [times, from, to] = [
...cmd.matchAll(/\d+/g)
].map(match => +match[0])
for (let i = times; i > 0; i--) {
let crate = stacks[from - 1].pop()
stacks[to - 1].push(crate)
}
})

return stacks.map(s => s[s.length - 1]).join('')
``````

## Part 2

1. Method swaps
2. My algorithm in JavaScript

### Method swaps

• `pop()` for `splice()`
• `push()` for `concat()`

#### `pop()` for `splice()`

• `pop()` removes the last element
• `splice()` removes several elements

#### `push()` for `concat()`

• `push()` adds one element
• `concat()` combines multiple arrays into a single array

Using this example again:

``````move 3 from 1 to 3
``````

In pseudocode, I need to:

``````splice(3 from the end) from stack 0
concat(stack 2 with 3 from the end)
``````

### My algorithm in JavaScript

``````// stacks = [ [...], [...], [...] ]

input
.split('\n\n')[1]
.split('\n')
.forEach(cmd => {
let [times, from, to] = [
...cmd.matchAll(/\d+/g)
].map(match => +match[0])
let crates = stacks[from - 1].splice(-times)
stacks[to - 1] = stacks[to - 1].concat(crates)
})

return stacks.map(s => s[s.length - 1]).join('')
``````

## Saved for later

I want to programmatically build the stack of crates.

1. Analyzing the input
2. My algorithm in pseudocode
3. My algorithm in JavaScript

### Analyzing the input

``````    [D]
[N] [C]
[Z] [M] [P]
1   2   3
``````
• The letters appear at indices: 1, 5, 9
• The rows at the bottom are the crates earliest in the stack
• The first row is useless for my purposes

### My algorithm in pseudocode

``````Split the multi-line string into an array of strings
Reverse the array to put rows in their insertion order
Remove the first row containing the column numbers
For each row
Start at the second character (index 1)
Skip 4 characters each iteration
Go until moving passed the end of the string
If there's no nested array corresponding to the current column
Create an empty one
If the current character is anything other than a string with a single space
Add the character to the appropriate nested array
``````

### My algorithm in JavaScript

``````let stacks = []
input
.split('\n\n')[0]
.split('\n')
.reverse()
.slice(1)
.forEach(line => {
for (let i = 1; i < line.length; i += 4) {
if (typeof stacks[(i - 1) / 4] !== 'object') {
stacks.push([])
}
if (line[i] !== ' ') {
stacks[(i - 1) / 4].push(line[i])
}
}
})
``````

## Building the simulator

Now that I have:

• Solved Part 1
• Solved Part 2
• Programmatically built the stack of crates

It's time to build a simulator of the CrateMover 9000 and 9001!

...

How it went:

• Pretty smoothly overall
• I got stuck wondering why it wasn't working
• Then I realized I forgot to replace my loops with performing a single command each time!

The fun bit of code is in rendering the crates after each command:

``````stacks.map(
row => row.map(
el => `[\${el}]`
).join('')
).join('\n')
``````

## I did it!!

I was initially concerned that this would be a `shortest path` puzzle, given the rearranging of items.

Thankfully, since it is only Day 5, it was a different challenge type: list manipulation.

Still a fun one that gave me more practice!