Advent of Code 2020 in Elixir - Day 12

Rain Risk

defmodule Aoc2020.Day12 do
  @moduledoc "Rain Risk"

  def run() do
    parse_input()
    |> follow_instructions({0, 0, :east})
    |> (fn {x, y, _} -> abs(x) + abs(y) end).()
  end

  def parse_input() do
    # test_input()
    File.read!("priv/inputs/2020/day12.txt")
    |> String.trim()
    |> String.split("\n")
    |> Enum.map(fn line ->
      {action, value} = String.split_at(line, 1)
      {action_name(action), String.to_integer(value)}
    end)
  end

  def action_name(letter) do
    Map.fetch!(
      %{
        "N" => :north,
        "S" => :south,
        "E" => :east,
        "W" => :west,
        "R" => :right,
        "L" => :left,
        "F" => :forward
      },
      letter
    )
  end

  def test_input do
    "F10\nN3\nF7\nR90\nF11"
  end

  def follow_instructions(instructions, from) do
    Enum.reduce(instructions, from, fn instruction, location -> step(location, instruction) end)
  end

  def step({x, y, facing}, {:north, dist}), do: {x, y - dist, facing}
  def step({x, y, facing}, {:south, dist}), do: {x, y + dist, facing}
  def step({x, y, facing}, {:east, dist}), do: {x + dist, y, facing}
  def step({x, y, facing}, {:west, dist}), do: {x - dist, y, facing}

  def step({x, y, facing}, {:right, degress}), do: {x, y, compass_direction(facing, degress)}
  def step({x, y, facing}, {:left, degress}), do: {x, y, compass_direction(facing, 0 - degress)}

  def step({x, y, facing}, {:forward, dist}), do: step({x, y, facing}, {facing, dist})

  def compass_direction(current, turn_degrees) do
    compass = %{0 => :north, 90 => :east, 180 => :south, 270 => :west}
    current_degrees = elem(Enum.find(compass, fn {_, v} -> v == current end), 0)
    t2 = rem(current_degrees + turn_degrees, 360)

    case t2 >= 0 do
      true -> Map.fetch!(compass, t2)
      false -> Map.fetch!(compass, 360 + t2)
    end
  end
end