Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 1: Not Quite Lisp

2015/1.livemd

Day 1: Not Quite Lisp

Mix.install([
  {:kino, "~> 0.12.0"}
])

Modules

defmodule Santa do
  @moduledoc """
  Functions for navigating Santa up and down a large apartment
  building. 
  """

  @typedoc "The direction of travel"
  @type direction() :: :up | :down

  @doc """
  Provides Santa with directions to follow. Returns the floor number reached.

  ## Example
  ```elixir
  iex> [:up, :up, :up, :down, :up, :down]
  iex> |> Santa.follow()
  2
  ```
  """
  @spec follow(list(direction())) :: integer()
  def follow(directions) do
    directions
    |> Enum.reduce(0, &next_floor/2)
  end

  @doc """
  Finds the position such that Santa first enters a specified floor, given
  a list of directions.

  ## Example
  ```elixir
  iex> [:up, :down, :up, :up, :down, :down]
  iex> |> Santa.find_floor(2)
  4
  ```
  """
  @spec find_floor(list(direction()), integer()) :: pos_integer()
  def find_floor(directions, desired_floor) do
    directions
    |> Stream.with_index()
    |> Enum.reduce_while(0, fn
      {_, position}, ^desired_floor -> {:halt, position}
      {direction, _}, floor -> {:cont, next_floor(direction, floor)}
    end)
  end

  defp next_floor(direction, current_floor)
  defp next_floor(:up, current_floor), do: current_floor + 1
  defp next_floor(:down, current_floor), do: current_floor - 1
end
defmodule Parser do
  @moduledoc """
  For parsing a string into directions that Santa can follow.
  """

  @doc """
  Parses a string of parentheses into a list of directions.

  ## Example
  ```elixir
  iex> Parser.parse("))(()")
  [:down, :down, :up, :up, :down]
  """
  @spec parse(String.t()) :: list(Santa.direction())
  def parse(str) do
    str
    |> String.graphemes()
    |> Enum.map(&direction/1)
  end

  defp direction(symbol)
  defp direction("("), do: :up
  defp direction(")"), do: :down
end

Input

input = Kino.Input.textarea("Please paste your puzzle input:")

Part 1

input
|> Kino.Input.read()
|> Parser.parse()
|> Santa.follow()

Part 2

input
|> Kino.Input.read()
|> Parser.parse()
|> Santa.find_floor(-1)