games_dice 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +46 -0
- data/Rakefile +1 -0
- data/games_dice.gemspec +22 -0
- data/lib/games_dice.rb +6 -0
- data/lib/games_dice/die.rb +92 -0
- data/lib/games_dice/version.rb +3 -0
- data/spec/die_spec.rb +95 -0
- metadata +75 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Neil Slater
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# GamesDice
|
2
|
+
|
3
|
+
A library for simulating dice, intended for constructing a variety of dice systems as used in
|
4
|
+
role-playing and board games.
|
5
|
+
|
6
|
+
## Special Note on Versions Prior to 1.0.0
|
7
|
+
|
8
|
+
The author is using this code as an exercise in gem "best practice". As such, the gem
|
9
|
+
will have a deliberately limited set of functionality prior to version 1.0.0, and there should be
|
10
|
+
many small release increments before then.
|
11
|
+
|
12
|
+
The functionality should expand to cover dice systems seen in many role-playing systems, as it
|
13
|
+
progresses through 0.x.y versions (in fact much of this code is already written and working, so if
|
14
|
+
you have a burning need to simulate dice rolls for a specific game, feel free to get in touch).
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
Add this line to your application's Gemfile:
|
19
|
+
|
20
|
+
gem 'games_dice'
|
21
|
+
|
22
|
+
And then execute:
|
23
|
+
|
24
|
+
$ bundle
|
25
|
+
|
26
|
+
Or install it yourself as:
|
27
|
+
|
28
|
+
$ gem install games_dice
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
require 'games_dice'
|
33
|
+
|
34
|
+
# Simple 6-sided die, more to follow
|
35
|
+
d = GamesDice::Die.new( 6 )
|
36
|
+
d.roll # => 4
|
37
|
+
d.result # => 4
|
38
|
+
d.explain_roll # => "4"
|
39
|
+
|
40
|
+
## Contributing
|
41
|
+
|
42
|
+
1. Fork it
|
43
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
44
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
45
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
46
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/games_dice.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'games_dice/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "games_dice"
|
8
|
+
gem.version = GamesDice::VERSION
|
9
|
+
gem.authors = ["Neil Slater"]
|
10
|
+
gem.email = ["slobo777@gmail.com"]
|
11
|
+
gem.description = %q{A simulated-dice library, with flexible rules that allow dice systems from
|
12
|
+
many board and roleplay games to be built, run and reported.}
|
13
|
+
gem.summary = %q{Simulates and explains dice rolls from a variety of game systems.}
|
14
|
+
gem.homepage = ""
|
15
|
+
|
16
|
+
gem.add_development_dependency "rspec"
|
17
|
+
|
18
|
+
gem.files = `git ls-files`.split($/)
|
19
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
20
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
21
|
+
gem.require_paths = ["lib"]
|
22
|
+
end
|
data/lib/games_dice.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
module GamesDice
|
2
|
+
# basic die that rolls 1..N, typically with equal weighting for each value
|
3
|
+
# d = Die.new(6)
|
4
|
+
# d.roll # => Integer in range 1..6
|
5
|
+
# d.result # => same Integer value as returned by d.roll
|
6
|
+
class Die
|
7
|
+
# sides is e.g. 6 for traditional cubic die, or 20 for icosahedron.
|
8
|
+
# It can take non-traditional values, such as 7, but must be at least 1.
|
9
|
+
# prng is an object that has a rand(x) method. If provided, it will be called as
|
10
|
+
# prng.rand(sides), and is expected to return an integer in range 0...sides
|
11
|
+
def initialize( sides, prng=nil )
|
12
|
+
@sides = Integer(sides)
|
13
|
+
raise ArgumentError, "sides value #{sides} is too low, it must be 1 or greater" if @sides < 1
|
14
|
+
raise ArgumentError, "prng does not support the rand() method" if prng && ! prng.respond_to?(:rand)
|
15
|
+
@prng = prng
|
16
|
+
@result = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
# number of sides as set by #new
|
20
|
+
attr_reader :sides
|
21
|
+
|
22
|
+
# integer result of last call to #roll, nil if no call made yet
|
23
|
+
attr_reader :result
|
24
|
+
|
25
|
+
# minimum possible value
|
26
|
+
def min
|
27
|
+
1
|
28
|
+
end
|
29
|
+
|
30
|
+
# maximum possible value
|
31
|
+
def max
|
32
|
+
@sides
|
33
|
+
end
|
34
|
+
|
35
|
+
# returns a hash of value (Integer) => probability (Float) pairs
|
36
|
+
def probabilities
|
37
|
+
return @probabilities if @probabilities
|
38
|
+
density = 1.0/@sides
|
39
|
+
@probabilities = (1..@sides).inject({}) { |h,x| h[x] = density; h }
|
40
|
+
end
|
41
|
+
|
42
|
+
# returns mean expected value as a Float
|
43
|
+
def expected_result
|
44
|
+
0.5 * (1 + @sides)
|
45
|
+
end
|
46
|
+
|
47
|
+
# returns probability than a roll will produce a number greater than target integer
|
48
|
+
def probability_gt target
|
49
|
+
probability_ge( Integer(target) + 1 )
|
50
|
+
end
|
51
|
+
|
52
|
+
# returns probability than a roll will produce a number greater than or equal to target integer
|
53
|
+
def probability_ge target
|
54
|
+
target = Integer(target)
|
55
|
+
return 1.0 if target <= 1
|
56
|
+
return 0.0 if target > @sides
|
57
|
+
return 1.0 * (1.0 + @sides - target )/@sides
|
58
|
+
end
|
59
|
+
|
60
|
+
# returns probability than a roll will produce a number less than or equal to target integer
|
61
|
+
def probability_le target
|
62
|
+
target = Integer(target)
|
63
|
+
return 1.0 if target >= @sides
|
64
|
+
return 0.0 if target < 1
|
65
|
+
return 1.0 * target/@sides
|
66
|
+
end
|
67
|
+
|
68
|
+
# returns probability than a roll will produce a number less than target integer
|
69
|
+
def probability_lt target
|
70
|
+
probability_le( Integer(target) - 1 )
|
71
|
+
end
|
72
|
+
|
73
|
+
# generates Integer between #min and #max, using rand()
|
74
|
+
def roll
|
75
|
+
if @prng
|
76
|
+
@result = @prng.rand(@sides) + 1
|
77
|
+
else
|
78
|
+
@result = rand(@sides) + 1
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# always nil, available for compatibility with ComplexDie
|
83
|
+
def rerolls
|
84
|
+
nil
|
85
|
+
end
|
86
|
+
|
87
|
+
# always nil, available for compatibility with ComplexDie
|
88
|
+
def maps
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
end # class Die
|
92
|
+
end # module GamesDice
|
data/spec/die_spec.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'games_dice/die'
|
2
|
+
|
3
|
+
# Test helper class, a stub of a PRNG
|
4
|
+
class TestPRNG
|
5
|
+
def initialize
|
6
|
+
# Numbers that I randomly thought up!
|
7
|
+
@numbers = [0.123,0.234,0.345,0.999,0.876,0.765,0.543,0.111,0.333,0.777]
|
8
|
+
end
|
9
|
+
def rand(n)
|
10
|
+
Integer( n * @numbers.pop )
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe GamesDice::Die do
|
15
|
+
|
16
|
+
before do
|
17
|
+
# Set state of default PRNG
|
18
|
+
srand(4567)
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#new" do
|
22
|
+
it "should return an object that represents e.g. a six-sided die" do
|
23
|
+
die = GamesDice::Die.new(6)
|
24
|
+
die.min.should == 1
|
25
|
+
die.max.should == 6
|
26
|
+
die.sides.should == 6
|
27
|
+
die.probabilities.should == { 1 => 1.0/6, 2 => 1.0/6, 3 => 1.0/6, 4 => 1.0/6, 5 => 1.0/6, 6 => 1.0/6 }
|
28
|
+
die.expected_result.should == 3.5
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should accept any object with a rand(Integer) method as the second param" do
|
32
|
+
prng = TestPRNG.new()
|
33
|
+
die = GamesDice::Die.new(20,prng)
|
34
|
+
[16,7,3,11,16,18,20,7].each do |expected|
|
35
|
+
die.roll.should == expected
|
36
|
+
die.result.should == expected
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#roll and #result" do
|
42
|
+
it "should return results based on Ruby's internal rand() by default" do
|
43
|
+
die = GamesDice::Die.new(10)
|
44
|
+
[5,4,10,4,7,8,1,9].each do |expected|
|
45
|
+
die.roll.should == expected
|
46
|
+
die.result.should == expected
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#min and #max" do
|
52
|
+
it "should calculate correct min, max" do
|
53
|
+
die = GamesDice::Die.new(20)
|
54
|
+
die.min.should == 1
|
55
|
+
die.max.should == 20
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#expected_result" do
|
60
|
+
it "should calculate correct weighted mean" do
|
61
|
+
die = GamesDice::Die.new(20)
|
62
|
+
die.expected_result.should be_within(1e-10).of 10.5
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#probabilities" do
|
67
|
+
it "should calculate probabilities accurately" do
|
68
|
+
die = GamesDice::Die.new(6)
|
69
|
+
die.probabilities[1].should be_within(1e-10).of 1/6.0
|
70
|
+
die.probabilities[2].should be_within(1e-10).of 1/6.0
|
71
|
+
die.probabilities[3].should be_within(1e-10).of 1/6.0
|
72
|
+
die.probabilities[4].should be_within(1e-10).of 1/6.0
|
73
|
+
die.probabilities[5].should be_within(1e-10).of 1/6.0
|
74
|
+
die.probabilities[6].should be_within(1e-10).of 1/6.0
|
75
|
+
die.probabilities.values.inject(:+).should be_within(1e-9).of 1.0
|
76
|
+
|
77
|
+
die.probability_gt(6).should == 0.0
|
78
|
+
die.probability_gt(-20).should == 1.0
|
79
|
+
die.probability_gt(4).should be_within(1e-10).of 2/6.0
|
80
|
+
|
81
|
+
die.probability_ge(20).should == 0.0
|
82
|
+
die.probability_ge(1).should == 1.0
|
83
|
+
die.probability_ge(4).should be_within(1e-10).of 0.5
|
84
|
+
|
85
|
+
die.probability_le(6).should == 1.0
|
86
|
+
die.probability_le(-3).should == 0.0
|
87
|
+
die.probability_le(5).should be_within(1e-10).of 5/6.0
|
88
|
+
|
89
|
+
die.probability_lt(7).should == 1.0
|
90
|
+
die.probability_lt(1).should == 0.0
|
91
|
+
die.probability_lt(3).should be_within(1e-10).of 2/6.0
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: games_dice
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Neil Slater
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: ! "A simulated-dice library, with flexible rules that allow dice systems
|
31
|
+
from\n many board and roleplay games to be built, run and
|
32
|
+
reported."
|
33
|
+
email:
|
34
|
+
- slobo777@gmail.com
|
35
|
+
executables: []
|
36
|
+
extensions: []
|
37
|
+
extra_rdoc_files: []
|
38
|
+
files:
|
39
|
+
- .gitignore
|
40
|
+
- Gemfile
|
41
|
+
- LICENSE.txt
|
42
|
+
- README.md
|
43
|
+
- Rakefile
|
44
|
+
- games_dice.gemspec
|
45
|
+
- lib/games_dice.rb
|
46
|
+
- lib/games_dice/die.rb
|
47
|
+
- lib/games_dice/version.rb
|
48
|
+
- spec/die_spec.rb
|
49
|
+
homepage: ''
|
50
|
+
licenses: []
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
requirements: []
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.8.24
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: Simulates and explains dice rolls from a variety of game systems.
|
73
|
+
test_files:
|
74
|
+
- spec/die_spec.rb
|
75
|
+
has_rdoc:
|