Day 1 - Sonar Sweep
Part 1
defmodule Setup do
## parsing the input, converting it to a list of integers
def parse_input(prompt) do
case IO.gets(prompt) do
:eof -> []
line -> [line |> String.trim() |> String.to_integer() | parse_input(prompt)]
end
end
end
input = Setup.parse_input("Input")
defmodule DepthMeasurements do
def count_increments(measurements) do
measurements
# create shifted value tuples: {previous, current}
|> Enum.zip(tl(measurements))
# count when the current reading is bigger than the previous
|> Enum.count(fn {previous, current} -> current > previous end)
end
end
DepthMeasurements.count_increments(input)
Part 2
defmodule SlidingWindow do
@moduledoc "create tri-sums with Enum.chunk_while to iterate over the list in triplets"
defp chunk_fun(a, [b, c]) do
# emit the tri-sum and create the next triplet
{:cont, a + b + c, [a, b]}
end
defp chunk_fun(e, acc) do
# collect until we have a three readings
{:cont, [e | acc]}
end
defp after_fun(_) do
# no new element in the list, ignore the remainder
{:cont, []}
end
def trisums(input) do
Enum.chunk_while(input, [], &chunk_fun/2, &after_fun/1)
end
end
input
|> SlidingWindow.trisums()
|> DepthMeasurements.count_increments()
Bonus - Quick
defmodule QuickSolve do
def solve(list, acc \\ 0)
def solve([a, _, _, b | _] = list, acc) when b > a, do: solve(tl(list), acc + 1)
def solve([_, _, _, _ | _] = list, acc), do: solve(tl(list), acc)
def solve(_, acc), do: acc
end
QuickSolve.solve(input)
defmodule ChunkSolve do
def solve(input) do
input
|> Enum.chunk_every(3, 1, :discard)
|> Enum.map(&Enum.sum/1)
|> DepthMeasurements.count_increments()
end
end
ChunkSolve.solve(input)
Tests
ExUnit.start()
defmodule Tests do
use ExUnit.Case
setup do
{:ok, input: [199, 200, 208, 210, 200, 207, 240, 269, 260, 263]}
end
test "count_increments", %{input: input} do
assert DepthMeasurements.count_increments(input) == 7
end
test "sliding window", %{input: input} do
assert input |> SlidingWindow.trisums() |> DepthMeasurements.count_increments() == 5
end
test "quick solve", %{input: input} do
assert QuickSolve.solve(input) == 5
end
test "chunk solve", %{input: input} do
assert ChunkSolve.solve(input) == 5
end
end
ExUnit.run()
Benchmarking
Mix.install([:benchee])
Benchee.run(%{
"QuickSolve" => fn -> QuickSolve.solve(input) end,
"SlidingWindow" => fn ->
SlidingWindow.trisums(input)
|> DepthMeasurements.count_increments()
end,
"ChunkSolve" => fn -> ChunkSolve.solve(input) end
})
:ok