88 lines
1.9 KiB
Elixir
88 lines
1.9 KiB
Elixir
|
defmodule Oasis do
|
||
|
@moduledoc """
|
||
|
Day 9 of Advent of Code 2023.
|
||
|
|
||
|
Link: https://adventofcode.com/2023/day/9.
|
||
|
"""
|
||
|
|
||
|
def solve() do
|
||
|
input =
|
||
|
File.stream!("input.txt")
|
||
|
|> Stream.map(&String.trim_trailing/1)
|
||
|
# Get lists of strings.
|
||
|
|> Stream.map(&String.split/1)
|
||
|
# Get lists of integers.
|
||
|
|> Stream.map(fn list -> Enum.map(list, &String.to_integer/1) end)
|
||
|
|
||
|
# Predict next value for each list.
|
||
|
input
|
||
|
|> Stream.map(fn list -> predict(list, &predict_next_value/2) end)
|
||
|
|> Enum.sum()
|
||
|
|> IO.puts()
|
||
|
|
||
|
# Predict previous value for each list.
|
||
|
input
|
||
|
|> Stream.map(fn list -> predict(list, &predict_prev_value/2) end)
|
||
|
|> Enum.sum()
|
||
|
|> IO.puts()
|
||
|
end
|
||
|
|
||
|
@doc """
|
||
|
Predict a value for the list.
|
||
|
Predictor_fun is a function that takes current row and previous prediction result and returns new prediction.
|
||
|
|
||
|
Examples:
|
||
|
|
||
|
iex> Oasis.predict([0, 3, 6, 9, 12, 15], &Oasis.predict_next_value/2)
|
||
|
18
|
||
|
|
||
|
iex> Oasis.predict([1, 3, 6, 10, 15, 21], &Oasis.predict_next_value/2)
|
||
|
28
|
||
|
|
||
|
iex> Oasis.predict([10, 13, 16, 21, 30, 45], &Oasis.predict_prev_value/2)
|
||
|
5
|
||
|
"""
|
||
|
def predict(list, predictor_fun) do
|
||
|
diff = get_diff(list)
|
||
|
|
||
|
if zeros_only?(diff) do
|
||
|
predictor_fun.(list, 0)
|
||
|
else
|
||
|
predictor_fun.(list, predict(diff, predictor_fun))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def predict_next_value(list, prev_result) do
|
||
|
Enum.at(list, -1) + prev_result
|
||
|
end
|
||
|
|
||
|
def predict_prev_value(list, prev_result) do
|
||
|
hd(list) - prev_result
|
||
|
end
|
||
|
|
||
|
@doc """
|
||
|
Get a list of differences between values.
|
||
|
|
||
|
Examples:
|
||
|
|
||
|
iex> Oasis.get_diff([1, 3, 6, 10, 15, 21])
|
||
|
[2, 3, 4, 5, 6]
|
||
|
"""
|
||
|
def get_diff([head | tail]) do
|
||
|
case tail do
|
||
|
[] -> []
|
||
|
[val | _] -> [val - head | get_diff(tail)]
|
||
|
end
|
||
|
end
|
||
|
|
||
|
def zeros_only?(list) do
|
||
|
case list do
|
||
|
[] ->
|
||
|
true
|
||
|
|
||
|
[head | tail] ->
|
||
|
if head != 0, do: false, else: zeros_only?(tail)
|
||
|
end
|
||
|
end
|
||
|
end
|