Blackjack simulation in Ruby results in strange probabilities
-
13-07-2021 - |
質問
Below is the code for a simulation of a simple blackjack game. The player and dealer (house) draw two cards. The player then hits until he reaches 17. The dealer (house) then hits until he draws with the player or goes bust. Considering the player plays first the odds of him winning should be less than 50% for any strategy. However, for some reason when I repeat the simulation it seems the player wins more than 50% of the time. There must be some error in my code giving me this result.
one_suit = [2,3,4,5,6,7,8,9,10,10,10,10,11]; #the value of the cards for blackjack
$full_deck = one_suit*4; #clubs, diamonds, hearts and spades
$deck = $full_deck.dup; #start off the game with a full deck
class Player
attr_accessor :ace_count
attr_accessor :hand_value
def initialize(ace_count,hand_value)
@ace_count = ace_count;
@hand_value = hand_value;
end
def hit #instance method, vs. self.hit = class method
choice_of_card = rand($deck.length); #choose a random card out of the deck
drawn_card = $deck[choice_of_card]; #draw that random card from the deck
$deck.delete_at(choice_of_card); #remove that card from the array
if drawn_card == 11 #if you draw an ace
self.ace_count += 1;
end
self.hand_value += drawn_card;
end
def flip_aces
while self.hand_value > 21 && self.ace_count > 0 #repeat until hand is below 21 or aces are all flipped
self.ace_count -= 1 #ace gets flipped to a 1
self.hand_value -= 10 #ace goes from 11 to 1
end
end
end
def oneplayergame
$deck = $full_deck.dup; #start a new game with a full deck
#generate the house and the player
house = Player.new(0,0);
player1 = Player.new(0,0);
#both the house and the player draw two cards
house.hit; house.hit; player1.hit; player1.hit;
while player1.hand_value <= 17 #PLAYER STRATEGY: ON WHAT CARD DOES THE PLAYER STAND
player1.hit;
player1.flip_aces;
end
while house.hand_value < player1.hand_value && player1.hand_value <=21 #HOUSE DRAWS CARDS IF UNDER PLAYER VALUE AND PLAYER IS NOT BUST
house.hit;
house.flip_aces;
end
#outcome
if player1.hand_value < house.hand_value && house.hand_value <= 21
return -1;
elsif player1.hand_value > house.hand_value && player1.hand_value <= 21
return 1;
elsif player1.hand_value < house.hand_value && house.hand_value > 21
return 1;
elsif player1.hand_value > house.hand_value && player1.hand_value > 21
return -1;
else return 0;
end
end
#the simulation
wins = 0;
losses = 0;
rounds=10000;
for i in 1..rounds
oneplayergame;
if oneplayergame >0
wins +=1;
elsif oneplayergame <0
losses +=1
end
end
print wins/(wins+losses).round(3)*100;
解決
This code
for i in 1..rounds
oneplayergame;
if oneplayergame >0
wins +=1;
elsif oneplayergame <0
losses +=1
end
Is wrong: that is calling oneplayergame
three times: a loss is only counted if a player looses the second and 3rd calls, which would skew the results. You should only call oneplayergame
once, assigning the result to a local variable