Here's my solution, with a sample run.
Comments, corrections, criticism welcome.
/dh
$ ./blackjack.rb
Odds for each dealer outcome based on initial upcard (2 deck game)
17 18 19 20 21 BUST
A 12.58% 12.82% 12.75% 12.85% 36.07% 12.93%
2 13.93% 13.33% 13.07% 12.39% 11.92% 35.36%
3 13.27% 13.06% 12.45% 12.18% 11.53% 37.50%
4 13.07% 12.02% 12.10% 11.63% 11.31% 39.88%
5 12.10% 12.28% 11.73% 10.90% 10.73% 42.25%
6 16.62% 10.62% 10.67% 10.12% 9.75% 42.21%
7 37.05% 13.82% 7.80% 7.88% 7.34% 26.11%
8 12.97% 36.12% 12.90% 6.89% 6.96% 24.16%
9 12.09% 11.20% 35.41% 12.11% 6.10% 23.09%
10 11.29% 11.22% 11.30% 33.56% 11.31% 21.32%
J 11.29% 11.22% 11.30% 33.56% 11.31% 21.32%
Q 11.29% 11.22% 11.30% 33.56% 11.31% 21.32%
K 11.29% 11.22% 11.30% 33.56% 11.31% 21.32%
$ cat blackjack.rb
#!/usr/bin/env ruby
CARDS = %w(A 2 3 4 5 6 7 8 9 10 J Q K)
DECKS = ARGV.size == 1 ? ARGV[0].to_i : 2
SUITS = 4
def hand_value(hand)
value = 0
# First calculate values ignoring aces
hand.each do |c|
if c=='A'
next
elsif 'JQK'.include? c
value += 10
else
value += c.to_i
end
end
# Then add aces as 11 unless they would bust the hand
hand.each do |c|
if c=='A'
if value>10
value += 1
else
value += 11
end
end
end
value
end
def new_shute
cards = []
CARDS.each do |c|
DECKS.times { SUITS.times { cards << c }}
end
cards
end
def odds_of(cards, v)
count = 0
cards.each { |c| count += 1 if c==v }
(1.0 * count) / cards.length
end
# calc the odds of reaching result from a given hand
def calc_odds(hand, result)
current = hand_value(hand)
return 1.0 if current == result
return 0.0 if current >= 17
# Remove hand cards from full shute
cards = new_shute
hand.each {|c| cards.delete_at(cards.index(c))}
odds = 0.0
CARDS.each do |c|
odds_of_card = odds_of(cards, c)
if odds_of_card > 0.0
hand.push c
odds_of_result = calc_odds(hand, result)
odds += odds_of_card * odds_of_result
hand.pop
end
end
return odds
end
puts "Odds for each dealer outcome based on initial upcard (#{DECKS}
deck game)"
puts " 17 18 19 20 21 BUST"
CARDS.each do |c|
odds = {}
bust = 100.0
(17..21).each do |r|
odds[r] = calc_odds([c], r) * 100.0
bust -= odds[r]
end
printf "%2s %5.02f%% %5.02f%% %5.02f%% %5.02f%% %5.02f%% %5.02f%%
\n", c, odds[17], odds[18], odds[19], odds[20], odds[21], bust
end