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

Day 4

2023/day4.livemd

Day 4

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

Section

input = Kino.Input.textarea("Input")
input_data = Kino.Input.read(input)

defmodule Sol4 do
  def s2n(s) do
    Enum.map(String.split(s), fn x -> String.to_integer(x) end)
  end

  def read_case(text) do
    [_, rest] = String.split(text, ":")
    [winning_cards, have_cards] = String.split(rest, "|")
    {s2n(winning_cards), s2n(have_cards)}
  end

  def read(text) do
    cases = String.split(text, "\n")
    Enum.map(cases, fn x -> read_case(x) end)
  end

  def score_part1({winning_cards, have_cards}) do
    Float.pow(
      2.0,
      MapSet.size(MapSet.intersection(MapSet.new(winning_cards), MapSet.new(have_cards))) - 1
    )
    |> floor
  end

  def score_part2({winning_cards, have_cards}) do
    MapSet.size(MapSet.intersection(MapSet.new(winning_cards), MapSet.new(have_cards)))
  end

  def update_scratchcards(scratchcards, card_id, winning_cards) do
    win_copies = Enum.at(winning_cards, card_id - 1)
    current_copies = Map.get(scratchcards, card_id)

    if win_copies > 0 do
      Enum.reduce((card_id + 1)..(card_id + win_copies), scratchcards, fn grow_id, acc ->
        Map.put(acc, grow_id, current_copies + Map.get(acc, grow_id, 0))
      end)
    else
      scratchcards
    end
  end
end
test_cases = Sol4.read(input_data)

answer1 =
  test_cases
  |> Enum.map(&Sol4.score_part1(&1))
  |> Enum.sum()
winning_cards =
  test_cases
  |> Enum.map(&Sol4.score_part2(&1))

init_scratchcards = for key <- 1..length(test_cases), into: %{}, do: {key, 1}

answer2 =
  Enum.reduce(1..length(test_cases), init_scratchcards, fn card_id, cards ->
    Sol4.update_scratchcards(cards, card_id, winning_cards)
  end)
  |> Map.values()
  |> Enum.sum()