Robert Mion

Posted on

# Two-Factor Authentication

## Part 1

1. A look back at message-unscrambling puzzles
2. Marquee tool, circular operations, and nested lists
3. Extracting each instruction's important bits
4. Building the skeleton of my `reduce()`
5. Handling rectangle instructions
6. Handling row rotation instructions
7. Handling column rotation instructions
8. Revealing my message - and counting 'on' lights

### A look back at message-unscrambling puzzles

Hmm. I thought there were more.

Anyway:

• I had fun attempting each of those
• I solved both parts of each one
• I'm excited to attempt and solve this one!

### Marquee tool, circular operations, and nested lists

This puzzle combines some familiar and novel concepts:

1. String splitting or regular expressions to determine the instruction type, dimensions or row/column numbers and rotation amounts
2. A marquee tool is represented by the continual selection of a rectangular subset of the grid from the top-left corner
3. Circular operations are enacted by the rotation of values left-to-right wrapping and top-to-bottom wrapping
4. Nested lists are the data structure I've always used to represent a grid of items

1,2 and 4 are simple enough by now.

3 seems simple - at least for row rotations.

But for column rotations, it may require some more complex programming.

### Extracting each instruction's important bits

Example instructions include:

``````rect 14x1
rotate column x=12 by 1
rotate row y=0 by 40
``````

If using string splitting, I can depend on:

• Items of length two to be rectangular selection instructions
• For all other instructions, I can discern column/row from the second phrase

### Building the skeleton of my `reduce()`

I'll process each line using `reduce()`.

That way, I can package the mutating grid and the instructions together.

The starting state of the accumulating grid should be a nested array whose length is 6 and whose nested arrays' lengths are 50...all filled with `.`s.

My control flow therefore looks like:

``````input.reduce((grid, instruction) => {
let parts = instruction.split(' ')
if (parts.length == 2) {
// Rectangle-selection rule
} else if (parts[1] == 'column') {
// Column rotation rule
} else {
// Row rotation rule
}
}, new Array(6).fill(null).map(
el => new Array(50).fill(null).map(el => ' ')
)
)
``````

### Handling rectangle instructions

My algorithm as pseudocode:

``````After splitting the instruction string at each space character into an array
If the there are only two items in the array
Split the second item at the x
Coerce each string into a number
Store as width and height
Update the appropriate cells in the grid
Starting from the top-left corner
Setting each cell's value as #
``````

My algorithm as JavaScript:

``````let parts = instruction.split(' ')
if (parts.length == 2) {
let [width, height] = parts[1].split('x').map(Number)
for (let row = 0; row < height; row++) {
for (let col = 0; col < width; col++) {
a[row][col] = "#"
}
}
}
``````

### Handling row rotation instructions

My algorithm as pseudocode:

``````After splitting the instruction string at each space character into an array
If no other conditions are true
Use a regular expression to match all integers
Store each integer as row and amount
For i from 0 to amount
Remove the last string in the nested array who's index matches row
Add it to the beginning of that array
``````

My algorithm in JavaScript:

``````else {
let [row, amount] = [...c.matchAll(/\d+/g)].map(el => +el[0])
for (let i = 0; i < amount; i++) {
a[row].unshift(a[row].pop())
}
}
``````

### Handling column rotation instructions

My algorithm as pseudocode:

``````After splitting the instruction string at each space character into an array
If the second string is column
Use a regular expression to match all integers
Store each integer as column and amount
For each nested array
Extract the value from the appropriate column
Store an array called band containing all strings from the column in order from top to bottom
For i from 0 to amount
Remove the last string in the array
Add it to the beginning of the array
For each nested array
Update the value in the appropriate column with the corresponding string in the same index as the current nested array
``````

My algorithm in JavaScript:

``````else if (parts[1] == 'column') {
let [column, amount] = [...c.matchAll(/\d+/g)]
.map(el => +el[0])
let band = a.map(row => row[column])
for (let i = 0; i < amount; i++) {
band.unshift(band.pop())
}
for (let row = 0; row < a.length; row++) {
a[row][column] = band[row]
}
}
``````

### Revealing my message - and counting 'on' lights

After storing the latest state of my grid as `screen`:

``````return screen.map(el => el.join('')).join('\n')
``````
• Mutate each nested array into a string of its concatenated characters
• Concatenate each string with a newline character
• Print the resulting multi-line string

Replacing all `.`s with characters to better see the message:

``````####  ##   ##  ###   ##  ###  #  # #   # ##   ##
#    #  # #  # #  # #  # #  # #  # #   ##  # #  #
###  #  # #  # #  # #    #  # ####  # # #  # #  #
#    #  # #### ###  # ## ###  #  #   #  #### #  #
#    #  # #  # # #  #  # #    #  #   #  #  # #  #
####  ##  #  # #  #  ### #    #  #   #  #  #  ##
``````

Using another double-`reduce()` to count the `#` characters:

``````screen.reduce(
(sum, line) => sum += line.reduce(
(sum, character) => sum += character == '#' ? 1 : 0
, 0)
, 0)
``````

It counted 128 `lights on`.

## Part 2

• I already revealed my message!
• And it was the correct answer!

## Building a simulator to show each instruction

I created a new array called `snapshots`:

``````let snapshots = []
``````

In each of the three `for` loops within my three conditions, I inserted a statement that added a stringified snapshot of the grid at each state - after a rectangular area was turned on, and after each single rotation.

By the time my `reduce()` was done running, `snapshots` would be full of strings representing a sort of stop-motion animation.

Indeed, it replays the instructions back as if in real-time!

## I did it!!

• I solved both parts!
• For the first time, I solved Part 2 before Part 1, since I technically saw the message before I counted the amount of lights on!
• I built a simulator that replays the message reveal process like a stop-motion animation!
• I remain undefeated for all message-revealing puzzles!