-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdice.rb
133 lines (106 loc) · 3.1 KB
/
dice.rb
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
module Dice
RANDOM = Random.new
DIE_ROLL_REGEX = /\$(\d+)d(\S+)\s*(.*)/.freeze
ROLL_CHAR_CAP = 800
MAX_DICE = 100_000
ZELDA_DIE_TYPE_RE = /^((10)|Z|z)$/.freeze
ORITHAN_DIE_TYPE_RE = /^((6)|O|o)$/.freeze
def self.new(roll_phrase)
num_dice, die_type, comment = roll_phrase.match(DIE_ROLL_REGEX).captures
num_dice = [Integer(num_dice), MAX_DICE].min
comment = comment.strip
die_variant =
case die_type
when ZELDA_DIE_TYPE_RE then ZeldaDie
when ORITHAN_DIE_TYPE_RE then OrithanDie
else NumericDie
end
die_variant.new(num_dice, die_type, comment)
end
class Die
def initialize(num_dice, die_type, comment)
@num_dice = num_dice
@die_type = die_type
@comment = comment
end
def beautify_int(i)
i.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
end
def roll(roller)
display_comment = ''
display_comment = " (#{comment})" unless comment.empty?
outcome = perform_roll
"**#{roller}**: #{outcome[:rolls]}#{display_comment}\n#{outcome[:result]}"
end
protected
attr_reader :num_dice, :die_type, :comment
end
class NumericDie < Die
def initialize(num_dice, die_type, comment)
super(num_dice, die_type, comment)
end
def perform_roll
sides = Integer(die_type)
rolls = (0...num_dice).collect { |_| RANDOM.rand(sides) + 1 }
total = rolls.reduce(0, :+)
roll_text = rolls.collect(&method(:beautify_int)).reduce { |accum, x| accum << ", #{x}" }
roll_text = roll_text[0...ROLL_CHAR_CAP] << '...' if roll_text.size > ROLL_CHAR_CAP
{ rolls: roll_text, result: "**Total**: #{beautify_int(total)}" }
end
end
class SuccessDie < Die
def initialize(num_dice, die_type, comment)
super(num_dice, die_type, comment)
end
def format_successes(roll_val)
s = map_successes(roll_val)
if s == 1 then "**#{roll_val}**"
elsif s == 2 then "__**#{roll_val}**__"
else roll_val.to_s
end
end
def perform_roll
sides = Integer(die_type)
rolls = (0...num_dice).collect { |_| RANDOM.rand(sides) + 1 }
is_over_cap = false
roll_text =
rolls
.collect(&method(:format_successes))
.reduce do |accum, x|
if accum.length + x.length + 5 <= ROLL_CHAR_CAP
accum << ", #{x}"
else
is_over_cap = true
accum
end
end
roll_text = roll_text << '...' if is_over_cap
successes = rolls.collect(&method(:map_successes)).reduce(0, :+)
{ rolls: roll_text, result: "**Successes**: #{beautify_int(successes)}" }
end
end
class ZeldaDie < SuccessDie
def initialize(num_dice, _die_type, comment)
super(num_dice, 10, comment)
end
def map_successes(x)
case x
when 5..9 then 1
when 10 then 2
else 0
end
end
end
class OrithanDie < SuccessDie
def initialize(num_dice, _die_type, comment)
super(num_dice, 6, comment)
end
def map_successes(x)
case x
when 4..5 then 1
when 6 then 2
else 0
end
end
end
end