Initial release

This commit is contained in:
Aurélien Geron
2024-12-06 19:44:29 +13:00
commit adfaafec83
10 changed files with 1323 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
defmodule Aoc2024.Day01 do
def parse(input) do
numbers =
input
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
line
|> String.split(~r/\s+/)
|> Enum.map(fn int_str ->
case int_str |> Integer.parse() do
{int, ""} -> int
_ -> raise "Invalid integer #{int_str}"
end
end)
end)
numbers
|> Enum.map(&List.to_tuple/1)
|> Enum.unzip()
end
def part1({col0, col1}) do
sorted_col0 = col0 |> Enum.sort()
sorted_col1 = col1 |> Enum.sort()
Enum.zip(sorted_col0, sorted_col1)
|> Enum.map(fn {val0, val1} ->
abs(val0 - val1)
end)
|> Enum.sum()
end
def part2({col0, col1}) do
col0
|> Enum.map(fn val0 ->
count = Enum.count(col1, fn val1 -> val0 == val1 end)
count * val0
end)
|> Enum.sum()
end
end
+89
View File
@@ -0,0 +1,89 @@
defmodule Mix.Tasks.Aoc2024.Run do
use Mix.Task
@shortdoc "Run all the solutions, or just the ones for the given days"
def run(args) do
days =
if args |> Enum.empty?() do
1..25 |> Enum.map(&Integer.to_string/1)
else
args
end
days |> Enum.each(&run_day/1)
end
defp check_and_pad_day(day_str) do
case day_str |> Integer.parse() do
{day, ""} when day >= 1 and day <= 25 ->
IO.puts("---- Day #{day}")
{:ok, day |> Integer.to_string() |> String.pad_leading(2, "0")}
_ ->
{:error, "Invalid day `#{day_str}`"}
end
end
defp load_module(padded_day_str) do
module = Module.concat([Aoc2024, "Day#{padded_day_str}"])
if match?({:module, _}, Code.ensure_loaded(module)) do
{:ok, module}
else
{:error, "Module `#{inspect(module)}` is not defined."}
end
end
defp load_input(padded_day_str) do
file_path = "data/day_#{padded_day_str}.txt"
case File.read(file_path) do
{:ok, content} ->
{:ok, content}
{:error, reason} ->
{:error, "Failed to read #{file_path}: #{reason}"}
end
end
defp parse_input(module, input) do
if function_exported?(module, :parse, 1) do
{:ok, module.parse(input)}
else
{:ok, input}
end
end
defp run_part1(module, parsed) do
if function_exported?(module, :part1, 1) do
result1 = module.part1(parsed)
IO.inspect(result1)
{:ok, true}
else
{:error, "Function `#{inspect(module)}.part1/1` is not defined."}
end
end
defp run_part2(module, parsed) do
if function_exported?(module, :part2, 1) do
result2 = module.part2(parsed)
IO.inspect(result2)
{:ok, true}
else
{:error, "Function `#{inspect(module)}.part2/1` is not defined."}
end
end
defp run_day(day_str) do
with {:ok, padded_day_str} <- check_and_pad_day(day_str),
{:ok, module} <- load_module(padded_day_str),
{:ok, input} <- load_input(padded_day_str),
{:ok, parsed_input} <- parse_input(module, input),
{:ok, _success} <- run_part1(module, parsed_input),
{:ok, _success} <- run_part2(module, parsed_input) do
else
{:error, msg} ->
IO.puts("Error: #{msg}")
end
end
end