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)