Day 1: Sonar Sweep
Puzzle Description
Scala Center Link
Scala Center Advent of Code 2021, Day 1
The first two days I actually wrote my solution in Elixir, but I quickly got tired of it. As a treat though, I've updated my Elixir code to a more sensible solution so it can stand alongside my Scala.
Solution Summary
- Parse input into
List[Int]
- For part 2, calculate the sliding sums of this list.
- Count instances where a number is greater than its previous number
Part 1
Parsing is easy (in Scala, at least). Elixir forces you to always handle errors, but frankly I couldn't care less here.
def parse(str: String): List[Int] =
str.linesIterator.map(_.toInt).toList
All Elixir functions will be inside defmodule Day1
.
defmodule Day1 do
def parse_int!(str) do
case Integer.parse(str) do
{ v, "" } -> v
:error -> nil
end
end
def parse(str) do
for line <- String.split(String.trim(str), "\n"),
line != "",
do: Day1.parse_int!(String.trim(line))
end
end
Let's then do an easy measurement. It's just a sliding window:
def measureScans(scans: List[Int]): Int =
scans.sliding(2).count: ls =>
ls.head < ls.tail.head
# inside Day1...
def measurement_basic(list) do
Enum.chunk_every(list, 2, 1, :discard)
|> Enum.count(fn a -> Enum.at(a, 0) < Enum.at(a, 1) end)
end
And hook it up:
def part1(input: List[Int]): Int =
measureScans(input)
def part1(list) do
measurement_basic(list)
end
And that's part 1.
Part 2
Part 2 is easy - we convert the input list into a new list then rerun part 1 on this new list.
Let's convert the list with sliding sums:
def slidingSums(scans: List[Int]): List[Int] =
scans.sliding(3).map(_.sum).toList
def sliding_sum(list) do
Enum.chunk_every(list, 3, 1, :discard)
|> Enum.map(fn a -> Enum.sum(a) end)
end
Then hook it up:
def part2(input: List[Int]): Int =
measureScans(slidingSums(input))
def part2(list) do
list |> sliding_sum |> measurement_basic
end
And that's part 2.
Final Code
def parse(str: String): List[Int] =
str.linesIterator.map(_.toInt).toList
def measureScans(scans: List[Int]): Int =
scans.sliding(2).count: ls =>
ls.head < ls.tail.head
def part1(input: List[Int]): Int =
measureScans(input)
def slidingSums(scans: List[Int]): List[Int] =
scans.sliding(3).map(_.sum).toList
def part2(input: List[Int]): Int =
measureScans(slidingSums(input))
defmodule Day1 do
def parse_int!(str) do
case Integer.parse(str) do
{ v, "" } -> v
:error -> nil
end
end
def measurement_basic(list) do
Enum.chunk_every(list, 2, 1, :discard)
|> Enum.count(fn a -> Enum.at(a, 0) < Enum.at(a, 1) end)
end
def part1(list) do
measurement_basic(list)
end
def sliding_sum(list) do
Enum.chunk_every(list, 3, 1, :discard)
|> Enum.map(fn a -> Enum.sum(a) end)
end
def part2(list) do
list |> sliding_sum |> measurement_basic
end
def parse(str) do
for line <- String.split(String.trim(str), "\n"),
line != "",
do: Day1.parse_int!(String.trim(line))
end
end
Benchmark
Part 1
Mean |
Error |
|
---|---|---|
JVM |
1.611 ms |
+/- 0.208 ms |
JS |
2.566 ms |
+/- 0.192 ms |
Native |
0.675 ms |
+/- 0.092 ms |
Part 2
Mean |
Error |
|
---|---|---|
JVM |
5.670 ms |
+/- 0.331 ms |
JS |
5.893 ms |
+/- 1.405 ms |
Native |
1.190 ms |
+/- 0.041 ms |