Two-Factor Authentication
Tags: adventofcode, algorithms, javascript, programming
Published: 2022-08-28 15:05:48

## [Advent of Code 2016 Day 8](https://adventofcode.com/2016/day/8)

## [Try the simulator using your puzzle input!](https://aoctwofactorauthentication.rmion.repl.co/)
![Message being revealed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9d6xlgpl04rcfp2icwm8.gif)

## 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
- [2021 Day 13: Transparent Origami](https://adventofcode.com/2021/day/13)
- [2021 Day 8: Seven Segment Search](https://adventofcode.com/2021/day/8)
- [2019 Day 11: Space Police](https://adventofcode.com/2019/day/11)
- [2018 Day 10: The Stars Align](https://adventofcode.com/2018/day/10)

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:
```js
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:
```js
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:
```js
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:
```js
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`:
```js
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:
```js
screen.reduce(
  (sum, line) => sum += line.reduce(
    (sum, character) => sum += character == '#' ? 1 : 0
  , 0)
, 0)
```

It counted 128 `lights on`.

That was the correct answer!

## 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`:
```js
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!
![Animating the message reveal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fq4qpumu3j7xz500gpfg.gif)

## 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!