プログラミング入門者からの卒業試験は『ブラックジャック』を開発すべし
のルールでチャレンジしてみたブラックジャック。
スコアの計算、Aの処理の部分は少し考えてみるとシンプルに。
スコアの計算
元ルールの処理:
JとQとKは10として扱う
Aはとりあえず「1」としてだけ扱う
sc = sum(min(10, c.rank) for c in self)
拡張版:Aを1か11、有利な方でカウント
if (sc <= 11 and 1 in [c.rank for c in self]): sc += 10
こちらの機能拡張も一行追加するのみ。
「Aは2枚以上11とカウントされない(22をオーバーしてしまう)」
⇒ 「全体スコアが11以下の時のみ、Aが11とカウントされる場合がある」
と考えるとシンプルに。
改行入れてもソース全体で60行程度、Pythonは手軽に書きやすいなぁと思いました。
ブラウザで動かす版はこちら(colab)
BlackJack:ソース全体(改行込みで60行)
class Card: #カード:ユニコードでSuit表示
SUITS = '♤♡♢♧'
RANKS = '0 A 2 3 4 5 6 7 8 9 10 J Q K'.split()
def __init__(self, suit, rank): self.suit, self.rank = suit, rank
def __repr__(self): return f'{Card.SUITS[self.suit]}{Card.RANKS[self.rank]}'
import random
class Deck(list): #トランプの山
def __init__(self):
super().__init__([Card(suit, rank) for suit in range(4) for rank in range(1, 14)])
random.shuffle(self)
class Hand(list): # 手札
@property
def score(self): # ブラックジャックのスコア(Bustした場合は負の数を返す)
sc = sum(min(10, c.rank) for c in self)
if (sc <= 11 and 1 in [c.rank for c in self]): sc += 10
return sc if sc <= 21 else -sc
class Player:
def __init__(self, deck):
self.deck = deck
self.hand = Hand()
self.draw()
def __repr__(self): return (f"{self.__class__.__name__} {self.hand} :Score={self.hand.score}")
def draw(self):
self.hand.append(self.deck.pop())
return self.hand.score
def confirm_hit(self):
view(self)
return confirm('もう一枚引きますか?')
def deal(self):
while (self.draw() > 0):
if (not self.confirm_hit()): return self.hand.score
view(f"{self.__class__.__name__} の負け!バーストしました。 {self.hand} ")
class Dealer(Player):
def confirm_hit(self): return self.hand.score < 17
def game():
deck = Deck()
dealer, player = Dealer(deck), Player(deck)
view(dealer)
if (player.deal() and dealer.deal()):
view(dealer)
if (player.hand.score >= dealer.hand.score):
view('Playerの勝ちです。おめでとうございます!')
else:
view('Dealerの勝ちです。残念!')
def view(msg): print(msg)
def confirm(msg): return input(f'{msg} [y/n]').lower() == 'y'
if __name__ == '__main__':
game()
while confirm('もう一度ゲームしますか?'): game()
実行結果例
Dealer [♧4] :Score=4
Player [♧A, ♡K] :Score=21
もう一枚引きますか? [y/n]n
Dealer [♧4, ♧8, ♡4, ♢2] :Score=18
Playerの勝ちです。おめでとうございます!
もう一度ゲームしますか? [y/n]y
Dealer [♧7] :Score=7
Player [♧Q, ♤7] :Score=17
もう一枚引きますか? [y/n]n
Dealer [♧7, ♤4, ♢10] :Score=21
Dealerの勝ちです。残念!
もう一度ゲームしますか? [y/n]y
Dealer [♢A] :Score=11
Player [♢9, ♢J] :Score=19
もう一枚引きますか? [y/n]n
Dealer [♢A, ♤3, ♤K, ♢6] :Score=20
Dealerの勝ちです。残念!
もう一度ゲームしますか? [y/n]n
検討課題:
クラスや関数の名前、継承関係。GUI