動機
カジノって面白いですよね.ポーカーやバカラ,ブラックジャックなど暇つぶしについついやってしまいます.
そんななか昨日,誰しもが一度は思う「俺ってめっちゃ強いんじゃね?」が再燃しました.
今度カジノに行ったとき,自信を持ってやるために,シミュレーションで確認して(確率的に)強いことを証明しよう!
ルール
ダブルダウンは有り
スプリットはめんどうなので無し
(ベーシックストラテジーでは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%のようですね.
ギャンブルはほどほどにしましょう.
