bag_of_holding 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +37 -0
- data/Rakefile +17 -0
- data/bin/boh +28 -0
- data/lib/bag_of_holding/dice/addition_operation.rb +18 -0
- data/lib/bag_of_holding/dice/constant.rb +23 -0
- data/lib/bag_of_holding/dice/constant_result.rb +27 -0
- data/lib/bag_of_holding/dice/die.rb +39 -0
- data/lib/bag_of_holding/dice/die_result.rb +26 -0
- data/lib/bag_of_holding/dice/die_roller.rb +51 -0
- data/lib/bag_of_holding/dice/die_validator.rb +23 -0
- data/lib/bag_of_holding/dice/division_operation.rb +18 -0
- data/lib/bag_of_holding/dice/multiplication_operation.rb +18 -0
- data/lib/bag_of_holding/dice/operation.rb +45 -0
- data/lib/bag_of_holding/dice/operation_result.rb +38 -0
- data/lib/bag_of_holding/dice/parser.rb +50 -0
- data/lib/bag_of_holding/dice/pool.rb +58 -0
- data/lib/bag_of_holding/dice/pool_factory.rb +70 -0
- data/lib/bag_of_holding/dice/pool_result.rb +37 -0
- data/lib/bag_of_holding/dice/subtraction_operation.rb +18 -0
- data/lib/bag_of_holding/dice/transform.rb +59 -0
- data/lib/bag_of_holding/dice.rb +41 -0
- data/lib/bag_of_holding.rb +1 -0
- data/spec/dice/addition_operation_spec.rb +23 -0
- data/spec/dice/constant_result_spec.rb +48 -0
- data/spec/dice/constant_spec.rb +31 -0
- data/spec/dice/die_result_spec.rb +70 -0
- data/spec/dice/die_roller_spec.rb +76 -0
- data/spec/dice/die_spec.rb +111 -0
- data/spec/dice/die_validator_spec.rb +34 -0
- data/spec/dice/division_operation_spec.rb +35 -0
- data/spec/dice/multiplication_operation_spec.rb +27 -0
- data/spec/dice/operation_result_spec.rb +64 -0
- data/spec/dice/operation_spec.rb +55 -0
- data/spec/dice/parser_spec.rb +215 -0
- data/spec/dice/pool_factory_spec.rb +71 -0
- data/spec/dice/pool_result_spec.rb +63 -0
- data/spec/dice/pool_spec.rb +126 -0
- data/spec/dice/subtraction_operation_spec.rb +27 -0
- data/spec/dice/transform_spec.rb +237 -0
- data/spec/spec_helper.rb +24 -0
- metadata +186 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::DieRoller do
|
2
|
+
let(:die) { BagOfHolding::Dice::Die.new sides: 20, explode: 19, reroll: 2 }
|
3
|
+
subject { BagOfHolding::Dice::DieRoller.new die: die }
|
4
|
+
|
5
|
+
# Spec ::build
|
6
|
+
describe '::roll' do
|
7
|
+
it 'passes the argument to new' do
|
8
|
+
klass = BagOfHolding::Dice::DieRoller
|
9
|
+
die = double('Die', roll: true)
|
10
|
+
expect(klass).to receive(:new).with(die: die).and_return(subject)
|
11
|
+
klass.roll die
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#roll' do
|
16
|
+
context 'with no options' do
|
17
|
+
it 'returns the roll' do
|
18
|
+
allow(subject).to receive(:rng).and_return(5)
|
19
|
+
expect(subject.roll).to eq(
|
20
|
+
BagOfHolding::Dice::DieResult.new rolls: [5],
|
21
|
+
value: 5,
|
22
|
+
die: subject
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with rerolling die' do
|
28
|
+
it 're-rolls and adds a number larger if we are equal to the reroll' do
|
29
|
+
allow(subject).to receive(:rng).and_return(2, 3)
|
30
|
+
expect(subject.roll).to eq(
|
31
|
+
BagOfHolding::Dice::DieResult.new rolls: [2, 3],
|
32
|
+
value: 3,
|
33
|
+
die: subject
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 're-rolls and adds a number larger if we are less than the reroll' do
|
38
|
+
allow(subject).to receive(:rng).and_return(1, 5)
|
39
|
+
expect(subject.roll).to eq(
|
40
|
+
BagOfHolding::Dice::DieResult.new rolls: [1, 5],
|
41
|
+
value: 5,
|
42
|
+
die: subject
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'with an exploding die' do
|
48
|
+
it 'accumulates and re-rolls if we are equal to the explode number' do
|
49
|
+
allow(subject).to receive(:rng).and_return(19, 3)
|
50
|
+
expect(subject.roll).to eq(
|
51
|
+
BagOfHolding::Dice::DieResult.new rolls: [19, 3],
|
52
|
+
value: 22,
|
53
|
+
die: subject
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'accumulates and re-rolls if we are greater than the explode number' do
|
58
|
+
allow(subject).to receive(:rng).and_return(20, 5)
|
59
|
+
expect(subject.roll).to eq(
|
60
|
+
BagOfHolding::Dice::DieResult.new rolls: [20, 5],
|
61
|
+
value: 25,
|
62
|
+
die: subject
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'accumulates and re-rolls if we continue to explode' do
|
67
|
+
allow(subject).to receive(:rng).and_return(20, 20, 4)
|
68
|
+
expect(subject.roll).to eq(
|
69
|
+
BagOfHolding::Dice::DieResult.new rolls: [20, 20, 4],
|
70
|
+
value: 44,
|
71
|
+
die: subject
|
72
|
+
)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::Die do
|
2
|
+
subject { BagOfHolding::Dice::Die.new sides: 20, explode: 19, reroll: 2 }
|
3
|
+
|
4
|
+
describe '#initialize' do
|
5
|
+
it 'sets the attributes on the class' do
|
6
|
+
die = BagOfHolding::Dice::Die.new sides: 8, explode: 20, reroll: 1
|
7
|
+
expect(die.sides).to eq(8)
|
8
|
+
expect(die.explode).to eq(20)
|
9
|
+
expect(die.reroll).to eq(1)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#sides=' do
|
14
|
+
it 'sets the number of sides on the die' do
|
15
|
+
subject.sides = 100
|
16
|
+
expect(subject.sides).to eq(100)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#sides' do
|
21
|
+
it 'returns the number of sides on the die' do
|
22
|
+
expect(subject.sides).to eq(20)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#explode=' do
|
27
|
+
it 'sets the number of explode on the die' do
|
28
|
+
subject.explode = 15
|
29
|
+
expect(subject.explode).to eq(15)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#explode' do
|
34
|
+
it 'returns the number of explode on the die' do
|
35
|
+
expect(subject.explode).to eq(19)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#reroll=' do
|
40
|
+
it 'sets the number of reroll on the die' do
|
41
|
+
subject.reroll = 2
|
42
|
+
expect(subject.reroll).to eq(2)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#reroll' do
|
47
|
+
it 'returns the number of reroll on the die' do
|
48
|
+
expect(subject.reroll).to eq(2)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#==' do
|
53
|
+
let(:other) do
|
54
|
+
BagOfHolding::Dice::Die.new sides: subject.sides,
|
55
|
+
explode: subject.explode,
|
56
|
+
reroll: subject.reroll
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'returns true for a die with the same attributes' do
|
60
|
+
expect(subject == other).to eq(true)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'returns false for a die with different sides' do
|
64
|
+
other.sides = 10_000
|
65
|
+
expect(subject == other).to eq(false)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'returns false for a die with different explode' do
|
69
|
+
other.explode = 1
|
70
|
+
expect(subject == other).to eq(false)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'returns false for a die with different reroll' do
|
74
|
+
other.reroll = 4
|
75
|
+
expect(subject == other).to eq(false)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#valid?' do
|
80
|
+
it 'passes itself to DieValidator' do
|
81
|
+
allow(BagOfHolding::Dice::DieValidator).to(
|
82
|
+
receive(:valid?).and_return(true)
|
83
|
+
)
|
84
|
+
|
85
|
+
expect(subject.valid?).to eq(true)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns true with a valid die' do
|
89
|
+
expect(subject.valid?).to eq(true)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#roll' do
|
94
|
+
context 'with an invalid die' do
|
95
|
+
before { subject.sides = nil }
|
96
|
+
|
97
|
+
it 'raises a StandardError' do
|
98
|
+
allow(subject).to receive(:valid?).and_return(false)
|
99
|
+
expect { subject.roll }.to raise_error(StandardError)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'passes itself to DieRoller' do
|
104
|
+
result = BagOfHolding::Dice::DieResult.new rolls: [5],
|
105
|
+
value: 5,
|
106
|
+
die: subject
|
107
|
+
allow(BagOfHolding::Dice::DieRoller).to receive(:roll).and_return(result)
|
108
|
+
expect(subject.roll).to eq(result)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::DieValidator do
|
2
|
+
let(:die) { BagOfHolding::Dice::Die.new sides: 20 }
|
3
|
+
subject { BagOfHolding::Dice::DieValidator.new die: die }
|
4
|
+
|
5
|
+
context 'with a reroll higher than explode' do
|
6
|
+
before do
|
7
|
+
die.explode = 10
|
8
|
+
die.reroll = 11
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns false' do
|
12
|
+
expect(subject.valid?).to eq(false)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'with an explode equal to reroll' do
|
17
|
+
before do
|
18
|
+
die.explode = 10
|
19
|
+
die.reroll = 10
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'returns false' do
|
23
|
+
expect(subject.valid?).to eq(false)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with no sides set' do
|
28
|
+
before { die.sides = nil }
|
29
|
+
|
30
|
+
it 'returns false' do
|
31
|
+
expect(subject.valid?).to eq(false)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::DivisionOperation do
|
2
|
+
let(:left) { BagOfHolding::Dice::Constant.new value: 4 }
|
3
|
+
let(:right) { BagOfHolding::Dice::Constant.new value: 2 }
|
4
|
+
|
5
|
+
subject do
|
6
|
+
BagOfHolding::Dice::DivisionOperation.new left: left,
|
7
|
+
right: right
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '::operator' do
|
11
|
+
it 'returns /' do
|
12
|
+
expect(BagOfHolding::Dice::DivisionOperation.operator).to eq('/')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#value' do
|
17
|
+
it 'subtracts the right value from the left' do
|
18
|
+
expect(subject.value).to eq(2)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'rounds down any values' do
|
22
|
+
BagOfHolding::Dice::Constant.new value: 5
|
23
|
+
BagOfHolding::Dice::Constant.new value: 2
|
24
|
+
op = BagOfHolding::Dice::DivisionOperation.new left: left,
|
25
|
+
right: right
|
26
|
+
expect(op.value).to eq(2)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#operator' do
|
31
|
+
it 'returns /' do
|
32
|
+
expect(subject.operator).to eq('/')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::MultiplicationOperation do
|
2
|
+
let(:left) { BagOfHolding::Dice::Constant.new value: 4 }
|
3
|
+
let(:right) { BagOfHolding::Dice::Constant.new value: 2 }
|
4
|
+
|
5
|
+
subject do
|
6
|
+
BagOfHolding::Dice::MultiplicationOperation.new left: left,
|
7
|
+
right: right
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '::operator' do
|
11
|
+
it 'returns *' do
|
12
|
+
expect(BagOfHolding::Dice::MultiplicationOperation.operator).to eq('*')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#value' do
|
17
|
+
it 'subtracts the right value from the left' do
|
18
|
+
expect(subject.value).to eq(8)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#operator' do
|
23
|
+
it 'returns *' do
|
24
|
+
expect(subject.operator).to eq('*')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::OperationResult do
|
2
|
+
let(:left) { BagOfHolding::Dice::Constant.new value: 3 }
|
3
|
+
let(:right) { BagOfHolding::Dice::Constant.new value: 5 }
|
4
|
+
|
5
|
+
let(:operation) do
|
6
|
+
BagOfHolding::Dice::AdditionOperation.new left: left,
|
7
|
+
right: right
|
8
|
+
end
|
9
|
+
|
10
|
+
subject do
|
11
|
+
BagOfHolding::Dice::OperationResult.new left_result: left.roll,
|
12
|
+
operation: operation,
|
13
|
+
right_result: right.roll,
|
14
|
+
value: 8
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#initialize' do
|
18
|
+
it 'assigns the attributes that are passed' do
|
19
|
+
result = BagOfHolding::Dice::OperationResult.new left_result: left.roll,
|
20
|
+
operation: operation,
|
21
|
+
right_result: right.roll,
|
22
|
+
value: 8
|
23
|
+
expect(result.left_result).to eq(left.roll)
|
24
|
+
expect(result.operation).to eq(operation)
|
25
|
+
expect(result.right_result).to eq(right.roll)
|
26
|
+
expect(result.value).to eq(8)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#to_s' do
|
31
|
+
it 'returns a string with the left result, operator and right result' do
|
32
|
+
expect(subject.to_s).to eq('3 + 5')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#inspect' do
|
37
|
+
it 'returns the inspected left and right results and operator' do
|
38
|
+
expect(subject.to_s).to eq('3 + 5')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#==' do
|
43
|
+
let(:other) do
|
44
|
+
BagOfHolding::Dice::OperationResult.new left_result: left.roll,
|
45
|
+
operation: operation,
|
46
|
+
right_result: right.roll,
|
47
|
+
value: 8
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns true when other has matching attributes' do
|
51
|
+
expect(subject == other).to eq(true)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'returns false with a different left_result' do
|
55
|
+
other.left_result = right.roll
|
56
|
+
expect(subject == other).to eq(false)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'returns false with a different right_result' do
|
60
|
+
other.right_result = left.roll
|
61
|
+
expect(subject == other).to eq(false)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::Operation do
|
2
|
+
let(:left) { BagOfHolding::Dice::Constant.new value: 3 }
|
3
|
+
let(:operator) { '+' }
|
4
|
+
let(:right) { BagOfHolding::Dice::Constant.new value: 5 }
|
5
|
+
|
6
|
+
subject do
|
7
|
+
BagOfHolding::Dice::Operation.new left: left,
|
8
|
+
right: right
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#initialize' do
|
12
|
+
it 'sets the attributes passed' do
|
13
|
+
op = BagOfHolding::Dice::Operation.new left: left,
|
14
|
+
right: right
|
15
|
+
expect(op.left).to eq(left)
|
16
|
+
expect(op.right).to eq(right)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#roll' do
|
21
|
+
it 'returns an OperationResult' do
|
22
|
+
allow(subject).to receive(:value).and_return(8)
|
23
|
+
|
24
|
+
expect(subject.roll).to eq(
|
25
|
+
BagOfHolding::Dice::OperationResult.new(
|
26
|
+
left_result: left.roll,
|
27
|
+
right_result: right.roll,
|
28
|
+
operation: subject,
|
29
|
+
value: 8
|
30
|
+
)
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe '#==' do
|
36
|
+
let(:other) do
|
37
|
+
BagOfHolding::Dice::Operation.new left: left,
|
38
|
+
right: right
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'returns true when matching attributes' do
|
42
|
+
expect(subject == other).to eq(true)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'returns false with a different left' do
|
46
|
+
other.left = BagOfHolding::Dice::Constant.new value: 30
|
47
|
+
expect(subject == other).to eq(false)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'returns false with a different right' do
|
51
|
+
other.left = BagOfHolding::Dice::Constant.new value: 40
|
52
|
+
expect(subject == other).to eq(false)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
RSpec.describe BagOfHolding::Dice::Parser do
|
2
|
+
subject { BagOfHolding::Dice::Parser.new }
|
3
|
+
|
4
|
+
describe '#parse' do
|
5
|
+
it 'parses 5' do
|
6
|
+
tree = subject.parse '5'
|
7
|
+
expect(tree).to match(
|
8
|
+
[constant: '5']
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'parses 1d20' do
|
13
|
+
tree = subject.parse '1d20'
|
14
|
+
expect(tree).to match([
|
15
|
+
{ count: '1', die: [{ sides: '20' }] }
|
16
|
+
])
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'parses 2d20k' do
|
20
|
+
tree = subject.parse '2d20k'
|
21
|
+
expect(tree).to match([
|
22
|
+
{ count: '2', die: [{ sides: '20' }, { keep: nil }] }
|
23
|
+
])
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'parses 3d20k2' do
|
27
|
+
tree = subject.parse '3d20k2'
|
28
|
+
expect(tree).to match([
|
29
|
+
{ count: '3', die: [{ sides: '20' }, { keep: '2' }] }
|
30
|
+
])
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'parses 1d20,1d8' do
|
34
|
+
tree = subject.parse '1d20,1d8'
|
35
|
+
expect(tree).to match(
|
36
|
+
[
|
37
|
+
{ count: '1', die: [{ sides: '20' }] },
|
38
|
+
{ count: '1', die: [{ sides: '8' }] }
|
39
|
+
]
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'parses d20' do
|
44
|
+
tree = subject.parse 'd20'
|
45
|
+
expect(tree).to match([
|
46
|
+
die: [{ sides: '20' }]
|
47
|
+
])
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'parses 3d8 (Attack)' do
|
51
|
+
tree = subject.parse '3d8 (Attack)'
|
52
|
+
expect(tree).to match([
|
53
|
+
{ count: '3', die: [{ sides: '8' }], label: 'Attack' }
|
54
|
+
])
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'parses 1d20r' do
|
58
|
+
tree = subject.parse '1d20r'
|
59
|
+
expect(tree).to match([
|
60
|
+
{ count: '1', die: [{ sides: '20' }, { reroll: nil }] }
|
61
|
+
])
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'parses 5+6' do
|
65
|
+
tree = subject.parse '5+6'
|
66
|
+
expect(tree).to match([
|
67
|
+
{ left: { constant: '5' }, operator: '+', right: { constant: '6' } }
|
68
|
+
])
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'parses 5-2' do
|
72
|
+
tree = subject.parse '5-2'
|
73
|
+
expect(tree).to match([
|
74
|
+
{ left: { constant: '5' }, operator: '-', right: { constant: '2' } }
|
75
|
+
])
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'parses 4/2' do
|
79
|
+
tree = subject.parse '4/2'
|
80
|
+
expect(tree).to match([
|
81
|
+
{ left: { constant: '4' }, operator: '/', right: { constant: '2' } }
|
82
|
+
])
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'parses 4*2' do
|
86
|
+
tree = subject.parse '4*2'
|
87
|
+
expect(tree).to match([
|
88
|
+
{ left: { constant: '4' }, operator: '*', right: { constant: '2' } }
|
89
|
+
])
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'parses 8, 9' do
|
93
|
+
tree = subject.parse '8, 9'
|
94
|
+
expect(tree).to match([
|
95
|
+
{ constant: '8' },
|
96
|
+
{ constant: '9' }
|
97
|
+
])
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'parses 1 + 2, 3' do
|
101
|
+
tree = subject.parse('1 + 2, 3')
|
102
|
+
expect(tree).to match([
|
103
|
+
{ left: { constant: '1' }, operator: '+', right: { constant: '2' } },
|
104
|
+
{ constant: '3' }
|
105
|
+
])
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'parses 1d20r (Defense)' do
|
109
|
+
tree = subject.parse('1d20r (Defense)')
|
110
|
+
expect(tree).to match([
|
111
|
+
{
|
112
|
+
count: '1',
|
113
|
+
die: [
|
114
|
+
{ sides: '20' },
|
115
|
+
{ reroll: nil }
|
116
|
+
],
|
117
|
+
label: 'Defense' }
|
118
|
+
])
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'parses 1d20r2' do
|
122
|
+
tree = subject.parse('1d20r2')
|
123
|
+
expect(tree).to match([
|
124
|
+
{ count: '1', die: [{ sides: '20' }, { reroll: '2' }] }
|
125
|
+
])
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'parses 1d20e' do
|
129
|
+
tree = subject.parse('1d20e')
|
130
|
+
expect(tree).to match([
|
131
|
+
{ count: '1', die: [{ sides: '20' }, { explode: nil }] }
|
132
|
+
])
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'parses 1d20e18' do
|
136
|
+
tree = subject.parse('1d20e18')
|
137
|
+
expect(tree).to match([
|
138
|
+
{ count: '1', die: [{ sides: '20' }, { explode: '18' }] }
|
139
|
+
])
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'parses 1d20e18r2' do
|
143
|
+
tree = subject.parse('1d20e18r2')
|
144
|
+
expect(tree).to match([
|
145
|
+
{
|
146
|
+
count: '1',
|
147
|
+
die: [
|
148
|
+
{ sides: '20' },
|
149
|
+
{ explode: '18' },
|
150
|
+
{ reroll: '2' }
|
151
|
+
]
|
152
|
+
}
|
153
|
+
])
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'parses 1d20r2e18' do
|
157
|
+
tree = subject.parse('1d20r2e18')
|
158
|
+
expect(tree).to match([
|
159
|
+
{
|
160
|
+
count: '1',
|
161
|
+
die: [
|
162
|
+
{ sides: '20' },
|
163
|
+
{ reroll: '2' },
|
164
|
+
{ explode: '18' }
|
165
|
+
]
|
166
|
+
}
|
167
|
+
])
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'parses 1d20 + 5' do
|
171
|
+
tree = subject.parse('1d20 + 5')
|
172
|
+
expect(tree).to match([
|
173
|
+
{
|
174
|
+
left: {
|
175
|
+
count: '1',
|
176
|
+
die: [
|
177
|
+
{ sides: '20' }
|
178
|
+
]
|
179
|
+
},
|
180
|
+
operator: '+',
|
181
|
+
right: {
|
182
|
+
constant: '5'
|
183
|
+
}
|
184
|
+
}
|
185
|
+
])
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'parses 2d6+ 1d4 + 2' do
|
189
|
+
tree = subject.parse('2d6+ 1d4 + 2')
|
190
|
+
expect(tree).to match([
|
191
|
+
{
|
192
|
+
left: {
|
193
|
+
count: '2',
|
194
|
+
die: [
|
195
|
+
{ sides: '6' }
|
196
|
+
]
|
197
|
+
},
|
198
|
+
operator: '+',
|
199
|
+
right: {
|
200
|
+
left: {
|
201
|
+
count: '1',
|
202
|
+
die: [
|
203
|
+
{ sides: '4' }
|
204
|
+
]
|
205
|
+
},
|
206
|
+
operator: '+',
|
207
|
+
right: {
|
208
|
+
constant: '2'
|
209
|
+
}
|
210
|
+
}
|
211
|
+
}
|
212
|
+
])
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|