0
0

More than 3 years have passed since last update.

ブラックジャックの親のバーストの確率を乱数を使用せず、確率計算のみでプログラムで計算する

Last updated at Posted at 2021-03-20

はじめに

ブラックジャックの親のバーストの確率をノーコードで計算する の記事で親の手札の確率を計算しましたが、その計算式では使用済みのカードの出現率の減少を考慮していませんでした。(Aを立て続けに3枚引いても、次にAを引く確率は変わらない)
予想では、考慮した場合の計算と比べても無視できるほどの誤差の範囲と思いましたが、実際に考慮した場合の確率を計算して本当にそうなのか確認したくて、プログラミングしてみました。

2021/4/26 追記
乱数を使用して計算する方法も以下の記事で掲載しましたので興味のある方は一読下さい。

プログラム

検証用ツール部分

セル関数で検証可能にします。

'*****************************************************************************
'[概要] 親のハンドの確率を配列数式で返す
'[引数] OpenCard:親の初手(0の時は、初手の出現確率も含めて計算する)
'       Decks:トランプの組数
'[戻値] 配列数式
'*****************************************************************************
Public Function CalcHandRate(ByVal OpenCard As Long, ByVal Decks As Double) As Variant
    Call Initilize(Decks)
    Call SetHand(OpenCard)

    Dim i As Long
    Dim Result(17 To 22)
    For i = 17 To 21
        Result(i) = HardHandRate(i) + SoftHandRate(i)
    Next
    'バーストの確率は22に設定
    Result(22) = HardHandRate(22) + SoftHandRate(22) _
               + HardHandRate(23) + SoftHandRate(23) _
               + HardHandRate(24) + SoftHandRate(24) _
               + HardHandRate(25) + SoftHandRate(25) _
               + HardHandRate(26) + SoftHandRate(26)
    CalcHandRate = Result
End Function

以下のC4セルのように =CalcHandRate(初手,組数) でセル関数を入力します。
その時、配列数式となるように、1行6列(例では、C4:H4)の範囲を選択し、Ctrl+Shift+Enter を押下します。

image.png

計算メイン部分

以下のグローバル変数に、それぞれ計算した結果の確率が格納されます。

HardHandRate(1 To 26) As Double 'ハードハンドの確率の計算結果 
SoftHandRate(1 To 26) As Double 'ソフトハンドの確率の計算結果 
Option Explicit

Private Cards(1 To 10) As Long 'A~10カードの山の枚数
Private CardsCount As Long 'カードのトータル枚数
Private HardHandRate(1 To 26) As Double 'ハードハンドの確率の計算結果
Private SoftHandRate(1 To 26) As Double 'ソフトハンドの確率の計算結果

'*****************************************************************************
'[概要] 配列の初期化など
'[引数] Decks:トランプの組数
'*****************************************************************************
Private Sub Initilize(ByVal Decks As Double)
    Erase HardHandRate()
    Erase SoftHandRate()

    Dim i As Long
    For i = 1 To 9
        Cards(i) = Decks * 4
    Next
    Cards(10) = Decks * 16
    CardsCount = Decks * 52
End Sub

'*****************************************************************************
'[概要] 各ハンドの確率を設定する
'[引数] 親の初手(0の時は、初手の出現確率も含めて計算する)
'*****************************************************************************
Private Sub SetHand(ByVal OpenCard As Long)
    If OpenCard = 0 Then
        'オープンカードの出現確率も含めて確率を計算する時
        Dim i As Long
        Dim Rate As Double
        For i = 1 To 10
            Rate = Cards(i) / CardsCount 'iのカードの出現確率を計算
            Call DecCard(i) 'iのカードを山から1枚減らす
            If i = 1 Then
                'Aの時は、ソフトハンドの11とみなして計算する
                Call SetSoftHandRate(11, Rate)
            Else
                Call SetHardHandRate(i, Rate)
            End If
            Call IncCard(i) 'iのカードを山に戻す
        Next
        Exit Sub
    End If

    Call DecCard(OpenCard) 'オープンカードを山から1枚減らす
    If OpenCard = 1 Then
        'Aの時は、ソフトハンドの11とみなして計算する
        Call SetSoftHandRate(11, 1)
    Else
        Call SetHardHandRate(OpenCard, 1)
    End If
End Sub

'*****************************************************************************
'[概要] ソフトハンドの確率を設定する(多重ループを再帰関数で実現する)
'[引数] Hand:現在の手,HandRate:現在の手の出現確率
'*****************************************************************************
Private Sub SetSoftHandRate(ByVal Hand As Long, ByVal HandRate As Double)
    Dim i As Long
    Dim Rate As Double
    Dim NextHand As Long

    For i = 1 To 10
        '山に対象のカードが残っているか判定
        If Cards(i) > 0 Then
            NextHand = Hand + i
            Rate = HandRate * Cards(i) / CardsCount
            If NextHand > 21 Then
                'ソフトハンドがバーストした時はハードハンドで再計算する
                NextHand = NextHand - 10
                HardHandRate(NextHand) = HardHandRate(NextHand) + Rate
                If NextHand < 17 Then
                    '17未満なら次のカードを引く
                    Call DecCard(i) 'iのカードを山から1枚減らす
                    Call SetHardHandRate(NextHand, Rate)
                    Call IncCard(i) 'iのカードを山に戻す
                End If
            Else
                SoftHandRate(NextHand) = SoftHandRate(NextHand) + Rate
                If NextHand < 17 Then
                    '17未満なら次のカードを引く
                    Call DecCard(i) 'iのカードを山から1枚減らす
                    Call SetSoftHandRate(NextHand, Rate)
                    Call IncCard(i) 'iのカードを山に戻す
                End If
            End If
        End If
    Next
End Sub

'*****************************************************************************
'[概要] ハードハンドの確率を設定する(多重ループを再帰関数で実現する)
'[引数] Hand:現在の手,HandRate:現在の手の出現確率
'*****************************************************************************
Private Sub SetHardHandRate(ByVal Hand As Long, ByVal HandRate As Double)
    Dim i As Long
    Dim Rate As Double
    Dim NextHand As Long

    For i = 1 To 10
        '山に対象のカードが残っているか判定
        If Cards(i) > 0 Then
            NextHand = Hand + i
            Rate = HandRate * Cards(i) / CardsCount
            If i = 1 And Hand <= 10 Then
                'ソフトハンド(Aを11)として計算する
                NextHand = Hand + 11
                SoftHandRate(NextHand) = SoftHandRate(NextHand) + Rate
                If NextHand < 17 Then
                    '17未満なら次のカードを引く
                    Call DecCard(i) 'iのカードを山から1枚減らす
                    Call SetSoftHandRate(NextHand, Rate)
                    Call IncCard(i) 'iのカードを山に戻す
                End If
            Else
                HardHandRate(NextHand) = HardHandRate(NextHand) + Rate
                If NextHand < 17 Then
                    '17未満なら次のカードを引く
                    Call DecCard(i) 'iのカードを山から1枚減らす
                    Call SetHardHandRate(NextHand, Rate)
                    Call IncCard(i) 'iのカードを山に戻す
                End If
            End If
        End If
    Next
End Sub

'*****************************************************************************
'[概要] カードを山から1枚減らす
'[引数] 対象のカード(1~10のいずれか)
'*****************************************************************************
Private Sub DecCard(ByVal Card As Long)
'    Exit Sub  '使用済みカードの出現率の減少を考慮しない場合
    Cards(Card) = Cards(Card) - 1
    CardsCount = CardsCount - 1
End Sub

'*****************************************************************************
'[概要] カードを山に戻す
'[引数] 対象のカード(1~10のいずれか)
'*****************************************************************************
Private Sub IncCard(ByVal Card As Long)
'    Exit Sub  '使用済みカードの出現率の減少を考慮しない場合
    Cards(Card) = Cards(Card) + 1
    CardsCount = CardsCount + 1
End Sub

2021/4/14
SetHardHandRate関数とSetSoftHandRate関数を統合して
ロジックをシンプルにしてみた

'*****************************************************************************
'[概要] 各ハンドの確率を設定する
'[引数] 親の初手(0の時は、初手の出現確率も含めて計算する)
'*****************************************************************************
Private Sub SetHand(ByVal OpenCard As Long)
    If OpenCard = 0 Then
        'オープンカードの出現確率も含めて確率を計算する時
        Dim i As Long
        Dim Rate As Double
        For i = 1 To 10
            Rate = Cards(i) / CardsCount 'iのカードの出現確率を計算
            Call DecCard(i) 'iのカードを山から1枚減らす
            If i = 1 Then
                'Aの時は、ソフトハンドの11とみなして計算する
                Call SetHandRate(11, Rate, True)
                'Call SetSoftHandRate(11, Rate)
            Else
                Call SetHandRate(i, Rate, False)
                'Call SetHardHandRate(i, Rate)
            End If
            Call IncCard(i) 'iのカードを山に戻す
        Next
        Exit Sub
    End If

    Call DecCard(OpenCard) 'オープンカードを山から1枚減らす
    If OpenCard = 1 Then
        'Aの時は、ソフトハンドの11とみなして計算する
        Call SetHandRate(11, 1, True)
        'Call SetSoftHandRate(11, 1)
    Else
        Call SetHandRate(OpenCard, 1, False)
        'Call SetHardHandRate(OpenCard, 1)
    End If
End Sub

'*****************************************************************************
'[概要] 各ハンドの確率を設定する(多重ループを再帰関数で実現する)
'[引数] Hand:現在の手,HandRate:現在の手の出現確率,IsSoftHand:ソフトハンドの時True
'*****************************************************************************
Private Sub SetHandRate(ByVal Hand As Long, ByVal HandRate As Double, ByVal IsSoftHand As Boolean)
    Dim i As Long
    Dim Rate As Double
    Dim NextHand As Long
    Dim NextIsSoftHand As Boolean

    For i = 1 To 10
        '山に対象のカードが残っているか判定
        If Cards(i) > 0 Then
            NextIsSoftHand = IsSoftHand
            NextHand = Hand + i
            If i = 1 And NextIsSoftHand = False Then
                'ハードハンドをソフトハンドに変更
                NextIsSoftHand = True
                NextHand = NextHand + 10
            End If
            If NextHand > 21 And NextIsSoftHand = True Then
                'ソフトハンドをハードハンドに変更
                NextIsSoftHand = False
                NextHand = NextHand - 10
            End If

            Rate = HandRate * Cards(i) / CardsCount
            If NextIsSoftHand Then
                SoftHandRate(NextHand) = SoftHandRate(NextHand) + Rate
            Else
                HardHandRate(NextHand) = HardHandRate(NextHand) + Rate
            End If
            If NextHand < 17 Then
                '17未満なら次のカードを引く
                Call DecCard(i) 'iのカードを山から1枚減らす
                Call SetHandRate(NextHand, Rate, NextIsSoftHand)
                Call IncCard(i) 'iのカードを山に戻す
            End If
        End If
    Next
End Sub

ロジックの大略

ハードハンド1とソフトハンド2 それぞれのすべてのハンドの出現パターンとその各々の出現確率の総和を総当りで計算しています。
出現パターンをすべて総当りで網羅するには、カード引く回数分の階層の多重ループとなるため、多重ループ部分を再帰関数で実現しています。

計算結果

使用済みのカードの出現率の減少を考慮しない場合

こちら の記事の計算結果と完全一致
※DecCard()関数とIncCard()関数の中身をコメントアウトして実行

初手 17 18 19 20 21 BS
1 13.08% 13.08% 13.08% 13.08% 36.16% 11.53%
2 13.98% 13.49% 12.97% 12.40% 11.80% 35.36%
3 13.50% 13.05% 12.56% 12.03% 11.47% 37.39%
4 13.05% 12.59% 12.14% 11.65% 11.12% 39.45%
5 12.23% 12.23% 11.77% 11.31% 10.82% 41.64%
6 16.54% 10.63% 10.63% 10.17% 9.72% 42.32%
7 36.86% 13.78% 7.86% 7.86% 7.41% 26.23%
8 12.86% 35.93% 12.86% 6.94% 6.94% 24.47%
9 12.00% 12.00% 35.08% 12.00% 6.08% 22.84%
10 11.14% 11.14% 11.14% 34.22% 11.14% 21.21%
平均 14.51% 13.95% 13.35% 18.03% 12.01% 28.16%

1組52枚の場合

初手 17 18 19 20 21 BS
1 12.61% 13.10% 12.95% 13.16% 36.53% 11.65%
2 13.90% 13.18% 13.18% 12.39% 12.05% 35.30%
3 13.03% 13.09% 12.38% 12.33% 11.60% 37.56%
4 13.10% 11.42% 12.07% 11.63% 11.51% 40.28%
5 11.97% 12.35% 11.69% 10.47% 10.63% 42.89%
6 16.69% 10.65% 10.72% 10.07% 9.79% 42.08%
7 37.23% 13.86% 7.73% 7.89% 7.30% 25.99%
8 13.09% 36.30% 12.94% 6.83% 6.98% 23.86%
9 12.19% 10.39% 35.74% 12.23% 6.11% 23.34%
10 11.44% 11.29% 11.47% 32.89% 11.49% 21.43%
平均 14.58% 13.81% 13.48% 17.58% 12.19% 28.36%

使用済みカードを考慮しない場合との乖離幅

初手 17 18 19 20 21 BS
1 -0.47% 0.02% -0.13% 0.08% 0.37% 0.13%
2 -0.08% -0.31% 0.22% -0.01% 0.25% -0.06%
3 -0.47% 0.05% -0.18% 0.30% 0.13% 0.17%
4 0.05% -1.18% -0.07% -0.02% 0.39% 0.83%
5 -0.26% 0.12% -0.08% -0.85% -0.19% 1.25%
6 0.15% 0.02% 0.09% -0.10% 0.07% -0.23%
7 0.38% 0.08% -0.13% 0.03% -0.11% -0.25%
8 0.23% 0.37% 0.09% -0.11% 0.04% -0.61%
9 0.19% -1.61% 0.66% 0.23% 0.03% 0.50%
10 0.30% 0.15% 0.32% -1.33% 0.35% 0.22%
平均 0.07% -0.14% 0.14% -0.44% 0.18% 0.20%

乖離幅の多きいものから8個
初手9の18:-1.61%
初手10の20:-1.33%
初手5のBS:+1.25%
初手4の18:-1.18%
初手5の20:-0.85%
初手4のBS:+0.83%
初手9の19:+0.66%
初手8のBS:-0.61%

4組208枚の場合

初手 17 18 19 20 21 BS
1 12.96% 13.08% 13.05% 13.10% 36.25% 11.56%
2 13.96% 13.41% 13.02% 12.40% 11.86% 35.35%
3 13.39% 13.06% 12.51% 12.11% 11.50% 37.43%
4 13.06% 12.31% 12.12% 11.64% 11.22% 39.65%
5 12.16% 12.25% 11.75% 11.11% 10.78% 41.94%
6 16.58% 10.62% 10.65% 10.15% 9.73% 42.27%
7 36.95% 13.80% 7.83% 7.87% 7.37% 26.17%
8 12.91% 36.03% 12.88% 6.91% 6.95% 24.32%
9 12.05% 11.60% 35.24% 12.06% 6.09% 22.97%
10 11.22% 11.18% 11.22% 33.89% 11.23% 21.27%
平均 14.53% 13.91% 13.38% 17.92% 12.05% 28.21%

使用済みカードを考慮しない場合との乖離幅

初手 17 18 19 20 21 BS
1 -0.12% 0.00% -0.03% 0.02% 0.09% 0.03%
2 -0.02% -0.08% 0.05% 0.00% 0.06% -0.02%
3 -0.11% 0.01% -0.05% 0.07% 0.03% 0.05%
4 0.01% -0.28% -0.02% -0.01% 0.10% 0.20%
5 -0.06% 0.03% -0.02% -0.20% -0.05% 0.30%
6 0.04% -0.01% 0.02% -0.02% 0.02% -0.05%
7 0.10% 0.02% -0.03% 0.01% -0.04% -0.06%
8 0.06% 0.09% 0.02% -0.03% 0.01% -0.16%
9 0.05% -0.40% 0.16% 0.06% 0.01% 0.12%
10 0.07% 0.04% 0.08% -0.33% 0.08% 0.05%
平均 0.02% -0.04% 0.03% -0.11% 0.04% 0.05%

乖離幅の多きいものから8個
初手9の18:-0.40%
初手10の20:-0.33%
初手5のBS:+0.30%
初手4の18:-0.28%
初手5の20:-0.20%
初手4のBS:+0.20%
初手9の19:+0.16%
初手8のBS:-0.16%

6組312枚の場合

初手 17 18 19 20 21 BS
1 13.00% 13.08% 13.06% 13.09% 36.22% 11.55%
2 13.97% 13.44% 13.00% 12.40% 11.84% 35.35%
3 13.43% 13.05% 12.52% 12.08% 11.49% 37.42%
4 13.06% 12.41% 12.13% 11.64% 11.19% 39.58%
5 12.18% 12.24% 11.76% 11.18% 10.79% 41.84%
6 16.57% 10.62% 10.64% 10.16% 9.73% 42.28%
7 36.92% 13.79% 7.84% 7.87% 7.38% 26.19%
8 12.89% 36.00% 12.87% 6.92% 6.95% 24.37%
9 12.03% 11.73% 35.19% 12.04% 6.09% 22.92%
10 11.19% 11.17% 11.19% 34.00% 11.20% 21.25%
平均 14.52% 13.93% 13.37% 17.95% 12.04% 28.19%

使用済みカードを考慮しない場合との乖離幅

初手 17 18 19 20 21 BS
1 -0.08% 0.00% -0.02% 0.01% 0.06% 0.02%
2 -0.02% -0.05% 0.04% 0.00% 0.04% -0.01%
3 -0.07% 0.01% -0.04% 0.05% 0.02% 0.03%
4 0.01% -0.19% -0.01% 0.00% 0.06% 0.13%
5 -0.04% 0.02% -0.01% -0.14% -0.03% 0.20%
6 0.03% -0.01% 0.02% -0.02% 0.01% -0.03%
7 0.06% 0.01% -0.02% 0.01% -0.03% -0.04%
8 0.04% 0.06% 0.02% -0.02% 0.01% -0.10%
9 0.03% -0.26% 0.11% 0.04% 0.01% 0.08%
10 0.05% 0.02% 0.05% -0.22% 0.06% 0.04%
平均 0.01% -0.02% 0.02% -0.07% 0.03% 0.03%

乖離幅の多きいものから8個
初手9の18:-0.26%
初手10の20:-0.22%
初手5のBS:+0.20%
初手4の18:-0.19%
初手5の20:-0.14%
初手4のBS:+0.13%
初手9の19:+0.11%
初手8のBS:-0.10%

8組416枚の場合

初手 17 18 19 20 21 BS
1 13.02% 13.08% 13.06% 13.09% 36.20% 11.54%
2 13.97% 13.45% 12.99% 12.40% 11.83% 35.35%
3 13.45% 13.05% 12.53% 12.07% 11.49% 37.41%
4 13.05% 12.45% 12.13% 11.65% 11.17% 39.55%
5 12.19% 12.24% 11.76% 11.21% 10.80% 41.79%
6 16.56% 10.62% 10.64% 10.16% 9.72% 42.29%
7 36.90% 13.79% 7.85% 7.87% 7.39% 26.20%
8 12.88% 35.98% 12.87% 6.93% 6.95% 24.40%
9 12.02% 11.80% 35.16% 12.03% 6.09% 22.90%
10 11.18% 11.16% 11.18% 34.06% 11.18% 21.24%
平均 14.52% 13.93% 13.36% 17.97% 12.03% 28.18%

使用済みカードを考慮しない場合との乖離幅

初手 17 18 19 20 21 BS
1 -0.06% 0.00% -0.01% 0.01% 0.05% 0.01%
2 -0.01% -0.04% 0.03% 0.00% 0.03% -0.01%
3 -0.06% 0.00% -0.03% 0.04% 0.02% 0.02%
4 0.00% -0.14% -0.01% 0.00% 0.05% 0.10%
5 -0.03% 0.01% -0.01% -0.10% -0.02% 0.15%
6 0.02% -0.01% 0.01% -0.01% 0.01% -0.02%
7 0.05% 0.01% -0.01% 0.00% -0.02% -0.03%
8 0.03% 0.05% 0.01% -0.01% 0.01% -0.08%
9 0.02% -0.20% 0.08% 0.03% 0.00% 0.06%
10 0.04% 0.02% 0.04% -0.16% 0.04% 0.03%
平均 0.01% -0.02% 0.02% -0.05% 0.02% 0.02%

乖離幅の多きいものから8個
初手9の18:-0.20%
初手10の20:-0.16%
初手5のBS:+0.15%
初手4の18:-0.14%
初手5の20:-0.10%
初手4のBS:+0.10%
初手9の19:+0.08%
初手8のBS:-0.08%

結論

1組52枚では最大 1.61%の乖離が見られたが、1デックのカジノはほとんどないはず。
通常のカジノでは6組以上のカードを使用するのが一般的ではないかと思われる。
仮に、4組としても最大0.4%の乖離幅であるので、ほぼ当初の見込み通り出現したカードの減少を考慮せず、親の手札の確率を理論計算したとしても、考慮した場合の計算と比べても無視できるほどの誤差と言えると思います。

関連記事

ブラックジャックの親のバーストの確率をノーコードで計算する
ブラックジャックの期待値をノーコードで計算する
ブラックジャックの親のバーストの確率を乱数(モンテカルロ法)を使用して、計算する


  1. ハードハンド:Aを含まない または Aを1として計算した手 

  2. ソフトハンド:Aを11として計算した手(10を引いてもバーストしない) 

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0