Current section

Files

Jump to
osu_ex lib utils.ex
Raw

lib/utils.ex

defmodule OsuEx.Utils do
@moduledoc "Utility functions."
use Bitwise, only_operators: true
@mods [
:NF,
:EZ,
:TD,
:HD,
:HR,
:SD,
:DT,
:RL,
:HT,
:NC,
:FL,
:AT,
:SO,
:AP,
:PF,
:K4,
:K5,
:K6,
:K7,
:K8,
:FI,
:RN,
:CN,
:TG,
:K9,
:KC,
:K1,
:K3,
:K2,
:V2,
:LM
]
@mod_to_num @mods
|> Enum.with_index()
|> Enum.map(fn {m, i} -> {m, round(:math.pow(2, i))} end)
|> Enum.into(%{})
@doc """
Translates bitwise mods into a list of atoms and vice versa.
This function does not handle the `KeyMod`, `FreeModAllowed`, or `ScoreIncreaseMods`.
## Examples
iex> OsuEx.API.Utils.mods(24) |> elem(1) |> MapSet.to_list()
[:HD, :HR]
iex> OsuEx.API.Utils.mods([:DT, :FL])
{:ok, 1088}
iex> OsuEx.API.Utils.mods([:QQ])
{:error, {:unknown_mod, :QQ}}
"""
def mods(_m)
@spec mods(0..2_147_483_647) :: {:ok, MapSet.t()}
def mods(n) when is_integer(n) do
l =
Enum.reduce(@mod_to_num, [], fn {m, i}, acc ->
if((i &&& n) === i, do: acc ++ [m], else: acc)
end)
l = if(Enum.member?(l, :NC), do: List.delete(l, :DT), else: l)
l = if(Enum.member?(l, :PF), do: List.delete(l, :SD), else: l)
{:ok, MapSet.new(l)}
end
@spec mods(Enum.t()) :: {:ok, 0..2_147_483_647} | {:error, {:unknown_mod, atom}}
def mods(l) do
val =
Enum.reduce_while(l, 0, fn m, acc ->
case @mod_to_num[m] do
nil -> {:halt, {:error, {:unknown_mod, m}}}
n -> {:cont, acc + n}
end
end)
if is_integer(val) do
val =
if Enum.member?(l, :NC) and not Enum.member?(l, :DT) do
val + @mod_to_num[:DT]
else
val
end
val =
if Enum.member?(l, :PF) and not Enum.member?(l, :SD) do
val + @mod_to_num[:SD]
else
val
end
{:ok, val}
else
val
end
end
end