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

Day 2

day2.livemd

Day 2

Mix.install([:kino])

Read File

file_value = Kino.Input.file("Please Select Input File")
file_input = Kino.Input.read(file_value)
file_path = Kino.Input.file_path(file_input.file_ref)
contents = File.read!(file_path)
reports =
  contents
  |> String.split("\n")
  |> Enum.map(fn line -> String.split(line, " ") end)
  |> Enum.map(fn numbers ->
    numbers
    |> Enum.reject(fn n -> String.length(n) == 0 end)
    |> Enum.map(&String.to_integer/1)
  end)
  |> Enum.reject(&Enum.empty?/1)
defmodule ReportEvaluator do
  defstruct last: nil, direction: nil, max_difference: 3

  def run(numbers) when is_list(numbers),
    do: run(%ReportEvaluator{}, numbers)
  
  def run(_state, []),
    do: true
  def run(%ReportEvaluator{last: nil} = state, [n | t]),
    do: run(%{state | last: n}, t)
  def run(%ReportEvaluator{last: m, max_difference: max}, [n | _]) when n > m and n - m > max,
    do: false
  def run(%ReportEvaluator{last: m, max_difference: max}, [n | _]) when m > n and m - n > max,
    do: false
  def run(%ReportEvaluator{last: m, direction: nil} = state, [n | t]) when n > m,
    do: run(%{state | direction: :asc, last: n}, t)
  def run(%ReportEvaluator{last: m, direction: nil} = state, [n | t]) when n < m,
    do: run(%{state | direction: :desc, last: n}, t)
  def run(%ReportEvaluator{last: n}, [n | _]),
    do: false
  def run(%ReportEvaluator{last: m, direction: :asc}, [n | _]) when n < m,
    do: false
  def run(%ReportEvaluator{last: m, direction: :desc}, [n | _]) when n > m,
    do: false
  def run(%ReportEvaluator{} = state, [n | t]),
    do: run(%{state | last: n}, t)
end
defmodule ProblemDampener do
  def run(numbers, evaluator) when is_function(evaluator, 1),
    do: run(numbers, evaluator, evaluator.(numbers), 0, length(numbers))
  def run(_numbers, _evaluator, true, _index, _length),
    do: true
  def run(_numbers, _evaluator, result, length, length),
    do: result
  def run(numbers, evaluator, false, index, length),
    do: run(numbers, evaluator, evaluator.(List.delete_at(numbers, index)), index + 1, length)
end

Part 1

reports
  |> Enum.filter(&amp;ReportEvaluator.run/1)
  |> length()

Part 2

reports
  |> Enum.filter(fn numbers -> 
    ProblemDampener.run(numbers, &amp;ReportEvaluator.run/1) 
  end)
  |> length()