polyhedral 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+