Skip to content

Commit

Permalink
2024 day 05 solution ⭐ ⭐
Browse files Browse the repository at this point in the history
  • Loading branch information
wasi0013 committed Dec 5, 2024
1 parent 5347577 commit b4642a7
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 0 deletions.
97 changes: 97 additions & 0 deletions lib/y2024/day_05.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
defmodule Aoc.Y2024.Day05 do
@moduledoc """
Solved https://adventofcode.com/2024/day/5
"""
import Aoc.Helper.IO

def solve_part1(data), do: data |> process(%{}, []) |> sum_correct_order()
def solve_part2(data), do: data |> process(%{}, []) |> sum_incorrect_order()

def sum_correct_order([], _, result), do: result

def sum_correct_order([a | rest], order, result) do
if is_valid?(a, order) do
sum_correct_order(rest, order, result + Enum.at(a, div(length(a), 2)))
else
sum_correct_order(rest, order, result)
end
end

def sum_correct_order({list, order}), do: sum_correct_order(list, order, 0)

def process([], order, ins), do: {ins, order}

def process([[key, value] | data], order, ins),
do: process(data, Map.update(order, key, [value], fn existing -> Enum.sort([value | existing]) end), ins)

def process([a | data], order, ins), do: process(data, order, [a | ins])

def sum_incorrect_order([], _, result), do: result

def sum_incorrect_order([a | rest], order, result) do
if not is_valid?(a, order) do
sum_incorrect_order(rest, order, result + Enum.at(fix_list(a, order), div(length(a), 2)))
else
sum_incorrect_order(rest, order, result)
end
end

def sum_incorrect_order({list, order}), do: sum_incorrect_order(list, order, 0)

def fix_list(list, order) do
if not is_valid?(list, order) do
find_invalid_pair(list, order) |> swap(list) |> fix_list(order)
else
list
end
end
def find_invalid_pair(list, order) do
Enum.reduce_while(list, [], fn num, visited ->
if Map.has_key?(order, num) do
invalid_nums = Map.get(order, num, [])
invalids = Enum.filter(invalid_nums, &(&1 in visited))

if invalids != [] do
{:halt, List.first(invalids) |> then(fn x -> {x, num} end)}
else
{:cont, [num | visited]}
end
else
{:cont, [num | visited]}
end
end)
end

def is_valid?(list, order) do
Enum.reduce_while(list, {[], true}, fn num, {visited, is_valid} ->
if Map.has_key?(order, num) do
restricted = Map.get(order, num, [])

if Enum.any?(restricted, &(&1 in visited)) do
{:halt, {visited, false}}
else
{:cont, {[num | visited], is_valid}}
end
else
{:cont, {[num | visited], is_valid}}
end
end)
|> elem(1)
end

def swap({a, b}, list),
do:
list
|> List.update_at(Enum.find_index(list, fn x -> x == a end), fn _ -> b end)
|> List.update_at(Enum.find_index(list, fn x -> x == b end), fn _ -> a end)

def get_input() do
get_string_input("2024", "05")
|> String.split("\n", trim: true)
|> Enum.map(fn
x -> String.split(x, [",", "|"], trim: true) |> Enum.map(&String.to_integer/1)
end)
end

def solved_status(), do: :solved
end
13 changes: 13 additions & 0 deletions test/y2024/day_05_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
defmodule AocTest.Y2024.Day05Test do
@moduledoc false
use ExUnit.Case, async: true
import Aoc.Y2024.Day05

test "Part 1 is solved" do
assert solve_part1(get_input()) == 4569
end

test "Part 2 is solved" do
assert solve_part2(get_input()) == 6456
end
end

0 comments on commit b4642a7

Please sign in to comment.