Advent of Code, Day 5

Day 5 of Advent of Code is here! Check out Day 1 for what this is all about. See all of my solutions here.

Did you join my leaderboard? I invite you to join my board, and we can see who can win it ;) Go to “Leaderboard” in the top nav and enter 1030369-e174b794 to join my board.

Get your leaderboard in Slack! See my other post, written by a friend of mine, on how to get your leaderboard into your Slack channel with a fun lambda and slash command!

I have also loaded up the pure code from this and my other days on github, you can follow along there too: pretty pages or the repo.

Spoilers ahead!

I highly encourage you to get through the day’s challenge on your own. I would love to hear how you did! Did you find a better approach than I did? Do tell!

Day 5: Binary Boarding

Part I

I lost my boarding pass!

“You write a quick program to use your phone’s camera to scan all of the nearby boarding passes (your puzzle input); perhaps you can find your seat through process of elimination. Instead of zones or groups, this airline uses binary space partitioning to seat people. A seat might be specified like FBFBBFFRLR, where F means “front”, B means “back”, L means “left”, and R means “right”.” ref

The data looks like this

As always, we need to get all of the data, I’ve consolidated my typical two liner into one line:

var seats = document.getElementsByTagName('pre')[0].innerText.split('\n')

Side note on chaining properties and methods

A lot of what we code can be consolidated with chaining. Basically, chaining takes the output of the method or property it’s attached to and then calls the next method, and so on. The above line could look like this if we didn’t chain at all:

var seatsDataElements = document.getElementsByTagName('pre')
var seatsDataElement = seatsDataElements[0]
var seatsDataString = seatsDataElement.innerText
var seats = seatsDataString.split('\n')

Those four lines can be collapsed into the 1 line I posted above. Although chaining is really nice because it does simplify our code some (yay less code) it can become difficult to read (boo). Sometimes, we can chain too much, and may lose sight of what each method is doing. If a developer didn’t know what [0] was about, obviously it’s an array, but for the sake of the example, chaining the data selector might confuse a developer, it might get overlooked, and cause bugs down the line. However, in this example, it really is straight forward so a one-liner is easy enough.

Coding shouldn’t be about less code; it should be about good code. Sometimes we need to write more code for it to be readable and understandable for the next developer.

Me

Ok, back to the challenge

We got our seats in the variable seats, so let’s loop!

var allSeatIds = []
seats.forEach(s => allSeatIds.push({ code: s, seatId: calcSeatId(s) }))

As I loop through seats, we’re going to push the seat with the calculated seat id in a new array, called allSeatIds.

I created a new method to calculate the seat id.

But first, a mental model

I enjoy making mental models about what I’m working on. It helps a ton to be able to picture something in my head. Sometimes, it helps to actually draw it out to visualize it IRL, especially when we’re working with loops, 0 based indexes, and counters.

Picture an airplane floor plan:

As you can see, the Front half of the cabin are lower numbers, the Back half are higher numbers. Important to keep that in mind. Also, Left is lower, Right is higher. If you can draw this out, as you’re coding, you can grab a pencil (marker, crayon, etc) and draw what the code is doing on your mental model, and visualize the code in a very unique way.

Back to the code

var calcSeatId = (seat) => {
  var minRow = 0
  var maxRow = 127
  var minCol = 0
  var maxCol = 7;

  [...seat].forEach(s => {
      if(s === "F" || s === "B"){
          var diffRow = maxRow - minRow
          var halfRow = Math.ceil(diffRow/2)-1

          if(s === "F") {
              maxRow = minRow + halfRow
          }
          if(s === "B") {
              minRow = maxRow - halfRow
          }
      }
      if(s === "R" || s === "L"){
          var diffCol = maxCol - minCol
          var halfCol = Math.ceil(diffCol/2)-1

          if(s === "L") {
              maxCol = minCol+ halfCol
          }
          if(s === "R") {
              minCol = maxCol - halfCol
          }
      }
  })

  return minRow * 8 + minCol
}

Calculating a seat id goes like:

  • We set some variables, like the min and max amount of rows of seats and seats per row (I call col for column. Those seats are very grid-like, rows and columns)
  • Now we loop through each letter in the seat code. Doing [...seat] turns our string into an array, it splits it by character, so ABCDEFG becomes ['A','B','C','D','E','F','G']
  • We then handle the pairs F and B, and R and L uniquely
  • This might get a little tricky but the mental model should help there
    • var diffRow = maxRow - minRow Get the number of rows we’re going to split in half
    • var halfRow = Math.ceil(diffRow/2)-1 – Split the difference to get the half value
    • if(s === "F") { – If it’s the front half, it’s the lower half of numbers, so we set the new maximum to the minimum plus the half row
    • if(s === "B") { – If it’s the back half, it’s the upper half of numbers, so we set the new minimum to the max minus the half row
    • Rinse and repeat for the columns
    • if you think through the code, looking at the airplane, it makes sense, I swear

And finally, let’s grab the biggest number:

console.log('highest seat id', allSeatIds.sort((a,b) => a.seatId < b.seatId ? 1 : -1)[0])

I do a little sort() to get the biggest number first, then grab the first item in the array

Part II

Time to board! But I still don’t have my boarding pass.

“It’s a completely full flight, so your seat should be the only missing boarding pass in your list. However, there’s a catch: some of the seats at the very front and back of the plane don’t exist on this aircraft, so they’ll be missing from your list as well. Your seat wasn’t at the very front or back, though; the seats with IDs +1 and -1 from yours will be in your list.” ref

This may have been one of the easiest Part II so far! Assuming you’ve run the above code, we can then add the following:

allSeatIds.sort((a,b) => a.seatId > b.seatId ? 1 : -1).forEach((seat, index) => {
    if(seat.seatId > 0) {
        if(seat.seatId + 1 !== allSeatIds[index+1].seatId){
            console.warn('missing seat',seat.seatId + 1)
        }
    }
})
  • This loops through all the seats, sorted, and checks to see if the current seat id equals the next one when we add 1 to it. Fortunately, there’s only 1 seat missing so that my seat!

How did you do?

How did you find the answer on your own? How did you do it? I’d love to hear how you did! Please comment below!

Leave a Reply

Powered by WordPress.com.

Up ↑

%d bloggers like this: