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

Advent 2021 - Day 6

day6.livemd

Advent 2021 - Day 6

Setup

Mix.install([
  {:vega_lite, "~> 0.1.2"},
  {:kino, github: "livebook-dev/kino"}
])
alias VegaLite, as: Vl
input = Kino.Input.textarea("Please paste your input file:")
initial_lanternfish =
  input
  |> Kino.Input.read()
  |> String.trim()
  |> String.split(",")
  |> Enum.map(&String.to_integer(&1))
  |> Enum.reduce(%{}, fn lanternfish, acc ->
    Map.get_and_update(acc, lanternfish, fn val ->
      next_val = if val == nil, do: 1, else: val + 1
      {val, next_val}
    end)
    |> elem(1)
  end)

Utils

defmodule Utils do
  def sum_lanternfish(lanternfish) do
    lanternfish |> Map.values() |> Enum.sum()
  end

  def grow_lanternfish(_widget, lanternfish, days) when days == 0 do
    lanternfish
  end

  def grow_lanternfish(widget, lanternfish, days) do
    lanternfish =
      lanternfish
      |> Enum.map(fn {k, v} -> {k - 1, v} end)
      |> Enum.into(%{})

    lanternfish =
      if Map.has_key?(lanternfish, -1) do
        refresh_count = Map.get(lanternfish, -1)

        lanternfish
        |> Map.drop([-1])
        |> Map.update(6, refresh_count, &(&1 + refresh_count))
        |> Map.update(8, refresh_count, &(&1 + refresh_count))
      else
        lanternfish
      end

    data = %{"day" => floor(days * -1), "number of fish" => sum_lanternfish(lanternfish)}
    Kino.VegaLite.push(widget, data, window: 40)

    Process.sleep(25)

    grow_lanternfish(widget, lanternfish, days - 1)
  end
end

Part 1

part1_widget =
  Vl.new(width: 800, height: 300)
  |> Vl.mark(:bar)
  |> Vl.encode_field(:x, "day", type: :temporal)
  |> Vl.encode_field(:y, "number of fish", type: :quantitative)
  |> Kino.VegaLite.new()
Utils.grow_lanternfish(part1_widget, initial_lanternfish, 80) |> Utils.sum_lanternfish()

Part 2

part2_widget =
  Vl.new(width: 800, height: 300)
  |> Vl.mark(:bar)
  |> Vl.encode_field(:x, "day", type: :temporal)
  |> Vl.encode_field(:y, "number of fish", type: :quantitative)
  |> Kino.VegaLite.new()
Utils.grow_lanternfish(part2_widget, initial_lanternfish, 256) |> Utils.sum_lanternfish()