Skip to content

Commit 2cef13a

Browse files
committed
Day 02: Gift Shop
1 parent e6ab77e commit 2cef13a

File tree

9 files changed

+184
-0
lines changed

9 files changed

+184
-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 GiftShop.Benchmark do
2+
def jobs do
3+
input = File.read!(Path.join(__DIR__, "../input/puzzle_input.txt"))
4+
5+
%{
6+
"day02.gift_shop.invalid_id_sum" => fn -> GiftShop.invalid_id_sum(input) end,
7+
"day02.gift_shop.extended_invalid_id_sum" => fn -> GiftShop.extended_invalid_id_sum(input) end
8+
}
9+
end
10+
end
11+
12+
if System.get_env("AOC_COMBINED_BENCHMARK") do
13+
GiftShop.Benchmark.jobs()
14+
else
15+
Benchee.run(
16+
GiftShop.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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124
480 Bytes
Binary file not shown.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
defmodule GiftShop.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("Invalid ID sum (2-fold repetition): #{GiftShop.invalid_id_sum(input)}")
24+
25+
IO.puts(
26+
"Invalid ID sum (n-fold repetition, n >= 2): #{GiftShop.extended_invalid_id_sum(input)}"
27+
)
28+
end
29+
end
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
defmodule GiftShop do
2+
@doc """
3+
Sum up all invalid gift IDs that are made of a 2-fold repetition of a number.
4+
"""
5+
def invalid_id_sum(input) do
6+
input
7+
|> String.split(",")
8+
|> Enum.map(&String.split(&1, "-"))
9+
|> Enum.map(fn [a, b] ->
10+
invalid_ids_in_range(String.to_integer(a), String.to_integer(b), 2)
11+
end)
12+
|> List.flatten()
13+
|> Enum.sum()
14+
end
15+
16+
@doc """
17+
Sum up all invalid gift IDs that are made of a n-fold repetition of a number, for n >= 2.
18+
"""
19+
def extended_invalid_id_sum(input) do
20+
input
21+
|> String.split(",")
22+
|> Enum.map(&String.split(&1, "-"))
23+
|> Enum.map(fn [a, b] ->
24+
Enum.map(2..length(Integer.digits(String.to_integer(b))), fn repeats ->
25+
invalid_ids_in_range(String.to_integer(a), String.to_integer(b), repeats)
26+
end)
27+
end)
28+
|> List.flatten()
29+
|> Enum.uniq()
30+
|> Enum.sum()
31+
end
32+
33+
# Get all invalid IDs in the range [a, b] that are made of `repeats`-fold repetition of a number.
34+
defp invalid_ids_in_range(a, b, repeats) do
35+
Enum.map(
36+
first_number_part(a, repeats, :floor)..first_number_part(b, repeats, :ceil),
37+
fn num ->
38+
num |> Integer.digits() |> List.duplicate(repeats) |> List.flatten() |> Integer.undigits()
39+
end
40+
)
41+
|> Enum.filter(fn num -> num >= a and num <= b end)
42+
end
43+
44+
# Get the first part of the number when split into `repeats` parts.
45+
defp first_number_part(num, repeats, rounding) do
46+
digits = Integer.digits(num)
47+
48+
split_point =
49+
case rounding do
50+
:floor -> floor(length(digits) / repeats)
51+
:ceil -> ceil(length(digits) / repeats)
52+
end
53+
54+
digits
55+
|> Enum.split(split_point)
56+
|> elem(0)
57+
|> Integer.undigits()
58+
end
59+
end

2025/apps/day02_gift_shop/mix.exs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
defmodule GiftShop.MixProject do
2+
use Mix.Project
3+
4+
def project do
5+
[
6+
app: :day02_gift_shop,
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: GiftShop.CLI, path: "../../_build/bin/gift_shop"],
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/gift_shop -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/gift_shop #{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 GiftShopTest do
2+
use ExUnit.Case
3+
doctest GiftShop
4+
5+
test "invalid_id_sum" do
6+
input = File.read!("input/example_input.txt")
7+
assert GiftShop.invalid_id_sum(input) == 1_227_775_554
8+
end
9+
10+
test "extended_invalid_id_sum" do
11+
input = File.read!("input/example_input.txt")
12+
assert GiftShop.extended_invalid_id_sum(input) == 4_174_379_265
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)