Skip to content

Commit 654bb37

Browse files
committed
Day 05: Cafeteria
1 parent e861917 commit 654bb37

File tree

9 files changed

+194
-0
lines changed

9 files changed

+194
-0
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Used by "mix format"
2+
[
3+
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
4+
]
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
defmodule Cafeteria.Benchmark do
2+
def jobs do
3+
input = File.read!(Path.join(__DIR__, "../input/puzzle_input.txt"))
4+
5+
%{
6+
"day05.cafeteria.fresh_ingredients" => fn -> Cafeteria.fresh_ingredients(input) end,
7+
"day05.cafeteria.all_fresh_ingredient_ids" => fn -> Cafeteria.all_fresh_ingredient_ids(input) end
8+
}
9+
end
10+
end
11+
12+
if System.get_env("AOC_COMBINED_BENCHMARK") do
13+
Cafeteria.Benchmark.jobs()
14+
else
15+
Benchee.run(
16+
Cafeteria.Benchmark.jobs(),
17+
print: [fast_warning: false],
18+
formatters: [{Benchee.Formatters.Console, extended_statistics: true}],
19+
warmup: 1,
20+
time: 2,
21+
memory_time: 2,
22+
reduction_time: 2
23+
)
24+
end
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
3-5
2+
10-14
3+
16-20
4+
12-18
5+
6+
1
7+
5
8+
8
9+
11
10+
17
11+
32
22.3 KB
Binary file not shown.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
defmodule Cafeteria do
2+
@doc """
3+
Check how many ingredient IDs are considered fresh based on the provided ranges.
4+
"""
5+
def fresh_ingredients(input) do
6+
[range_section, id_section] = input |> String.split(["\r\n\r\n", "\n\n"], trim: true)
7+
8+
id_ranges =
9+
range_section
10+
|> String.split(["\r\n", "\n"], trim: true)
11+
|> Enum.map(fn range ->
12+
[min, max] = range |> String.split("-", trim: true) |> Enum.map(&String.to_integer/1)
13+
{min, max}
14+
end)
15+
16+
ids =
17+
id_section
18+
|> String.split(["\r\n", "\n"], trim: true)
19+
|> Enum.map(&String.to_integer/1)
20+
21+
Enum.filter(ids, fn id ->
22+
Enum.any?(id_ranges, fn {min, max} -> id >= min and id <= max end)
23+
end)
24+
|> Enum.count()
25+
end
26+
27+
@doc """
28+
Calculate the total number of unique fresh ingredient IDs based on the provided ranges.
29+
"""
30+
def all_fresh_ingredient_ids(input) do
31+
[range_section, _] = input |> String.split(["\r\n\r\n", "\n\n"], trim: true)
32+
33+
id_ranges =
34+
range_section
35+
|> String.split(["\r\n", "\n"], trim: true)
36+
|> Enum.map(fn range ->
37+
[min, max] = range |> String.split("-", trim: true) |> Enum.map(&String.to_integer/1)
38+
{min, max}
39+
end)
40+
41+
merge_ranges(id_ranges)
42+
|> Enum.reduce(0, fn {min, max}, acc -> acc + (max - min + 1) end)
43+
end
44+
45+
# Merge all overlapping ranges
46+
defp merge_ranges(ranges) do
47+
ranges
48+
|> Enum.sort_by(fn {min, _max} -> min end)
49+
|> Enum.reduce([], fn
50+
{min, max}, [] ->
51+
[{min, max}]
52+
53+
{min, max}, [{last_min, last_max} | rest] ->
54+
if min <= last_max do
55+
new_max = max(last_max, max)
56+
[{last_min, new_max} | rest]
57+
else
58+
[{min, max}, {last_min, last_max} | rest]
59+
end
60+
end)
61+
end
62+
end
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
defmodule Cafeteria.CLI do
2+
def main(args) do
3+
args |> parse_args |> read_file |> run
4+
end
5+
6+
defp parse_args(args) do
7+
{options, _, _} =
8+
OptionParser.parse(args, switches: [filename: :string], aliases: [f: :filename])
9+
10+
options[:filename]
11+
end
12+
13+
defp read_file(nil) do
14+
IO.puts("Usage: --filename <filename> or -f <filename>")
15+
System.halt(1)
16+
end
17+
18+
defp read_file(filename) do
19+
File.read!(filename)
20+
end
21+
22+
defp run(input) do
23+
IO.puts("Number of fresh ingredients: #{Cafeteria.fresh_ingredients(input)}")
24+
IO.puts("Number of all fresh ingredient IDs: #{Cafeteria.all_fresh_ingredient_ids(input)}")
25+
end
26+
end

2025/apps/day05_cafeteria/mix.exs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
defmodule Cafeteria.MixProject do
2+
use Mix.Project
3+
4+
def project do
5+
[
6+
app: :day05_cafeteria,
7+
version: "0.1.0",
8+
build_path: "../../_build",
9+
deps_path: "../../deps",
10+
lockfile: "../../mix.lock",
11+
elixir: "~> 1.19",
12+
start_permanent: Mix.env() == :prod,
13+
escript: [main_module: Cafeteria.CLI, path: "../../_build/bin/cafeteria"],
14+
deps: deps(),
15+
aliases: aliases()
16+
]
17+
end
18+
19+
# Run "mix help compile.app" to learn about applications.
20+
def application do
21+
[
22+
extra_applications: [:logger]
23+
]
24+
end
25+
26+
# Run "mix help deps" to learn about dependencies.
27+
defp deps do
28+
[
29+
{:benchee, "~> 1.0"},
30+
{:benchee_html, "~> 1.0"},
31+
{:junit_formatter, "~> 3.4", only: [:test]}
32+
]
33+
end
34+
35+
defp aliases do
36+
[
37+
bench: "run #{__DIR__}/benchmarks/puzzle_benchmarks.exs",
38+
exec: [&run_escript_with_args/1],
39+
solve: ["escript.build", &run_escript/1]
40+
]
41+
end
42+
43+
defp run_escript(_) do
44+
Mix.shell().cmd("escript ../../_build/bin/cafeteria -f #{__DIR__}/input/puzzle_input.txt")
45+
end
46+
47+
defp run_escript_with_args(_) do
48+
args = System.argv() |> Enum.join(" ")
49+
Mix.shell().cmd("escript ../../_build/bin/cafeteria #{args}")
50+
end
51+
end
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
defmodule CafeteriaTest do
2+
use ExUnit.Case
3+
doctest Cafeteria
4+
5+
test "fresh_ingredients" do
6+
input = File.read!("input/example_input.txt")
7+
assert Cafeteria.fresh_ingredients(input) == 3
8+
end
9+
10+
test "all_fresh_ingredient_ids" do
11+
input = File.read!("input/example_input.txt")
12+
assert Cafeteria.all_fresh_ingredient_ids(input) == 14
13+
end
14+
end
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ExUnit.configure(formatters: [JUnitFormatter, ExUnit.CLIFormatter])
2+
ExUnit.start()

0 commit comments

Comments
 (0)