defmodule Rollex.Tokens.FudgeDice do
@regex ~r/\G(\d*)[dD][fF]/
defstruct regex: @regex,
is_dice: true,
quantity: 0,
sides: 3,
valid_rolls: [],
rejected_rolls: [],
arithmetic: 0.0
@type t :: %__MODULE__{}
defimpl Rollex.Token, for: Rollex.Tokens.FudgeDice do
@left_binding_precedence 0
def nud(token, rest) do
{:ok,
%{
arithmetic: token.arithmetic,
successes: Enum.count(token.valid_rolls)
}, rest}
end
def led(_token, _left, _rest) do
{:error, "Unexpected dice token"}
end
def lbp(_token) do
@left_binding_precedence
end
def create(_token, roll_expr, [
{_token_start, token_length},
{quantity_start, quantity_length}
]) do
{
%Rollex.Tokens.FudgeDice{
quantity:
roll_expr
|> String.slice(quantity_start, quantity_length)
|> Rollex.Utilities.simple_integer_parse()
},
token_length
}
end
end
defimpl Rollex.Dice, for: Rollex.Tokens.FudgeDice do
def roll(token) do
{fails, successes, total} =
Enum.reduce(1..token.quantity, {[], [], 0}, fn _, {fails, successes, total} ->
case :rand.uniform(3) - 2 do
1 -> {fails, [1 | successes], total + 1}
0 -> {[0 | fails], successes, total}
-1 -> {[-1 | fails], successes, total - 1}
end
end)
%{
token
| rejected_rolls: fails,
valid_rolls: successes,
arithmetic: total
}
end
def min(token), do: -token.quantity
def max(token), do: token.quantity
end
end