Day 9: Rope Bridge
Mix.install([:kino])
input = Kino.Input.textarea("Please paste your input:")
Part 1
https://adventofcode.com/2022/day/9
motions =
input
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.map(fn <> <> " " <> step_str ->
direction =
case direction_str do
"U" -> :up
"D" -> :down
"L" -> :left
"R" -> :right
end
step = step_str |> String.to_integer()
direction |> List.duplicate(step)
end)
|> List.flatten()
defmodule Solver.Part1 do
def run(motions) do
do_run(motions, {{0, 0}, {0, 0}}, [{{0, 0}, {0, 0}}])
|> Enum.reverse()
|> Enum.map(fn {_h_pos, t_pos} -> t_pos end)
|> Enum.uniq()
|> Enum.count()
end
defp do_run([], _pos, visited) do
visited
end
defp do_run([motion | rest_motions], {h_pos, t_pos}, visited) do
new_h_pos = calc_h_pos(h_pos, motion)
new_t_pos = calc_t_pos(new_h_pos, t_pos)
do_run(rest_motions, {new_h_pos, new_t_pos}, [{new_h_pos, new_t_pos} | visited])
end
defp calc_h_pos({x, y}, direction) do
case direction do
:up -> {x + 1, y}
:down -> {x - 1, y}
:left -> {x, y - 1}
:right -> {x, y + 1}
end
end
defp calc_t_pos({h_x, h_y}, {t_x, t_y}) do
case {h_x - t_x, h_y - t_y} do
{x, _} when x >= 2 -> {h_x - 1, h_y}
{x, _} when x <= -2 -> {h_x + 1, h_y}
{_, y} when y >= 2 -> {h_x, h_y - 1}
{_, y} when y <= -2 -> {h_x, h_y + 1}
_ -> {t_x, t_y}
end
end
end
Solver.Part1.run(motions)
Part 2
https://adventofcode.com/2022/day/9#part2
defmodule Solver.Part2 do
@knot_count 10
def run(motions) do
init_poss = {0, 0} |> List.duplicate(@knot_count)
do_run(motions, init_poss, [init_poss])
|> Enum.reverse()
|> Enum.map(fn poss -> poss |> List.last() end)
|> Enum.uniq()
|> Enum.count()
end
defp do_run([], _poss, visited) do
visited
end
defp do_run([motion | rest_motions], poss, visited) do
new_poss = calc_new_poss(poss, motion)
do_run(rest_motions, new_poss, [new_poss | visited])
end
defp calc_new_poss([h_pos | rest_poss], motion) do
new_h_pos = calc_new_pos(motion, h_pos)
rest_poss
|> Enum.reduce([new_h_pos], fn pos, [prev_pos | _] = new_poss ->
new_pos = calc_new_pos(prev_pos, pos)
[new_pos | new_poss]
end)
|> Enum.reverse()
end
defp calc_new_pos(direction, {x, y}) when is_atom(direction) do
case direction do
:up -> {x, y + 1}
:down -> {x, y - 1}
:left -> {x - 1, y}
:right -> {x + 1, y}
end
end
defp calc_new_pos({h_x, h_y}, {t_x, t_y}) do
case {h_x - t_x, h_y - t_y} do
{2, 2} -> {h_x - 1, h_y - 1}
{-2, 2} -> {h_x + 1, h_y - 1}
{2, -2} -> {h_x - 1, h_y + 1}
{-2, -2} -> {h_x + 1, h_y + 1}
{2, _} -> {h_x - 1, h_y}
{-2, _} -> {h_x + 1, h_y}
{_, 2} -> {h_x, h_y - 1}
{_, -2} -> {h_x, h_y + 1}
_ -> {t_x, t_y}
end
end
end
Solver.Part2.run(motions)