DEV Community

Discussion on: Daily Challenge #44 - Mexican Wave

Collapse
 
thepeoplesbourgeois profile image
Josh • Edited

As an Elixir function, including documentation! And a language feature I'm writing about in an upcoming post UPDATE: the post is up!! 😃

defmodule W do
  @doc ~S"""
  Takes in a string, ensures it's downcased, converts it to a charlist,
  and then processes the charlist by subtracting the proper amount from
  the `next` raw byte to arrive at the same capitalized character in the
  ASCII chart. This letter is then inserted into an iodata list in
  between the raw bytes that have already been `waved` through and the
  `rest` of the raw bytes. This iodata list is then converted back to a
  string, which is added to the head of a list of strings that represent
  the in-motion version of the wave. To finalize the in-motion wave, it
  is reversed once the input charlist has been fully processed.

  When `next` is not a lowercase letter, it is added to `waved` without
  adding a new string to `waves`.

  ## Examples

      iex>W.ave("HELLO")
      ["Hello", "hEllo", "heLlo", "helLo", "hellO"]

      iex>W.ave("hello world!")
      ["Hello world!", "hEllo world!", "heLlo world!", "helLo world!", "hellO world!",
       "hello World!", "hello wOrld!", "hello woRld!", "hello worLd!", "hello worlD!"]
  """
  def ave(string) do
    string
      |> String.downcase
      |> String.to_charlist
      |> do_wave
  end

  @ascii_upcase_val 32 # ?a - ?A

  defp do_wave(waving, waves \\ [], waved \\ '')
  defp do_wave([] = _done_waving, waves, _waved), do: Enum.reverse(waves)
  defp do_wave([next | rest], waves, waved) when next in ?a..?z do
    uppercase = next - @ascii_upcase_val
    do_wave(rest, [IO.iodata_to_binary([waved, uppercase, rest]) | waves], [waved, next])
  end
  defp do_wave([next | rest], waves, waved), do: do_wave(rest, waves, [waved, next])
end