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 |
404.259 μs |
+/- 1.897 μs |
JS |
882.609 μs |
+/- 1.218 μs |
Native |
618.692 μs |
+/- 0.692 μs |
Elixir |
764.940 μs |
+/- 4.372 μs |
Part 2
Mean |
Error |
|
---|---|---|
JVM |
996.083 μs |
+/- 6.191 μs |
JS |
1923.613 μs |
+/- 2.470 μs |
Native |
1319.122 μs |
+/- 6.143 μs |
Elixir |
953.730 μs |
+/- 4.702 μs |