AoC 2024 Day 01: Historian Hysteria
Table of Contents
For December, I’m working to improve my Kotlin and functional programming skills by attempting the Advent of Code puzzles. The first puzzle of 2024 involves two lists of integers that, for some convoluted reason involving Santa, the North Pole, and historians, are location IDs that represent places of historical significance.
Input Data #
The input is a text file containing a list of lines, each of which is a pair of integers separated by three spaces. Here’s an example:
3 4
4 3
2 5
1 3
3 9
3 3
Read Input #
As we’re going to be reading lots of input files for AoC we’ll write a utility function to read an input file into a list of strings.
fun readInput(name: String) = Path("src/$name.txt").readText().trim().lines()
The function takes a file name (without the .txt
extension) as input, reads the file from the src/
directory, removes any leading or trailing whitespace from its contents, and then splits the text into a list of lines. Ultimately, it returns a List<String>
containing all the lines from the file.
To use it we just need to pass the name of the file we want to read. For example, to read the input for this puzzle we’d call it as follows:
val input = readInput("Day01")
Parse Input #
Let’s take the list of strings and turn it into a list of pairs of integers. Each row of the input file contains two integers separated by three spaces, so we’ll need to split each line into two parts and then convert each part into an integer. The result be a list of pairs of integers (List<Pair<Int, Int>>
). Next, we unzip
that into two lists of integers (Pair<List<Int>, List<Int>>
).
fun splitLists(input: List<String>): Pair<List<Int>, List<Int>> =
input.map { line ->
line.split(" ").let { (left, right) -> left.toInt() to right.toInt() }
}.unzip()
Now we can read the real input data and get on to solving part 1 of the puzzle.
Part 1 #
The lists should be identical, but they’re not. Our task is to calculate the difference between the two lists. To do this we’ll need to to sort the lists, calculate the absolute difference between each pair, and then sum the differences.
For example:
Lists Sorted Difference Sum
3 4 1 3 2
4 3 2 3 1
2 5 ---> 3 3 ---> 0 ---> 11
1 3 3 4 1
3 9 3 5 2
3 3 4 9 5
We need to sort the two lists, calculate the difference between each pair, and then sum the differences.
val (leftList, rightList) = splitLists(input)
val totalDistance = leftList.sorted().zip(rightList.sorted())
.sumOf { (left, right) -> (left - right).absoluteValue }
The sorted
function sorts the lists in ascending order, and then zip
combines the two lists into a list of pairs. The sumOf
function then calculates the sum of the absolute differences between each pair, giving us the total distance (difference).
Part 2 #
For this part we need to calculate how often each number from the left list appears in the right list, and then calculate a similarity score by adding up each number in the left list after multiplying it by the number of times it appears on the right list.
|
|
Line 1 groups (groupingBy
) the right list by its elements and counts how many times each element appears which creates a Map<Int, Int>
where the keys are the elements of the right list and the values are the number of times each element appears.
Lines 3-4 iterate over the left list, for each element left
in the left list, it multiplies left
by the number of times left
appears in the right list (or 0 where a number in the left list doesn’t appear in the right list) and then sums the results.
That’s it! A nice starter puzzle to ease us into December. The full source code is up on GitHub.