Post

Advent of Code 2022, Day 3 - Sanitizer

Preface

The objective of the third day is available on the advent of code website, so it won’t be shared here. On this page only the steps of achieving a solution are given with a solution build in Kotlin.

Design

When reading through the assignment we can identify in what kind of model we’d like to put our raw data. So the first step that we’re going to do is think about our data structure.

So we’ve got the following raw input.

1
2
3
4
5
6
vJrwpWtwJgWrhcsFMMfFFhFp
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
PmmdzqPrVvPwwTWBwg
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
ttgJtRGJQctTZtZT
CrZsJsPPZsGzwwsLwLmpwMDw

This input represents six rucksacks, where each rucksack consists of two compartments. The first compartment contains the first half of each line, and the second compartment contains the second half.

So if we split our data based on this information, we get the following structure.

 Compartment ACompartment B
Rucksack 1vJrwpWtwJgWrhcsFMMfFFhFp
Rucksack 2jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
Rucksack 3PmmdzqPrVvPwwTWBwg
Rucksack 4wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
Rucksack 5ttgJtRGJQctTZtZT
Rucksack 6CrZsJsPPZsGzwwsLwLmpwMDw

To achieve this data structure we need to split up our input on a newline character. This will give us a list of all rucksacks, but without the compartments.

1
2
3
4
5
6
7
8
[
    "vJrwpWtwJgWrhcsFMMfFFhFp",
    "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL",
    "PmmdzqPrVvPwwTWBwg",
    "wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn",
    "ttgJtRGJQctTZtZT",
    "CrZsJsPPZsGzwwsLwLmpwMDw"
]

Now for each rucksack we need to count the number of characters inside the string and split it in half. Then we can add both halfs into a pair so we get a list of pairs. In this list, each pair is a rucksack, and each pair item is a compartment.

1
2
3
4
5
6
7
8
[
    { "vJrwpWtwJgWr"    , "hcsFMMfFFhFp"     }, // Rucksack 1
    { "jqHRNqRjqzjGDLGL", "rsFMfFZSrLrFZsSL" }, // Rucksack 2
    { "PmmdzqPrV"       , "vPwwTWBwg"        }, // Rucksack 3
    { "wMqvLMZHhHMvwLH" , "jbvcjnnSBnvTQFn"  }, // Rucksack 4
    { "ttgJtRGJ"        , "QctTZtZT"         }, // Rucksack 5
    { "CrZsJsPPZsGz"    , "wwsLwLmpwMDw"     }  // Rucksack 6
]

Implementation

Sanitizer

Now we now how we want our data structure to look like, we can start creating the getItems(): List<Pair<String, String>> method inside our Sanitizer class. Because we’ve laid out the way we want to functionally setup our code. We can just implement it in Kotlin using the split and map methods on our input file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Sanitizer(
    private val resource: URL?
) {
    fun getItems(): List<Pair<String, String>>? =
      resource
          ?.readText()
          ?.split("\n")
          ?.map {
              val compartmentSize = it.length / 2 // Step 1
              val firstCompartment = it.substring(0, compartmentSize) // Step 2
              val secondCompartment = it.substring(compartmentSize, it.length) // Step 3

              Pair(firstCompartment, secondCompartment)
          }
}

At step 1 we sum up the entire length of the string and divide it by two because we know that each rucksack has only two compartments. At step 2 and step 3 we retrieve the compartments by retrieving the substring of the entire rucksack.

At step 2 we start the substring at index 0 up until the compartmentSize. Because the substring endIndex parameter is exclusive (Jetbrains, n.d.), we can threat it as if it’s a 1-based index. At step 3, we take the rest of the string with the compartmentSize as the startIndex. Because the startIndex is inclusive (Jetbrains, n.d.), we don’t need to subtract or add anything.

Which will finally give us the data model we designed in the previous chapter.

Test case

To validate that our logic works as expected, we create a test case based on the sample data from the assignment. This way we can validate that our sanitizer gives us the correct data structure which we can use in the assignments.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class SanitizerTest {
    @Test
    fun testGetItems() {
        // Arrange
        val resource = {}::class.java.getResource("/input.txt")
        val sut = Sanitizer(resource)
        val expectedItems = listOf(
            Pair("vJrwpWtwJgWr", "hcsFMMfFFhFp"),
            Pair("jqHRNqRjqzjGDLGL", "rsFMfFZSrLrFZsSL"),
            Pair("PmmdzqPrV", "vPwwTWBwg"),
            Pair("wMqvLMZHhHMvwLH", "jbvcjnnSBnvTQFn"),
            Pair("ttgJtRGJ", "QctTZtZT"),
            Pair("CrZsJsPPZsGz", "wwsLwLmpwMDw")
        )

        // Act
        val result = sut.getItems()

        // Assert
        assertContentEquals(expectedItems, result)
    }
}
This post is licensed under CC BY 4.0 by the author.