#はじめに
アドベントカレンダーが空いていたのでまたまた書いていこうと思います。今回は題名の通りブラックジャックを作りました。
前回の記事はこちら→ Pythonでおみくじ作った。
#環境
Ubuntu18.04LTS
Python3.6.9
vim
#コード
play_bj.py
from random import shuffle
class Deck:
"""
山札を表すクラス
"""
def __init__(self):
"""
山札を初期化して、シャッフルする。
"""
suits = ['スペード', 'クラブ', 'ダイヤモンド', 'ハート']
values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K']
self.deck = []
for i in suits:
for j in values:
self.deck.append((i, j))
shuffle(self.deck)
def draw(self):
"""
山札から1枚引き、引いたカードを返す。
"""
return self.deck.pop(0)
class Person:
"""
プレイヤーを表すクラス
"""
def __init__(self):
"""
手札を初期化する。
"""
self.hands = []
self.point = 0
def add(self, card):
"""
手札にカードを1枚加える。
"""
self.hands.append(card)
def point_sum(self):
"""
トランプの合計点数を求める。
"""
self.point = 0
for i in self.hands:
if i[1] in ['J', 'Q', 'K']:
self.point += 10
else:
self.point += i[1]
return self.point
def BJ():
"""
メインの処理
"""
print('ブラックジャックへようこそ!')
d = Deck()
p = Person()
c = Person()
drawing(d, p, 'あなた')
drawing(d, p, 'あなた')
drawing(d, c, 'CPU')
card = d.draw()
c.add(card)
player_point = p.point_sum()
cpu_point = c.point_sum()
if player_point == cpu_point == 21:
print('引き分けです。')
return
elif player_point == 21:
print('あなたの勝ちです!')
return
elif cpu_point == 21:
print('あなたの負けです。')
return
# ここではAは11にならないので上の条件分岐は本当はいらない。
while True:
choice = input('"Hit"または"Stand"を入力してください。: ')
while True:
if choice.lower() == 'hit' or choice.lower() == 'stand':
break
else:
choice = input('"Hit"または"Stand"を入力してください。: ')
if choice.lower() == 'hit':
drawing(d, p, 'あなた')
player_point = p.point_sum()
if player_point >= 22:
print('あなたの負けです。')
return
elif choice.lower() == 'stand':
break
else:
print('error')
return
print('CPUのもう1つのカードは{}の{}です。'.format(c.hands[1][0], c.hands[1][1]))
while True:
cpu_point = c.point_sum()
if cpu_point < 17:
drawing(d, c, 'CPU')
cpu_point = c.point_sum()
if cpu_point >= 22:
print('あなたの勝ちです!')
return
else:
break
if player_point == cpu_point:
print('引き分けです。')
return
elif player_point > cpu_point:
print('あなたの勝ちです!')
return
elif player_point < cpu_point:
print('あなたの負けです。')
return
def drawing(class1, class2, name):
"""
山札からカードを1枚引き手札に加える。
その後、加えたカードの情報を表示する。
"""
card = class1.draw()
class2.add(card)
print('{}の引いたカードは{}の{}です。'.format(name, card[0], card[1]))
if __name__ == '__main__':
BJ()
#おわりに
関数とクラスのいい勉強になりました。次は、Aに11も対応できるようにしようかな。もっと良いものができ次第、追記していきます。
#追記
クラスの継承などを利用してコードを整理しました。また、Aに11も対応できるようにしました。(12/09)
エラー処理,argparseを追加しました。(12/16)
loggingを追加しました。(01/04)
import argparse
import logging
from logging import getLogger, StreamHandler, FileHandler, Formatter
import sys
from random import shuffle
logger = getLogger(__file__)
logger.setLevel(logging.DEBUG)
stream_handler = StreamHandler()
file_handler = FileHandler('debug.log')
stream_handler.setLevel(logging.DEBUG)
file_handler.setLevel(logging.DEBUG)
stream_format = Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_format = Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
stream_handler.setFormatter(stream_format)
file_handler.setFormatter(file_format)
logger.addHandler(stream_handler)
logger.addHandler(file_handler)
class Card:
SUITS = 'スペード', 'クラブ', 'ダイヤモンド', 'ハート'
RANKS = 'A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K'
def __init__(self, suit, rank):
self.suit = suit
self.rank = rank
self.number = self.RANKS.index(rank) + 1
class Deck:
def __init__(self):
self.deck = [Card(suit, rank)
for suit in Card.SUITS
for rank in Card.RANKS]
shuffle(self.deck)
def draw(self):
return self.deck.pop()
class Participant:
def __init__(self, name):
self.name = name
self.hands = []
self.point = []
def drawing(self, card, display=True):
self.hands.append(card)
self.point.append(min(card.number, 10))
if display:
print('{}の引いたカードは{}の{}です。'
.format(self.name, card.suit, card.rank))
class Player(Participant):
def choose_a_first(self):
in_a = any(card.rank == 'A' for card in self.hands)
while in_a and sum(self.point) <= 11:
try:
choice_point = input('Aを1としますか11をしますか?: ')
except (KeyboardInterrupt, EOFError):
print()
print('ブラックジャックを終了しました。')
sys.exit()
else:
if choice_point == '11':
self.point.append(10)
break
if choice_point == '1':
break
print('{}の合計得点は{}です。'.format(self.name, sum(self.point)))
def choose_a(self):
while self.hands[-1].rank == 'A' and sum(self.point) <= 11:
try:
choice_point = input('Aを1としますか11をしますか?: ')
except (KeyboardInterrupt, EOFError):
print()
print('ブラックジャックを終了しました。')
sys.exit()
else:
if choice_point == '11':
self.point.append(10)
break
if choice_point == '1':
break
print('{}の合計得点は{}です。'.format(self.name, sum(self.point)))
def is_continue(self):
while True:
try:
choice = input('Hit または Standを入力してください。: ').lower()
except (KeyboardInterrupt, EOFError):
print()
print('ブラックジャックを終了しました。')
sys.exit()
else:
print()
if choice == 'hit':
return True
if choice == 'stand':
return False
class Dealer(Participant):
def choose_a_first(self):
in_a = any(card.rank == 'A' for card in self.hands)
if in_a and sum(self.point) <= 11:
self.point.append(10)
def choose_a(self):
if self.hands[-1].rank == 'A' and sum(self.point) <= 11:
self.point.append(10)
print('{}の合計得点は{}です。'.format(self.name, sum(self.point)))
def show_card(self):
print('{}のもう1枚のカードは{}の{}です。'
.format(self.name, self.hands[1].suit, self.hands[1].rank))
print('{}の合計得点は{}です。'.format(self.name, sum(self.point)))
print()
def is_continue(self):
if sum(self.point) < 17:
return True
else:
return False
class BlackJack:
def __init__(self):
try:
name = input('名前を入力してください。: ')
except (KeyboardInterrupt, EOFError):
print()
print('ブラックジャックを終了しました。')
sys.exit()
else:
self.deck = Deck()
self.player = Player(name)
self.dealer = Dealer('ディーラー')
def play(self):
print()
self.player.drawing(self.deck.draw())
self.player.drawing(self.deck.draw())
self.player.choose_a_first()
print()
self.dealer.drawing(self.deck.draw())
self.dealer.drawing(self.deck.draw(), False)
self.dealer.choose_a_first()
print()
j_21 = self.judje_21(sum(self.player.point), sum(self.dealer.point))
if j_21:
logger.info('ナチュラル21')
return
while self.player.is_continue():
self.player.drawing(self.deck.draw())
self.player.choose_a()
print()
if sum(self.player.point) >= 22:
print('{}の負けです。'.format(self.player.name))
logger.info('プレイヤーバスト')
return
self.dealer.show_card()
while self.dealer.is_continue():
self.dealer.drawing(self.deck.draw())
self.dealer.choose_a()
print()
self.judje(sum(self.player.point), sum(self.dealer.point))
def judje_21(self, player_point, dealer_point):
if player_point == dealer_point == 21:
print('{}もナチュラル21です。'.format(self.dealer.name))
print('引き分けです。')
return True
elif player_point == 21:
print('{}の勝ちです。'.format(self.player.name))
return True
elif dealer_point == 21:
print('{}はナチュラル21です。'.format(self.dealer.name))
print('{}の負けです。'.format(self.player.name))
return True
def judje(self, player_point, dealer_point):
if player_point == dealer_point:
print('引き分けです。')
elif player_point > dealer_point or dealer_point >= 22:
print('{}の勝ちです。'.format(self.player.name))
elif player_point < dealer_point:
print('{}の負けです。'.format(self.player.name))
def get_parser():
parser = argparse.ArgumentParser(description='ターミナル上でブラックジャックができます。')
parser.add_argument('-q', '--qiita', action='store_true', help='ソースコードがあるQiitaのリンク')
parser.add_argument('-r', '--rules', action='store_true', help='ブラックジャックのルールを説明')
args = parser.parse_args()
return args
def main():
args = get_parser()
if args.qiita:
print('https://qiita.com/yoshige/items/d06382f2a8b76ce6cd79')
return
if args.rules:
print('ブラックジャックのルールはこちらをご覧ください')
print('https://ja.wikipedia.org/wiki/ブラックジャック')
return
logger.info('start')
print('ブラックジャックへようこそ!')
bj = BlackJack()
bj.play()
logger.info('end')
if __name__ == '__main__':
main()