Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 9

day09.livemd

Day 9

Mix.install([
  {:kino, "~> 0.11.3"}
])

Solutions

input = Kino.Input.textarea("Please paste your input file:")

Part 1

Premise: OASIS calculations. Extrapolate the next value. Sum the extrapolated values.

Sample data:

0 3 6 9 12 15
1 3 6 10 15 21
10 13 16 21 30 45

Result: 114

Part 2

Premise: Extrapolate the previous values and sum.

Result: 2

defmodule InputHelpers do
  def parse_input(input) do
    input
    |> String.split("\n", trim: true)
    |> Enum.map(&String.trim/1)
  end

  def parse_integer_list(string) do
    string
    |> String.split(" ", trim: true)
    |> Enum.map(&String.to_integer/1)
  end
end
input = Kino.Input.read(input)

import InputHelpers

defmodule Y2023.D9 do
  @moduledoc """
  https://adventofcode.com/2023/day/9
  """

  def p1(input) do
    input
    |> parse_input()
    |> Enum.map(fn line ->
      line
      |> parse_integer_list()
      |> find_next_value()
      |> List.last()
    end)
    |> Enum.sum()
  end

  def find_next_value(list) do
    cond do
      contains_only_zeros?(list) ->
        [0 | list]

      true ->
        next_list =
          list
          |> calculate_interval_list()
          |> find_next_value()

        next_value = List.last(next_list) + List.last(list)
        previous_value = hd(list) - hd(next_list)
        [previous_value] ++ list ++ [next_value]
    end
  end

  def calculate_interval_list([head1, head2]) do
    [head2 - head1]
  end

  def calculate_interval_list([head1, head2 | rest]) do
    [head2 - head1 | calculate_interval_list([head2 | rest])]
  end

  def calculate_interval_list([_value]), do: []

  @doc """
      iex> import Y2023.D9
      iex> contains_only_zeros?([0, 0, 0])
      true
      iex> contains_only_zeros?(-3..14)
      false
      iex> contains_only_zeros?([])
      true
  """
  def contains_only_zeros?(list) do
    not Enum.any?(list, &(&1 !== 0))
  end

  def p2(input) do
    input
    |> parse_input()
    |> Enum.map(fn line ->
      extrapolated_line =
        line
        |> parse_integer_list()
        |> find_next_value()

      hd(extrapolated_line)
    end)
    |> Enum.sum()
  end
end

Y2023.D9.p1(input) |> IO.puts()
Y2023.D9.p2(input) |> IO.puts()

Observations

This one was fairly smooth. You are basically just implementing the algorithm given in the problem. Part 2 was just a slight tweak and I didn’t need to write any new functions.