Powered by AppSignal & Oban Pro

Day 2

2023/day_2.livemd

Day 2

Mix.install([:kino])

Get input

input =
  Kino.Input.textarea("Paste input here",
    default: """
    Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green
    Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue
    Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red
    Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red
    Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green
    """
  )
defmodule Helper do
  def is_game_possible?(reveals) do
    max_red = 12
    max_green = 13
    max_blue = 14

    reveals
    |> Enum.all?(fn reveal ->
      Map.get(reveal, "red", 0) <= max_red and
        Map.get(reveal, "green", 0) <= max_green and
        Map.get(reveal, "blue", 0) <= max_blue
    end)
  end
end
parsed_input =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)
  |> Stream.map(fn str ->
    [game, cubes] =
      String.split(str, "Game ")
      |> Kernel.then(fn [_, s] -> String.split(s, ": ") end)

    reveals =
      cubes
      |> String.split("; ")
      |> Stream.map(fn subset ->
        String.split(subset, ", ")
        |> Stream.map(&String.split(&1, " "))
        |> Stream.map(&List.to_tuple/1)
        |> Stream.map(fn {count, colour} ->
          {count_i, _} = Integer.parse(count)
          {colour, count_i}
        end)
        |> Enum.into(%{})
      end)

    {game_i, _} = Integer.parse(game)
    {game_i, reveals}
  end)

Part 1

parsed_input
|> Stream.filter(fn {_, reveals} -> Helper.is_game_possible?(reveals) end)
|> Stream.map(fn {game, _} -> game end)
|> Enum.sum()

Part 2

parsed_input
|> Stream.map(fn {_, reveals} ->
  reveals
  |> Enum.reduce(
    %{"red" => 0, "green" => 0, "blue" => 0},
    fn x, %{"red" => max_r, "green" => max_g, "blue" => max_b} ->
      %{
        "red" => max(max_r, Map.get(x, "red", 0)),
        "green" => max(max_g, Map.get(x, "green", 0)),
        "blue" => max(max_b, Map.get(x, "blue", 0))
      }
    end
  )
end)
|> Stream.map(fn %{"red" => r, "green" => g, "blue" => b} -> r * g * b end)
|> Enum.sum()