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

Day 02

2023/day02.livemd

Day 02

input = File.stream!("./2023/input_day02.txt")

Common

defmodule Blocs do
  @enforce_keys [:id, :sets]
  defstruct [:id, :sets]

  def parse_entry(line) do
    line = String.trim_trailing(line)

    [game_str, sets_str] = String.split(line, ":", parts: 2)
    id = parse_id(game_str)
    sets = parse_sets(sets_str)

    %__MODULE__{
      id: id,
      sets: sets
    }
  end

  defp parse_id("Game " <> id) do
    String.to_integer(id)
  end

  defp parse_sets(sets_str) do
    sets_str
    |> String.split(";")
    |> Enum.map(fn set_str ->
      cubes_str = String.split(set_str, ",")
      Enum.map(cubes_str, &amp;parse_cube/1)
    end)
  end

  defp parse_cube(cube_str) do
    [nb_str, color_str] = String.split(cube_str, " ", parts: 2, trim: true)
    {String.to_existing_atom(color_str), String.to_integer(nb_str)}
  end

  def possible?(entry, cubes) do
    entry.sets
    |> List.flatten()
    |> Enum.all?(fn {color, nb} ->
      Map.fetch!(cubes, color) >= nb
    end)
  end

  def minimal_set(entry) do
    entry.sets
    |> List.flatten()
    |> Enum.group_by(&amp;elem(&amp;1, 0), &amp;elem(&amp;1, 1))
    |> Enum.map(fn {color, list_of_nbs} ->
      {color, Enum.max(list_of_nbs)}
    end)
  end

  def set_power(set) do
    Enum.reduce(set, 1, fn {_color, nb}, acc -> nb * acc end)
  end
end

Part 1

cubes = %{
  red: 12,
  green: 13,
  blue: 14
}

input
|> Stream.map(&amp;Blocs.parse_entry/1)
|> Stream.filter(&amp;Blocs.possible?(&amp;1, cubes))
|> Stream.map(&amp; &amp;1.id)
|> Enum.sum()

Part 2

input
|> Stream.map(&amp;Blocs.parse_entry/1)
|> Stream.map(&amp;Blocs.minimal_set/1)
|> Stream.map(&amp;Blocs.set_power/1)
|> Enum.sum()