Module: RubyLabs::RandomLab
- Defined in:
- lib/randomlab.rb
Overview
RandomLab
The RandomLab module has definitions of classes and methods used in the projects for Chapter 9 of Explorations in Computing. The module has methods used in experiments with pseudorandom number generators.
Defined Under Namespace
Classes: Card, DotPlot, Histogram, NumberLine, PRNG
Constant Summary collapse
- @@numberLineOptions =
{ :lineThickness => 3, :lineColor => '#777777', :tickHeight => 20, :tickWidth => 1, :tickColor => '#0000FF', }
- @@histogramOptions =
{ :binColor => '#000080', :boxIncrement => 8.0, :rescaleTrigger => 50, }
- @@dotPlotOptions =
{ :dotColor => '#000080', :dotRadius => 1.0, }
- @@drawing =
nil
- @@delay =
0.01
Instance Method Summary collapse
-
#brackets(a, i, r) ⇒ Object
A helper method intended to be called via a probe to print the contents of an array during the execution of the
permute!
method. -
#get_counts ⇒ Object
Return an array of counts for the bins in the histogram currently on the RubyLabs Canvas.
-
#new_deck ⇒ Object
Make a new deck of cards.
-
#pdup(n, d) ⇒ Object
Compute the probability of a duplicate item in a collection of
n
items drawn from the range [1..d]. -
#plot_point(x, y) ⇒ Object
Add a point at location ‘x’, ‘y’ to the dot plot on the RubyLabs Canvas.
-
#poker_counts ⇒ Object
Initialize a Hash object with keys that are poker rank symbols and values that are all initially 0.
-
#poker_rank(a) ⇒ Object
Given an array of 5 Card objects, determine what type of poker hand is represented by the cards.
-
#poker_rankings ⇒ Object
Return a list of symbols used to classify poker hands.
-
#prng_sequence(a, c, m) ⇒ Object
Return an array of
m
numbers defined by the pseudorandom sequence with parametersa
,c
, andm
. -
#tick_mark(i) ⇒ Object
Draw a tick mark on the RubyLabs Canvas, provided the canvas has been initialized with a call to view_numberline.
-
#update_bin(x) ⇒ Object
Update the bin for data item
x
, presuming the RubyLabs Canvas has been initialized to show a histogram for data of this type. -
#view_dotplot(npoints, userOptions = {}) ⇒ Object
Initialize the RubyLabs Canvas to show a dot plot with
npoints
in both thex
andy
dimension. -
#view_histogram(*args) ⇒ Object
Initialize the RubyLabs Canvas to show a histogram with the specified bins.
-
#view_numberline(npoints, userOptions = {}) ⇒ Object
Initialize the RubyLabs Canvas with a drawing of a number line for integers from 0 to
npoints
-1.
Instance Method Details
#brackets(a, i, r) ⇒ Object
A helper method intended to be called via a probe to print the contents of an array during the execution of the permute!
method. The arguments are the array to display, the location of a left bracket, and the item location where the item next to the bracket will be moved on the next swap.
161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/randomlab.rb', line 161 def brackets(a, i, r) res = "#{r}: " if i <= 0 res += ("[" + a.join(" ") + "]") elsif i >= a.length res += (" " + a.join(" ") + " [ ]") else pre = a.slice(0..(i-1)) post = a.slice(i..-1) res += (" " + pre.join(" ") + " [" + post.join(" ") + "]") end return res end |
#get_counts ⇒ Object
Return an array of counts for the bins in the histogram currently on the RubyLabs Canvas.
488 489 490 491 492 493 494 495 |
# File 'lib/randomlab.rb', line 488 def get_counts if @@drawing.class == Histogram return @@drawing.counts else puts "current drawing is not a histogram" return nil end end |
#new_deck ⇒ Object
Make a new deck of cards. Returns an array of 52 card objects, arranged in order from card #0 (the ace of spades) through card #51 (the two of clubs).
137 138 139 |
# File 'lib/randomlab.rb', line 137 def new_deck (0..51).map { |i| Card.new(i) } end |
#pdup(n, d) ⇒ Object
Compute the probability of a duplicate item in a collection of n
items drawn from the range [1..d].
Example – to compute the probability of drawing the same card twice when sampling with replacement 5 times from a deck of 52 cards:
>> pdup(5, 52)
=> 0.179716221420819
151 152 153 154 |
# File 'lib/randomlab.rb', line 151 def pdup(n, d) return 1.0 if n > d return 1.0 - (1..(n-1)).inject(1.0) { |p, k| p * (1.0 - (k / 52.0)) } end |
#plot_point(x, y) ⇒ Object
Add a point at location ‘x’, ‘y’ to the dot plot on the RubyLabs Canvas.
Example: if the canvas was initialized to show a 250 x 250 plot, this call will display a point in the center of the drawing:
>> plot_point(125,125)
=> nil
520 521 522 523 524 525 526 527 528 529 530 531 532 533 |
# File 'lib/randomlab.rb', line 520 def plot_point(x,y) if @@drawing.class != DotPlot puts "call view_dotplot to initialize a dot plot" elsif x < 0 || x >= @@drawing.max || y < 0 || y >= @@drawing.max puts "plot_point: 0 <= x, y < #{@@drawing.max}" else px = (x.to_f / @@drawing.max) * Canvas.width py = (y.to_f / @@drawing.max) * Canvas.height r = @@drawing.[:dotRadius] color = @@drawing.[:dotColor] Canvas::Circle.new( px, py, r, :outline => color, :fill => color ) end return nil end |
#poker_counts ⇒ Object
Initialize a Hash object with keys that are poker rank symbols and values that are all initially 0. Used in experiments that count the number of times various hands are dealt.
Example:
>> poker_counts
=> {:flush=>0, :full_house=>0, ... :high_card=>0}
224 225 226 227 228 |
# File 'lib/randomlab.rb', line 224 def poker_counts h = Hash.new poker_rankings.each { |x| h[x] = 0 } return h end |
#poker_rank(a) ⇒ Object
Given an array of 5 Card objects, determine what type of poker hand is represented by the cards. The return value is a symbol, e.g. :pair
, :full_house
, etc. (call poker_rankings to see the complete list of symbols).
Example (assuming d
is a complete deck of 52 Card objects):
>> h = permute!(d).first(5)
=> [AH, 6S, 7C, JH, AC]
>> poker_rank(h)
=> :pair
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/randomlab.rb', line 186 def poker_rank(a) rcount = Array.new(Card::Ranks.length, 0) scount = Array.new(Card::Suits.length, 0) a.each do |x| rcount[ Card::Ranks.index(x.rank) ] += 1 scount[ Card::Suits.index(x.suit) ] += 1 end if rcount.max == 1 straight = (rcount.rindex(1) - rcount.index(1) == 4) flush = scount.max == 5 return :straight_flush if (straight && flush) return :straight if straight return :flush if flush return :high_card else rcount.reject! { |x| x == 0 } rcount.sort! { |x,y| y <=> x } return :four_of_a_kind if rcount[0] == 4 return :full_house if (rcount[0] == 3 && rcount[1] == 2) return :three_of_a_kind if rcount[0] == 3 return :two_pair if (rcount[0] == 2 && rcount[1] == 2) return :pair end end |
#poker_rankings ⇒ Object
Return a list of symbols used to classify poker hands.
213 214 215 |
# File 'lib/randomlab.rb', line 213 def poker_rankings return [:high_card, :pair, :two_pair, :three_of_a_kind, :straight, :flush, :full_house, :four_of_a_kind, :straight_flush] end |
#prng_sequence(a, c, m) ⇒ Object
Return an array of m
numbers defined by the pseudorandom sequence with parameters a
, c
, and m
. The first number in the sequence is 0, and the remaining numbers are defined by the recurrence
x[i+1] = (a * x[i] + c) % m
– :begin :prng_sequence
125 126 127 128 129 130 131 |
# File 'lib/randomlab.rb', line 125 def prng_sequence(a, c, m) seq = [0] (m-1).times do seq << (a * seq.last + c) % m end return seq end |
#tick_mark(i) ⇒ Object
Draw a tick mark on the RubyLabs Canvas, provided the canvas has been initialized with a call to view_numberline.
368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
# File 'lib/randomlab.rb', line 368 def tick_mark(i) if @@drawing.class != NumberLine puts "call view_numberline to initialize the number line" elsif i < 0 || i >= @@drawing.npoints puts "tick_mark: 0 <= i < #{@@drawing.npoints}" else x0, y0, x1, y1 = @@drawing.line.coords tx = (i.to_f / @@drawing.npoints) * (x1-x0) ty = y0 - @@drawing.[:tickHeight] Canvas::Line.new(tx, y0, tx, ty, :width => @@drawing.[:tickWidth], :fill => @@drawing.[:tickColor]) sleep(@@delay) end return true end |
#update_bin(x) ⇒ Object
Update the bin for data item x
, presuming the RubyLabs Canvas has been initialized to show a histogram for data of this type. The bin for x
increases in height. If it reaches the maximum height, rescale all the bins and increase the maximum height.
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 |
# File 'lib/randomlab.rb', line 448 def update_bin(x) if @@drawing.class != Histogram puts "call view_histogram to initialize a histogram" return nil end if @@drawing.keys i = @@drawing.keys.index(x) if i.nil? puts "unknown bin: #{x}" return nil end else xmax = @@drawing.max nb = @@drawing.bins.length if x < 0 || x >= xmax puts "x must be between 0 and #{xmax-1}" return nil end i = ((x / xmax) * nb).to_i end @@drawing.counts[i] += 1 rect = @@drawing.bins[i] x1, y1, x2, y2 = rect.coords y1 = y1 - @@drawing.[:boxIncrement] rect.coords = [x1, y1, x2, y2] if y1 < @@drawing.[:rescaleTrigger] base = @@drawing.base @@drawing.bins.each do |rect| x1, y1, x2, y2 = rect.coords y1 = base - ((base - y1) / 2) rect.coords = [x1, y1, x2, y2] end @@drawing.[:boxIncrement] /= 2 end sleep(@@delay) return true end |
#view_dotplot(npoints, userOptions = {}) ⇒ Object
Initialize the RubyLabs Canvas to show a dot plot with npoints
in both the x
and y
dimension. Drawing options and their defaults are
:dotColor => '#000080'
:dotRadius => 1.0
Example: intialize the drawing for a 250 x 250 dot plot with green dots:
>> view_dotplot(250, :dotColor => 'darkgreen')
=> true
506 507 508 509 510 511 |
# File 'lib/randomlab.rb', line 506 def view_dotplot(npoints, userOptions = {}) Canvas.init(500, 500, "RandomLab::DotPlot") = @@dotPlotOptions.merge(userOptions) @@drawing = DotPlot.new(npoints, ) return true end |
#view_histogram(*args) ⇒ Object
Initialize the RubyLabs Canvas to show a histogram with the specified bins. In the initial drawing each bin is represented by a rectangle one pixel tall, i.e. a horizontal line.
As items are added to a bin the rectangle will grow in height. If any rectangle reaches the maximum height, all the rectangles are rescaled so the bins can continue to grow.
The argument to view_histogram can either be an integer, which specifies the number of bins, or an array of symbols, in which case there will be one bin for each symbol. If the argument is an integer, a second argument can specify a maximum data value; for example, calling view_histogram(10,100)
will make a histogram with 10 bins for numbers between 0 and 99, so that data values 0 through 9 will go in the first bin, 10 through 19 in the second bin, and so on.
Display options and their default values are:
:binColor => '#000080'
:boxIncrement => 8.0
:rescaleTrigger => 50
Example: make a histogram for the numbers between 0 and 5:
>> view_histogram(6)
=> true
Example: make a histogram to count the number of times each type of poker hand is seen in an experiment:
>> view_histogram(poker_rankings, :binColor => 'darkgreen')
=> true
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
# File 'lib/randomlab.rb', line 407 def view_histogram(*args) begin if args[0].class == Array userOptions = args.length > 1 ? args[1] : { } raise "usage: view_histogram(keys, options)" unless userOptions.class == Hash keys = args[0] nbins = max = keys.length else userOptions = args.length > 2 ? args[2] : { } raise "usage: view_histogram(nbins, max, options)" unless userOptions.class == Hash nbins = args[0] max = args.length > 1 ? args[1] : nbins keys = nil end rescue Exception => e puts e return false end Canvas.init(500, 300, "RandomLab::Histogram") counts = Hash.new(0) = @@histogramOptions.merge(userOptions) bins = [] binHeight = 3 binBorder = 2 binWidth = (500/(nbins+1)) binTop = 280 nbins.times do |i| x = i * binWidth + binWidth/2 bins << Canvas::Rectangle.new( x + binBorder, binTop, x + binWidth - binBorder, binTop + binHeight, :outline => [:binColor], :fill => [:binColor] ) end @@drawing = Histogram.new(bins, max.to_f, keys, counts, binTop, ) return true end |
#view_numberline(npoints, userOptions = {}) ⇒ Object
Initialize the RubyLabs Canvas with a drawing of a number line for integers from 0 to npoints
-1. Options that control the appearance of the display, and their default values, are:
:lineThickness => 3
:lineColor => '#777777'
:tickHeight => 20
:tickWidth => 1
:tickColor => '#0000FF'
Example:
>> view_numberline(500, :lineColor => 'blue', :lineThickness => 1)
=> true
357 358 359 360 361 362 363 |
# File 'lib/randomlab.rb', line 357 def view_numberline(npoints, userOptions = {}) Canvas.init(500, 100, "RandomLab::NumberLine") = @@numberLineOptions.merge(userOptions) line = Canvas::Line.new(0, 70, 500, 70, :width => [:lineThickness], :fill => [:lineColor]) @@drawing = NumberLine.new(line, npoints, ) return true end |