Powered by AppSignal & Oban Pro

Day 6

day_6.livemd

Day 6

Setup

Mix.install([
  {:kino, "~> 0.4.1"}
])
input = Kino.Input.textarea("Please provide your input:")
input =
  Kino.Input.read(input)
  |> String.split([",", "\n"], trim: true)
  |> Enum.map(&String.to_integer(&1))
defmodule Lanternfish do
  defstruct days: 8

  @empty_pop %{
    0 => 0,
    1 => 0,
    2 => 0,
    3 => 0,
    4 => 0,
    5 => 0,
    6 => 0,
    7 => 0,
    8 => 0
  }

  def get_empty_pop, do: @empty_pop

  def cycle(%Lanternfish{days: days}) do
    days_left = days - 1

    case days_left do
      -1 -> {:new, %Lanternfish{days: 6}, %Lanternfish{}}
      _x -> {:ok, %Lanternfish{days: days_left}}
    end
  end

  def cycle_v2(pop) do
    pop
    |> Enum.reduce(@empty_pop, fn {day, value}, new ->
      case day do
        0 -> Map.update!(new, 6, &(&1 + value))
        7 -> Map.update!(new, 6, &(&1 + value))
        _x -> Map.put(new, day - 1, value)
      end
    end)
    |> Map.put(8, Map.get(pop, 0, 0))
  end
end

Part 1

defmodule AdventOfCode.DaySix do
  def solve_part_one(population, days) do
    population = Enum.map(population, &%Lanternfish{days: &1})

    Enum.reduce(1..days, population, fn _day, population ->
      Enum.reduce(population, [], fn fish, new_population ->
        case Lanternfish.cycle(fish) do
          {:new, fish, baby} -> [baby | [fish | new_population]]
          {:ok, fish} -> [fish | new_population]
        end
      end)
    end)
    |> Enum.count()
  end

  def solve_part_two(input, days) do
    population_by_freq =
      input
      |> parse_input()

    Enum.reduce(1..days, population_by_freq, fn _day, population_by_freq ->
      Lanternfish.cycle_v2(population_by_freq)
    end)
    |> Enum.reduce(0, fn {_k, val}, acc -> acc + val end)
  end

  defp parse_input(input) do
    Map.merge(Lanternfish.get_empty_pop(), Enum.frequencies(input))
  end
end

# AdventOfCode.DaySix.solve_part_one(input, 80)
AdventOfCode.DaySix.solve_part_two(input, 256)