advent_of_code/lib/day9.ex
2023-11-11 12:26:23 -05:00

98 lines
2.1 KiB
Elixir

defmodule Day9 do
def init_state(p) when p == :part1 do
{ [ {0,0}, {0,0} ], MapSet.new() }
end
def init_state(p) when p == :part2 do
{ [ {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}], MapSet.new() }
end
def execute(line, state) when line == "" do
state
end
def execute(line, state) do
[ movement, count] = line |> String.split(" ");
{ count, _ } = Integer.parse(count);
Enum.reduce(
1..count,
state,
fn (_, state) ->
{ rope, tail_positions } = state
rope = movement
|> string_to_movement_direction()
|> move_rope_by_head(rope)
{ rope, MapSet.put(tail_positions, List.last(rope)) }
end
);
end
def get_answer(state) do
{_, tail_positions } = state
MapSet.size(tail_positions)
end
defp move_rope_by_head(direction, rope) do
[head | tail ] = rope
reconcile_tail([add_2_tuple(head, direction)], tail)
end
defp reconcile_tail(_, tail) when tail == [] do
tail
end
defp reconcile_tail(head, tail) do
leader = head |> List.last()
[ follower | tail ] = tail
reconcile_tail(head ++ [keep_min_distance(follower, leader, 1)], tail)
end
defp keep_min_distance(tail, head, min_distance) do
difference = distance_vector(tail, head)
if max_coord_difference(tail, head) <= min_distance do
tail
else
{a, b} = difference
add_2_tuple(tail, {megan(a, 0, -1, 1), megan(b, 0, -1, 1)})
end
end
defp megan(x, _, _, pos) when x > 0 do
pos
end
defp megan(x, _, neg, _) when x < 0 do
neg
end
defp megan(0, zero, _, _) do
zero
end
defp string_to_movement_direction(direction) do
case direction do
"R" -> {1, 0}
"L" -> {-1, 0}
"U" -> {0, 1}
"D" -> {0, -1}
end
end
defp add_2_tuple(x, y) do
{ elem(x,0) + elem(y,0), elem(x,1) + elem(y,1) }
end
defp distance_vector(x, y) do
{ elem(y,0) - elem(x,0), elem(y,1) - elem(x,1) }
end
defp max_coord_difference(x, y) do
{a, b} = { abs(elem(x,0)-elem(y,0)), abs(elem(x,1)-elem(y,1)) }
max(a, b)
end
end