advent-of-code/2022-elixir/lib/solutions/day_09.ex

114 lines
2.5 KiB
Elixir
Raw Normal View History

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