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

AoC 2023 D04

2023/d04.livemd

AoC 2023 D04

Mix.install([:kino])

defmodule Utils do
  def split(line, sep \\ "") do
    String.split(line, sep, trim: true)
  end

  def split_all_lines(text, sep \\ "") do
    text
    |> String.split("\n", trim: true)
    |> Enum.map(&split(&1, sep))
  end

  def to_numbers(number) when is_binary(number) do
    String.to_integer(number)
  end

  def to_numbers(numbers) when is_list(numbers) do
    Enum.map(numbers, &to_numbers/1)
  end

  def to_matrix(text, sep \\ "") do
    text
    |> split_all_lines(sep)
    |> then(fn data ->
      for {row, r} <- Enum.with_index(data), {col, c} <- Enum.with_index(row) do
        {{r, c}, col}
      end
    end)
    |> Map.new()
  end
end

Setup

import Utils

input = Kino.Input.textarea("Input:")
text = Kino.Input.read(input)
data =
  split(text, ["\n", "|"])
  |> Enum.map(fn line ->
    line
    |> String.replace(~r/Card\s+\d+:/, "")
    |> then(fn line -> Regex.scan(~r/\d+/, line) end)
    |> List.flatten()
    |> Enum.map(&amp;String.to_integer/1)
  end)
  |> Enum.chunk_every(2)
List.last(data)

P1

defmodule P1 do
  def solve(data) do
    data
    |> winning_count()
    |> Enum.map(&amp;floor(2 ** (&amp;1 - 1)))
    |> Enum.sum()
  end

  def winning_count(data) do
    data
    |> Enum.map(fn [winnings, nums] ->
      diff = nums -- winnings
      length(nums -- diff)
    end)
  end
end

P1.solve(data)

P2

defmodule P2 do
  def solve(data) do
    data =
      data
      |> P1.winning_count()
      |> Enum.with_index(1)

    data
    |> Enum.reduce(Map.new(1..length(data), &amp;{&amp;1, 1}), fn {wc, k}, counter ->
      increment = counter[k]

      Enum.reduce((k + 1)..(k + wc)//1, counter, fn k, counter ->
        Map.update!(counter, k, &amp;(&amp;1 + increment))
      end)
    end)
    |> Map.values()
    |> Enum.sum()
  end
end

P2.solve(data)