動機
カジノって面白いですよね.ポーカーやバカラ,ブラックジャックなど暇つぶしについついやってしまいます.
そんななか昨日,誰しもが一度は思う「俺ってめっちゃ強いんじゃね?」が再燃しました.
今度カジノに行ったとき,自信を持ってやるために,シミュレーションで確認して(確率的に)強いことを証明しよう!
ルール
ダブルダウンは有り
スプリットはめんどうなので無し
(ベーシックストラテジーではAAや88ではスプリットはした方が良いらしい 参考).
ナチュラルブラックジャックは配当1.5
プレイヤーのバーストはディーラーの手によらずプレイヤーの負け
コード
何の変哲もない普通のpythonコードです.
デッキの状態によって変化が起こるか気になったので,デッキが無限にある状態と1セットのみの場合の2パターンを検証しました.
bj.py
import random
# カードデッキを初期化
suits = ['Hearts', 'Diamonds', 'Clubs', 'Spades']
ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
single_deck = [(rank, suit) for suit in suits for rank in ranks]
def shuffle_deck(deck):
random.shuffle(deck)
return deck
def deal_card(deck, infinite_deck):
if infinite_deck:
return random.choice(single_deck)
else:
return deck.pop()
def calculate_hand_value(hand):
value = 0
aces = 0
for card, suit in hand:
if card in ['J', 'Q', 'K']:
value += 10
elif card == 'A':
aces += 1
value += 11
else:
value += int(card)
while value > 21 and aces:
value -= 10
aces -= 1
return value
def is_blackjack(hand):
return len(hand) == 2 and calculate_hand_value(hand) == 21
def player_decision(player_hand, dealer_card):
player_value = calculate_hand_value(player_hand)
dealer_value = calculate_hand_value([dealer_card])
# 基本戦略に基づくプレイヤーの決定
if player_value >= 17:
return "stand"
elif player_value <= 11:
return "hit"
else:
if dealer_value >= 7:
return "hit"
else:
return "stand"
def play_blackjack_simulation(count, infinite_deck=False):
player_wins = 0
dealer_wins = 0
ties = 0
double_down_wins = 0
double_down_losses = 0
natural_blackjacks = 0
total_payout = 0 # 収支の計算
for _ in range(count): # 100,000回のシミュレーション
if infinite_deck:
deck = single_deck.copy()
else:
deck = shuffle_deck(single_deck.copy())
player_hand = [deal_card(deck, infinite_deck), deal_card(deck, infinite_deck)]
dealer_hand = [deal_card(deck, infinite_deck), deal_card(deck, infinite_deck)]
# ナチュラルブラックジャックの判定
if is_blackjack(player_hand):
if is_blackjack(dealer_hand):
ties += 1
else:
player_wins += 1
natural_blackjacks += 1
total_payout += 1.5 # ナチュラルブラックジャックのペイアウト
continue
elif is_blackjack(dealer_hand):
dealer_wins += 1
total_payout -= 1
continue
# プレイヤーのターン
double_down = False
if calculate_hand_value(player_hand) == 11:
player_hand.append(deal_card(deck, infinite_deck))
double_down = True
while not double_down and player_decision(player_hand, dealer_hand[0]) == "hit":
player_hand.append(deal_card(deck, infinite_deck))
if calculate_hand_value(player_hand) > 21:
break
# ディーラーのターン
while calculate_hand_value(dealer_hand) < 17:
dealer_hand.append(deal_card(deck, infinite_deck))
player_value = calculate_hand_value(player_hand)
dealer_value = calculate_hand_value(dealer_hand)
if player_value > 21:
if double_down:
double_down_losses += 1
total_payout -= 2 # ダブルダウンの敗北
else:
dealer_wins += 1
total_payout -= 1 # 通常の敗北
elif dealer_value > 21 or player_value > dealer_value:
if double_down:
double_down_wins += 1
total_payout += 2 # ダブルダウンの勝利
else:
player_wins += 1
total_payout += 1 # 通常の勝利
elif player_value < dealer_value:
if double_down:
double_down_losses += 1
total_payout -= 2 # ダブルダウンの敗北
else:
dealer_wins += 1
total_payout -= 1 # 通常の敗北
else:
ties += 1
# 結果の表示
print(f"プレイヤーの勝ち数: {player_wins}")
print(f"ディーラーの勝ち数: {dealer_wins}")
print(f"引き分け数: {ties}")
print(f"ナチュラルブラックジャックの勝ち数: {natural_blackjacks}")
print(f"ダブルダウンの勝ち数: {double_down_wins}")
print(f"ダブルダウンの負け数: {double_down_losses}")
print(f"最終収支: {total_payout}")
count = 1000000
print(f"総ゲーム回数:{count}")
# デッキが無限の場合
print("☆無限デッキの場合の結果:")
play_blackjack_simulation(count, infinite_deck=True)
print("\n")
# デッキが1セットの場合の結果
print("☆1セットのデッキの場合の結果:")
play_blackjack_simulation(count, infinite_deck=False)
実行結果
総ゲーム回数:1000000
☆無限デッキの場合の結果:
プレイヤーの勝ち数: 403170
ディーラーの勝ち数: 468785
引き分け数: 86416
ナチュラルブラックジャックの勝ち数: 44609
ダブルダウンの勝ち数: 25231
ダブルダウンの負け数: 16398
最終収支: -25644.5
☆1セットのデッキの場合の結果:
プレイヤーの勝ち数: 406788
ディーラーの勝ち数: 467542
引き分け数: 83349
ナチュラルブラックジャックの勝ち数: 46387
ダブルダウンの勝ち数: 25512
ダブルダウンの負け数: 16809
最終収支: -20154.5
普通に負け...
97.5~98%のようですね.
ギャンブルはほどほどにしましょう.