ブラックジャックは、カジノで行われるカードを使ったゲームです。
このゲームの参加者はお互いに競うのではなく、カジノが指定したディーラーと競います。
今回は、プレイヤーとディーラーの間で行われるブラックジャックゲームをゼロから作り、端末でプレイできるようにします。
ブラックジャックのルール
ブラックジャックをプレイしたことがない読者のために、簡単なルールを説明します。
ブラックジャックのマジックナンバーは21です。
プレイヤーに配られたカードの値を全て足し、その合計が21を超えたら、プレイヤーは即座にバストし、負けになる。
21がぴったり揃えば、ディーラーに勝ちます。
それ以外の場合、勝つためには、プレイヤーのカードの合計がディーラーのカードの合計より多くなければなりません。
各フェイスカードは10と決まっていますが、エースは1または11と数えることができ、プレイヤーの勝率を決定します。
残りのカードの価値は、その数によって定義される。
ブラックジャックゲームのカードの配り方は以下の通りです。
- 上向きのプレイヤーにカードが配られる(全員から見える)。
- ディーラーは全員に見えるように自分自身にカードを配る。
- 別のカードが上向きのプレイヤーに配られます。
- ディーラーは自分自身に下向きのカードを配る。
- プレイヤーは、現在のカードセットでスタンドするか、別のカードをもらうか決めなければならない。
- ヒットすることを決定した場合、別のカードが配られます。
- プレイヤーがスタンドすると決めた場合、ディーラーは隠していたカードを公開します。
- ディーラーにはヒットかスタンドかを決定する権限はありません。ディーラーは、ディーラーのカードの合計が17より少ない場合、より多くのカードをヒットし続ける必要があるというのが一般的なルールです。
- ディーラーのカードの合計が17枚以上になった時点で、ディーラーはスタンドする義務があります。
- 最終的なカードの合計で勝敗を決めます。
ブラックジャックゲームのプログラミングは、ルールさえ理解できれば簡単です。
ターミナルベースのゲームをゼロから作るには、3つの主要なコンポーネントが必要です。
ゲームデザイン, ゲームロジック, そしてプレイヤーとのインタラクションの管理です。
ブラックジャックゲームデモ
ブラックジャックゲームのデモ
Pythonでブラックジャックをデザインする
まず最初に、ゲームの設計に取り組みます。
私たちの仕事は、次の図のようなカードの列を端末に効果的に表示することです。
# Function to print the cardsdef print_cards(cards, hidden):
s = ""
for card in cards:
s = s + " ________________"
if hidden:
s += " ________________"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | |" print(s)
s = ""
for card in cards:
if card.value == '10':
s = s + " | {} |".format(card.value)
else:
s = s + " | {} |".format(card.value)
if hidden:
s += " | |" print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | * * |"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | * * |"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | * * |"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | * * |"
print(s)
s = ""
for card in cards:
s = s + " | {} |".format(card.suit)
if hidden:
s += " | * |"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | * |"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | * |"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | |"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | |"
print(s)
s = ""
for card in cards:
if card.value == '10':
s = s + " | {} |".format(card.value)
else:
s = s + " | {} |".format(card.value)
if hidden:
s += " | * |" print(s)
s = ""
for card in cards:
s = s + " |________________|"
if hidden:
s += " |________________|"
print(s)
print()
|
そのためには、カードの枚数に依存せず、一連のカードを表示する関数が必要です。
次のコードは我々の問題を解決します。
# The Card Class definitionclass Card:
def __init__(self, suit, value, card_value):
# Suit of the Card like Spades and Clubs
self.suit = suit
# Representing Value of the Card like A for Ace, K for King
self.value = value
# Score Value for the Card like 10 for King
self.card_value = card_value
|
各カードの詳細は Card Object として保存される。
カードの作成
クラスとオブジェクトを使って、スーツと値のアンサンブルを作り、「トランプ」を表現することができる。
ブラックジャックでは、カードは3つのプロパティ、スーツ、表象値、スコアとしての値を持っています。
これらの特性は、以下のCardクラスで管理されます。
# The type of suitsuits = ["Spades", "Hearts", "Clubs", "Diamonds"]
# The suit value suits_values = {"Spades":"u2664", "Hearts":"u2661", "Clubs": "u2667", "Diamonds": "u2662"}
# The type of cardcards = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]
# The card valuecards_values = {"A": 11, "2":2, "3":3, "4":4, "5":5, "6":6, "7":7, "8":8, "9":9, "10":10, "J":10, "Q":10, "K":10}
|
上記のクラスを使って、52枚のCardオブジェクトを含む適切なカードのデッキを作成することができます。
いくつかの基本的な価値観
カードゲームには、スーツの種類、カードの種類、各カードの価値など、基本的な価値観が必要です。
# The deck of cardsdeck = []
# Loop for every type of suitfor suit in suits:
# Loop for every type of card in a suit
for card in cards:
# Adding card to the deck
deck.append(Card(suits_values[suit], card, cards_values[card]))
|
ここで注意しなければならないのは、最初はエースが11点カードとしてマークされていることです。
これは、プレイヤーやディーラーの点数が21を超えそうになったときに、(配られた)エースの点数を1点に減らすというものです。
この減点の実装は、この記事の後半で見ることにします。
トランプの山札を生成する
通常のトランプは52枚のカードで構成され、各カードはスーツと価値の組み合わせが異なる。
上記の基本値とCardクラスを使って、トランプの山を生成します。
blackjack_game(deck) |
実際には、ブラックジャックのゲームでは複数のデッキを使用するため、上記のループは複数のデッキを生成するために再利用することができます。
新しく作成されたデッキは、ゲームを実行する関数に渡されます。
# Function for a single game of blackjackdef blackjack_game(deck):
global cards_values
# Cards for both dealer and player
player_cards = []
dealer_cards = []
# Scores for both dealer and player
player_score = 0
dealer_score = 0
|
プレイヤーとコンピュータ上のディーラーとの間のブラックジャックゲームの1回の繰り返しの背後にあるゲームロジックを学んでみよう.
重要なゲーム変数の宣言
どの時点でも、以下のゲーム変数が必要です。
- プレイヤーとディーラーに配られたカードのリスト。
- プレイヤーとディーラーに配られたカードのリスト。
# Initial dealing for player and dealerwhile len(player_cards) < 2:
# Randomly dealing a card
player_card = random.choice(deck)
player_cards.append(player_card)
deck.remove(player_card)
# Updating the player score
player_score += player_card.card_value
# In case both the cards are Ace, make the first ace value as 1
if len(player_cards) == 2:
if player_cards[0].card_value == 11 and player_cards[1].card_value == 11:
player_cards[0].card_value = 1
player_score -= 10
# Print player cards and score
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
input()
# Randomly dealing a card
dealer_card = random.choice(deck)
dealer_cards.append(dealer_card)
deck.remove(dealer_card)
# Updating the dealer score
dealer_score += dealer_card.card_value
# Print dealer cards and score, keeping in mind to hide the second card and score
print("DEALER CARDS: ")
if len(dealer_cards) == 1:
print_cards(dealer_cards, False)
print("DEALER SCORE = ", dealer_score)
else:
print_cards(dealer_cards[:-1], True)
print("DEALER SCORE = ", dealer_score - dealer_cards[-1].card_value)
# In case both the cards are Ace, make the second ace value as 1
if len(dealer_cards) == 2:
if dealer_cards[0].card_value == 11 and dealer_cards[1].card_value == 11:
dealer_cards[1].card_value = 1
dealer_score -= 10
input()
# Player gets a blackjack if player_score == 21:
print("PLAYER HAS A BLACKJACK!!!!")
print("PLAYER WINS!!!!")
quit()
|
これらのゲーム変数は、ゲームロジックを設計する際に必要となります。
Python ブラックジャックゲームロジック
ゲーム全体のロジックは、カードの配り方と、プレイヤーのヒットかスタンディングかの選択を中心に展開される。
上記の2つを処理したら、その日は終わりです。
ディーリングの第一段階 マンダトリーカード
最初のディーリングでは、プレイヤーとディーラーに2枚のカードを渡します。
ただし、ディーラーの2枚目のカードは不明のままでなければならない。
# Print dealer and player cardsprint("DEALER CARDS: ")
print_cards(dealer_cards[:-1], True)
print("DEALER SCORE = ", dealer_score - dealer_cards[-1].card_value)
print()
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
# Managing the player moveswhile player_score < 21:
choice = input("Enter H to Hit or S to Stand : ")
# Sanity checks for player's choice
if len(choice) != 1 or (choice.upper() != 'H' and choice.upper() != 'S'):
clear()
print("Wrong choice!! Try Again")
# If player decides to HIT
if choice.upper() == 'H':
# Dealing a new card
player_card = random.choice(deck)
player_cards.append(player_card)
deck.remove(player_card)
# Updating player score
player_score += player_card.card_value
# Updating player score in case player's card have ace in them
c = 0
while player_score > 21 and c < len(player_cards):
if player_cards[c].card_value == 11:
player_cards[c].card_value = 1
player_score -= 10
c += 1
else:
c += 1 clear()
# Print player and dealer cards
print("DEALER CARDS: ")
print_cards(dealer_cards[:-1], True)
print("DEALER SCORE = ", dealer_score - dealer_cards[-1].card_value)
print()
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
# If player decides to Stand
if choice.upper() == 'S':
break
# Check if player has a Blackjackif player_score == 21:
print("PLAYER HAS A BLACKJACK")
quit()
# Check if player bustsif player_score > 21:
print("PLAYER BUSTED!!! GAME OVER!!!")
quit()
|
一見簡単そうに見えるディーリングですが、その内容は多岐に渡ります。
上のコードの処理を理解しましょう。
- メインループは、プレイヤーとディーラーがそれぞれ2枚のカードを獲得するまで実行されます。
- カードはデッキからランダムに選ばれ、次のステップでそのカードはデッキから取り除かれます。
- カードの価値はプレイヤーのスコアに加算されます。
- 同様に、カードはディーラーのために無作為に選ばれ、その価値はディーラーのスコアに加えられる。
- プレイヤーのカードは通常通り画面に表示されます。
- ディーラーのカードは、2枚目のカードとその価値がわからないように注意深く表示されます。
- どちらかがダブルエースを出した場合、どちらもバストにならないように点数を調整します。
- 以上のことがスムーズに行われた後、第2ステージのディーリングに移ります。
注:プレイヤーの得点調整とディーラーの得点調整には微妙な違いがある。
前者は1枚目のカードの価値を調整するのに対し、後者は2枚目のカードの価値を調整します。
>
2枚目のカードの価値を調整する理由は、1枚目のカードを調整してしまうと、隠れていたカードがエースであることがバレてしまうからです。
ここで最後に、プレイヤーがすでにブラックジャックを持っているかどうかをチェックする必要がある。
もし持っていれば、そのプレイヤーの勝ちとなり、ゲームは終了します。
注意: input()関数は、プレイヤーが “ENTER “を押すまで、プログラムを一時停止します。
これは、すべてのゲームイベントの素早いフォールスルーを防ぐためです。
>
clear()`関数は、端末をクリアし、ゲームの美観を整える役割を果たします。
ディーリングの第二段階 プレイヤーの選択
ディーリングの第2段階は、点数を上げるためにもう1枚カードが欲しいか、現在のカードで我慢するか、プレイヤーの決断によります。
# Managing the dealer moveswhile dealer_score < 17:
clear()
print("DEALER DECIDES TO HIT.....")
# Dealing card for dealer
dealer_card = random.choice(deck)
dealer_cards.append(dealer_card)
deck.remove(dealer_card)
# Updating the dealer's score
dealer_score += dealer_card.card_value
# Updating player score in case player's card have ace in them
c = 0
while dealer_score > 21 and c < len(dealer_cards):
if dealer_cards[c].card_value == 11:
dealer_cards[c].card_value = 1
dealer_score -= 10
c += 1
else:
c += 1
# print player and dealer cards
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
print()
print("DEALER CARDS: ")
print_cards(dealer_cards, False)
print("DEALER SCORE = ", dealer_score)
input()
|
プレイヤーがヒットするかスタンドするかを決めるのは、スコアが21を超えるか、プレイヤーがスタンドすることを決めるまでです。
プレイヤーに配られるカードの枚数には制限はなく、得点にのみ制限がある。
プレイヤーがヒットを決定するたびに、山札から新しいカードが配られ、スコアが更新されます。
前述したように、Aceは1にも11にもカウントされる。
スコアが21を超えた場合、Aceの値を11から1に変換する特別なコードがあります。
プレーヤーは、現在のスコアに満足したら、スタンドします。
彼が立つと、ブラックジャックやバスティングシナリオのようないくつかの必須チェックを行った後、ディーリングの最終ステージに移る。
ディーリングの最終段階。ディーラーのカード
ディーリングの最終段階では、ディーラーの隠していたカードが公開され、ディーラーの点数も公開されます。
ブラックジャックの標準的なルールでは、ディーラーはその点数が17以上になるまで、自分自身にカードを配り続けなければなりません。
# Dealer bustsif dealer_score > 21:
print("DEALER BUSTED!!! YOU WIN!!!")
quit()
# Dealer gets a blackjackif dealer_score == 21:
print("DEALER HAS A BLACKJACK!!! PLAYER LOSES")
quit()
# TIE Gameif dealer_score == player_score:
print("TIE GAME!!!!")
# Player Winselif player_score > dealer_score:
print("PLAYER WINS!!!")
# Dealer Winselse:
print("DEALER WINS!!!")
|
ディーラーは点数が17を超えるまでヒットを続ける。
必要であれば、エースのカードの値を11から1に変換する同様の実装もある。
エンド・ゲーム
ディーラーのスコアが17以上になったら、ゲームの勝者を決めるエンドゲームに移行します。
いくつかのシナリオが考えられる。
- ディーラーがバストした場合 – ディーラーのスコアが21を超えた場合。
- ディーラーがブラックジャック – ディーラーは21の正確なスコアを持っています。
- タイゲーム – プレイヤーとディーラーの両方が同じスコアを持っています。
- プレーヤーの勝利 – プレーヤーのスコアはディーラーのそれよりも大きいです。
- ディーラーの勝利 – ディーラーのスコアはプレイヤーのそれよりも多くなっています。
上記の可能性を確認し、勝者を決定します。
import random
import os
import time
# The Card class definitionclass Card:
def __init__(self, suit, value, card_value):
# Suit of the Card like Spades and Clubs
self.suit = suit
# Representing Value of the Card like A for Ace, K for King
self.value = value
# Score Value for the Card like 10 for King
self.card_value = card_value
# Clear the terminaldef clear():
os.system("clear")
# Function to print the cardsdef print_cards(cards, hidden):
s = ""
for card in cards:
s = s + " ________________"
if hidden:
s += " ________________"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | |" print(s)
s = ""
for card in cards:
if card.value == '10':
s = s + " | {} |".format(card.value)
else:
s = s + " | {} |".format(card.value)
if hidden:
s += " | |" print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | * * |"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | * * |"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | * * |"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | * * |"
print(s)
s = ""
for card in cards:
s = s + " | {} |".format(card.suit)
if hidden:
s += " | * |"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | * |"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | * |"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | |"
print(s)
s = ""
for card in cards:
s = s + " | |"
if hidden:
s += " | |"
print(s)
s = ""
for card in cards:
if card.value == '10':
s = s + " | {} |".format(card.value)
else:
s = s + " | {} |".format(card.value)
if hidden:
s += " | * |" print(s)
s = ""
for card in cards:
s = s + " |________________|"
if hidden:
s += " |________________|"
print(s)
print()
# Function for a single game of blackjackdef blackjack_game(deck):
# Cards for both dealer and player
player_cards = []
dealer_cards = []
# Scores for both dealer and player
player_score = 0
dealer_score = 0
clear()
# Initial dealing for player and dealer
while len(player_cards) < 2:
# Randomly dealing a card
player_card = random.choice(deck)
player_cards.append(player_card)
deck.remove(player_card)
# Updating the player score
player_score += player_card.card_value
# In case both the cards are Ace, make the first ace value as 1
if len(player_cards) == 2:
if player_cards[0].card_value == 11 and player_cards[1].card_value == 11:
player_cards[0].card_value = 1
player_score -= 10
# Print player cards and score
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
input()
# Randomly dealing a card
dealer_card = random.choice(deck)
dealer_cards.append(dealer_card)
deck.remove(dealer_card)
# Updating the dealer score
dealer_score += dealer_card.card_value
# Print dealer cards and score, keeping in mind to hide the second card and score
print("DEALER CARDS: ")
if len(dealer_cards) == 1:
print_cards(dealer_cards, False)
print("DEALER SCORE = ", dealer_score)
else:
print_cards(dealer_cards[:-1], True)
print("DEALER SCORE = ", dealer_score - dealer_cards[-1].card_value)
# In case both the cards are Ace, make the second ace value as 1
if len(dealer_cards) == 2:
if dealer_cards[0].card_value == 11 and dealer_cards[1].card_value == 11:
dealer_cards[1].card_value = 1
dealer_score -= 10
input()
# Player gets a blackjack
if player_score == 21:
print("PLAYER HAS A BLACKJACK!!!!")
print("PLAYER WINS!!!!")
quit()
clear()
# Print dealer and player cards
print("DEALER CARDS: ")
print_cards(dealer_cards[:-1], True)
print("DEALER SCORE = ", dealer_score - dealer_cards[-1].card_value)
print()
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
# Managing the player moves
while player_score < 21:
choice = input("Enter H to Hit or S to Stand : ")
# Sanity checks for player's choice
if len(choice) != 1 or (choice.upper() != 'H' and choice.upper() != 'S'):
clear()
print("Wrong choice!! Try Again")
# If player decides to HIT
if choice.upper() == 'H':
# Dealing a new card
player_card = random.choice(deck)
player_cards.append(player_card)
deck.remove(player_card)
# Updating player score
player_score += player_card.card_value
# Updating player score in case player's card have ace in them
c = 0
while player_score > 21 and c < len(player_cards):
if player_cards[c].card_value == 11:
player_cards[c].card_value = 1
player_score -= 10
c += 1
else:
c += 1 clear()
# Print player and dealer cards
print("DEALER CARDS: ")
print_cards(dealer_cards[:-1], True)
print("DEALER SCORE = ", dealer_score - dealer_cards[-1].card_value)
print()
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
# If player decides to Stand
if choice.upper() == 'S':
break
clear()
# Print player and dealer cards
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
print()
print("DEALER IS REVEALING THE CARDS....")
print("DEALER CARDS: ")
print_cards(dealer_cards, False)
print("DEALER SCORE = ", dealer_score)
# Check if player has a Blackjack
if player_score == 21:
print("PLAYER HAS A BLACKJACK")
quit()
# Check if player busts
if player_score > 21:
print("PLAYER BUSTED!!! GAME OVER!!!")
quit()
input()
# Managing the dealer moves
while dealer_score < 17:
clear()
print("DEALER DECIDES TO HIT.....")
# Dealing card for dealer
dealer_card = random.choice(deck)
dealer_cards.append(dealer_card)
deck.remove(dealer_card)
# Updating the dealer's score
dealer_score += dealer_card.card_value
# Updating player score in case player's card have ace in them
c = 0
while dealer_score > 21 and c < len(dealer_cards):
if dealer_cards[c].card_value == 11:
dealer_cards[c].card_value = 1
dealer_score -= 10
c += 1
else:
c += 1
# print player and dealer cards
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
print()
print("DEALER CARDS: ")
print_cards(dealer_cards, False)
print("DEALER SCORE = ", dealer_score)
input()
# Dealer busts
if dealer_score > 21:
print("DEALER BUSTED!!! YOU WIN!!!")
quit()
# Dealer gets a blackjack
if dealer_score == 21:
print("DEALER HAS A BLACKJACK!!! PLAYER LOSES")
quit()
# TIE Game
if dealer_score == player_score:
print("TIE GAME!!!!")
# Player Wins
elif player_score > dealer_score:
print("PLAYER WINS!!!")
# Dealer Wins
else:
print("DEALER WINS!!!")
if __name__ == '__main__':
# The type of suit
suits = ["Spades", "Hearts", "Clubs", "Diamonds"]
# The suit value
suits_values = {"Spades":"u2664", "Hearts":"u2661", "Clubs": "u2667", "Diamonds": "u2662"}
# The type of card
cards = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]
# The card value
cards_values = {"A": 11, "2":2, "3":3, "4":4, "5":5, "6":6, "7":7, "8":8, "9":9, "10":10, "J":10, "Q":10, "K":10}
# The deck of cards
deck = []
# Loop for every type of suit
for suit in suits:
# Loop for every type of card in a suit
for card in cards:
# Adding card to the deck
deck.append(Card(suits_values[suit], card, cards_values[card]))
blackjack_game(deck)
|
これで,プレイヤーとディーラーのブラックジャックゲームの1回の繰り返しが終了する.
ブラックジャックゲームの完全なPythonコード

読者は、コーディングの順序に従うことを義務づけられてはいない。
上記のコードには、ディーラーに対する複数のプレイヤーの機能を追加することで、様々な修正が可能です。
まとめ
ブラックジャックゲームは,最初は単純でランダムに見えるかもしれない.しかし,カードカウンティングのような特定の戦略に従ったときだけ,ゲームは複雑化される.
ブラックジャックには,スウェーデンのパブブラックジャックやホームゲームブラックジャックなど,様々なバージョンが存在する.好奇心旺盛な読者は,これらのバージョンについて学び,この記事で得た知識を使って実践してみてはどうだろうか.
読んでくれてありがとう.Pythonでマスターマインドゲームを開発する方法もご覧ください。
この記事もチェック:Pythonでマスターマインドゲームと言う暗号解読ゲームを作る方法