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

AOC 2023 day 2

2023/elixir/day2.livemd

AOC 2023 day 2

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

Section

textarea = Kino.Input.textarea("input")
raw_data = Kino.Input.read(textarea)
data = String.split(raw_data, "\n")
defmodule Day2 do
  def parse_game(line) do
    line
    |> String.split(": ")
    |> then(fn [game, sets] ->
      {game_index(game), parse_sets(sets)}
    end)
  end

  def game_index(game_name) do
    game_name
    |> then(&Regex.run(~r/(\d+)/, &1, capture: :all_but_first))
    |> then(fn [i] -> String.to_integer(i) end)
  end

  def parse_sets(sets) do
    sets
    |> String.split("; ")
    |> Enum.map(&parse_set/1)
  end

  def parse_set(set) do
    set
    |> String.split(", ")
    |> Enum.map(&parse_colors/1)
    |> Enum.into(%{})
  end

  def parse_colors(color) do
    color
    |> String.split(" ")
    |> then(fn [n, c] -> {c, String.to_integer(n)} end)
  end
end

Part 1

defmodule Part1 do
  def valid_game?({_, sets}) do
    sets
    |> Enum.all?(fn set ->
      Map.get(set, "red", 0) <= 12 &amp;&amp;
        Map.get(set, "green", 0) <= 13 &amp;&amp;
        Map.get(set, "blue", 0) <= 14
    end)
  end
end

data
|> Enum.map(&amp;Day2.parse_game/1)
|> Enum.filter(&amp;Part1.valid_game?/1)
# |> IO.inspect()
|> Enum.map(&amp;elem(&amp;1, 0))
|> Enum.sum()

Part2

defmodule Part2 do
  @empty %{"red" => 0, "green" => 0, "blue" => 0}

  def minimals({_, sets}) do
    Enum.reduce(sets, @empty, &amp;merge_reducer/2)
  end

  defp merge_reducer(acc, set) do
    Map.merge(acc, set, fn _k, v1, v2 -> max(v1, v2) end)
  end

  def min(key, map1, map2) do
    [map1, map2]
    |> Enum.map(&amp;Map.get(&amp;1, key))
    |> Enum.min()
  end
end

data
|> Enum.map(&amp;Day2.parse_game/1)
|> Enum.map(&amp;Part2.minimals/1)
|> Enum.map(&amp;Map.values/1)
|> Enum.map(&amp;Enum.product/1)
|> Enum.sum()
|> dbg()