From: tho_mica_l Date: 2008-01-07T00:35:00+09:00 Subject: Re: Studying Blackjack (#151) Here is my solution. I originally tried to run through all solutions but then adopted the simulation strategy already mentioned by others before. If sample size is 55000 (default is 10000), this script runs about as long (with ruby 1.8) as Denis Hennessy's solution (which uses much less memory though). Also, I get constantly less bust counts for an Ace as upcard which makes me wonder if I did something wrong here. The other figures appear about the same. Sample results: $ ruby quiz151b.rb 55000 bust natural 17 18 19 20 21 A: 11.62% 31.09% 12.65% 13.09% 12.88% 13.33% 5.35% 2: 35.43% 0.00% 13.84% 13.45% 12.88% 12.35% 12.05% 3: 37.39% 0.00% 13.56% 12.85% 12.73% 12.03% 11.43% 4: 40.08% 0.00% 12.85% 11.97% 12.11% 11.72% 11.28% 5: 42.21% 0.00% 12.25% 12.19% 12.02% 10.85% 10.48% 6: 41.83% 0.00% 16.71% 10.58% 10.74% 10.45% 9.68% 7: 26.29% 0.00% 36.96% 13.76% 7.76% 7.90% 7.32% 8: 24.48% 0.00% 13.05% 35.85% 12.92% 6.63% 7.06% 9: 23.39% 0.00% 11.97% 11.10% 35.50% 11.94% 6.11% 10: 21.21% 7.85% 11.01% 11.12% 11.52% 33.77% 3.52% B: 21.15% 7.71% 11.26% 11.11% 11.50% 33.77% 3.49% D: 21.36% 7.73% 11.25% 11.08% 11.32% 33.74% 3.52% K: 21.65% 7.77% 11.47% 11.28% 11.17% 33.16% 3.51% Regards, Thomas. #!/usr/bin/env ruby # Author:: Thomas Link (micathom AT gmail com) # Created:: 2008-01-05. class Quiz151b LABELS = ['bust', 'natural', *(17..21).to_a] NAMES = ['A', *(2..10).to_a] << 'B' << 'D' << 'K' CARDS = (1..10).to_a + [10] * 3 class << self def run(sample=10000, decks=2) puts ' ' + LABELS.map {|k| '%-7s' % k}.join(' ') 13.times do |upcard| puts Quiz151b.new(upcard, decks).run(sample) end end end def initialize(upcard, decks) @upcard = upcard @cards = CARDS * (4 * decks) @hands = [] end def run(sample) sample.times {@hands << deal(@upcard)} self end def to_s total = @hands.size acc = Hash.new(0) @hands.each do |sum, hand| label = sum > 21 ? 'bust' : sum == 21 && hand.size == 2 ? 'natural' : sum acc[label] += 1 end '%02s: %s' % [ NAMES[@upcard], LABELS.map {|k| '%6.2f%%' % (100.0 * acc[k] / total)}.join(' ') ] end def deal(idx) cards = @cards.dup hand = [] sum = 0 loop do hand << cards.delete_at(idx) sum = count(hand) return [sum, hand] if sum >= 17 idx = rand(cards.size) end end def count(hand) sum = 0 tidx = 21 - hand.size - 10 hand.dup.sort.reverse.each_with_index do |c, i| sum += c == 1 && sum <= tidx + i ? 11 : c end return sum end end if __FILE__ == $0 case ARGV[0] when '-h', '--help' puts "#$0 [DEALS=10000] [DECKS=2]" else Quiz151b.run(*ARGV.map {|e| e.to_i}) end end