polyhedral 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.
Files changed (4) hide show
  1. data/README +23 -0
  2. data/lib/polyhedral.rb +22 -0
  3. data/lib/polyhedral/die.rb +313 -0
  4. metadata +55 -0
data/README ADDED
@@ -0,0 +1,23 @@
1
+ == What
2
+ Ye classic polyhedral dice program, complete with personalization.
3
+
4
+ == How
5
+ require 'rubygems'
6
+ require 'polyhedral'
7
+
8
+ == Install
9
+ To construct a Ruby gem, just type:
10
+
11
+ rake gem
12
+
13
+ To install it, type:
14
+
15
+ sudo gem install polyhedral-0.0.1.gem
16
+
17
+ == Notes
18
+ I haven't tested this code with YARV, so YMMV.
19
+
20
+ == Contribute
21
+ The source is availble at github: git://github.com/yesmar/polyhedral.git. Feel
22
+ free to clone it and implement your own awesome ideas. You can also send your
23
+ patches by email to yesmar[at]speakeasy[dot]net.
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # polyhedram.rb
4
+ # yesmar@speakeasy.net
5
+
6
+ module Polyhedral
7
+ Polyhedral::NAME = 'polyhedral'
8
+ Polyhedral::VERSION = '0.0.1'
9
+ Polyhedral::COPYRIGHT = 'Copyright (c) 2008 Ramsey Dow'
10
+ def self.copyright() Polyhedral::COPYRIGHT end
11
+ def self.version() Polyhedral::VERSION end
12
+ def self.libdir() File.expand_path(__FILE__).gsub(%r/\.rb$/, '') end
13
+ end
14
+
15
+ $LOAD_PATH.unshift(File.dirname(__FILE__)+'/polyhedral')
16
+
17
+ require 'die'
18
+
19
+ # TODO: bad developer, no unit tests
20
+ # TODO: need to finish developing example programs
21
+
22
+ raise RuntimeError, 'This library is for require only' if $0 == __FILE__
@@ -0,0 +1,313 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # die.rb
4
+ # yesmar@speakeasy.net
5
+
6
+ module Polyhedral
7
+ class Die
8
+ attr_reader :sides, :material, :color
9
+ attr_accessor :name
10
+
11
+ DEFAULT_SIDES = 6
12
+ DEFAULT_TIMES = 1
13
+
14
+ # initialize Die instance
15
+ def initialize(sides=DEFAULT_SIDES, name=nil, material=nil, color=nil,
16
+ seed=nil
17
+ )
18
+ raise ArgumentError, 'nil sides' if sides.nil?
19
+ raise ArgumentError, 'invalid sides class' if !sides.is_a?(Integer)
20
+ if !name.nil?
21
+ raise ArgumentError, 'nil name' if name.nil?
22
+ raise ArgumentError, 'invalid name' if name.class != String
23
+ raise ArgumentError, 'empty name' if name.empty?
24
+ end
25
+ if !material.nil?
26
+ raise ArgumentError, 'nil material' if material.nil?
27
+ raise ArgumentError, 'invalid material' if material.class != String
28
+ raise ArgumentError, 'empty material' if material.empty?
29
+ end
30
+ if !color.nil?
31
+ raise ArgumentError, 'nil color' if color.nil?
32
+ raise ArgumentError, 'invalid color' if color.class != String
33
+ raise ArgumentError, 'empty color' if color.empty?
34
+ end
35
+ if !seed.nil?
36
+ raise ArgumentError, 'invalid seed class' if !seed.is_a?(Integer)
37
+ end
38
+
39
+ @sides = sides
40
+ @seed = seed
41
+
42
+ if !@seed.nil?
43
+ srand(@seed)
44
+ else
45
+ srand
46
+ end
47
+
48
+ @count = 0
49
+ @frequency = Array.new(@sides, 0)
50
+
51
+ @name = name
52
+ @material = material
53
+ @color = color
54
+
55
+ nil
56
+ end
57
+
58
+ # dump instance state to specified output stream
59
+ def dump(stream=STDOUT, indent=0)
60
+ raise ArgumentError, 'nil stream' if stream.nil?
61
+ raise ArgumentError, 'invalid stream class' if stream.class != IO
62
+ raise ArgumentError, 'nil indent' if indent.nil?
63
+ raise ArgumentError, 'invalid indent class' if !indent.is_a?(Integer)
64
+ raise ArgumentError, 'indent range error' if indent < 0
65
+
66
+ # instance
67
+ indent.times { stream << ' ' }
68
+ stream << "#{self.class}<id=#{self.object_id}>:\n"
69
+
70
+ indent += 2
71
+
72
+ # sides
73
+ indent.times { stream << ' ' }
74
+ stream << "sides: #{@sides}\n"
75
+
76
+ # seed
77
+ indent.times { stream << ' ' }
78
+ stream << "seed: #{@seed ? @seed : 'nil'}\n"
79
+
80
+ # count
81
+ indent.times { stream << ' ' }
82
+ stream << "count: #{@count}\n"
83
+
84
+ # frequency
85
+ indent.times { stream << ' ' }
86
+ stream << "frequency<id=#{@frequency.object_id}>:\n"
87
+ (indent-1).times { stream << ' ' }
88
+ @frequency.each { |f| stream << " #{f}" }
89
+ stream << "\n"
90
+
91
+ # name
92
+ indent.times { stream << ' ' }
93
+ stream << "name: #{@name ? @name : 'nil'}\n"
94
+
95
+ # material
96
+ indent.times { stream << ' ' }
97
+ stream << "material: #{@material ? @material : 'nil'}\n"
98
+
99
+ # color
100
+ indent.times { stream << ' ' }
101
+ stream << "color: #{@color ? @color : 'nil'}\n"
102
+
103
+ nil
104
+ end
105
+
106
+ # throw die n times (applying modifier as appropriate)
107
+ def throw(quantity=DEFAULT_TIMES, modifier=0)
108
+ raise ArgumentError, 'nil quantity' if quantity.nil?
109
+ raise ArgumentError, 'invalid quantity class' if !quantity.is_a?(Integer)
110
+ raise ArgumentError, 'invalid quantity value' if quantity < 1
111
+ raise ArgumentError, 'nil modifier' if modifier.nil?
112
+ raise ArgumentError, 'invalid modifier class' if !modifier.is_a?(Integer)
113
+
114
+ score = 0
115
+
116
+ # update throw count
117
+ @count += quantity
118
+
119
+ quantity.times do
120
+ result = rand(@sides) + 1
121
+ score += result
122
+
123
+ # update frequency count
124
+ @frequency[result-1] += 1
125
+ end
126
+
127
+ score+modifier
128
+ end
129
+
130
+ # emit Die instance as Integer
131
+ def to_i
132
+ @sides
133
+ end
134
+
135
+ # emit Die instance as String
136
+ def to_s
137
+ "d#{sides}"
138
+ end
139
+
140
+ # return description of the Die instance
141
+ def inspect
142
+ desc = []
143
+
144
+ desc << "#{@name} is " if !@name.nil? && !@name.empty?
145
+ desc << 'a'
146
+ desc << " #{@color}" if !@color.nil? && !@color.empty?
147
+ desc << " #{@material}" if !@material.nil? && !@material.empty?
148
+ desc << " #{self}"
149
+
150
+ desc << " (#{@count} throw"
151
+ if @count != 1
152
+ desc << 's)'
153
+ else
154
+ desc << ')'
155
+ end
156
+
157
+ desc.join
158
+ end
159
+
160
+ # dump frequency graph to specified output stream
161
+ def frequency(stream=STDOUT)
162
+ raise ArgumentError, 'nil stream' if stream.nil?
163
+ raise ArgumentError, 'invalid stream class' if stream.class != IO
164
+
165
+ num = max_frequency
166
+ min = min_frequency
167
+ min -= 1 if min > 0
168
+
169
+ stream << "Throws Frequency Graph"
170
+ stream << " for #{@name}" if !@name.nil? && !@name.empty?
171
+ stream << "\n\n"
172
+
173
+ while num > min do
174
+ printf(stream, "%6d", num)
175
+
176
+ @frequency.each do |f|
177
+ if f >= num
178
+ stream << ' *'
179
+ else
180
+ stream << ' '
181
+ end
182
+ end
183
+
184
+ stream << "\n"
185
+ num -= 1
186
+ end
187
+
188
+ stream << "\n "
189
+ @frequency.length.times do |f|
190
+ n = f+1
191
+ if n.to_s.length >= 2
192
+ stream << ' '
193
+ else
194
+ stream << ' '
195
+ end
196
+ stream << n
197
+ end
198
+ stream << "\n"
199
+
200
+ nil
201
+ end
202
+
203
+ # return array of historically lowest scoring side(s)
204
+ def lowest
205
+ min_f = 1000000
206
+ low_side = @sides-1
207
+
208
+ @sides.times do |s|
209
+ if @frequency[s] < min_f
210
+ min_f = @frequency[s]
211
+ low_side = s
212
+ end
213
+ end
214
+
215
+ low_set = Array.new
216
+ low_set << low_side+1
217
+
218
+ @sides.times do |s|
219
+ next if s == low_side
220
+ low_set << s+1 if @frequency[s] == @frequency[low_side]
221
+ end
222
+
223
+ low_set
224
+ end
225
+
226
+ # return array of historically highest scoring side(s)
227
+ def highest
228
+ max_f = 0
229
+ high_side = 0
230
+
231
+ @sides.times do |s|
232
+ if @frequency[s] > max_f
233
+ max_f = @frequency[s]
234
+ high_side = s
235
+ end
236
+ end
237
+
238
+ high_set = Array.new
239
+ high_set << high_side+1
240
+
241
+ @sides.times do |s|
242
+ next if s == high_side
243
+ high_set << s+1 if @frequency[s] == @frequency[high_side]
244
+ end
245
+
246
+ high_set
247
+ end
248
+
249
+ # store Die instance to disk
250
+ def to_file(pathname)
251
+ # validate arguments
252
+ raise ArgumentError, 'nil pathname' if pathname.nil?
253
+ raise ArgumentError, 'invalid pathname class' if pathname.class != String
254
+ raise ArgumentError, 'empty pathname' if pathname.empty?
255
+
256
+ begin
257
+ f = File.open(pathname, 'w')
258
+ Marshal.dump(self, f)
259
+ rescue Exception => e
260
+ return false
261
+ ensure
262
+ f.close
263
+ end
264
+
265
+ return true
266
+ end
267
+
268
+ # load Die instance from disk
269
+ def Die.from_file(pathname)
270
+ # validate arguments
271
+ raise ArgumentError, 'nil pathname' if pathname.nil?
272
+ raise ArgumentError, 'invalid pathname class' if pathname.class != String
273
+ raise ArgumentError, 'empty pathname' if pathname.empty?
274
+
275
+ begin
276
+ f = File.open(pathname, 'r')
277
+ object = Marshal.load(f)
278
+ rescue Exception => e
279
+ return nil
280
+ ensure
281
+ f.close unless f.nil?
282
+ end
283
+
284
+ return object
285
+ end
286
+
287
+ private
288
+
289
+ # return minimum frequency
290
+ def min_frequency
291
+ min_f = 1000000
292
+ @frequency.each { |f| min_f = f if f < min_f }
293
+ min_f
294
+ end
295
+
296
+ # return maximum frequency
297
+ def max_frequency
298
+ max_f = 0
299
+ @frequency.each { |f| max_f = f if f > max_f }
300
+ max_f
301
+ end
302
+
303
+ @sides
304
+ @seed
305
+ @count
306
+ @frequency
307
+ @name
308
+ @material
309
+ @color
310
+ end
311
+ end
312
+
313
+ raise RuntimeError, 'This library is for require only' if $0 == __FILE__
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: polyhedral
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ramsey Dow
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-02-27 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: yesmar @nospam@ speakeasy.net
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - lib/polyhedral.rb
26
+ - lib/polyhedral/die.rb
27
+ - README
28
+ has_rdoc: true
29
+ homepage: http://polyhedral.rubyforge.org/
30
+ post_install_message:
31
+ rdoc_options: []
32
+
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: "0"
40
+ version:
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ requirements: []
48
+
49
+ rubyforge_project: http://rubyforge.org/projects/polyhedral/
50
+ rubygems_version: 1.0.1
51
+ signing_key:
52
+ specification_version: 2
53
+ summary: Ye classic polyhedral dice
54
+ test_files: []
55
+