Skip to Content

Advent of Code 2020 - Day 6, in Kotlin - Custom Customs

Kotlin solutions to parts 1 and 2 of Advent of Code 2020, Day 6: 'Custom Customs'

Posted on

Today’s puzzle has us reformatting our input so we can make Kotin figure out the answers for us. I think today’s puzzle shows off a couple of nice functions from the Kotlin standard library that we haven’t seen so far this year.

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

Problem Input

We will take our input into our daily class as a single String representing the entire input file and manipulate it once we’ve got it in there.

class Day06(input: String) {

    private val answers: List<List<String>> = input
        .split("\n\n")
        .map { it.lines().filter { line -> line.isNotBlank() } }

}

To separate each set of records, we will split our big String into a List<String> every time we see two newlines (\n\n). Then for each String, which represents a record, we will split that into a List<String> using lines(), taking care to filter out any rows that are blank. If you don’t filter out blank rows, the count we perform in part 2 will be off, because we’ll calculate the size of the group incorrectly. That’s getting a bit ahead of ourselves, maybe remember that we’ve done it after you’ve finished Part 2 and come back here to understand why this works.

So now we have a List<List<String>>, where the inner List<String> represents a complete record.

This is a common pattern now, we’ve seen it twice: A file with records spread across a few lines, and records separated by two newlines. If we see it again, we should probably consider writing some helper code to make life easier for us. But then again, there isn’t that much code here, so I’m inclined to wait on that.

⭐ Day 6, Part 1

The puzzle text can be found here.

Since we’ve done a good job of formatting our input into a useful format, we can use a couple of functions out of the Kotlin standard library to solve Part 1:

fun solvePart1(): Int =
    answers.sumBy { it.joinToString("").toSet().size }

We will use sumBy(), which sums the elements of answers according to some function we provide. In that function, we will join each of our List<String> into one String. This is to remove the newline characters, otherwise they’ll effect the count of unique characters we’re about to do. Converting to a single String allows us to call toSet() on it, which returns a Set<Char>. All that’s left is to figure out the size of that set. Summing those up gives us the answer to part 1!

Onward!

⭐ Day 6, Part 2

The puzzle text can be found here.

Part 2 is actually quite similar to part 1, we just have to do a bit more manipulating and perform our count differently. Thankfully, the Kotlin standard library makes this easy.

fun solvePart2(): Int =
    answers.sumBy { group ->
        group
            .joinToString("")
            .groupingBy { it }
            .eachCount()
            .count { it.value == group.size }
    }

We’ll use sumBy() once again, but this time we have to provide a function that determines how many answers every member of a group answered true to. To do that, we’ll join our group, which is a List<String> into a String as before. Why not just do that as part of the input parsing and not once for part 1 and again for part 2? Because in part 2, we need to know the number of members in each group (how many lines are in the List<String>. Once we have that, we can use groupingBy() from the Kotlin standard library. I love using groupingBy() because it behaves almost like groupBy, but allows me to call eachCount() and get a Map<Char, Int>, where the key is the character, and the value is the number of times it occurred. Alternatively, we could do groupBy { it } and get a Map<Char,List<Char>>, and count up the map’s values ourselves. They both do the same thing, I just think using groupingBy/eachCount is so nice and clean.

Once we have that, we can count the number of values in the map have the same number as there are group members. This tells us how many answers each group had in common, and summing that gives us our answer!

Star earned! See you tomorrow!

Further Reading

  1. Index of All Solutions - All posts and solutions for 2020, in Kotlin.
  2. My Github repo - Solutions and tests for each day.
  3. Solution - Full code for day 6
  4. Advent of Code - Come join in and do these challenges yourself!