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


# 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]

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

	return 12 == max-min

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

t_by_sort = 0.0
t_by_scan = 0.0
t_by_minmax = 0.0

TRIALS.times do
	cards = (1..52).to_a

	t0 =
	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 = - t0
	t_by_sort += dt_sort

	p_scan = 0
	t0 =
	[1,2,3,4].each { |handno| 
		p_scan += 1 if perfect_hand_by_scan?(cards, handno)
	dt_scan = - t0
	t_by_scan += dt_scan

	p_minmax = 0
	t0 =
	[1,2,3,4].each { |handno| 
		p_minmax += 1 if perfect_hand_by_minmax?(cards, handno)
	dt_minmax = - t0
	t_by_minmax += dt_minmax

	perfect_hands += p_sort

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.