From: Alex LeDonne Date: 2007-10-03T01:39:56+09:00 Subject: Re: [QUIZ] Probable Iterations (#141) Just for fun, I implemented two solutions: one actually does and counts the iterations. The other fakes it for the no-option and option -s cases (but produces EXACTLY the same output) and only does the iterations for the -v (for which it is slower). Both coded with lots of hard-coded magic numbers, like 6-sided dice, looking for 5s, etc, but easily modified. --------------------------------- Straight iterative: require 'optparse' options = {} OptionParser.new do |opts| opts.banner = "Usage: example.rb [options]" opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| options[:v] = 1 end opts.on("-s", "--sample", "Run in sample mode") do |s| options[:s] = 1 end end.parse! total_dice, at_least_5 = Integer(ARGV[0]), Integer(ARGV[1]) des=0 tot=6**total_dice roll = Array.new(total_dice){1} roll[0] = 0 (0..tot-1).each { |serial| marker = "" roll[0]+=1 (0..total_dice-1).each do |idx| if roll[idx]==7 roll[idx]=1 roll[idx+1]+=1 else break end end if roll.select{|die| die==5}.length >= at_least_5 marker = " <==" des += 1 end if options[:v] || (options[:s] && (serial % 50000)==0 ) puts "#{serial+1} #{roll.inspect} #{marker}" end } puts "\nNumber of desirable outcomes is #{des}" puts "Number of possible outcomes is #{tot}" puts "\nProbability is %16.16f" %(des.to_f/tot) ----------------- Fake it when possible using closed-form calculation: # Math.nCr(n,r) borrowed from Brian Candler's # post in ruby_talk def Math.nCr(n,r) a, b = r, n-r a, b = b, a if a < b # a is the larger numer = (a+1..n).inject(1) { |t,v| t*v } # n!/r! denom = (2..b).inject(1) { |t,v| t*v } # (n-r)! numer/denom end class DiceAtLeastFive def self.int_to_roll( serial, numdice ) # good for reality, too slow for a quiz - #pow is expensive. # raise if serial >= 6**numdice serial.to_s(6).rjust(numdice,"0").split(//).map!{|ele| ele.to_i + 1 }.reverse end def self.total_rolls(numdice) 6**numdice end def self.desirable(numdice, min_fives) (min_fives..numdice).inject(0) { |tot, val| tot + (Math.nCr(numdice,val) * 5**(numdice-val)) } end end require 'optparse' options = {} OptionParser.new do |opts| opts.banner = "Usage: example.rb [options]" opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| options[:iter_step] = 1 end opts.on("-s", "--sample", "Run in sample mode") do |s| options[:iter_step] = 50000 end end.parse! total_dice, at_least_5 = Integer(ARGV[0]), Integer(ARGV[1]) des=DiceAtLeastFive.desirable(total_dice,at_least_5) tot=DiceAtLeastFive.total_rolls(total_dice) if options[:iter_step] (0..tot-1).step(options[:iter_step]) { |serial| marker = "" roll = DiceAtLeastFive.int_to_roll(serial, total_dice) if roll.select{|die| die==5}.length >= at_least_5 marker = " <==" end puts "#{serial+1} #{roll.inspect} #{marker}" } end puts "\nNumber of desirable outcomes is #{des}" puts "Number of possible outcomes is #{tot}" puts "\nProbability is %16.16f" %(des.to_f/tot)