Pythonですべてのアクションを網羅したブラックジャックを作ってみる(その1)

Photo by Clifford Photography on Unsplash

当ページのリンクには広告やプロモーションが含まれています。

ブラックジャックの還元率の高さを確かめたいのがモチベーション

ブラックジャックはカジノの中でも還元率の高いゲームとして知られています。

ルーレットは還元率の高いヨーロピアンルーレットでも還元率が97.3%であるのに対し、ブラックジャックは98102%と言われています。

(ヨーロピアンルーレットの特殊ルールでアンプリゾン方式ラパルタージュ方式が採用されているカジノに行けば98.6%の還元率になりますが、そのようなカジノは少数です)

 

なぜ98102%までの幅があるのかと言うと、ベーシックストラテジーと呼ばれる定石に沿ってプレーすれば98%、それにカウンティングというテクニックを使うことによって最大4%上積みされるためです。

還元率が100%を超えるということは、ゲームを多く繰り返すほど手持ちのお金が増えていく確率が高いということです。

本当にそんなにうまい話がこの世に存在するのでしょうか?

 

それをシミュレーションで確かめたくなりました。

ところがブラックジャックにはプレーヤーが打てるアクションにいろいろな選択肢があり、すべてを網羅するシミュレーションソフトを作るのは困難そうに思えます。

それに敢えて挑戦してみることにしました。

今回はその第一弾です。

続編で機能追加していきます。

 

今回のコードで網羅する機能

  • デックをシャッフルする
  • はじめに配られる2枚の手札がナチュラルブラックジャックになっているかを判断する
  • ディーラーの2枚の手札は最初の1枚だけを公開する
  • ヒットかスタンドを選択し、ヒットなら1枚カードを追加した後に新しいスコアを計算し、バスト(21を超える)なら負けを確定させる
  • スタンドならディーラーのスコアが17以上になるまでカードを追加し、プレーヤーのスコアと比較してプレーヤーの勝ち負けを確定させる
  • ディーラーがバストすればプレーヤーの勝ちを確定させる
  • Aの値は基本は1とカウントするが、手札にAが含まれスコアが11以下の場合にはAを11とカウントする(ソフトハンド)
  • Aを11とカウントしたがスコアが22以上となる場合には再びAを1とカウントする(ハードハンド)
  • はじめに配られる2枚のカードを見てダブルダウンを選択でき、選択した場合には賭金を2倍にしてあと1枚だけ引きスタンドする

 

Pythonコード

冗長なコードだということはわかっています。

シンプルなコードにして下さる方がいらっしゃれば有り難いです。

自分でも続編で機能増強しながら改良していくつもりです。

import random

suits = ['♤', '♡', '☘', '♢'] #スートの定義
cards = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'] #数の定義
values = {'A': 1, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9, '10':10, 'J':10, 'Q':10, 'K':10} #値の定義

class shuffle_deck: #デックをシャッフルする
    def __init__(self):
        self.deck = []
        for suit in suits:
            for card in cards:
                self.deck.append((card, suit))

    def shuffle(self):
        random.shuffle(self.deck)
        return self.deck

class draw_card: #カードを1枚引く
    def __init__(self, deck):
        self.deck = deck

    def draw(self):
        if len(self.deck) == 0:
            return None
        card = self.deck.pop(0)
        return card

class value_card: #カードの値を判断
    def __init__(self, card, ace_flg):
        self.card = card
        self.ace_flg = ace_flg

    def value(self):
        key = self.card[0]
        value = values[key]
        if value == 1:
            self.ace_flg = True
        return value, self.ace_flg

class update_value: #手札のスコアを更新
    def __init__(self,current_value, card, soft_flg, ace_flg):
        self.current_value = current_value
        self.card = card
        self.soft_flg = soft_flg
        self.ace_flg = ace_flg

    def update(self):
        Value = value_card(self.card, self.ace_flg)
        value, self.ace_flg = Value.value()
        updated_value = self.current_value + value
        if updated_value < 12 and self.ace_flg:
            self.soft_flg = True
            updated_value += 10
        if updated_value > 21 and self.soft_flg:
            self.soft_flg = False
            updated_value -= 10
        return updated_value, self.soft_flg, self.ace_flg

class bet: #最初に2枚ずつ配られた手札のスコアを計算
    p_score = 0
    p_soft_flg = False
    p_ace_flg = False
    d_score = 0
    d_soft_flg = False
    d_ace_flg = False
    deck = []

    def init_draw(self):
        Shuffle = shuffle_deck()
        bet.deck = Shuffle.shuffle()
        score = 0

        ace_flg = False
        soft_flg = False

        Deck = draw_card(bet.deck)
        card = Deck.draw()
        p_1 = card
        Update = update_value(score, card, soft_flg, ace_flg)
        bet.p_score, bet.p_soft_flg, bet.p_ace_flg = Update.update()

        Deck = draw_card(bet.deck)
        card = Deck.draw()
        d_1 = card
        Update = update_value(score, card, soft_flg, ace_flg)
        bet.d_score, bet.d_soft_flg, bet.d_ace_flg = Update.update()

        Deck = draw_card(bet.deck)
        card = Deck.draw()
        p_2 = card
        Update = update_value(bet.p_score, card, bet.p_soft_flg, bet.p_ace_flg)
        bet.p_score, bet.p_soft_flg, bet.p_ace_flg = Update.update()
        hand_p = 'ソフト' if bet.p_soft_flg == True else 'ハード'
        print('あなたの手札は {} と {} です。'.format(p_1, p_2))
        print('あなたのスコアは {} 、{}ハンドです。'.format(bet.p_score, hand_p))

        Deck = draw_card(bet.deck)
        card = Deck.draw()
        d_2 = card
        Update = update_value(bet.d_score, card, bet.d_soft_flg, bet.d_ace_flg)
        bet.d_score, bet.d_soft_flg, bet.d_ace_flg = Update.update()
        hand_d = 'ソフト' if bet.d_soft_flg == True else 'ハード'
        print('ディーラーの手札は {} です。'.format(d_1))

        Judge = judge()
        Judge.choice()

class judge(bet): #ナチュラルブラックジャックでなければダブルダウンするかどうかを選択
    pass  
    def choice(self):
        if bet.p_score == 21:
            print('ナチュラルブラックジャック!あなたの勝ちです!')
        else:
            double_choice = input('ダブルダウンしますか?【y or n】:')
            if double_choice == 'y':
                Double = double()
                Double.run()
            else:
                Play = play()
                Play.run()

class double(bet): #ダブルダウンを選択した場合の結果
    pass

    def run(self):
        Deck = draw_card(bet.deck)
        card = Deck.draw()
        Update = update_value(bet.p_score, card, bet.p_soft_flg, bet.p_ace_flg)
        bet.p_score, bet.p_soft_flg, bet.p_ace_flg = Update.update()
        hand_p = 'ソフト' if bet.p_soft_flg == True else 'ハード'
        hand_d = 'ソフト' if bet.d_soft_flg == True else 'ハード'
        print('あなたのスコアは {} 、{}ハンドです。'.format(bet.p_score, hand_p))
        while bet.d_score < 17:
            Deck = draw_card(bet.deck)
            card = Deck.draw()
            Update = update_value(bet.d_score, card, bet.d_soft_flg, bet.d_ace_flg)
            bet.d_score, bet.d_soft_flg, bet.d_ace_flg = Update.update()
        print('ディーラーのスコアは {}  、{}ハンドです。'.format(bet.d_score, hand_d))
        if bet.p_score > 21:
            print('バストしました!あなたの負けです!')
            repeat_flg = False
        else:
            if bet.d_score > 21:
                print('ディーラーがバストしました!あなたの勝ちです!')
            elif bet.d_score == bet.p_score:
                print('ドローです!')
            elif bet.d_score > bet.p_score:
                print('あなたの負けです!')
            else:
                print('あなたの勝ちです!')

class play(bet): #ヒットまたはスタンドを何回か選択した後、結果を表示
    pass

    def run(self):
        repeat_flg = True
        while repeat_flg:     
            choice = input('ヒットしますか?スタンドしますか?【h or s】:')
            if choice == 'h':
                Deck = draw_card(bet.deck)
                card = Deck.draw()
                Update = update_value(bet.p_score, card, bet.p_soft_flg, bet.p_ace_flg)
                bet.p_score, bet.p_soft_flg, bet.p_ace_flg = Update.update()
                hand_p = 'ソフト' if bet.p_soft_flg == True else 'ハード'
                hand_d = 'ソフト' if bet.d_soft_flg == True else 'ハード'
                print('あなたのスコアは {} 、{}ハンドです。'.format(bet.p_score, hand_p))
                print('ディーラーのスコアは {}  、{}ハンドです。'.format(bet.d_score, hand_d))
                if bet.p_score > 21:
                    print('バストしました!あなたの負けです!')
                    repeat_flg = False
            elif choice == 's':
                while bet.d_score < 17:
                    Deck = draw_card(bet.deck)
                    card = Deck.draw()
                    Update = update_value(bet.d_score, card, bet.d_soft_flg, bet.d_ace_flg)
                    bet.d_score, bet.d_soft_flg, bet.d_ace_flg = Update.update()
                hand_p = 'ソフト' if bet.p_soft_flg == True else 'ハード'
                hand_d = 'ソフト' if bet.d_soft_flg == True else 'ハード'
                print('あなたのスコアは {} 、{}ハンドです。'.format(bet.p_score, hand_p))
                print('ディーラーのスコアは {}  、{}ハンドです。'.format(bet.d_score, hand_d))
                if bet.d_score > 21:
                    print('ディーラーがバストしました!あなたの勝ちです!')
                elif bet.d_score == bet.p_score:
                    print('ドローです!')
                elif bet.d_score > bet.p_score:
                    print('あなたの負けです!')
                else:
                    print('あなたの勝ちです!')
                repeat_flg = False
            else:
                print('もう一度正確に入力して下さい。【h or s】:')

Bet = bet()
Bet.init_draw()

 

実行結果

はじめのスコアが高くてスタンドしたら勝った!

あなたの手札は ('J', '♤') と ('9', '♡') です。
あなたのスコアは 19 、ハードハンドです。
ディーラーの手札は ('8', '♡') です。
ダブルダウンしますか?【y or n】:n
ヒットしますか?スタンドしますか?【h or s】:s
あなたのスコアは 19 、ハードハンドです。
ディーラーのスコアは 22  、ハードハンドです。
ディーラーがバストしました!あなたの勝ちです!

 

はじめのスコアが低かったのでヒットしたら負けた!

あなたの手札は ('4', '♤') と ('Q', '♢') です。
あなたのスコアは 14 、ハードハンドです。
ディーラーの手札は ('J', '♤') です。
ダブルダウンしますか?【y or n】:n
ヒットしますか?スタンドしますか?【h or s】:h
あなたのスコアは 22 、ハードハンドです。
ディーラーのスコアは 20  、ハードハンドです。
バストしました!あなたの負けです!

 

はじめのスコアが低かったけどダブルダウンしたら勝った!

あなたの手札は ('A', '♤') と ('3', '♢') です。
あなたのスコアは 14 、ソフトハンドです。
ディーラーの手札は ('5', '☘') です。
ダブルダウンしますか?【y or n】:y
あなたのスコアは 20 、ソフトハンドです。
ディーラーのスコアは 17  、ハードハンドです。
あなたの勝ちです!

 

ナチュラルブラックジャックで勝った!

あなたの手札は ('A', '♢') と ('J', '♢') です。
あなたのスコアは 21 、ソフトハンドです。
ディーラーの手札は ('Q', '♢') です。
ナチュラルブラックジャック!あなたの勝ちです!

 

つづく…