Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move logic for multi rolls #25

Merged
merged 4 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading