DEV Community

benboorstein
benboorstein

Posted on • Edited on

Advent of Code 2018 Day 2 Part 2 - Solution and Explanation

The challenge itself can be found here once Part 1 has been solved. (My Part 1 article can be found here.)

Please note that:

  • This article focuses on only one solution to a challenge to which there are multiple solutions.
  • The solution in its entirety can be found at the bottom.
  • The solution utilizes two main functions, loops, array methods, and conditionals.

Because the challenge's actual "puzzle input" is very long, we will be working with the challenge's example "puzzle input":

abcde
fghij
klmno
pqrst
fguij
axcye
wvxyz

Before we can get to the main part of the challenge, we have to convert what's just above into JavaScript, so that we can then convert it into an array of strings (each string will be a box ID).

So how do we interpret what the seven lines of text are? In other words, as they are currently, how can we translate (so to speak) them into JavaScript?

Well, we consider it to be one long string with line breaks:

'abcde\nfghij\nklmno\npqrst\nfguij\naxcye\nwvxyz'
Enter fullscreen mode Exit fullscreen mode

How can we be sure this is correct?

Well if we log the string to the console, what we'll see printed is the original input:

abcde
fghij
klmno
pqrst
fguij
axcye
wvxyz

So we know it's correct.

Let's save the string into a variable called examplePuzzleInput.

const examplePuzzleInput = 'abcde\nfghij\nklmno\npqrst\nfguij\naxcye\nwvxyz'
Enter fullscreen mode Exit fullscreen mode

Next, let's...

  1. use the split() method to convert this long string into an array of strings
  2. store our result in a variable called boxIDsArr
const boxIDsArr = examplePuzzleInput.split('\n')
Enter fullscreen mode Exit fullscreen mode

What does boxIDsArr log?

['abcde', 'fghij', 'klmno', 'pqrst', 'fguij', 'axcye', 'wvxyz']

So now we have our array and we can move on to the main part of the challenge.

Our task is to...

  1. find the two box IDs that differ by only one letter, with this differing letter being at the same position in each box ID, e.g., fghij and fguij
  2. remove, from either box ID, the differing letter to get a shorter-by-one box ID with only the letters shared by the two similar box IDs, e.g., fgij

First we'll set up a function called findTheTwoBoxIDs that takes the parameter input. Input is the alias we'll use for the array of box IDs that's shown above.

function findTheTwoBoxIDs(input) {

}
Enter fullscreen mode Exit fullscreen mode

Because we want to access each box ID string in input, we'll loop through input.

function findTheTwoBoxIDs(input) {
    for (let i = 0; i < input.length; i++) {

    }
}
Enter fullscreen mode Exit fullscreen mode

And we'll log each input[i] string to the console so that we can see each string. At this point, doing this isn't very helpful, but, later, once we've logged other steps as well, it will prove to be quite useful in enabling us to see exactly what the function is doing.

function findTheTwoBoxIDs(input) {
    for (let i = 0; i < input.length; i++) {
        console.log(input[i])
    }
}
Enter fullscreen mode Exit fullscreen mode

Let's pause and think about exactly what we need to do next. Because we need to find, out of all the strings, which two strings differ by only one same-positioned letter, and because it's highly unlikely that these two strings will be positioned consecutively in input, what we need to do is compare the first string to every string after it, then compare the second string to every string after it, then compare the third string to every string after it, and so on. So, what we want is a loop inside of our first loop that will start at the string after input[i].

This way, when the first string ('abcde') is input[i], the first string will be compared to every other string ('fghij', 'klmno', 'pqrst', 'fguij', 'axcye', and 'wvxyz'), and the next time through the outer loop, when the second string ('fghij') is input[i], the second string will be compared to every other string ('klmno', 'pqrst', 'fguij', 'axcye', and 'wvxyz'), and so on.

Note that, later, once we have several different console.log()s, we'll be able to see this process playing out.

function findTheTwoBoxIDs(input) {
    for (let i = 0; i < input.length; i++) {
        console.log(input[i])

        for (let j = i + 1; j < input.length; j++) {

        }
    }
}
Enter fullscreen mode Exit fullscreen mode

And we'll log each input[j] string to the console.

function findTheTwoBoxIDs(input) {
    for (let i = 0; i < input.length; i++) {
        console.log(input[i])

        for (let j = i + 1; j < input.length; j++) {
            console.log(input[j])
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Now that we have access to a 'control' string (input[i]) and a 'comparison' string (input[j]), and because we're going to need to access each letter in each string, let's use the split() method to convert each string to an array of letters. We'll store the converted 'control' string in a variable called boxIdLettersArr and the converted 'comparison' string in a variable called nextBoxIdLettersArr.

function findTheTwoBoxIDs(input) {
    for (let i = 0; i < input.length; i++) {
        console.log(input[i])

        for (let j = i + 1; j < input.length; j++) {
            console.log(input[j])

            let boxIdLettersArr = input[i].split('')
            let nextBoxIdLettersArr = input[j].split('')
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

And because we're going to be counting the number of letters in each two box ID comparison that are not the same, let's declare a counter variable called mismatchedLetters and start it at 0.

function findTheTwoBoxIDs(input) {
    for (let i = 0; i < input.length; i++) {
        console.log(input[i])

        for (let j = i + 1; j < input.length; j++) {
            console.log(input[j])

            let boxIdLettersArr = input[i].split('')
            let nextBoxIdLettersArr = input[j].split('')
            let mismatchedLetters = 0
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

In order to compare the letters of boxIdLettersArr and nextBoxIdLettersArr, we need another loop, this one inside our inner loop.

function findTheTwoBoxIDs(input) {
    for (let i = 0; i < input.length; i++) {
        console.log(input[i])

        for (let j = i + 1; j < input.length; j++) {
            console.log(input[j])

            let boxIdLettersArr = input[i].split('')
            let nextBoxIdLettersArr = input[j].split('')
            let mismatchedLetters = 0

            for (let k = 0; k < boxIdLettersArr.length; k++) {

            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

What might be a good way to compare the letters of boxIdLettersArr and nextBoxIdLettersArr?

How about an if statement that checks if each letter of boxIdLettersArr at position k is different than each letter of nextBoxIdLettersArr at position k?

function findTheTwoBoxIDs(input) {
    for (let i = 0; i < input.length; i++) {
        console.log(input[i])

        for (let j = i + 1; j < input.length; j++) {
            console.log(input[j])

            let boxIdLettersArr = input[i].split('')
            let nextBoxIdLettersArr = input[j].split('')
            let mismatchedLetters = 0

            for (let k = 0; k < boxIdLettersArr.length; k++) {
                if (boxIdLettersArr[k] !== nextBoxIdLettersArr[k]) {

                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

And if it is the case that the letter at position k in each letter array is not the same letter, then let's increment our counter variable by 1.

function findTheTwoBoxIDs(input) {
    for (let i = 0; i < input.length; i++) {
        console.log(input[i])

        for (let j = i + 1; j < input.length; j++) {
            console.log(input[j])

            let boxIdLettersArr = input[i].split('')
            let nextBoxIdLettersArr = input[j].split('')
            let mismatchedLetters = 0

            for (let k = 0; k < boxIdLettersArr.length; k++) {
                if (boxIdLettersArr[k] !== nextBoxIdLettersArr[k]) {
                    mismatchedLetters++
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Our next step is to log mismatchedLetters to the console, making sure to log it outside of the loop so that mismatchedLetters has finished incrementing by the time we log it.

function findTheTwoBoxIDs(input) {
    for (let i = 0; i < input.length; i++) {
        console.log(input[i])

        for (let j = i + 1; j < input.length; j++) {
            console.log(input[j])

            let boxIdLettersArr = input[i].split('')
            let nextBoxIdLettersArr = input[j].split('')
            let mismatchedLetters = 0

            for (let k = 0; k < boxIdLettersArr.length; k++) {
                if (boxIdLettersArr[k] !== nextBoxIdLettersArr[k]) {
                    mismatchedLetters++
                }
            }

            console.log(mismatchedLetters)
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

We certainly have not solved the whole challenge yet, but let's take a moment to log our function, as it is now, to the console.

function findTheTwoBoxIDs(input) {
    for (let i = 0; i < input.length; i++) {
        console.log(input[i])

        for (let j = i + 1; j < input.length; j++) {
            console.log(input[j])

            let boxIdLettersArr = input[i].split('')
            let nextBoxIdLettersArr = input[j].split('')
            let mismatchedLetters = 0

            for (let k = 0; k < boxIdLettersArr.length; k++) {
                if (boxIdLettersArr[k] !== nextBoxIdLettersArr[k]) {
                    mismatchedLetters++
                }
            }

            console.log(mismatchedLetters)
        }
    }
}

console.log(findTheTwoBoxIDs(boxIDsArr))
Enter fullscreen mode Exit fullscreen mode

Notice what it is that the function's three console.log()s are enabling us to see.

In the console, we can now see...

  1. the process described farther above of each box ID being compared, one by one, to every box ID below it
  2. the number of mismatched letters for each comparison

Just for fun at this point, try to find the comparison for which mismatchedLetters logs 1!

Just as a quick reminder: If mismatchedLetters logs 1, then we know that the two box IDs whose comparison generated this 1 are the two box IDs we're trying to find. In other words, these are the two box IDs that vary by only one letter at the same position in each box ID.

So how do we put this into our function?

How about an if statement that checks if mismatchedLetters is ever exactly 1?

function findTheTwoBoxIDs(input) {
    for (let i = 0; i < input.length; i++) {
        console.log(input[i])

        for (let j = i + 1; j < input.length; j++) {
            console.log(input[j])

            let boxIdLettersArr = input[i].split('')
            let nextBoxIdLettersArr = input[j].split('')
            let mismatchedLetters = 0

            for (let k = 0; k < boxIdLettersArr.length; k++) {
                if (boxIdLettersArr[k] !== nextBoxIdLettersArr[k]) {
                    mismatchedLetters++
                }
            }

            console.log(mismatchedLetters)

            if (mismatchedLetters === 1) {

            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

And if mismatchedLetters is ever exactly 1, then what? Well first let's see what we get by logging boxIdLettersArr and nextBoxIdLettersArr (and remember that each of these is an array of letters, as opposed to a string).

function findTheTwoBoxIDs(input) {
    for (let i = 0; i < input.length; i++) {
        console.log(input[i])

        for (let j = i + 1; j < input.length; j++) {
            console.log(input[j])

            let boxIdLettersArr = input[i].split('')
            let nextBoxIdLettersArr = input[j].split('')
            let mismatchedLetters = 0

            for (let k = 0; k < boxIdLettersArr.length; k++) {
                if (boxIdLettersArr[k] !== nextBoxIdLettersArr[k]) {
                    mismatchedLetters++
                }
            }

            console.log(mismatchedLetters)

            if (mismatchedLetters === 1) {
                console.log(boxIdLettersArr)
                console.log(nextBoxIdLettersArr)
            }
        }
    }
}

console.log(findTheTwoBoxIDs(boxIDsArr))
Enter fullscreen mode Exit fullscreen mode

We see that what's logged is two box IDs, ['f', 'g', 'h', 'i', 'j'] and ['f', 'g', 'u', 'i', 'j'], respectively.

So have we solved the first item of our two-item task list?

Recall it was: "find the two box IDs that differ by only one letter, with this differing letter being at the same position in each box ID, e.g., fghij and fguij".

So yes we have!

Now for the second task, which was: "remove, from either box ID, the differing letter to get a shorter-by-one box ID with only the letters shared by the two similar box IDs, e.g., fgij".

So how should we do this?

Well we could accomplish this within the findTheTwoBoxIDs function, but instead let's call a new function, just because it's a bit cleaner.

We'll call the new function findSharedLetters, because the purpose of this function is to find the letters that the two box IDs have in common.

So given that, in findSharedLetters, we are going to be working with the two box IDs, and given that working with them is easiest in array form, what arguments do we want to pass to findSharedLetters?

The arrays we just logged: boxIdLettersArr and nextBoxIdLettersArr.

And let's not forget to return findSharedLetters to findTheTwoBoxIDs.

function findTheTwoBoxIDs(input) {
    for (let i = 0; i < input.length; i++) {
        console.log(input[i])

        for (let j = i + 1; j < input.length; j++) {
            console.log(input[j])

            let boxIdLettersArr = input[i].split('')
            let nextBoxIdLettersArr = input[j].split('')
            let mismatchedLetters = 0

            for (let k = 0; k < boxIdLettersArr.length; k++) {
                if (boxIdLettersArr[k] !== nextBoxIdLettersArr[k]) {
                    mismatchedLetters++
                }
            }

            console.log(mismatchedLetters)

            if (mismatchedLetters === 1) {
                console.log(boxIdLettersArr) // ['f', 'g', 'h', 'i', 'j']
                console.log(nextBoxIdLettersArr) // ['f', 'g', 'u', 'i', 'j']

                return findSharedLetters(boxIdLettersArr, nextBoxIdLettersArr)
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Now let's construct findSharedLetters.

And note that the aliases for findSharedLetters's arguments will be IdLettersArr and nextIdLettersArr, respectively.

function findSharedLetters(IdLettersArr, nextIdLettersArr) {

}
Enter fullscreen mode Exit fullscreen mode

In findSharedLetters, we need to compare our two box IDs and, in the end, return a string with only the letters that the box IDs share.

The string that we need to return will be converted from an array of letters. So we can safely say we're going to be creating a new array.

So let's do that first. We'll call our new array sharedLettersArr.

function findSharedLetters(IdLettersArr, nextIdLettersArr) {
    let sharedLettersArr = []
}
Enter fullscreen mode Exit fullscreen mode

What we want is a way to push only the shared letters into sharedLettersArr.

So we'll need access to each box ID letter. Let's pick just one of the box IDs and loop through it.

function findSharedLetters(IdLettersArr, nextIdLettersArr) {
    let sharedLettersArr = []

    for (let i = 0; i < IdLettersArr.length; i++) {

    }
}
Enter fullscreen mode Exit fullscreen mode

Because we want to push only the shared letters of the two box IDs, let's add an if statement that checks if each letter of IdLettersArr at position i is the same as each letter of nextIdLettersArr at position i.

function findSharedLetters(IdLettersArr, nextIdLettersArr) {
    let sharedLettersArr = []

    for (let i = 0; i < IdLettersArr.length; i++) {
        if (IdLettersArr[i] === nextIdLettersArr[i]) {

        }
    }
}
Enter fullscreen mode Exit fullscreen mode

And now let's push the common letters to sharedLettersArr.

function findSharedLetters(IdLettersArr, nextIdLettersArr) {
    let sharedLettersArr = []

    for (let i = 0; i < IdLettersArr.length; i++) {
        if (IdLettersArr[i] === nextIdLettersArr[i]) {
            sharedLettersArr.push(IdLettersArr[i])
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

For the final couple steps of this function, let's convert sharedLettersArr to a string using the join() method, store it in a variable called sharedLettersStr, and return sharedLettersStr.

function findSharedLetters(IdLettersArr, nextIdLettersArr) {
    let sharedLettersArr = []

    for (let i = 0; i < IdLettersArr.length; i++) {
        if (IdLettersArr[i] === nextIdLettersArr[i]) {
            sharedLettersArr.push(IdLettersArr[i])
        }
    }

    const sharedLettersStr = sharedLettersArr.join('')
    return sharedLettersStr
}
Enter fullscreen mode Exit fullscreen mode

Before moving on to the end, just note that the following is a more concise (though less explicit) way to accomplish what all the code in findSharedLetters accomplishes:

return IdLettersArr.filter((letter, index) => letter === nextIdLettersArr[index]).join('')
Enter fullscreen mode Exit fullscreen mode

Now for our final step: Let's put it all together.

function findTheTwoBoxIDs(input) {
    for (let i = 0; i < input.length; i++) {
        console.log(input[i])

        for (let j = i + 1; j < input.length; j++) {
            console.log(input[j])

            let boxIdLettersArr = input[i].split('')
            let nextBoxIdLettersArr = input[j].split('')
            let mismatchedLetters = 0

            for (let k = 0; k < boxIdLettersArr.length; k++) {
                if (boxIdLettersArr[k] !== nextBoxIdLettersArr[k]) {
                    mismatchedLetters++
                }
            }

            console.log(mismatchedLetters)

            if (mismatchedLetters === 1) {
                console.log(boxIdLettersArr) // ['f', 'g', 'h', 'i', 'j']
                console.log(nextBoxIdLettersArr) // ['f', 'g', 'u', 'i', 'j']

                return findSharedLetters(boxIdLettersArr, nextBoxIdLettersArr)
            }
        }
    }
}

console.log(findTheTwoBoxIDs(boxIDsArr)) // fgij // f, g, i, and j are the common letters of the two box IDs that differed by one letter

function findSharedLetters(IdLettersArr, nextIdLettersArr) {
    let sharedLettersArr = []

    for (let i = 0; i < IdLettersArr.length; i++) {
        if (IdLettersArr[i] === nextIdLettersArr[i]) {
            sharedLettersArr.push(IdLettersArr[i])
        }
    }

    const sharedLettersStr = sharedLettersArr.join('')
    return sharedLettersStr
}
Enter fullscreen mode Exit fullscreen mode

I hope this has been clear and helpful!

Thank you for reading!

Top comments (0)