Skip to content

Instantly share code, notes, and snippets.

@chorn
Created March 2, 2016 21:56
Show Gist options
  • Save chorn/4ddea713df61a0a67c1f to your computer and use it in GitHub Desktop.
Save chorn/4ddea713df61a0a67c1f to your computer and use it in GitHub Desktop.
#!/usr/bin/env elixir
defmodule Roller do
def roll_a_die(n_sided_die), do: roll_a_die(n_sided_die, false)
def roll_a_die(1, _), do: 1
def roll_a_die(n_sided_die, false), do: :rand.uniform(n_sided_die)
def roll_a_die(n_sided_die, true) do
maybe = roll_a_die(n_sided_die)
result = cond do
maybe == 1 ->
roll_a_die(n_sided_die, true)
true ->
maybe
end
result
end
def spawn_roll_a_die(_, n_sided_die, reroll_ones) do
parent = self()
spawn_link fn -> send(parent, { :roll, roll_a_die(n_sided_die, reroll_ones) } ) end
roll = receive do
{:roll, response} -> response
end
roll
end
def find_index_of_minimum(rolls, n_sided_die) do
min = Enum.reduce(rolls, n_sided_die, fn(element, acc) -> if(element < acc, do: element, else: acc) end)
Enum.find_index(rolls, &(&1 == min))
end
def format_by_width(value, width) do
to_string(:io_lib.format("~#{width}s", ["#{value}"]))
end
def format_a_roll(roll, width) do
format_a_roll(roll, width, false)
end
def format_a_roll(roll, width, false) do
format_by_width(roll, width)
end
def format_a_roll(roll, width, true) do
format_a_roll("[#{roll}]", width, false)
end
def format_a_set(set_of_rolls, index_of_minimum, width) do
for {roll, index} <- Enum.with_index(set_of_rolls) do
format_a_roll(roll, width, index == index_of_minimum)
end
|> Enum.intersperse(format_by_width("+", width))
end
def format_the_modifier(adjusted, modifier) do
plus_minus = fn(modifier) -> if modifier < 0, do: "-", else: "+" end
if modifier == 0 do
""
else
a_width = String.length(to_string(adjusted + 1))
m_width = String.length(to_string(modifier + 1))
" = #{format_a_roll(adjusted, a_width)} #{plus_minus.(modifier)} #{format_a_roll(abs(modifier), m_width)}"
end
end
def roll_a_set_of_dice(n_sided_die, reroll_ones, iterations, drop_lowest, modifier) do
expression_d = fn(drop) -> if drop, do: "D", else: "d" end
expression_r = fn(reroll) -> if reroll, do: "r", else: "" end
expression_m = fn(modi) -> if modi == 0, do: "", else: to_string(modi) end
set_of_rolls = 1..iterations |> Enum.map(&Roller.spawn_roll_a_die(&1, n_sided_die, reroll_ones))
index_of_minimum = Roller.find_index_of_minimum(set_of_rolls, n_sided_die)
minimum = Enum.min(set_of_rolls)
sum = Enum.sum(set_of_rolls) + modifier
width = String.length(to_string(sum)) + 2
adjusted = sum - minimum
expression = to_string(iterations) <> expression_d.(drop_lowest) <> to_string(n_sided_die) <> expression_r.(reroll_ones) <> expression_m.(modifier)
formatted_set = Enum.join(format_a_set(set_of_rolls, index_of_minimum, width))
%{
:set => set_of_rolls,
:index_of_minimum => index_of_minimum,
:minimum => minimum,
:sum => sum,
:adjusted => adjusted,
:expression => expression,
:formatted_set => formatted_set,
:output => "#{expression}: #{formatted_set} #{format_the_modifier(sum, modifier)}"
}
end
end
# parent = self()
n_sided_die = 6
reroll_ones = false
iterations = 4
drop_lowest = true
modifier = -2
roll_map = Roller.roll_a_set_of_dice(n_sided_die, reroll_ones, iterations, drop_lowest, modifier)
IO.inspect(roll_map)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment