diff --git a/lib/aoc2024/day_07.ex b/lib/aoc2024/day_07.ex index 86fc534..247306b 100644 --- a/lib/aoc2024/day_07.ex +++ b/lib/aoc2024/day_07.ex @@ -1,13 +1,65 @@ defmodule Aoc2024.Day07 do def parse(input) do - input |> String.split("\n", trim: true) + input + |> String.split("\n", trim: true) + |> Enum.map(fn x -> x |> String.split(": ") |> Enum.into([]) end) + |> Enum.map(fn [x, y] -> {String.to_integer(x), y |> String.split(" ") |> Enum.map(&String.to_integer/1)} end) + |> Enum.into([]) end - def part1(_lines) do - :todo1 + def part1(input) do + input + |> Enum.map(fn {target, numbers} -> Task.async(fn -> compute(target, numbers) end) end) + |> Enum.map(&Task.await/1) + |> Enum.filter(&Kernel.is_integer/1) + |> Enum.sum() end - def part2(_lines) do - :todo2 + defp compute(target, numbers), do: compute(target, Enum.reverse(numbers), target) + defp compute(_, _, current) when current < 0, do: nil + defp compute(target, [], 0), do: target + defp compute(_, _, 0), do: nil + defp compute(_, [], _), do: nil + defp compute(target, [x | numbers], current) do + if rem(current, x) == 0 do + if compute(target, numbers, div(current, x)) == target do + target + else + compute(target, numbers, current - x) + end + else + compute(target, numbers, current - x) + end + end + + + + def part2(input) do + input + |> Enum.map(fn {target, numbers} -> Task.async(fn -> compute2(target, numbers) end) end) + |> Enum.map(&Task.await/1) + |> Enum.filter(&Kernel.is_integer/1) + |> Enum.sum() + end + + defp compute2(target, numbers), do: compute2(target, Enum.reverse(numbers), target) + defp compute2(_, _, current) when current < 0, do: nil + defp compute2(target, [], 0), do: target + defp compute2(_, _, 0), do: nil + defp compute2(_, [], _), do: nil + defp compute2(target, [x | numbers], current) do + s_c = current |> Integer.to_string() + s_x = x |> Integer.to_string() + nc = s_c |> String.replace_suffix(s_x, "") + cond do + s_c |> String.ends_with?(s_x) + and nc != "" + and compute2(target, numbers, nc |> String.to_integer()) == target -> + target + rem(current, x) == 0 and compute2(target, numbers, div(current, x)) == target -> + target + true -> + compute2(target, numbers, current - x) + end end end diff --git a/lib/aoc2024/day_08.ex b/lib/aoc2024/day_08.ex index ef8e35f..22226ea 100644 --- a/lib/aoc2024/day_08.ex +++ b/lib/aoc2024/day_08.ex @@ -1,13 +1,80 @@ defmodule Aoc2024.Day08 do def parse(input) do - input |> String.split("\n", trim: true) + input = input |> String.trim() |> String.split("\n") |> Enum.map(&String.codepoints/1) + w = Enum.count(Enum.at(input, 0)) + h = Enum.count(input) + + input = + walk(input, w, h) + |> Enum.reduce(%{}, fn {x, i, j}, m -> + if Map.has_key?(m, x) do + %{m | x => [{i, j} | m[x]]} + else + Map.put(m, x, [{i, j}]) + end + end) + + {input, w, h} end - def part1(_lines) do - :todo1 + defp walk(t, w, h), do: walk(t, 0, 0, w, h, []) + defp walk(_t, i, _j, _w, h, towers) when i == h, do: towers + defp walk(t, i, j, w, h, towers) when j == w, do: walk(t, i + 1, 0, w, h, towers) + + defp walk(t, i, j, w, h, towers) do + case t |> Enum.at(i) |> Enum.at(j) do + "." -> walk(t, i, j + 1, w, h, towers) + x -> walk(t, i, j + 1, w, h, [{x, i, j} | towers]) + end end - def part2(_lines) do - :todo2 + def part1({input, w, h}) do + for {_x, all} <- input do + Task.async(fn -> comb(&antinodes/4, all) end) + end + |> Enum.map(&Task.await/1) + |> List.flatten() + |> Enum.into(MapSet.new()) + |> Enum.filter(fn {i, j} -> i >= 0 and j >= 0 and i < h and j < w end) + |> Enum.count() + end + + defp comb(antinodes, [current | others]), do: comb(antinodes, others, current, others, []) + defp comb(_antinodes, [_], _, [], res), do: res + + defp comb(antinodes, [current | others], _, [], res), + do: comb(antinodes, others, current, others, res) + + defp comb(antinodes, others, {i1, j1} = current, [{i2, j2} | tail], res) do + comb(antinodes, others, current, tail, [antinodes.(i1, j1, i2, j2) | res]) + end + + defp antinodes(i1, j1, i2, j2) do + di = i2 - i1 + dj = j2 - j1 + [{i1 - di, j1 - dj}, {i2 + di, j2 + dj}] + end + + def part2({input, w, h}) do + for {_x, all} <- input do + Task.async(fn -> comb(fn i1, j1, i2, j2 -> antinodes2(w, h, i1, j1, i2, j2) end, all) end) + end + |> Enum.map(&Task.await/1) + |> List.flatten() + |> Enum.into(MapSet.new()) + |> Enum.count() + end + + defp antinodes2(w, h, i1, j1, i2, j2) do + di = i2 - i1 + dj = j2 - j1 + + Stream.iterate({i1, j1}, fn {i, j} -> {i + di, j + dj} end) + |> Stream.take_while(fn {i, j} -> i >= 0 and j >= 0 and i < h and j < w end) + |> Stream.concat( + Stream.iterate({i2, j2}, fn {i, j} -> {i - di, j - dj} end) + |> Stream.take_while(fn {i, j} -> i >= 0 and j >= 0 and i < h and j < w end) + ) + |> Enum.into([]) end end diff --git a/test/day08_test.exs b/test/day08_test.exs new file mode 100644 index 0000000..e3a2f7e --- /dev/null +++ b/test/day08_test.exs @@ -0,0 +1,6 @@ +defmodule TestDay08 do + use ExUnit.Case + + test "name" do + end +end