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

AoC 2023 - Day 04

2023/lang-elixir/04.livemd

AoC 2023 - Day 04

Mix.install([
  {:kino, "~> 0.11.3"}
])

Section

input_e1 =
  "day04-e1.txt"
  |> Kino.FS.file_path()
  |> File.read!()
  |> String.trim()

input =
  "day04.txt"
  |> Kino.FS.file_path()
  |> File.read!()
  |> String.trim()

[input_e1, input]
defmodule Solution do
  def part_1(input) do
    input
    |> String.split("\n")
    |> Enum.map(fn card ->
      [numbers, winning_numbers] = split(card)

      matches =
        numbers
        |> MapSet.intersection(winning_numbers)
        |> MapSet.size()

      if matches > 0 do
        round(:math.pow(2, matches - 1))
      else
        0
      end
    end)
    |> Enum.sum()
  end

  def part_2(input) do
    lines = String.split(input, "\n")
    cards = List.duplicate(1, length(lines))

    lines
    |> Enum.with_index()
    |> Enum.reduce(cards, fn {card, n}, acc ->
      [numbers, winning_numbers] = split(card)

      cards_won =
        numbers
        |> MapSet.intersection(winning_numbers)
        |> MapSet.size()

      range = (n + 1)..(cards_won + n)//1

      Enum.reduce(range, acc, fn i, acc ->
        List.update_at(acc, i, &(&1 + Enum.at(acc, n)))
      end)
    end)
    |> Enum.sum()
  end

  defp split(line) do
    [_card, card] = String.split(line, ":", trim: true)

    card
    |> String.split("|", trim: true)
    |> Enum.map(&String.split(&1, " ", trim: true))
    |> Enum.map(&MapSet.new/1)
  end
end
Solution.part_1(input)
Solution.part_2(input)