# Advent of Code 2019 - Day 4, in Kotlin

Kotlin solutions to parts 1 and 2 of Advent of Code 2019, Day 4: 'Secure Container'

Posted on

Today’s puzzle has quite a few solutions if you’re willing to get creative. I went with one that largely involves the Kotlin Standard Library, which continues to impress me with how many useful functions it has!

If you’d rather just view code, the GitHub Repository is here .

Problem Input

We’re given a string of text representing a range of integers for our input. The class for today’s solution (which I drive via unit tests) takes in an `IntRange` that has already been parsed.

``````class Day04(private val range: IntRange)
``````

While this can be inserted manually, here’s how I parsed the `String` into an `IntRange` in my test:

``````private val inputRange = resourceAsString("day4.txt").split("-").let {
it[0].toInt()..it[1].toInt()
}
``````

#### ⭐ Day 4, Part 1

The puzzle text can be found here.

One thing that struck me about the way this problem description is written is that it goes out of its way to say “each number is sorted”. Once I realized this, I figured there were a few ways to solve it. The way I picked was to turn each of our candidate `Int`s into a `String` and use a combination of `zipWithNext` and `all` to see if the characters are in order:

``````private fun isSorted(input: String): Boolean =
input.zipWithNext().all { it.first <= it.second }
``````

The `zipWithNext` function comes in handy when comparing adjacent elements in a `String` or a `List` (I’m simplifying this concept here). Essentially, it turns each adjacent pair of elements into a `Pair`. For example, if we have the string “Todd”, and we call `"Todd".zipwithNext()`, we end up with several pairs in a List: `Pair("T", "o"), Pair("o", "d"), and Pair("d", "d")`. Neat, huh? If you’ve ever used `windowed` from the standard library to do the same thing, this is similar except that `zipWithNext` returns a `List<Pair<T, T>>` instead of a `List<List<T>>`.

Once we have our data in that format, we can make sure that `all` of the `Pair`s have their elements in the right order (either they match, or the `first` element comes before the `second` element).

Another way to do this would be to turn our `String` into a `CharArray`, sort it, and then compare the results with a `CharArray` version of the original. But I felt that `zipWithNext` and `all` was cleaner and easier to read (for me).

Next, we need to make sure our candidate `String` contains two of the same number somewhere within it. As we’ve just discovered, we can assume that our `String` is sorted at this point in the calculation. This allows us to use `zipWithNext` again, but instead of `all`, we want to know if `any` elements are identical:

``````private fun containsMatchingPair(input: String): Boolean =
input.zipWithNext().any { it.first == it.second }
``````

Combining these two functions is all we need to solve part 1:

``````fun solvePart1(): Int =
range
.map { it.toString() }
.count { isSorted(it) && containsMatchingPair(it) }
``````

Take the range, convert each element to a `String` and `count` the number of times we find a `String` that is sorted and contains a pair.

Part 1 done! Star earned!

#### ⭐ Day 4, Part 2

The puzzle text can be found here.

Thankfully we’re pretty close to having Part 2 done, we just need to write one more helper function. In this case, we need to know if any number appears in the string exactly twice. We can’t reuse `containsMatchingPair` because it can’t tell the difference between matching two in a row and three in a row.

Once again, we’ll go to the Kotlin Standard Library to find a solution - `groupBy` to the rescue:

``````private fun containsIsolatedPair(input: String): Boolean =
input.groupBy { it }.any { it.value.size == 2 }
``````

In this case we can call `groupBy` on our `String`, which groups by each `Char` in the `String`. Then we use `any` to determine if any group contains exactly two elements, meaning there is a pair that is not part of a bigger set of identical items.

It’s worth noting we could re-implement `contanisMatchingPair` from Part 1 with this approach:

``````private fun containsMatchingPair(input: String): Boolean =
input.groupBy { it }.any { it.value.size >= 2 }
``````

See the difference? We want a group whose size is at least 2 rather than exactly 2. Both versions of `containsMatchingPair` give the same results, it’s just up to you to decide which is clearer to you.

Now that we have all we need, we can solve Part 2:

``````fun solvePart2(): Int =
range
.map { it.toString() }
.count { isSorted(it) && containsIsolatedPair(it) }
``````

It looks pretty similar to Part 1’s solution, doesn’t it? There might be more efficient ways to solve today’s problems, but I feel that these are clear and show off the power of the Kotlin Standard Library.

Part 2 solved, and star earned!