Powered by AppSignal & Oban Pro

Advent of code day 04

2023/livebooks/day-04.livemd

Advent of code day 04

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

Setup input

# shout out to https://www.youtube.com/watch?v=P96I1X_iGlk&list=PL2DxwWG9IY3ZqpSS8BLQyKmqvIPSMjdop&index=3
# sharing his thoughts specially on part 2

example = Kino.Input.textarea("Please paste your input example:")
input = Kino.Input.textarea("Please paste your real input:")

Part 01

input
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
  [_, winners, numbers | _] = line |> String.split(~r/(:)|(\|)/, trim: true)

  winners =
    String.split(winners, " ", trim: true)
    |> Enum.map(&String.to_integer/1)
    |> MapSet.new()

  total_wins =
    String.split(numbers, " ", trim: true)
    |> Enum.map(&String.to_integer/1)
    |> Enum.filter(&MapSet.member?(winners, &1))
    |> Enum.count()

  if total_wins > 0, do: 2 ** (total_wins - 1), else: 0
end)
|> Enum.sum()

Part 02

cards =
  example
  |> Kino.Input.read()
  |> String.split("\n", trim: true)

cards
|> Enum.with_index(1)
|> Enum.map(fn {line, index} ->
  [_, winners, numbers | _] = line |> String.split(~r/(:)|(\|)/, trim: true)

  winners =
    String.split(winners, " ", trim: true)
    |> Enum.map(&String.to_integer/1)
    |> MapSet.new()

  total_wins =
    String.split(numbers, " ", trim: true)
    |> Enum.map(&String.to_integer/1)
    |> Enum.filter(&MapSet.member?(winners, &1))
    |> Enum.count()

  {index, total_wins}
end)
|> Enum.reduce(
  # starts acc as card -> number of copies
  1..length(cards) |> Enum.map(&{&1, 1}) |> Enum.into(%{}),
  fn {game, wins}, acc ->
    if wins > 0 do
      (game + 1)..(game + wins)
      |> Enum.reduce(acc, fn i, internal_acc ->
        Map.put(internal_acc, i, internal_acc[i] + internal_acc[game])
      end)
    else
      acc
    end
  end
)
|> Map.values()
|> Enum.sum()