Problem 8 of Monte Carlo solutions to Fifty Challenging Problems...
(This is another part of the Fifty Problems series, a set of example applications of Monte Carlo methods. In each post, I present source code which answers a probabilistic question using simulated models of the underlying system.)
Problem 8: What is the chance of being dealt a perfect hand in bridge? (being dealt 13 cards of the same suit?)
This is one place where Monte Carlo falls flat on its face. Modeling this in any sort of reasonably simple (read: naive) fashion results in a program that takes quite some time to run. It's far better to find the probability through direct combinatorial calculations. This still poses some interesting programming problems, but they're of the numerical sort, so they won't appear in this series. (It would be really great if someone would post a comment linking to a solution of this problem using hadoop on EC2 or EMR!)
#!/usr/bin/env ruby
TRIALS=100
# We model this by laying out the 52 cards in an
# array, calling the spades 1..13.
#
# Then, we "deal" by breaking it up into contiguous
# 13-card chunks. If any the 4 chunks of 13 are
# 1..13, we win the "deal a perfect hand" game.
# Otherwise, we lose.
perfect_hands = 0
# I had some concerns about the performance here.
def perfect_hand_by_sort?(a)
ap = a.sort
return 12 == ap[12]-ap[0]
end
def perfect_hand_by_scan?(a, handno)
x = (handno-1)*13
min = 0
max = 53
while (x < (handno)*13)
ai = a[x]
min = ai if ai < min
max = ai if ai > max
x += 1
end
return 12 == max-min
end
def perfect_hand_by_minmax?(a, handno)
x = (handno-1)*13
min = a[x..x+12].min
max = a[x..x+12].max
return 12 == max-min
end
t_by_sort = 0.0
t_by_scan = 0.0
t_by_minmax = 0.0
TRIALS.times do
cards = (1..52).to_a
cards.shuffle!
t0 = Time.now
hand1 = cards[0..12]
hand2 = cards[13..25]
hand3 = cards[26..38]
hand4 = cards[39..51]
p_sort = 0
[hand1, hand2, hand3, hand4].each { |hand|
p_sort += 1 if perfect_hand_by_sort?(hand)
}
dt_sort = Time.now - t0
t_by_sort += dt_sort
p_scan = 0
t0 = Time.now
[1,2,3,4].each { |handno|
p_scan += 1 if perfect_hand_by_scan?(cards, handno)
}
dt_scan = Time.now - t0
t_by_scan += dt_scan
p_minmax = 0
t0 = Time.now
[1,2,3,4].each { |handno|
p_minmax += 1 if perfect_hand_by_minmax?(cards, handno)
}
dt_minmax = Time.now - t0
t_by_minmax += dt_minmax
perfect_hands += p_sort
end
puts "After #{TRIALS} trials, we got #{perfect_hands}"
puts "Times: "
puts " sort: #{t_by_sort}"
puts " scan: #{t_by_scan}"
puts " minmax: #{t_by_minmax}"
I've been coding my way through Fifty Challenging Problems in Statistics with Solutions. This post is a part of the Fifty Challenging Problems series.
This was brought to you by Josh Myer. He has other fun things at his homepage.