Day 02
Mix.install([
{:kino_aoc, "~> 0.1"},
{:nimble_parsec, "~> 1.4"}
])
Input
{:ok, raw_input} =
KinoAOC.download_puzzle("2023", "2", System.fetch_env!("LB_AOC_SESSION"))
defmodule Parser do
import NimbleParsec
@prefix ignore(string("Game"))
|> ignore(string(" "))
|> integer(min: 1)
|> ignore(string(":"))
|> unwrap_and_tag(:game_number)
@color choice([
string("blue") |> replace(:BLUE),
string("red") |> replace(:RED),
string("green") |> replace(:GREEN)
])
@cube optional(ignore(string(" ")))
|> integer(min: 1)
|> ignore(string(" "))
|> concat(@color)
|> wrap
|> map({List, :to_tuple, []})
@draw @cube
|> repeat(
concat(
ignore(string(", ")),
@cube
),
min: 0
)
|> wrap
@draws @draw
|> repeat(
concat(
ignore(string(";")),
@draw
),
min: 0
)
|> tag(:draws)
@game @prefix |> concat(@draws)
defparsec(:parse_line, @game)
def parse(input) do
input
|> String.split("\n", trim: true)
|> Enum.map(&__MODULE__.parse_line/1)
|> Enum.map(&elem(&1, 1))
end
end
input = Parser.parse(raw_input)
input_example =
Parser.parse("""
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
""")
Part 1
defmodule Part1 do
def find_largest(game) do
game
|> Keyword.fetch!(:draws)
|> List.flatten()
|> Enum.group_by(&elem(&1, 1), &elem(&1, 0))
|> Enum.map(fn {key, val} ->
{key, Enum.max(val)}
end)
|> Enum.into(%{})
end
def is_possible(game, max \\ %{RED: 12, GREEN: 13, BLUE: 14}) do
largest = find_largest(game)
largest[:RED] <= max[:RED] and
largest[:GREEN] <= max[:GREEN] and
largest[:BLUE] <= max[:BLUE]
end
def calculate(input) do
input
|> Enum.filter(&is_possible(&1))
|> Enum.map(&Keyword.fetch!(&1, :game_number))
|> Enum.sum()
end
end
Part1.calculate(input_example)
Part1.calculate(input)
Part 2
defmodule Part2 do
def calculate_power(largest) do
largest[:RED] * largest[:GREEN] * largest[:BLUE]
end
def calculate(input) do
input
|> Enum.map(&Part1.find_largest/1)
|> Enum.map(&calculate_power/1)
|> Enum.sum()
end
end
Part2.calculate(input_example)
Part2.calculate(input)