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

Day09

day09.livemd

Day09

Setup

Mix.install([
  {:kino, "~> 0.5.0"}
])
sample_text = Kino.Input.textarea("sample")
input_text = Kino.Input.textarea("input")
sample = Kino.Input.read(sample_text)
input = Kino.Input.read(input_text)
defmodule Shared do
  def parse(text) do
    text
    |> String.split("\n", trim: true)
    |> Enum.map(&String.to_integer/1)
  end

  def is_valid?(list, next) do
    size = Enum.count(list)

    for i <- 0..(size - 2),
        j <- (i + 1)..(size - 1),
        Enum.at(list, i) + Enum.at(list, j) == next do
      :valid
    end != []
  end

  def find_error(band, preambule_size) do
    {list, [next | rest_of_band]} = Enum.split(band, preambule_size)
    find_error(list, next, rest_of_band)
  end

  def find_error(list, next, rest_of_band) do
    if is_valid?(list, next) do
      [_head | tail] = list
      [new_next | new_rest_of_band] = rest_of_band
      find_error(tail ++ [next], new_next, new_rest_of_band)
    else
      next
    end
  end

  def find_error_range(band, error) do
    {index, found?} =
      Enum.reduce_while(band, {0, 0}, fn x, {index, acc} ->
        if acc < error, do: {:cont, {index + 1, acc + x}}, else: {:halt, {index, acc == error}}
      end)

    if found?, do: Enum.slice(band, 0..(index - 1)), else: find_error_range(tl(band), error)
  end
end

part a

# sample
# |> Shared.parse()
# |> Shared.find_error(5)

input
|> Shared.parse()
|> Shared.find_error(25)

part b

band = input |> Shared.parse()
error = band |> Shared.find_error(25)

band
|> Shared.find_error_range(error)
|> Enum.min_max()
|> then(&amp;(elem(&amp;1, 0) + elem(&amp;1, 1)))