···
{dir, String.to_integer(steps)}
42
+
|> Enum.flat_map(fn {dir, steps} -> List.duplicate(dir, steps) end)
<!-- livebook:{"output":true} -->
48
+
["L", "R", "L", "U", "R", "R", "U", "D", "D", "R", "R", "U", "D", "D", "U", "U", "L", "L", "D", "U",
49
+
"D", "D", "L", "L", "D", "L", "L", "D", "D", "L", "U", "U", "R", "R", "L", "D", "D", "L", "L", "R",
50
+
"R", "D", "D", "L", "U", "R", "U", "L", "D", "R", ...]
55
+
@enforce_keys [:segments]
56
+
defstruct [:segments]
106
-
defstruct segments: [%{x: 0, y: 0}, %{x: 0, y: 0}]
do: %__MODULE__{segments: List.duplicate(@start, length + 1)}
63
+
def run(rope, moves) do
64
+
{_rope, tail_positions} =
65
+
Enum.reduce(moves, {rope, MapSet.new([Rope.last(rope)])}, fn dir, {rope, acc} ->
66
+
new_rope = Rope.move(rope, dir)
68
+
{new_rope, MapSet.put(acc, Rope.last(new_rope))}
71
+
MapSet.size(tail_positions)
def last(%__MODULE__{segments: list}), do: List.last(list)
def move(%__MODULE__{segments: [%{x: x, y: y} | tails]}, dir) do
116
-
"U" -> %{x: x + 1, y: y}
117
-
"D" -> %{x: x - 1, y: y}
118
-
"L" -> %{x: x, y: y + 1}
119
-
"R" -> %{x: x, y: y - 1}
79
+
"L" -> %{x: x + 1, y: y}
80
+
"R" -> %{x: x - 1, y: y}
81
+
"U" -> %{x: x, y: y + 1}
82
+
"D" -> %{x: x, y: y - 1}
122
-
segments = move_tails([head | tails])
124
-
%__MODULE__{segments: segments}
85
+
%__MODULE__{segments: move_tails([head | tails])}
defp move_tails([]), do: []
···
when abs(head.x - tail.x) < 2 and abs(head.y - tail.y) < 2,
135
-
defp move_tails([head, tail | rest])
136
-
when abs(head.y - tail.y) < 2,
137
-
do: [head | move_tails([%{x: head.x - sgn(head.x - tail.x), y: head.y} | rest])]
139
-
defp move_tails([head, tail | rest])
140
-
when abs(head.x - tail.x) < 2,
141
-
do: [head | move_tails([%{x: head.x, y: head.y - sgn(head.y - tail.y)} | rest])]
143
-
defp move_tails([head, tail | rest]),
146
-
| move_tails([%{x: head.x - sgn(head.x - tail.x), y: head.y - sgn(head.y - tail.y)} | rest])
96
+
defp move_tails([head, tail | rest]) do
97
+
{dx, dy} = step(head, tail)
98
+
[head | move_tails([%{x: head.x - dx, y: head.y - dy} | rest])]
def sgn(n) when n < 0, do: -1
105
+
defp step(%{x: x1, y: y1}, %{x: x2, y: y2}) do
106
+
{sgn(div(x1 - x2, 2)), sgn(div(y1 - y2, 2))}
<!-- livebook:{"output":true} -->
158
-
{:module, Rope, <<70, 79, 82, 49, 0, 0, 21, ...>>, {:sgn, 1}}
114
+
{:module, Rope, <<70, 79, 82, 49, 0, 0, 23, ...>>, {:step, 2}}
164
-
{_rope, tail_positions} =
166
-
|> Enum.flat_map(fn {dir, steps} -> List.duplicate(dir, steps) end)
167
-
|> Enum.reduce({rope, MapSet.new([Rope.last(rope)])}, fn dir, {rope, acc} ->
168
-
new_rope = Rope.move(rope, dir)
170
-
{new_rope, MapSet.put(acc, Rope.last(new_rope))}
173
-
MapSet.size(tail_positions)
120
+
Rope.run(Rope.new(1), moves)
<!-- livebook:{"output":true} -->
···
187
-
{_rope, tail_positions} =
189
-
|> Enum.flat_map(fn {dir, steps} -> List.duplicate(dir, steps) end)
190
-
|> Enum.reduce({rope, MapSet.new([Rope.last(rope)])}, fn dir, {rope, acc} ->
191
-
new_rope = Rope.move(rope, dir)
193
-
{new_rope, MapSet.put(acc, Rope.last(new_rope))}
196
-
MapSet.size(tail_positions)
132
+
Rope.run(Rope.new(9), moves)
<!-- livebook:{"output":true} -->