Qiitaの記事を見て、ブラックジャックのコードをPythonで書いてみました。
基本的な機能は簡単にコードにできたのですが、機能拡張を図る上でどのように設計すればいいかで悩んでいます。
Python
1# コードの概略 2class Card 3class Deck 4class Player: 5 def deal() 6class Dealer(Player): 7 def deal() 8 9def blackjack(): 10 # initialize deck, player, dealer 11 # player.deal() 12 # dealer.deal() 13 # showdown 14 15def confirm() 16def main(): 17 while True: 18 blackjack() 19 confirm()
player vs dealerの1対1の想定で、
ゲームのinitial deal
-> player action
-> dealer action
-> showdown
の4段階のうち、initial deal
, showdown
の2つがblackjack()
内で、残りの2つがそれぞれのクラス内でdeal()
として実装されています。
また、player.deal()
でもう1枚カードを引くかをプレイヤーに確認するために、クラス外のconfirm()
を呼び出しています。
ルールの拡張やプレイヤーの追加、各クラスを他のトランプゲームに使い回すことを考えると、ブラックジャック特有の機能をPlayer
, Dealer
から分けるべきだと考えています。
ここで悩んでいるのが、blackjack()
の関数内に全ての処理を記述すべきなのか、新たにBlackjack
クラスを用意して、その中で細かく処理を分けたほうがいいのかという点です。
関数内の処理は30-40行以内に収まるのが良いとも聞いたことがあります。
処理が複雑な場合、どういった基準で関数やクラス、あるいは他の形での実装を選ぶべきなのか、アドバイスをいただければ幸いです。
Python
1# コード全文 2# blackjack.py 3from random import shuffle 4 5 6class Card: 7 suits = ["H", "D", "S", "C"] 8 numbers = [i for i in range(1, 14)] 9 cards_converter = {**{i: i for i in range(2, 11)}, **{1: "A", 11: "J", 12: "Q", 13: "K"}} 10 11 def __init__(self, suit, number): 12 self.suit = suit 13 self.number = number 14 15 def __repr__(self): 16 return f"{self.suit}-{self.cards_converter[self.number]}" 17 18 19class Deck(list): 20 def __init__(self): 21 super().__init__(Card(suit, num) for suit in Card.suits for num in Card.numbers) 22 shuffle(self) 23 24 25class Player: 26 def __init__(self, deck: "Deck"): 27 self.deck = deck 28 self.hands = [] 29 self._initial_deal() 30 31 def __repr__(self): 32 return f"{self.__class__.__name__}: {self.score} pts / {self.hands}" 33 34 def _initial_deal(self) -> None: 35 for _ in range(2): 36 self.draw() 37 print(self) 38 39 def draw(self) -> int: 40 card = self.deck.pop() 41 self.hands.append(card) 42 return self.score 43 44 def deal(self) -> bool: 45 while confirm("Keep drawing a card?"): 46 score = self.draw() 47 print(self) 48 if score == 21: 49 print("<You win!>\n") 50 return False 51 elif score > 21: 52 print("<You lose...>\n") 53 return False 54 print_line() 55 return True 56 57 @property 58 def score(self) -> int: 59 # count royal cards as 10 60 score = sum(min(card.number, 10) for card in self.hands) 61 # exception of ace 62 if score <= 11 and 1 in {card.number for card in self.hands}: 63 score += 10 64 return score 65 66 67class Dealer(Player): 68 def _initial_deal(self) -> None: 69 self.draw() 70 print(self) 71 self.draw() # hide the second hand 72 73 def deal(self) -> bool: 74 while self.score < 17: 75 self.draw() 76 if self.score > 21: 77 print(self) 78 print("<You win!>\n") # dealer loses, and player wins 79 return False 80 print_line() 81 return True 82 83 84def blackjack() -> None: 85 # initialize / initial deal 86 deck = Deck() 87 player = Player(deck) 88 if player.score == 21: 89 print("<You win!>\n") 90 return 91 dealer = Dealer(deck) 92 93 # showdown 94 if player.deal() and dealer.deal(): 95 print(player, dealer, sep="\n") 96 if player.score == dealer.score: 97 print("<Draw>\n") 98 elif player.score > dealer.score: 99 print("<You win!>\n") 100 else: 101 print("<You lose...>\n") 102 print_line() 103 104 105def confirm(message: str) -> bool: 106 return input(f"{message} [y/n]").lower()[0] == "y" 107 108 109def print_line(length: int = 55) -> None: 110 print("-" * length) 111 112 113def main(): 114 blackjack() 115 while confirm("Play again?"): 116 print_line() 117 blackjack() 118 119 120if __name__ == "__main__": 121 main()
回答1件
あなたの回答
tips
プレビュー