見出し画像

Pythonでブラックジャックを作成

はじめに

ラスベガスに行くことになったので、pythonでブラックジャックのプログラムを作成しようと考えた。
⚠ブラックジャックのルールはこちらのサイトで詳しく説明されている。

なぜこの記事を書こうと思ったか

ブラックジャックをPythonで作成する記事はあったが、「A」の扱いを1としか扱わず本来の11としても1としても扱う記事が少なかったので、この記事を書こうと思った。

作成手順

  1. デッキ山の作成

  2. 初期手札の作成

  3. プレイヤーのアクション

  4. ディーラーのアクション

  5. ゲームの結果

  6. 1−5を用いて実際にやってみる

1.デッキ山の作成

まずはデッキ山の作成を行なう。
格サイトによると、ベガスでは1組のデッキ(13数×4柄=52枚)を8組合わせシャッフルすることで1つのデッキ山を作成しているらしい。つまり8回連続で同じ絵柄&数字を引く可能性もあるということだ。

import random as rd
rd.seed(10)

def shuffled_deck(): # make shuffled deck 
  global full_decks
  cards_deck = 4*[11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10] # a cards deck A 
  deck_num = 8 # def deck num
  full_decks = cards_deck * deck_num # number of cards deck
  rd.shuffle(full_decks) 
  return full_decks

Aは最初から11として扱い条件によって1に変更の方が都合が良さそうなので、11として扱う。J, Q, Kは10としてしか扱わないので、デッキの際にそのまま10として作成した。
cards_deckで1組の山を定義し、full_deckで1*8組の山を定義しrandom関数を用いてシャッフルしたという流れだ。
再現性を保つためとチェックの為、rd.seedを固定しておく。

2.初期手札の作成

作成したデッキ山の上からカードを引き、引いたデッキ山のカードを逐一削除してく形でプログラムした。初期手札はプレイヤー、ディラーともに2枚すづである。

def first_hand(): # first hand for player and dealer 
  global dealer_hand, player_hand
  dealer_hand = [] # reset the dealer hand
  player_hand = [] # reset the player_hand 
  dealer_hand = full_decks[0:2] # dealer hand 
  del full_decks[0:2]
  player_hand = full_decks[0:2] # player hand
  del full_decks[0:2]

関数外でも用いる為、globalに設定。
dealer_hand = full_decks[0:2]では、full_decksの0&1番目を抽出し、dealer_handに格納する。そしてfull_decksの0&1番目をdelによって削除する。同じことをplayer_handでも行なう。

3.プレイヤーのアクション

プレイヤーのアクションは以下の3つ
Hit                 : デッキからカードを引く
Double Down: 掛け金を2倍にし1枚だけ引く
Stand            : 現状の手で勝負

def players_action(player_hand): 
  global player_final_hand
  print(player_hand)
  if 11 in player_hand and 10 in player_hand: # BJ
    player_final_hand = player_hand
  else:
    action = ''
    while action != 'S': # while to become to True
      if sum(player_hand) > 21:
        break
      else: 
        action = input("H: Hit, S: Stand, D: Doubledown :")
        if action == 'H':
          player_hand.append(full_decks[0]) # draw card from deck
          del full_decks[0] # del a card from deck
          if sum(player_hand) > 21 and 11 in player_hand: 
            player_hand[player_hand.index(11)] = 1
          print(player_hand)
        elif action == 'D':
          player_hand.append(full_decks[0]) # draw card from deck
          del full_decks[0] # del a card from deck
          if sum(player_hand) > 21 and 11 in player_hand: 
            player_hand[player_hand.index(11)] = 1
          break
        else: 
          break
    player_final_hand = player_hand
  return player_final_hand

while文を用いて、ユーザからのinputが'S'になるまで処理を繰り返す。
ここでの11の扱いについては、ハンドが21を超えかつハンドに11がある場合は1に置き換える、という形で定義。

4.ディーラーのアクション

ディーラのアクションは単純だ、17以上になるまでカードを引きつづければよい。

def dealers_action(dealer_hand): # 0 < x < 17 draw, 17 <= x <= 21 stand, x > 22 Burst
  global dealer_final_hand
  while sum(dealer_hand) < 17:
    dealer_hand.append(full_decks[0]) # draw card from deck
    del full_decks[0] # del a card from deck
    if sum(dealer_hand) > 21 and 11 in dealer_hand: 
          dealer_hand[dealer_hand.index(11)] = 1
    print("Dealer's hand: ", dealer_hand)
  dealer_final_hand = dealer_hand
  return dealer_final_hand

デフォで11と定義したAの扱いは、ハンドが21を超えかつハンドに11がある場合は1に置き換える、という形で定義した。

5.ゲーム結果のプログラム

プレーヤーがバーストするとその時点でプレイヤーの負である。プレイヤーがBJでも相手もBJなら引き分けになる。
以上のことを踏まえて、以下に事象の順番で条件分岐を書いた。

  1. プレイヤーがバーストした事象

  2. 引き分けの事象

  3. プレイヤーがBJで勝つ事象

  4. プレイヤーがBJ以外で勝つ事象

  5. プレイヤーがバーストせず、ディーラーがバーストする事象

  6. それ以外の事象(プレイヤーが負ける)

def play_result(player_final_hand, dealer_final_hand):
  global result
  if sum(player_final_hand) > 21:
    result  = 'lost'
  elif player_final_hand == dealer_final_hand:
    result = 'draw'
  elif player_final_hand == [10, 11] or player_final_hand == [11, 10]:
    result = 'BJ_win'
  elif sum(player_final_hand) > sum(dealer_final_hand):
    result = 'win'
  elif sum(dealer_final_hand) > 21: 
    result = 'win'
  else:
    result = 'lost'
  print(result)

今回はだた勝ち負けのプログラムとした。

6.ゲームをやってみる

1−5で定義した関数を呼び出し、実際に数回プレイする。

shuffled_deck() 
x = ''
while x != 'yes':
  first_hand()
  players_action(player_hand)
  dealers_action(dealer_hand)
  play_result(player_final_hand, dealer_final_hand)
  x = input('Do you wanna quit this game?(yes or no): ')
プレイ結果

反省&今後

スプリットをサボってしまったので、スプリットを追加し、所持金とベット数でプレイできるようにする事。
BJには大負けしないと言われる、ベーシックストラテジー、カウンティングを用いて行なうパーフェクトストラテジーと呼ばれる戦略があるので、そのシュミレーションを可視化するプロラムを作ろうと考えている。

参考URL


いいなと思ったら応援しよう!