-
Notifications
You must be signed in to change notification settings - Fork 4
/
DiceRolls.jl
67 lines (52 loc) · 1.57 KB
/
DiceRolls.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
module DiceRolls
using LinearAlgebra: dot
export coin, @roll_str
include("dice.jl")
include("roll.jl")
include("operations.jl")
include("histogram.jl")
include("statistics.jl")
const coin = Dice(2) - 1
"""
@roll_str(str)
Convenient string macro. Format:
<n rolls>#<N>d<faces>+<modifier><mod effect>
<n rolls>, <N>, <modifier>, <mod effect> are optional.
Example:
```
r"2#1d20+6" # Rolls 1d20+6 twice
r"2d20kh1" # Rolls 2d20 and keeps highest
```
"""
macro roll_str(str)
# find the main die
parts = findall(r"[0-9]*d[0-9]*", str)
len_pts = length(parts)
len_pts == 1 || throw(ArgumentError("Require exactly 1 kind of die, found $len_pts."))
die_pos = only(parts)
main_die = str[die_pos]
# how many rolls
n_rolls = match(r"([0-9]*)#", str[1:first(die_pos)]) #search before the main die
n_rolls = isnothing(n_rolls) ? 1 : parse(Int, only(n_rolls.captures))
# + modifier
plus = match(r"\+([0-9]*)", str, last(die_pos)) #search after the main die
plus = isnothing(plus) ? 0 : only(plus.captures)
# kh<n> or kl<n> modifier
keep = match(r"(k[h|l])([0-9]*)", str, last(die_pos)) #search after the main die
kind, keep_n = isnothing(keep) ? (nothing, nothing) : keep.captures
kind = if kind == "kh"
:highest
elseif kind == "kl"
:lowest
else
nothing
end
ex = "$main_die + $plus"
ex = isnothing(kind) ? ex : "keep($ex, kind=:$kind, n=$keep_n)"
if n_rolls > 1
Meta.parse("sum([roll($ex) for _ in 1:$n_rolls])")
else
Meta.parse("roll($ex)")
end
end
end # module