rubylabs 0.5.4
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/LICENSE +20 -0
- data/README.rdoc +9 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/bin/bb.rb +12 -0
- data/bin/statistics2-0.53/ext/extconf.rb +11 -0
- data/bin/statistics2-0.53/ext/show.rb +11 -0
- data/bin/statistics2-0.53/ext/t.rb +46 -0
- data/bin/statistics2-0.53/mklist.rb +26 -0
- data/bin/statistics2-0.53/sample-tbl.rb +129 -0
- data/bin/statistics2-0.53/statistics2.rb +532 -0
- data/bin/statistics2-0.53/t-inv.rb +54 -0
- data/bin/statistics2.rb +532 -0
- data/data/aafreq.txt +20 -0
- data/data/cars.txt +50 -0
- data/data/century.txt +1 -0
- data/data/colors.txt +64 -0
- data/data/earth.yaml +15 -0
- data/data/fruit.txt +45 -0
- data/data/hacodes.txt +35 -0
- data/data/hafreq.txt +16 -0
- data/data/hvfreq.txt +5 -0
- data/data/nbody.R +23 -0
- data/data/nbody.out +731 -0
- data/data/nbody.pdf +3111 -0
- data/data/nbody.png +0 -0
- data/data/nbody3d.pdf +3201 -0
- data/data/outer.pdf +182785 -0
- data/data/solar.dat +36501 -0
- data/data/solarsystem.txt +17 -0
- data/data/suits.txt +1 -0
- data/data/wordlist.txt +210653 -0
- data/lib/bitlab.rb +624 -0
- data/lib/elizalab.rb +523 -0
- data/lib/encryptionlab.rb +42 -0
- data/lib/hashlab.rb +224 -0
- data/lib/introlab.rb +14 -0
- data/lib/iterationlab.rb +130 -0
- data/lib/randomlab.rb +294 -0
- data/lib/recursionlab.rb +228 -0
- data/lib/rubylabs.rb +507 -0
- data/lib/sievelab.rb +58 -0
- data/lib/sortlab.rb +213 -0
- data/lib/spherelab.rb +352 -0
- data/lib/temps.rb +41 -0
- data/lib/tsplab.rb +416 -0
- data/lib/viewer.rb +65 -0
- data/test/bit_test.rb +175 -0
- data/test/encryption_test.rb +20 -0
- data/test/iteration_test.rb +40 -0
- data/test/random_test.rb +64 -0
- data/test/recursion_test.rb +47 -0
- data/test/rubylabs_test.rb +18 -0
- data/test/sieve_test.rb +28 -0
- data/test/sphere_test.rb +130 -0
- data/test/temps_test.rb +24 -0
- data/test/test_helper.rb +18 -0
- metadata +112 -0
data/lib/hashlab.rb
ADDED
@@ -0,0 +1,224 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
|
3
|
+
== HashLab
|
4
|
+
|
5
|
+
Methods used in experiments on hash tables.
|
6
|
+
|
7
|
+
<b>NOTE:</b> the +insert+ and +find+ methods defined here are "stubs" used to test the hash
|
8
|
+
functions. Load the file <tt>hashmethods.rb</tt> to overwrite the stubs with the actual
|
9
|
+
methods that create and search buckets.
|
10
|
+
|
11
|
+
=end
|
12
|
+
|
13
|
+
module RubyLabs
|
14
|
+
|
15
|
+
module HashLab
|
16
|
+
|
17
|
+
=begin rdoc
|
18
|
+
|
19
|
+
Ruby version of the ``card catalog box'' number, a trivial hash function that
|
20
|
+
maps two-letter strings to numbers between 0 and 675.
|
21
|
+
|
22
|
+
=end
|
23
|
+
|
24
|
+
# :begin :ccb
|
25
|
+
def ccb(s)
|
26
|
+
return s[0].ord * 26 + s[1].ord
|
27
|
+
end
|
28
|
+
# :end :ccb
|
29
|
+
|
30
|
+
=begin rdoc
|
31
|
+
|
32
|
+
The "small card catalog box" number, a version of ccb that works
|
33
|
+
for a smaller catalog (n = 100 boxes).
|
34
|
+
|
35
|
+
=end
|
36
|
+
|
37
|
+
# :begin :sccb
|
38
|
+
def sccb(s)
|
39
|
+
return ccb(s) % 100
|
40
|
+
end
|
41
|
+
# :end :sccb
|
42
|
+
|
43
|
+
=begin rdoc
|
44
|
+
|
45
|
+
"Randomized" version of sccb that uses prime numbers to do
|
46
|
+
a better job of scattering words more evenly.
|
47
|
+
|
48
|
+
=end
|
49
|
+
|
50
|
+
# :begin :rccb
|
51
|
+
def rccb(s)
|
52
|
+
return (s[0].ord * 31 + s[1].ord * 107) % 100
|
53
|
+
end
|
54
|
+
# :end :rccb
|
55
|
+
|
56
|
+
=begin rdoc
|
57
|
+
|
58
|
+
Compute the sum of the letters in a string, where each letter is weighted
|
59
|
+
according to its position. Requires the +ord+ method added to Fixnum in the
|
60
|
+
RubyLabs module.
|
61
|
+
|
62
|
+
=end
|
63
|
+
|
64
|
+
# :begin :radix26
|
65
|
+
def radix26(s)
|
66
|
+
x = 0
|
67
|
+
s.each_byte do |b|
|
68
|
+
x = x * 26 + b.ord
|
69
|
+
end
|
70
|
+
return x
|
71
|
+
end
|
72
|
+
# :end :radix26
|
73
|
+
|
74
|
+
=begin rdoc
|
75
|
+
Trival hash function that uses only the first letter in the input string. +s+ is the
|
76
|
+
string to hash, +n+ is the size of the hash table.
|
77
|
+
=end
|
78
|
+
|
79
|
+
# :begin :h0
|
80
|
+
def h0(s, n)
|
81
|
+
return s[0].ord % n
|
82
|
+
end
|
83
|
+
# :end :h0
|
84
|
+
|
85
|
+
=begin rdoc
|
86
|
+
Slightly better hash function that uses the first two letters in the input string. +s+ is the
|
87
|
+
string to hash, +n+ is the size of the hash table.
|
88
|
+
=end
|
89
|
+
|
90
|
+
# :begin :h1
|
91
|
+
def h1(s, n)
|
92
|
+
return ((s[0].ord * 26) + s[1].ord) % n
|
93
|
+
end
|
94
|
+
# :end :h1
|
95
|
+
|
96
|
+
=begin rdoc
|
97
|
+
Hash function based on the radix-26 representation of the input string. +s+ is the
|
98
|
+
string to hash, +n+ is the size of the hash table.
|
99
|
+
=end
|
100
|
+
|
101
|
+
# :begin :hn
|
102
|
+
def hn(s, n)
|
103
|
+
return radix26(s) % n
|
104
|
+
end
|
105
|
+
# :end :hn
|
106
|
+
|
107
|
+
alias h hn
|
108
|
+
|
109
|
+
=begin rdoc
|
110
|
+
|
111
|
+
Make a hash table with +n+ buckets. The optional parameter is a symbol specifying
|
112
|
+
an alternative hash function (<tt>:h0</tt> or <tt>:h1</tt>); the default is the method +hn+, which
|
113
|
+
uses the radix26 function.
|
114
|
+
|
115
|
+
The object returned by this method is an array of the designated size. A bit of
|
116
|
+
Ruby magic defines three new methods just for the new object:
|
117
|
+
[<tt>h=(f)</tt>] tells the table to use method f for the hash function (:h0, :h1, or nil)
|
118
|
+
[<tt>h</tt>] returns the id of the hash function currently being used
|
119
|
+
[<tt>hash(s)</tt>] call the current hash function on string s
|
120
|
+
|
121
|
+
=end
|
122
|
+
|
123
|
+
def make_table(n, f = nil)
|
124
|
+
t = Array.new(n)
|
125
|
+
|
126
|
+
class <<t
|
127
|
+
attr_accessor :h
|
128
|
+
|
129
|
+
def hash(s)
|
130
|
+
return case self.h
|
131
|
+
when :h0 : h0(s, self.size)
|
132
|
+
when :h1 : h1(s, self.size)
|
133
|
+
else hn(s, self.size)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
t.h = f
|
139
|
+
return t
|
140
|
+
end
|
141
|
+
|
142
|
+
=begin rdoc
|
143
|
+
Return +true+ or +false+, depending on whether string +s+ is in hash table +t+. The
|
144
|
+
table must be an object created by a call to <tt>make_table</tt>.
|
145
|
+
=end
|
146
|
+
|
147
|
+
# :begin :find
|
148
|
+
def find(s, t)
|
149
|
+
i = t.hash(s)
|
150
|
+
return (t[i] == s)
|
151
|
+
end
|
152
|
+
# :end :find
|
153
|
+
|
154
|
+
=begin rdoc
|
155
|
+
Insert string +s+ into hash table +t+. The
|
156
|
+
table must be an object created by a call to <tt>make_table</tt>.
|
157
|
+
=end
|
158
|
+
|
159
|
+
# :begin :insert
|
160
|
+
def insert(s, t)
|
161
|
+
i = t.hash(s)
|
162
|
+
if t[i].nil?
|
163
|
+
t[i] = s
|
164
|
+
return true
|
165
|
+
else
|
166
|
+
puts "collision!"
|
167
|
+
return false
|
168
|
+
end
|
169
|
+
end
|
170
|
+
# :end :insert
|
171
|
+
|
172
|
+
=begin rdoc
|
173
|
+
Print a nicely formatted representation of hash table +t+. The optional parameter
|
174
|
+
is the number of rows to print, e.g. to print just the first 10 rows of a large table
|
175
|
+
+t+ call <tt>print_table(t,10)</tt>. Skips rows that have empty buckets.
|
176
|
+
=end
|
177
|
+
|
178
|
+
def print_table(t, max = nil)
|
179
|
+
max = t.length unless max
|
180
|
+
max.times { |i| print_row(i, t) unless t[i].nil? }
|
181
|
+
nil
|
182
|
+
end
|
183
|
+
|
184
|
+
def print_row(n, t) # :nodoc:
|
185
|
+
printf "%4d: ", n
|
186
|
+
p t[n]
|
187
|
+
end
|
188
|
+
|
189
|
+
=begin rdoc
|
190
|
+
Print usage statistics for hash table +t+. Prints lengths of longest and shortest
|
191
|
+
buckets, number of empty buckets, and mean bucket length.
|
192
|
+
=end
|
193
|
+
|
194
|
+
def print_stats(t)
|
195
|
+
max = 0
|
196
|
+
min = Float::MAX
|
197
|
+
nzero = 0
|
198
|
+
sum = 0
|
199
|
+
t.each do |bucket|
|
200
|
+
n = bucket.nil? ? 0 : bucket.length
|
201
|
+
min = n if n < min
|
202
|
+
max = n if n > max
|
203
|
+
sum += n
|
204
|
+
nzero += 1 if n == 0
|
205
|
+
end
|
206
|
+
puts "shortest bucket: #{min} items"
|
207
|
+
puts "longest bucket: #{max} items"
|
208
|
+
puts "empty buckets: #{nzero}"
|
209
|
+
puts "mean bucket length: #{sum.to_f / (t.length - nzero)}" unless nzero == t.length
|
210
|
+
nil
|
211
|
+
end
|
212
|
+
|
213
|
+
=begin rdoc
|
214
|
+
Scan the hash table +t+ and print all the buckets that have more than +cutoff+ entries.
|
215
|
+
=end
|
216
|
+
|
217
|
+
def print_long_rows(t, cutoff = 5)
|
218
|
+
t.length.times { |i| print_row(i, t) if !t[i].nil? && t[i].length >= cutoff }
|
219
|
+
nil
|
220
|
+
end
|
221
|
+
|
222
|
+
end # HashLab
|
223
|
+
|
224
|
+
end # RubyLabs
|
data/lib/introlab.rb
ADDED
data/lib/iterationlab.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
|
2
|
+
=begin rdoc
|
3
|
+
|
4
|
+
== IterationLab
|
5
|
+
|
6
|
+
The methods implemented in this module are
|
7
|
+
+contains?+ (linear search returning true or false),
|
8
|
+
+location+ (linear search returning the index of specified item), and
|
9
|
+
+isort+ (insertion sort). See the RecursionLab module for more
|
10
|
+
sophisticated "divide and conquer" searching and sorting algorithms.
|
11
|
+
|
12
|
+
=end
|
13
|
+
|
14
|
+
module RubyLabs
|
15
|
+
|
16
|
+
module IterationLab
|
17
|
+
|
18
|
+
=begin rdoc
|
19
|
+
Do a linear search of array +a+ to find item +key+, returning
|
20
|
+
+true+ or +false+ depending on whether the item was found.
|
21
|
+
=end
|
22
|
+
|
23
|
+
# :begin :contains?
|
24
|
+
def contains?(a, k)
|
25
|
+
a.each { |x| return true if x == k}
|
26
|
+
return false
|
27
|
+
end
|
28
|
+
# :end :contains?
|
29
|
+
|
30
|
+
=begin rdoc
|
31
|
+
Do a linear search of array +a+ to find item +k+, returning
|
32
|
+
the index of the first occurrence of +k+ or +nil+ if +k+ is
|
33
|
+
not found.
|
34
|
+
=end
|
35
|
+
|
36
|
+
# :begin :search
|
37
|
+
def search(a, k)
|
38
|
+
i = 0
|
39
|
+
while i < a.length
|
40
|
+
return i if a[i] == k
|
41
|
+
i += 1
|
42
|
+
end
|
43
|
+
return nil
|
44
|
+
end
|
45
|
+
# :end :search
|
46
|
+
|
47
|
+
=begin rdoc
|
48
|
+
Return a copy of +array+, sorted with the insertion sort algorithm.
|
49
|
+
On each iteration remove an item from the
|
50
|
+
array, find a location for it to the left of its original position,
|
51
|
+
and insert it back into the array at the new location.
|
52
|
+
=end
|
53
|
+
|
54
|
+
# :begin :isort :insert_left :less
|
55
|
+
def isort(array)
|
56
|
+
a = array.clone # don't modify the input array....
|
57
|
+
i = 1
|
58
|
+
while i < a.length
|
59
|
+
insert_left(a, i) # find a place for a[i] somewhere to the left
|
60
|
+
i += 1
|
61
|
+
end
|
62
|
+
return a
|
63
|
+
end
|
64
|
+
# :end :isort
|
65
|
+
|
66
|
+
# :begin :insert_left
|
67
|
+
def insert_left(a, i)
|
68
|
+
x = a.slice!(i) # remove the item at location i
|
69
|
+
j = i-1 # start scanning from the left of i
|
70
|
+
while j >= 0 && less(x, a[j])
|
71
|
+
j = j-1 # move left
|
72
|
+
end
|
73
|
+
a.insert(j+1, x) # insert x back into a at location j
|
74
|
+
end
|
75
|
+
# :end :insert_left
|
76
|
+
|
77
|
+
# :begin :less
|
78
|
+
def less(x, y)
|
79
|
+
return x < y
|
80
|
+
end
|
81
|
+
# :end :less
|
82
|
+
|
83
|
+
=begin rdoc
|
84
|
+
Simple demonstration of why nested loops lead to n^2 operations
|
85
|
+
=end
|
86
|
+
|
87
|
+
# :begin :nested
|
88
|
+
def nested(n)
|
89
|
+
n.times do |i|
|
90
|
+
n.times do |j|
|
91
|
+
puts "i = #{i}, j = #{j}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
# :end :nested
|
96
|
+
|
97
|
+
# code used in figure next to nested
|
98
|
+
|
99
|
+
def isnest(n)
|
100
|
+
i = 1
|
101
|
+
while i < n
|
102
|
+
j = i-1
|
103
|
+
while j >= 0
|
104
|
+
puts "i = #{i}, j = #{j}"
|
105
|
+
j = j-1
|
106
|
+
end
|
107
|
+
i = i+1
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
=begin rdoc
|
112
|
+
A helper method that can be called from a probe to display the contents
|
113
|
+
of an array during a search or sort.
|
114
|
+
=end
|
115
|
+
|
116
|
+
def brackets(a, i)
|
117
|
+
if i <= 0
|
118
|
+
return ("[" + a.join(" ") + "]")
|
119
|
+
elsif i >= a.length
|
120
|
+
return " " + a.join(" ") + " [ ]"
|
121
|
+
else
|
122
|
+
pre = a.slice(0..(i-1))
|
123
|
+
post = a.slice(i..-1)
|
124
|
+
return " " + pre.join(" ") + " [" + post.join(" ") + "]"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end # IterationLab
|
129
|
+
|
130
|
+
end # RubyLabs
|
data/lib/randomlab.rb
ADDED
@@ -0,0 +1,294 @@
|
|
1
|
+
|
2
|
+
=begin rdoc
|
3
|
+
|
4
|
+
== RandomLab
|
5
|
+
|
6
|
+
Random number generators and associated methods.
|
7
|
+
|
8
|
+
=end
|
9
|
+
|
10
|
+
module RubyLabs
|
11
|
+
|
12
|
+
module RandomLab
|
13
|
+
|
14
|
+
require 'statistics2.rb'
|
15
|
+
|
16
|
+
=begin rdoc
|
17
|
+
Simple random number generator, using "roulette wheel" algorithm.
|
18
|
+
=end
|
19
|
+
|
20
|
+
class Wheel
|
21
|
+
|
22
|
+
@@x = 0
|
23
|
+
@@c = 337
|
24
|
+
@@m = 1000
|
25
|
+
|
26
|
+
def Wheel.rand(n)
|
27
|
+
@@x = (@@x + @@c) % @@m
|
28
|
+
return @@x % n
|
29
|
+
end
|
30
|
+
|
31
|
+
def Wheel.params(*args)
|
32
|
+
if args.length == 0
|
33
|
+
return [@@x, @@m, @@c]
|
34
|
+
elsif args.length == 3
|
35
|
+
@@x, @@m, @@c = args
|
36
|
+
else
|
37
|
+
raise "params: expected 3 integers"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
=begin rdoc
|
43
|
+
Better random number generator, using parameters from Numerical Recipes in C.
|
44
|
+
=end
|
45
|
+
|
46
|
+
class PRNG
|
47
|
+
|
48
|
+
@@x = 0
|
49
|
+
@@a = 3
|
50
|
+
@@c = 337
|
51
|
+
@@m = 1000
|
52
|
+
|
53
|
+
def PRNG.rand(n)
|
54
|
+
@@x = (@@x * @@a + @@c) % @@m
|
55
|
+
return @@x % n
|
56
|
+
end
|
57
|
+
|
58
|
+
def PRNG.params(*args)
|
59
|
+
if args.length == 0
|
60
|
+
return [@@x, @@m, @@a, @@c]
|
61
|
+
elsif args.length == 4
|
62
|
+
@@x, @@m, @@a, @@c = args
|
63
|
+
else
|
64
|
+
raise "params: expected 4 integers"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
# :begin :uniform_test
|
71
|
+
def uniform_test(n, m, opt = nil)
|
72
|
+
bins = Array.new(m,0)
|
73
|
+
n.times { x = rand(m); bins[x] += 1 }
|
74
|
+
exp = Array.new(m, n/m)
|
75
|
+
if opt == :trace
|
76
|
+
print "bins: "
|
77
|
+
p bins
|
78
|
+
end
|
79
|
+
return chi_square_test(bins, exp, opt)
|
80
|
+
end
|
81
|
+
# :end :uniform_test
|
82
|
+
|
83
|
+
# :begin :poker_test
|
84
|
+
def poker_test(n, opt = nil)
|
85
|
+
types = [:nada, :pair, :two_pair, :three_of_a_kind, :full_house, :straight, :flush, :four_of_a_kind, :straight_flush]
|
86
|
+
counts = Hash.new
|
87
|
+
types.each { |x| counts[x] = 0 }
|
88
|
+
n.times do
|
89
|
+
h = random_deal(5)
|
90
|
+
# p h
|
91
|
+
t = poker_hand(h)
|
92
|
+
counts[t] += 1
|
93
|
+
end
|
94
|
+
return counts
|
95
|
+
end
|
96
|
+
# :end :poker_test
|
97
|
+
|
98
|
+
=begin rdoc
|
99
|
+
Compute the chi-square statistic for a set of bins containing results from n random draws.
|
100
|
+
The two parameters are arrays of equal length, containing the observed and expected values.
|
101
|
+
Return +true+ if the chi-square is less than the critical value for p = 0.95 (i.e. return
|
102
|
+
false if the hypothesis that the distributions are the same is rejected).
|
103
|
+
=end
|
104
|
+
|
105
|
+
def chi_square_test(obs, exp, opt = nil)
|
106
|
+
x2 = chi_square(obs, exp)
|
107
|
+
p = Statistics2.chi2dist(obs.length-1, x2)
|
108
|
+
if opt == :trace
|
109
|
+
printf "chi-square: %7.3f p = %.2f\n", x2, p
|
110
|
+
end
|
111
|
+
return p < 0.95
|
112
|
+
end
|
113
|
+
|
114
|
+
def chi_square(obs, exp)
|
115
|
+
sum = 0.0
|
116
|
+
for i in 0...obs.length
|
117
|
+
sum += ( (obs[i] - exp[i])**2 ).to_f / exp[i]
|
118
|
+
end
|
119
|
+
return sum
|
120
|
+
end
|
121
|
+
|
122
|
+
=begin rdoc
|
123
|
+
Make a random array of +n+ Card objects (selected without replacement).
|
124
|
+
=end
|
125
|
+
|
126
|
+
def random_deal(n)
|
127
|
+
h = Hash.new
|
128
|
+
while h.size < n
|
129
|
+
h[ rand(52) ] = 1
|
130
|
+
end
|
131
|
+
a = Array.new
|
132
|
+
h.keys.each do |x|
|
133
|
+
a << Card.new(x)
|
134
|
+
end
|
135
|
+
return a
|
136
|
+
end
|
137
|
+
|
138
|
+
=begin rdoc
|
139
|
+
Make a hand using numbers in array +a+ (used for testing)
|
140
|
+
=end
|
141
|
+
|
142
|
+
def deal(a)
|
143
|
+
a.map { |x| Card.new(x) }
|
144
|
+
end
|
145
|
+
|
146
|
+
=begin rdoc
|
147
|
+
Return a random shuffling of all 52 cards
|
148
|
+
=end
|
149
|
+
|
150
|
+
def shuffle
|
151
|
+
permutation((0..51).to_a).map { |x| Card.new(x) }
|
152
|
+
end
|
153
|
+
|
154
|
+
=begin rdoc
|
155
|
+
Classify a poker hand -- returns a symbol describing a hand. Return values:
|
156
|
+
:pair
|
157
|
+
:two_pair
|
158
|
+
:three_of_a_kind
|
159
|
+
:full_house
|
160
|
+
:straight
|
161
|
+
:flush
|
162
|
+
:four_of_a_kind
|
163
|
+
:straight_flush
|
164
|
+
=end
|
165
|
+
|
166
|
+
# TODO: royal flush in RAND test?
|
167
|
+
|
168
|
+
def poker_hand(a)
|
169
|
+
rcount = Array.new(Card::Ranks.length, 0)
|
170
|
+
scount = Array.new(Card::Suits.length, 0)
|
171
|
+
a.each do |x|
|
172
|
+
rcount[ Card::Ranks.index(x.rank) ] += 1
|
173
|
+
scount[ Card::Suits.index(x.suit) ] += 1
|
174
|
+
end
|
175
|
+
if rcount.max == 1
|
176
|
+
straight = (rcount.rindex(1) - rcount.index(1) == 4)
|
177
|
+
flush = scount.max == 5
|
178
|
+
return :straight_flush if (straight && flush)
|
179
|
+
return :straight if straight
|
180
|
+
return :flush if flush
|
181
|
+
return :nada
|
182
|
+
else
|
183
|
+
rcount.reject! { |x| x == 0 }
|
184
|
+
rcount.sort! { |x,y| y <=> x }
|
185
|
+
return :four_of_a_kind if rcount[0] == 4
|
186
|
+
return :full_house if (rcount[0] == 3 && rcount[1] == 2)
|
187
|
+
return :three_of_a_kind if rcount[0] == 3
|
188
|
+
return :two_pair if (rcount[0] == 2 && rcount[1] == 2)
|
189
|
+
return :pair
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
=begin rdoc
|
195
|
+
Class to represent cards from a standard 52-card deck. Includes comparators
|
196
|
+
to sort by rank or suit.
|
197
|
+
|
198
|
+
Call Card.new to get a random card, or Card.new(id) to get a specific card
|
199
|
+
where id is a number between 0 and 51.
|
200
|
+
=end
|
201
|
+
|
202
|
+
# To test the expression that assigns suits and ranks:
|
203
|
+
# 52.times { |x| puts (x/13).to_s + " " + (x%13).to_s }
|
204
|
+
|
205
|
+
class Card
|
206
|
+
attr_accessor :rank, :suit
|
207
|
+
|
208
|
+
unless defined? Suits
|
209
|
+
Suits = [:spades, :hearts, :diamonds, :clubs]
|
210
|
+
end
|
211
|
+
|
212
|
+
unless defined? Ranks
|
213
|
+
Ranks = [:ace, :king, :queen, :jack, :ten, :nine, :eight, :seven, :six, :five, :four, :three, :two]
|
214
|
+
end
|
215
|
+
|
216
|
+
def initialize(id = nil)
|
217
|
+
id = rand(52) if id.nil?
|
218
|
+
raise "card must be between 0 and 51" if id < 0 || id > 51
|
219
|
+
@suit = Suits[id / 13]
|
220
|
+
@rank = Ranks[id % 13]
|
221
|
+
end
|
222
|
+
|
223
|
+
def ==(x)
|
224
|
+
return @suit == x.suit && @rank == x.rank
|
225
|
+
end
|
226
|
+
|
227
|
+
def <=>(x)
|
228
|
+
r0 = Ranks.index(@rank); r1 = Ranks.index(x.rank)
|
229
|
+
s0 = Suits.index(@suit); s1 = Suits.index(x.suit)
|
230
|
+
if (res = (s0 <=> s1)) == 0
|
231
|
+
return (r0 <=> r1)
|
232
|
+
else
|
233
|
+
return res
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
@@outputform = :utf8
|
238
|
+
|
239
|
+
def inspect
|
240
|
+
s = ""
|
241
|
+
s << case @rank
|
242
|
+
when :ace : "A"
|
243
|
+
when :king : "K"
|
244
|
+
when :queen : "Q"
|
245
|
+
when :jack : "J"
|
246
|
+
when :ten : "10"
|
247
|
+
when :nine : "9"
|
248
|
+
when :eight : "8"
|
249
|
+
when :seven : "7"
|
250
|
+
when :six : "6"
|
251
|
+
when :five : "5"
|
252
|
+
when :four : "4"
|
253
|
+
when :three : "3"
|
254
|
+
when :two : "2"
|
255
|
+
end
|
256
|
+
if $KCODE[0] == ?U
|
257
|
+
if @@outputform == :utf8
|
258
|
+
s << case @suit
|
259
|
+
when :spades : "\xe2\x99\xa0"
|
260
|
+
when :hearts : "\xe2\x99\xa5"
|
261
|
+
when :clubs : "\xe2\x99\xa3"
|
262
|
+
when :diamonds : "\xe2\x99\xa6"
|
263
|
+
end
|
264
|
+
else
|
265
|
+
s << "!irb" + @suit.to_s.chop
|
266
|
+
end
|
267
|
+
else
|
268
|
+
s << case @suit
|
269
|
+
when :spades : "S"
|
270
|
+
when :hearts : "H"
|
271
|
+
when :clubs : "C"
|
272
|
+
when :diamonds : "D"
|
273
|
+
end
|
274
|
+
end
|
275
|
+
return s
|
276
|
+
# "#{@rank} #{@suit}"
|
277
|
+
end
|
278
|
+
|
279
|
+
alias to_s inspect
|
280
|
+
|
281
|
+
def Card.print_latex
|
282
|
+
@@outputform = :latex
|
283
|
+
end
|
284
|
+
|
285
|
+
def Card.print_utf8
|
286
|
+
@@outputform = :utf8
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
end
|
291
|
+
|
292
|
+
end # RandomLab
|
293
|
+
|
294
|
+
end # RubyLabs
|