Skip to content

Commit

Permalink
Merge pull request #25 from TTRPG-Dev/qmalcolm--move-logic-for-multi-…
Browse files Browse the repository at this point in the history
…rolls

Move logic for multi rolls
  • Loading branch information
QMalcolm authored Nov 25, 2024
2 parents d5f5649 + 9a782f4 commit d9652a1
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 14 deletions.
2 changes: 1 addition & 1 deletion lib/cli.ex
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ defmodule ExTTRPGDev.CLI do

def handle_roll(%Optimus.ParseResult{args: %{dice: dice}}) do
dice
|> Enum.map(fn dice_spec -> {dice_spec, Dice.roll(dice_spec)} end)
|> Dice.multi_roll!()
|> Enum.each(fn {dice_spec, results} -> IO.inspect(results, label: dice_spec) end)
end

Expand Down
68 changes: 55 additions & 13 deletions lib/dice.ex
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,29 @@ defmodule ExTTRPGDev.Dice do
str
end

@doc """
Tries to parse a given dice spec string into it's component parts
Returns: a tuple where the first item is the number of times to roll the die and the second indicates the number or sides the die has
## Examples
iex> ExTTRPGDev.Dice.parse_roll_spec!("3d4")
{3, 4}
iex> ExTTRPGDev.Dice.parse_roll_spec!("3")
** (RuntimeError) Improper dice format. Dice must be given in xdy where x and y are both integers
"""

def parse_roll_spec!(roll_spec) when is_bitstring(roll_spec) do
roll_spec
|> validate_dice_str()
|> String.split("d")
|> Enum.map(fn x -> String.to_integer(x) end)
|> List.to_tuple()
end

@doc """
Rolls the a number of multisided dice
Expand All @@ -39,32 +62,51 @@ defmodule ExTTRPGDev.Dice do
iex> ExTTRPGDev.Dice.roll(3, 8)
[4, 8, 5]
iex> :rand.seed(:exsplus, 1337)
iex> ExTTRPGDev.Dice.roll({3, 8})
[4, 8, 5]
iex> :rand.seed(:exsplus, 1337)
iex> ExTTRPGDev.Dice.roll("3d8")
[4, 8, 5]
iex> ExTTRPGDev.Dice.roll("bad_input")
** (RuntimeError) Improper dice format. Dice must be given in xdy where x and y are both integers
"""
def roll(str) when is_bitstring(str) do
{number_of_dice, sides} = parse_roll_spec!(str)
roll(number_of_dice, sides)
end

def roll({number_of_dice, sides}), do: roll(number_of_dice, sides)

def roll(number_of_dice, dice_sides) do
Enum.map(1..number_of_dice, fn _ -> roll_d(dice_sides) end)
end

@doc """
Roll dice defined by the input string
Roll multiple roll specs
Returns: List of die roll results
Returns: List of tuples, the first value being the roll spec, the second being the results
## Examples
# Although not necessary, let's seed the random algorithm
iex> :rand.seed(:exsplus, 1337)
iex> ExTTRPGDev.Dice.roll("3d4")
[4, 4, 1]
iex> ExTTRPGDev.Dice.multi_roll!(["3d4", "4d8", "2d20"])
[{"3d4", [4, 4, 1]}, {"4d8", [1, 3, 5, 6]}, {"2d20", [5, 12]}]
"""
def roll(str) when is_bitstring(str) do
[number_of_dice, sides] =
str
|> validate_dice_str()
|> String.split("d")
|> Enum.map(fn x -> String.to_integer(x) end)
iex> :rand.seed(:exsplus, 1337)
iex> ExTTRPGDev.Dice.multi_roll!([{3, 4}, {4, 8}, {2, 20}])
[{{3, 4}, [4, 4, 1]}, {{4, 8}, [1, 3, 5, 6]}, {{2, 20}, [5, 12]}]
roll(number_of_dice, sides)
iex> ExTTRPGDev.Dice.multi_roll!(["bad_spec", "oh_no!", "3d4"])
** (RuntimeError) Improper dice format. Dice must be given in xdy where x and y are both integers
"""
def multi_roll!(roll_specs) when is_list(roll_specs) do
roll_specs
|> Enum.map(fn roll_spec -> {roll_spec, roll(roll_spec)} end)
end

@doc """
Expand Down

0 comments on commit d9652a1

Please sign in to comment.