defmodule ResistorColorTrio do @type color :: :black | :brown | :red | :orange | :yellow | :green | :blue | :violet | :grey | :white @type colors :: [color] @type unit :: :ohms | :kiloohms | :megaohms | :gigaohms defguardp is_giga(value) when value >= 1_000_000_000 defguardp is_mega(value) when value >= 1_000_000 defguardp is_kilo(value) when value >= 1_000 @doc """ Calculate the resistance value in ohms from resistor colors """ @spec label(colors) :: {number, unit} def label(colors) do colors |> Enum.take(2) |> Enum.map(&code/1) |> Kernel.++(zeros(Enum.at(colors, 2))) |> Integer.undigits() |> with_unit() end @spec code(color) :: integer() defp code(:black), do: 0 defp code(:brown), do: 1 defp code(:red), do: 2 defp code(:orange), do: 3 defp code(:yellow), do: 4 defp code(:green), do: 5 defp code(:blue), do: 6 defp code(:violet), do: 7 defp code(:grey), do: 8 defp code(:white), do: 9 @spec zeros(color) :: list() defp zeros(color), do: List.duplicate(0, code(color)) @spec with_unit(integer) :: {integer, unit} defp with_unit(value) when is_giga(value), do: {div(value, 1_000_000_000), :gigaohms} defp with_unit(value) when is_mega(value), do: {div(value, 1_000_000), :megaohms} defp with_unit(value) when is_kilo(value), do: {div(value, 1_000), :kiloohms} defp with_unit(value), do: {value, :ohms} end