Skip to content

Instantly share code, notes, and snippets.

@Jwsonic
Created October 1, 2019 19:38
Show Gist options
  • Select an option

  • Save Jwsonic/15d2a8ddc9ebb39f703ac979de325b44 to your computer and use it in GitHub Desktop.

Select an option

Save Jwsonic/15d2a8ddc9ebb39f703ac979de325b44 to your computer and use it in GitHub Desktop.

Revisions

  1. Jwsonic created this gist Oct 1, 2019.
    80 changes: 80 additions & 0 deletions spiral.ex
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,80 @@
    defmodule Spiral do
    def order(matrix) do
    bounds = %{
    xmin: 0,
    xmax: matrix |> hd() |> length(),
    ymin: 0,
    ymax: length(matrix)
    }

    matrix |> next({0, 0}, {1, 0}, bounds, []) |> Enum.reverse()
    end

    # Guard clause that checks if we've reached the center of the matrix
    defguardp is_center?(x, y, matrix)
    when matrix |> hd() |> length() |> div(2) |> floor() == x and
    matrix |> length() |> div(2) |> floor() == y

    # We've reached the center, add it to the result and we're done
    defp next(matrix, {x, y}, _direction, _bounds, result) when is_center?(x, y, matrix) do
    [get(matrix, x, y) | result]
    end

    # When we get to the right edge, start moving downwards
    defp next(matrix, {x, y}, _direction, %{xmax: xmax, ymin: ymin} = bounds, result)
    when x >= xmax do
    next(matrix, {x - 1, y + 1}, {0, 1}, %{bounds | ymin: ymin + 1}, result)
    end

    # When we get to the bottom edge, start moving left
    defp next(matrix, {x, y}, _direction, %{ymax: ymax, xmax: xmax} = bounds, result)
    when y >= ymax do
    next(matrix, {x - 1, y - 1}, {-1, 0}, %{bounds | xmax: xmax - 1}, result)
    end

    # When we get to the left edge, start moving up
    defp next(matrix, {x, y}, _direction, %{xmin: xmin, ymax: ymax} = bounds, result)
    when x < xmin do
    next(matrix, {x + 1, y - 1}, {0, -1}, %{bounds | ymax: ymax - 1}, result)
    end

    # When we get to the top edge, start moving right
    defp next(matrix, {x, y}, _direction, %{ymin: ymin, xmin: xmin} = bounds, result)
    when y < ymin do
    next(matrix, {x + 1, y + 1}, {1, 0}, %{bounds | xmin: xmin + 1}, result)
    end

    # Process other cells normally
    defp next(matrix, {x, y}, {dx, dy} = direction, bounds, result) do
    next(matrix, {x + dx, y + dy}, direction, bounds, [get(matrix, x, y) | result])
    end

    # Returns the matrix element at (x, y)
    defp get(matrix, x, y), do: matrix |> Enum.at(y) |> Enum.at(x)
    end

    l = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
    ]

    IO.puts("Input: [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
    ]")
    IO.puts("Output: #{l |> Spiral.order() |> inspect()}")

    l = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12]
    ]

    IO.puts("Input: [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12]
    ]")
    IO.puts("Output: #{l |> Spiral.order() |> inspect()}")