diff --git a/2022-elixir/lib/solutions/day_09.ex b/2022-elixir/lib/solutions/day_09.ex new file mode 100644 index 0000000..7a593c1 --- /dev/null +++ b/2022-elixir/lib/solutions/day_09.ex @@ -0,0 +1,113 @@ +defmodule Aoc.Solution.Day09 do + import Aoc.Utils + + @name "Day 9: Rope Bridge" + @behaviour Solution + + @impl Solution + def get_name, do: @name + + @impl Solution + def present(solution), do: "The rope tail visits #{solution} positions at least once" + + @impl Solution + def present_again(solution), do: "Solution is #{solution}" + + @impl Solution + def parse!(raw) do + raw |> split_lines() + end + + @impl Solution + def solve(motions) do + motions + |> move() + |> visited() + end + + @impl Solution + def solve_again(_input) do + "(TBW)" + end + + def move(motions) when is_list(motions) do + {_h, _t, seen} = Enum.reduce(motions, {{0, 0}, {0, 0}, MapSet.new()}, &move/2) + + seen + end + + def move("R " <> steps, acc) do + change = {0, String.to_integer(steps)} + {h, t, seen} = acc + {y, x} = h + + {y, x + String.to_integer(steps)} + |> follow(change, t, seen) + end + + def move("L " <> steps, acc) do + change = {0, 0 - String.to_integer(steps)} + {h, t, seen} = acc + {y, x} = h + + {y, x - String.to_integer(steps)} + |> follow(change, t, seen) + end + + def move("U " <> steps, acc) do + change = {String.to_integer(steps), 0} + {h, t, seen} = acc + {y, x} = h + + {y + String.to_integer(steps), x} + |> follow(change, t, seen) + end + + def move("D " <> steps, acc) do + change = {0 - String.to_integer(steps), 0} + {h, t, seen} = acc + {y, x} = h + + {y - String.to_integer(steps), x} + |> follow(change, t, seen) + end + + def follow(h = {y2, x2}, _change, t = {y1, x1}, seen) when y2 == y1 and x2 == x1 do + {h, t, MapSet.put(seen, t)} + end + + def follow(h = {_yH, xH}, {change, 0}, {y, _x}, seen) when change > 2 do + pos = {y + change - 1, xH} + {h, pos, MapSet.put(seen, pos)} + end + + def follow(h = {_yH, xH}, {change, 0}, {y, _x}, seen) when change < -2 do + pos = {y + change + 1, xH} + {h, pos, MapSet.put(seen, pos)} + end + + def follow(h = {yH, _xH}, {0, change}, {_y, x}, seen) when change > 2 do + pos = {yH, x + change - 1} + {h, pos, MapSet.put(seen, pos)} + end + + def follow(h = {yH, _xH}, {0, change}, {_y, x}, seen) when change < -2 do + pos = {yH, x + change + 1} + {h, pos, MapSet.put(seen, pos)} + end + + def follow(h = {y2, x2}, _change, t = {y1, x1}, seen) do + pos = + case {abs(abs(y2) - abs(y1)), abs(abs(x2) - abs(x1))} do + {1, 1} -> t + {1, 0} -> t + {0, 1} -> t + end + + {h, pos, MapSet.put(seen, pos)} + end + + def visited(positions) do + MapSet.size(positions) + end +end diff --git a/2022-elixir/test/solutions/day_09_test.exs b/2022-elixir/test/solutions/day_09_test.exs new file mode 100644 index 0000000..f7425cc --- /dev/null +++ b/2022-elixir/test/solutions/day_09_test.exs @@ -0,0 +1,33 @@ +defmodule Day09Test do + use ExUnit.Case + doctest Aoc.Solution.Day09 + import Aoc.Solution.Day09 + + @input ~s( +R 4 +U 4 +L 3 +D 1 +R 4 +D 1 +L 5 +R 2 + ) + + @tag :skip + test "09: Rope Bridge, part 1" do + expected = 13 + + result = @input |> parse!() |> solve() + + assert result == expected + end + + # test "09: Rope Bridge, part 2" do + # expected = :something + + # result = @input |> parse!() |> solve_again() + + # assert result == expected + # end +end