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

Day 6

advent_of_code/2021/day-06.livemd

Day 6

Setup

Mix.install([
  {:kino, "~> 0.5.0"},
  {:nx, "~> 0.1.0"},
  {:vega_lite, "~> 0.1.1"}
])
input = Kino.Input.text("Please paste your input:")
fishes =
  input
  |> Kino.Input.read()
  |> String.split(",")
  |> Enum.map(&String.to_integer/1)

Part 1

defmodule Recursion1 do
  def recur(fishes) do
    recur(fishes, [])
  end

  defp recur([0 | fishes], children), do: [6 | recur(fishes, [8 | children])]
  defp recur([fish | fishes], children), do: [fish - 1 | recur(fishes, children)]
  defp recur([], children), do: Enum.reverse(children)
end

1..80
|> Enum.reduce(fishes, fn _, fishes -> Recursion1.recur(fishes) end)
|> length()

Part 2

defmodule Recursion2 do
  def recur({prev0, prev1, prev2, prev3, prev4, prev5, prev6, prev7, prev8}) do
    {prev1, prev2, prev3, prev4, prev5, prev6, prev7 + prev0, prev8, prev0}
  end
end

frequencies = Enum.frequencies(fishes)
amounts = Enum.map(0..8, fn i -> frequencies[i] || 0 end) |> List.to_tuple()

1..256
|> Enum.reduce(amounts, fn _, amounts -> Recursion2.recur(amounts) end)
|> Tuple.sum()

Part 2 - VegaLite

From: https://gist.github.com/jonatanklosko/449485d2308a249c87c1f84c78a1a29c

alias VegaLite, as: Vl

graph =
  Vl.new(height: 300, width: 300)
  |> Vl.mark(:line)
  |> Vl.encode_field(:x, "day", type: :quantitative)
  |> Vl.encode_field(:y, "count", type: :quantitative)
  # |> Vl.encode_field(:y, "count", type: :quantitative, scale: [type: :log])
  |> Kino.VegaLite.new()
  |> Kino.render()

Kino.VegaLite.periodically(
  graph,
  100,
  {0, amounts},
  fn {day, {t0, t1, t2, t3, t4, t5, t6, t7, t8} = t} ->
    count = Tuple.sum(t)
    Kino.VegaLite.push(graph, %{day: day, count: count})

    if day < 256 do
      t = {t1, t2, t3, t4, t5, t6, t7 + t0, t8, t0}
      {:cont, {day + 1, t}}
    else
      :halt
    end
  end
)
graph =
  Vl.new(height: 300, width: 300)
  |> Vl.mark(:bar)
  |> Vl.encode_field(:x, "timer", type: :nominal)
  |> Vl.encode_field(:y, "count", type: :quantitative)
  |> Kino.VegaLite.new()
  |> Kino.render()

Kino.VegaLite.periodically(
  graph,
  100,
  {0, amounts},
  fn {day, {t0, t1, t2, t3, t4, t5, t6, t7, t8} = t} ->
    histogram_points =
      t
      |> Tuple.to_list()
      |> Enum.with_index()
      |> Enum.map(fn {count, timer} -> %{count: count, timer: timer} end)

    Kino.VegaLite.push_many(graph, histogram_points, window: length(histogram_points))

    if day < 256 do
      t = {t1, t2, t3, t4, t5, t6, t7 + t0, t8, t0}
      {:cont, {day + 1, t}}
    else
      :halt
    end
  end
)

Part 2 - Nx

From https://gist.github.com/rhbvkleef/0ec152310954e62999170f70ca8c7489.

import Nx, only: :sigils

frequencies = Enum.frequencies(fishes)
tensor = Nx.tensor(Enum.map(0..5, fn i -> frequencies[i] || 0 end))

matrix = ~M"""
0 0 0 0 0 0 1 0 1
1 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1 0
"""

final =
  1..255
  |> Enum.reduce(matrix, fn _, acc ->
    Nx.dot(matrix, acc)
  end)
  |> Nx.sum(axes: [1])

Nx.dot(tensor, final[0..5])