hazard 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d73a6ac407a313337a1309b8f85680c2acdf9a36
4
- data.tar.gz: f26d0073ed98e7d10483815e6b16f6456e582142
3
+ metadata.gz: f9ae47cda73390cc30cd6d81a594879a0f142308
4
+ data.tar.gz: 7eb73440367d32076ddbef3b9d2ded4ecb772fe5
5
5
  SHA512:
6
- metadata.gz: 9b6aa19cf68606574fca81bbb5c3242fbabc44833806078de8a883de43fba72c16df8a10f42b163a0c18e829d70d873bb3e3450634cf30115c08254e43fe4fa4
7
- data.tar.gz: 4decd66c91587ad5a1eba94d94d575432c874589801fd9a087e7ba88c50930e6feb1ca1d11a8dfe8d40bdf7cbb221393d0dcc531b6785febcb02f915bbbcd960
6
+ metadata.gz: 7678295f955f7d2ddc157951b5da6d91746092eaf4f6eaad5c10dfbba7b19505bc676aa3d0baef9be415804e2ee5427d78802d45965ba486d94459d4453ada2d
7
+ data.tar.gz: 9c000fc08c2bd6debd467784dd728cd106f87958add39c9d8ab28d4b51d24a3f65930e22b55c9d80dee3e3f6b5f77a865b6a427a966552f3cf51da717ac976bb
data/README.md CHANGED
@@ -5,8 +5,23 @@
5
5
  [![Code Climate](https://codeclimate.com/github/czuger/hazard/badges/gpa.svg)](https://codeclimate.com/github/czuger/hazard)
6
6
  [![Test Coverage](https://codeclimate.com/github/czuger/hazard/badges/coverage.svg)](https://codeclimate.com/github/czuger/hazard/coverage)
7
7
 
8
- Hazard is a very simple dice library for ruby (see [usage](#usage)).
9
-
8
+ Hazard is a very simple dice library for ruby that allows you to :
9
+ * Roll dice and get the sum
10
+ * Roll dice and work with the detail
11
+ * Random pick elements from weighted lists
12
+
13
+ 1. [Installation](#installation)
14
+ 1. [Basic Usage](#basic-usage)
15
+ 1. [Roll a simple die](#roll-a-simple-die)
16
+ 1. [Roll multiple dice](#roll-multiple-dice)
17
+ 1. [Advanced Usage](#advanced-usage)
18
+ 1. [Roll dice and get the details](#roll-dice-and-get-the-details)
19
+ 1. [Some real cases](#some-real-cases)
20
+ 1. [Weighted Tables](#weighted-Tables)
21
+ 1. [If you have the weights](#if-you-have-the-weights)
22
+ 1. [If you don't have the weights (or are to lazy to get them)](#if-you-dont-have-the-weights-or-are-to-lazy-to-get-them)
23
+ 1. [Saving and loading](#saving-and-loading)
24
+
10
25
  ## Installation
11
26
 
12
27
  Add this line to your application's Gemfile:
@@ -27,9 +42,9 @@ If needed :
27
42
 
28
43
  $ require 'hazard'
29
44
 
30
- ## Usage
45
+ ## Basic Usage
31
46
 
32
- **Roll a simple die**
47
+ ### Roll a simple die
33
48
 
34
49
  >> Hazard.d<n> # where n is an number
35
50
  => Roll a n-sided die
@@ -46,7 +61,7 @@ Examples :
46
61
  => 38
47
62
 
48
63
 
49
- **Roll multiple dice**
64
+ ### Roll multiple dice
50
65
 
51
66
  >> Hazard.r<m>d<n> # where m and n are numbers
52
67
  => Roll m n-sided dice and return the sum
@@ -72,8 +87,9 @@ Examples :
72
87
  >> Hazard.d2d6
73
88
  => 8
74
89
 
90
+ ## Advanced Usage
75
91
 
76
- **Roll dice and get the details**
92
+ ### Roll dice and get the details
77
93
 
78
94
  >> Hazard.s<m>d<n> # where m and n are numbers
79
95
  => Roll m n-sided dice and return a RolledDice object
@@ -100,9 +116,9 @@ Examples :
100
116
  >> Hazard.s2d6
101
117
  => #<RolledDice:0x007f62e55a0010 @rolls=[1, 6], @result=7>
102
118
 
103
- **Some real cases**
119
+ ### Some real cases
104
120
 
105
- # Assuming you are playing DD Next
121
+ Assuming you are playing DD Next
106
122
 
107
123
  # You may want to roll 2 d20 dice with advantage (take the greatest)
108
124
  # This will rolls 2 d20, get the rolls and get the best of them
@@ -120,8 +136,50 @@ Examples :
120
136
  # Should you have the Elemental Adept feat, which mean that you treat all 1 as 2
121
137
  # If you cast a fireball, this will do the trick :
122
138
  >> Hazard.s8d6.rolls.map{ |d| d == 1 ? 2 : d }.reduce(:+)
123
- => 24
139
+ => 24
140
+
141
+ ## Weighted Tables
124
142
 
143
+ Weighted tables are object that allow to get weighted random.
144
+ Example : if you have two time foo and one time bar in your table.
145
+
146
+ ### If you have the weights
147
+
148
+ >> wt = WeightedTable.from_weighted_table( [ <weight1>, <object1> ], [ <weight2>, <object2> ], ... ]
149
+ # Create a weighted table storing objects according to theire weights
150
+
151
+ >> wt.sample
152
+ # Return weighted random object
153
+
154
+ Examples :
155
+
156
+ >> wt = WeightedTable.new.from_weighted_table( [ 2, :foo ], [ 1, :bar ] ]
157
+ >> wt.sample
158
+ # This ensure that you will get 66% foo and 33% bar
159
+
160
+
161
+ ### If you don't have the weights (or are to lazy to get them)
162
+
163
+ >> wt = WeightedTable.from_flat_table( <object1>, <object1>, <object2>, ... ]
164
+ # Create a weighted table storing objects computing the weight of the objects according to theire occurences
165
+
166
+ >> wt.sample
167
+ # Return weighted random object
168
+
169
+ Examples :
170
+
171
+ >> wt = WeightedTable.new.from_flat_table( :foo, :foo, :bar ]
172
+ >> wt.sample
173
+ # This ensure that you will get 66% foo and 33% bar
174
+
175
+ ### Saving and loading
176
+
177
+ # You can save your builded table for future usage
178
+ >> wt.to_file( filename )
179
+
180
+ # And load it
181
+ >> wt = WeightedTable.from_file( filename )
182
+
125
183
  ## Contributing
126
184
 
127
185
  Bug reports and pull requests are welcome on GitHub at https://github.com/czuger/hazard. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
@@ -1,3 +1,3 @@
1
1
  class Hazard
2
- VERSION = '1.0.4'
2
+ VERSION = '1.1.0'
3
3
  end
data/lib/hazard.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require_relative 'rolled_dice'
2
+ require_relative 'weighted_table'
2
3
 
3
4
  class Hazard
4
5
 
@@ -0,0 +1,88 @@
1
+ require 'yaml'
2
+
3
+ class WeightedTable
4
+
5
+ BASE_WEIGHT = 1
6
+
7
+ def initialize
8
+ @weights = {}
9
+ @max_weight = BASE_WEIGHT
10
+ end
11
+
12
+ # Load a WeightedTable with data
13
+ # Data format must be : [ [ weight, data ], [ weight, data ], ... ]
14
+ # Example : [ [ 2, :foo ], [ 1, :bar ] ]
15
+ #
16
+ # @return [WeightedTable] the current WeightedTable
17
+ def self.from_weighted_table( table )
18
+ WeightedTable.new.from_weighted_table( table )
19
+ end
20
+
21
+ # Load a WeightedTable with data
22
+ # Data format must be : [ [ weight, data ], [ weight, data ], ... ]
23
+ # Example : [ [ 2, :foo ], [ 1, :bar ] ]
24
+ #
25
+ # @return [WeightedTable] the current WeightedTable
26
+ def from_weighted_table( table )
27
+ raise 'Table must contain at least one element' if table.empty?
28
+ base = BASE_WEIGHT
29
+ table.each do |t|
30
+ w = base+t[0]
31
+ base = w
32
+ @weights[ w ] = t[1]
33
+ @max_weight = [ @max_weight, w-1 ].max
34
+ end
35
+ self
36
+ end
37
+
38
+ # Load a WeightedTable with data
39
+ # Data format must be : [ data, data, data ]
40
+ # Example : [ :foo, :foo, :bar ]
41
+ #
42
+ # @return [WeightedTable] the current WeightedTable
43
+ def self.from_flat_table( table )
44
+ from_weighted_table( table.group_by{ |e| e }.map{ |k, v| [ v.count, k ] } )
45
+ end
46
+
47
+ # Return a random item from a WeightedTable
48
+ #
49
+ # @return [Object] a random object given at the building of the table.
50
+ def sample
51
+ r = Kernel.rand( 1..@max_weight )
52
+ keys = @weights.keys.sort
53
+
54
+ low_mark = BASE_WEIGHT
55
+
56
+ until keys.empty?
57
+ high_mark = keys.shift
58
+ return @weights[high_mark] if r >= low_mark && r < high_mark
59
+ low_mark = high_mark
60
+ end
61
+
62
+ raise 'Rand not in key range'
63
+ end
64
+
65
+ # Load a WeightedTable with data
66
+ # Data format must be : [ data, data, data ]
67
+ # Example : [ :foo, :foo, :bar ]
68
+ #
69
+ # @return [WeightedTable] the current WeightedTable
70
+ def from_flat_table( table )
71
+ from_weighted_table( table.group_by{ |e| e }.map{ |k, v| [ v.count, k ] } )
72
+ end
73
+
74
+ # Save the table to a file
75
+ # @param filename [String] the filename where to save the table
76
+ def to_file( filename )
77
+ File.open( filename, 'w' ) do |f|
78
+ f.write( to_yaml )
79
+ end
80
+ end
81
+
82
+ # Read the table from a file
83
+ # @param filename [String] the filename from which to read the table
84
+ def self.from_file( filename )
85
+ YAML.load_file( filename )
86
+ end
87
+
88
+ end
data/test/test_helper.rb CHANGED
@@ -7,4 +7,5 @@ require 'hazard'
7
7
 
8
8
  require 'minitest/autorun'
9
9
  require 'mocha/mini_test'
10
+ require 'pp'
10
11
 
@@ -0,0 +1,73 @@
1
+ require 'test_helper'
2
+
3
+ class HazardTest < Minitest::Test
4
+
5
+ def test_empty_table
6
+ assert_raises do
7
+ WeightedTable.from_weighted_table []
8
+ end
9
+ assert_raises do
10
+ WeightedTable.from_flat_table []
11
+ end
12
+ end
13
+
14
+ def test_one_element_table
15
+ assert_equal :foo, WeightedTable.from_weighted_table( [ [ 3, :foo ] ] ).sample
16
+ assert_equal :foo, WeightedTable.from_flat_table( [ :foo, :foo, :foo ] ).sample
17
+ end
18
+
19
+ def test_two_element_table
20
+ Kernel.stubs( :rand ).returns( 0 )
21
+ assert_raises do
22
+ WeightedTable.from_weighted_table []
23
+ end
24
+ assert_raises do
25
+ WeightedTable.from_flat_table []
26
+ end
27
+
28
+ Kernel.stubs( :rand ).returns( 1 )
29
+ assert_equal :foo, WeightedTable.from_weighted_table( [ [ 3, :foo ], [ 1, :bar ] ] ).sample
30
+ assert_equal :foo, WeightedTable.from_flat_table( [ :foo, :foo, :foo, :bar ] ).sample
31
+ Kernel.stubs( :rand ).returns( 2 )
32
+ assert_equal :foo, WeightedTable.from_weighted_table( [ [ 3, :foo ], [ 1, :bar ] ] ).sample
33
+ assert_equal :foo, WeightedTable.from_flat_table( [ :foo, :foo, :foo, :bar ] ).sample
34
+ Kernel.stubs( :rand ).returns( 3 )
35
+ assert_equal :foo, WeightedTable.from_weighted_table( [ [ 3, :foo ], [ 1, :bar ] ] ).sample
36
+ assert_equal :foo, WeightedTable.from_flat_table( [ :foo, :foo, :foo, :bar ] ).sample
37
+ Kernel.stubs( :rand ).returns( 4 )
38
+ assert_equal :bar, WeightedTable.from_weighted_table( [ [ 3, :foo ], [ 1, :bar ] ] ).sample
39
+ assert_equal :bar, WeightedTable.from_flat_table( [ :foo, :foo, :foo, :bar ] ).sample
40
+
41
+ Kernel.stubs( :rand ).returns( 5 )
42
+ assert_raises do
43
+ WeightedTable.from_weighted_table []
44
+ end
45
+ assert_raises do
46
+ WeightedTable.from_flat_table []
47
+ end
48
+ end
49
+
50
+ def test_statistics
51
+
52
+ wt = WeightedTable.from_weighted_table [ [ 2, :foo ], [ 1, :bar ] ]
53
+ results = { foo: 0, bar: 0 }
54
+ 1.upto(100).each do
55
+ results[ wt.sample ] += 1
56
+ end
57
+
58
+ assert_in_delta 0.33, (results[:bar]*0.01), 0.1
59
+ assert_in_delta 0.66, (results[:foo]*0.01), 0.1
60
+ end
61
+
62
+ def test_save_and_load
63
+ wt = WeightedTable.from_weighted_table [ [ 2, :foo ], [ 1, :bar ] ]
64
+ wt.to_file( 'wt.yaml' )
65
+ wt = nil
66
+ wt = WeightedTable.from_file( 'wt.yaml' )
67
+ Kernel.stubs( :rand ).returns( 1 )
68
+ assert_equal :foo, wt.sample
69
+ assert_equal :foo, wt.sample
70
+ `rm wt.yaml`
71
+ end
72
+
73
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hazard
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cédric ZUGER
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-03-20 00:00:00.000000000 Z
11
+ date: 2018-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -71,8 +71,10 @@ files:
71
71
  - lib/hazard.rb
72
72
  - lib/hazard/version.rb
73
73
  - lib/rolled_dice.rb
74
+ - lib/weighted_table.rb
74
75
  - test/hazard_test.rb
75
76
  - test/test_helper.rb
77
+ - test/weighted_table_test.rb
76
78
  homepage: https://github.com/czuger/hazard
77
79
  licenses:
78
80
  - MIT
@@ -100,3 +102,4 @@ summary: Dice library for ruby
100
102
  test_files:
101
103
  - test/hazard_test.rb
102
104
  - test/test_helper.rb
105
+ - test/weighted_table_test.rb