Skip to content

Instantly share code, notes, and snippets.

@mkreyman
Created February 14, 2018 21:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mkreyman/81fc4a6139af20a1ca5d94618ea4738f to your computer and use it in GitHub Desktop.
Save mkreyman/81fc4a6139af20a1ca5d94618ea4738f to your computer and use it in GitHub Desktop.
Spiral traversal of a list of coordinates
# See https://gist.github.com/mkreyman/1891aaa70e41a3519a7487e7742a5eda
# for a spiral traversal of a matrix.
#
# coordinates =
# [
# {0, 0},
# {1, 0},
# {2, 0},
# {3, 0},
# {0, -1},
# {1, -1},
# {2, -1},
# {3, -1},
# {0, -2},
# {1, -2},
# {2, -2},
# {3, -2},
# {0, -3},
# {1, -3},
# {2, -3},
# {3, -3}
# ]
#
# iex(2)> Spiral.traverse(coordinates, [])
# [
# {0, 0},
# {1, 0},
# {2, 0},
# {3, 0},
# {3, -1},
# {3, -2},
# {3, -3},
# {2, -3},
# {1, -3},
# {0, -3},
# {0, -2},
# {0, -1},
# {1, -1},
# {2, -1},
# {2, -2},
# {1, -2}
# ]
defmodule Spiral do
def traverse([], traversed), do: Enum.reverse(traversed)
def traverse([head|[]], traversed) do
traversed = [head | traversed]
traverse([], traversed)
end
def traverse(coordinates, traversed) do
a = anchor(coordinates)
l = l(coordinates)
h = h(coordinates)
{filtered, coordinates} = Enum.split_with(coordinates, &(eastward?(&1, a, l, h)))
filtered = filtered |> Enum.reverse()
traversed = [filtered | traversed] |> List.flatten()
{filtered, coordinates} = Enum.split_with(coordinates, &(southward?(&1, a, l, h)))
filtered = filtered |> Enum.reverse()
traversed = [filtered | traversed] |> List.flatten
{filtered, coordinates} = Enum.split_with(coordinates, &(westward?(&1, a, l, h)))
traversed = [filtered | traversed] |> List.flatten()
{filtered, coordinates} = Enum.split_with(coordinates, &(northward?(&1, a, l, h)))
traversed = [filtered | traversed] |> List.flatten()
traverse(coordinates, traversed)
end
defp anchor(coordinates) do
coordinates
|> Enum.sort_by(fn({x, y}) -> {x,-y} end)
|> Enum.at(0)
end
defp eastward?({x, y}, {start_x, start_y}, _l, _h) do
x >= start_x and y == start_y
end
defp southward?({x, y}, {_, start_y}, l, _h) do
x == l and y < start_y
end
defp westward?({x, y}, _, l, h) do
x < l and y == h
end
defp northward?({x, y}, {start_x, _}, _l, h) do
x == start_x and y > h
end
defp l(coordinates) do
with {length, _} <- Enum.max_by(coordinates, fn({x,_}) -> x end), do: length
end
defp h(coordinates) do
with {_, height} <- Enum.min_by(coordinates, fn({_,y}) -> y end), do: height
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment