Advent of Code - Day 2
Mix.install([
{:kino_aoc, "~> 0.1"}
])
Introduction
–> Content
Puzzle
{:ok, puzzle_input} =
KinoAOC.download_puzzle("2023", "2", System.fetch_env!("LB_AOC_SESSION"))
Parser
Code - Parser
defmodule Parser do
def parse(input) do
end
end
Tests - Parser
ExUnit.start(autorun: false)
defmodule ParserTest do
use ExUnit.Case, async: true
import Parser
@input ""
@expected nil
test "parse test" do
actual = parse(@input)
assert actual == @expected
end
end
ExUnit.run()
Part One
Code - Part 1
defmodule PartOne do
def solve(input) do
IO.puts("--- Part One ---")
IO.puts("Result: #{run(input)}")
end
def run(input) do
input
|> String.split("\n", trim: true)
|> Enum.map(fn game_string ->
game_hash = input_to_hash(game_string)
IO.inspect(game_string)
IO.inspect(game_hash)
if possible?(game_hash) do
IO.puts(game_id(game_string))
IO.puts("")
game_id(game_string)
else
IO.puts("")
0
end
end)
|> Enum.sum()
end
defp input_to_hash(game_string) do
%{
red: counts_of(game_string, "red"),
green: counts_of(game_string, "green"),
blue: counts_of(game_string, "blue")
}
end
defp counts_of(game_string, color) do
Regex.scan(~r/(\d+) #{color}/, game_string)
|> Enum.map(fn matches ->
Enum.at(matches, 1) |> String.to_integer()
end)
end
defp possible?(bag, red \\ 12, green \\ 13, blue \\ 14) do
Enum.all?(bag[:red], &(&1 <= red)) &&
Enum.all?(bag[:green], &(&1 <= green)) &&
Enum.all?(bag[:blue], &(&1 <= blue))
end
defp game_id(game_string) do
Regex.run(~r/Game (\d+):/, game_string)
|> List.last()
|> String.to_integer()
end
end
Tests - Part 1
ExUnit.start(autorun: false)
defmodule PartOneTest do
use ExUnit.Case, async: true
import PartOne
@input """
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
"""
@expected 8
test "simple example" do
actual = run(@input)
assert actual == @expected
end
end
ExUnit.run()
Solution - Part 1
PartOne.solve(puzzle_input)
Part Two
Code - Part 2
defmodule PartTwo do
def solve(input) do
IO.puts("--- Part Two ---")
IO.puts("Result: #{run(input)}")
end
def run(input) do
input
|> String.split("\n", trim: true)
|> Enum.map(fn game_string ->
game_hash = input_to_hash(game_string)
Map.values(game_hash) |> Enum.product()
end)
|> Enum.sum()
end
defp input_to_hash(game_string) do
%{
red: minimum_bag_count_for(game_string, "red"),
green: minimum_bag_count_for(game_string, "green"),
blue: minimum_bag_count_for(game_string, "blue")
}
end
defp minimum_bag_count_for(game_string, color) do
counts_of(game_string, color) |> Enum.max() || 0
end
defp counts_of(game_string, color) do
Regex.scan(~r/(\d+) #{color}/, game_string)
|> Enum.map(fn matches ->
Enum.at(matches, 1) |> String.to_integer()
end)
end
end
Tests - Part 2
ExUnit.start(autorun: false)
defmodule PartTwoTest do
use ExUnit.Case, async: true
import PartTwo
@input """
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
"""
@expected 2286
test "simple example" do
actual = run(@input)
assert actual == @expected
end
end
ExUnit.run()
Solution - Part 2
PartTwo.solve(puzzle_input)