はじめに
Pythonと強化学習の勉強を兼ねて,ブラックジャックの戦略作りをやってみました.
ベーシックストラテジーという確率に基づいた戦略がありますが,それに追いつけるか試してみます.
こんな感じで進めていきます
- ブラックジャック実装 ← 今回はここ
- OpenAI gymの環境に登録
- 強化学習でブラックジャックの戦略を学習
なぜブラックジャック?
- プログラミングの勉強によさそう(プログラミング入門者からの卒業試験は『ブラックジャック』を開発すべし)
- 学習後の戦略をベーシックストラテジーと比較できる(ベンチマークがある)
- ブラックジャックうまくなりたい
開発環境
- Windows 10
- Python 3.6.9
- Anaconda 4.3.0 (64-bit)
ブラックジャックのルール
ブラックジャックはカジノの中でも人気のテーブルゲームです.
簡単にルールを紹介します.
基本ルール
- ディーラー対プレーヤーでカードを配布
- 手札の合計が21点に近い方が勝ち
- 手札の合計点が22点を超えると負け(バースト)
- ポイントの数え方
- 2~9・・・そのまま2~9点
- 10と絵札・・・10点
- A(エース)・・・1点または11点
実装するブラックジャックのルール
こんな感じのブラックジャックを作ります.
- トランプ6組を使用
- BET機能あり(ただし額は固定で$100.リターンは強化学習の報酬にします.)
- 初期の所持金は$1000
- Playerの選択肢
- スタンド(Stand)・・・カードを引かず勝負する
- ヒット(Hit)・・・もう一枚カードを引く
- ダブルダウン(Double Down)・・・BETを2倍にしてもう1枚だけカードを引く
- サレンダー(Surrender)・・・BETの半分を放棄してプレイを降りる
- 実装しないこと
- スプリット(Split)・・・配られた2枚のカードが同じ数字の場合,はじめのBETと同じ額を追加し2つに分けてプレイする
- インシュランス(Insurance)・・・ディーラーの表向きカードがAの時,BETの半分を追加して保険をかける
- ブラックジャック(BlackJack)・・・A+絵札or10の2枚で21点になること
実装
コード全体は末尾に記載します.
Cardクラス
トランプのカードを生成します.
ブラックジャックの特殊な絵札の点数の数え方はここで定義します.
Aも特殊なのですが,ここでは1点として生成します.
Aの点数はHandクラス内で他の手札の点数を考慮して決定します.
class Card:
'''
カードを生成
数字:A,2~10,J,Q,K
スート:スペード,ハート,ダイヤ,クラブ
'''
SUITS = '♠♥♦♣'
RANKS = range(1, 14) # 通常のRank
SYMBOLS = "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"
POINTS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10] # BlackJack用のポイント
def __init__(self, suit, rank):
self.suit = suit
self.rank = rank
self.index = suit + self.SYMBOLS[rank - self.RANKS[0]]
self.point = self.POINTS[rank - self.RANKS[0]]
def __repr__(self):
return self.index
Deckクラス
NUM_DECK = 6
と定義して,6組のトランプを使ったデッキを生成します.
デッキ生成と同時にシャッフルまでやってしまいます.
class Deck:
'''
カードがシャッフルされたデッキ(山札を生成)
'''
def __init__(self):
self.cards = [Card(suit, rank) \
for suit in Card.SUITS \
for rank in Card.RANKS]
if NUM_DECK > 1:
temp_cards = copy.deepcopy(self.cards)
for i in range(NUM_DECK - 1):
self.cards.extend(temp_cards)
random.shuffle(self.cards)
・・・略
Handクラス
手札へのカード追加やポイントの計算をします.
ソフトハンド(Aを含む手札)の判定も入れました.
class Hand:
"""
手札クラス
"""
def __init__(self):
self.hand = []
self.is_soft_hand = False
def add_card(self, card):
# 手札にカードを加える処理.
・・・略
def check_soft_hand(self):
# ソフトハンド(Aを含む手札)かチェックする
・・・略
def sum_point(self):
# 手札のポイントを計算.
# ソフトハンドなら,Aが1の場合と11の場合,両方計算する
・・・略
def calc_final_point(self):
# Dealerと勝負するときのポイントを計算する
# BUSTしていない最終的なポイントを返す
・・・略
def is_bust(self):
# 手札がBUST(21を超えている)かどうか判定する
・・・略
def deal(self, card):
# Deal時の処理
・・・略
def hit(self, card):
# Hit時の処理
・・・略
Playerクラス
StandやHitといった選択はここで定義します.
未実装のSplitやInsuranceも追記するならここへ.
おまけで自動プレイモードをつけました.後述の適当AIでプレイできます.
class Player:
def __init__(self):
self.hand = Hand()
self.chip = Chip()
self.done = False # Playerのターン終了を示すフラグ
self.hit_flag = False # Player が Hit を選択済みかどうか示すフラグ
self.is_human = False # True:人がプレイ,False:自動プレイ
def init_player(self):
# 手札や各フラグを初期化する
・・・略
def deal(self, card):
# Stand時の処理
・・・略
def hit(self, card):
# Hit時の処理
・・・略
def stand(self):
# Stand時の処理
・・・略
def double_down(self, card):
# Double down時の処理
・・・略
def surrender(self):
# Surrender時の処理
・・・略
Dealerクラス
Playerクラスと一緒でよかったかもしれません.
ディーラーならではのメソッドが必要かと思って作りましたが特にありませんでした.
Chipクラス
勝負の後のチップのやり取り.
勝ったら賭けた額の2倍がもらえ,負けたら全額没収.引き分けなら賭けた分がそのままPlayerに戻ります.
class Chip:
def __init__(self):
self.balance = INITIAL_CHIP
self.bet = 0
def bet_chip(self, bet):
self.balance -= bet
self.bet = bet
def pay_chip_win(self):
self.balance += self.bet * 2
def pay_chip_lose(self):
self.balance = self.balance
def pay_chip_push(self):
self.balance += self.bet
AIクラス
自動プレイ用の適当なAIが入っています.おまけ程度.
強化学習をする前のテスト用です.
class AI:
・・・略
def select_random3(self, hand, n):
if hand < 11:
selection = 'h' # hit
elif hand == 11 and n == 2:
selection = 'd' # double down
elif hand == 16 and n == 2:
selection = 'r' # surrender
elif hand > 17:
selection = 's' # stand
else:
r = random.randint(0, 1)
if r > 0.5:
selection = 'h' # hit
else:
selection = 's' # stand
return selection
Gameクラス
ブラックジャックのメイン機能です.
表示関係のメソッドが混在していて見にくいかも.改善の余地ありです.
player_step関数は,gymのstep関数でも使います.
class Game:
def __init__(self):
self.game_mode = 0 # 0:開始待ち,1:ゲーム中, 2:ゲーム終了
self.deck = Deck()
self.player = Player()
self.dealer = Dealer()
self.judgment = 0 # 1:勝ち,0:引き分け, -1:負け
self.game_count = 0
self.start()
self.message_on = True #self.player.is_human # True:コンソールにメッセージ表示する,False:コンソールにメッセージ表示しない
def start(self):
# デッキをシャッフル,Player, Dealerを初期化
・・・略
def reset_game(self):
# Player, Dealerの手札をリセット
・・・略
def bet(self, bet):
# PlayerがBETする
・・・略
def deal(self, n=2):
# Player, Dealerにカードを配る
・・・略
def player_turn(self):
# Playerのターン.行動をコンソールから入力する or 適当AIで自動決定する
・・・略
def player_step(self, action):
# Stand, Hit, Double down, Surrenderに応じた処理
・・・略
def show_card(self):
# カードを表示.Dealerの伏せられているカードは「?」表示
・・・略
def dealer_turn(self):
# Dealerのターン.ポイントが17以上になるまでカードを引く
・・・略
def open_dealer(self):
# Dealerの伏せられていたカードをオープンする
・・・略
def judge(self):
# 勝敗の判定
・・・略
def pay_chip(self):
# Chipの精算
・・・略
def check_chip(self):
# Playerの所持額がMinimum Bet(最低限賭けなければいけない額)を下回っていないかチェック
# 下回っていたらゲームを終了する
・・・略
def show_judgement(self):
# 勝敗の結果を表示
・・・略
def ask_next_game(self):
# ゲームを続けるか尋ねる
・・・略
def check_deck(self):
# カードの残り枚数をチェックし,少なければシャッフルする
・・・略
main関数
main関数にゲームの流れに沿った処理を書きます.
これを実行するとブラックジャックで遊べます.
ちなみに,
・ NUM_DECK = 6 # デッキ数
・ INITIAL_CHIP = 1000 # 初期チップ
・ MINIMUM_BET = 100 # 最低限賭けなければいけない額
としています.
def main():
game = Game()
game.start()
while game.game_mode == 1:
game.reset_game() # いろいろをリセットする
game.bet(bet=100) # 賭ける
game.deal() # カードを配る
game.player_turn() # プレイヤーのターン
game.dealer_turn() # ディーラーのターン
game.judge() # 勝敗の判定
game.pay_chip() # チップの精算
game.check_chip() # プレイヤーの残額を確認
game.ask_next_game() # ゲームを続けるか尋ねる
game.check_deck() # 残りカード枚数の確認
print("BlackJackを終了します")
print(str(game.game_count) + "回ゲームをしました")
return game.player.chip, game.game_count
実行結果
Hit(h) or Stand(s) or Double down(d) or Surrender(r):
の後に,
キーボードから文字を入力してPlayerの選択を決めます.
$100 賭けました
残りは $900
Playerのターン
Player : [♠A, ♦9] = [10, 20], soft card : True
Dealer : ♣6, ? = 6
Hit(h) or Stand(s) or Double down(d) or Surrender(r): s
Dealerのターン
Player : [♠A, ♦9] = 20
Dealer : [♣6, ♥K] = 16
Dealerのターン
Player : [♠A, ♦9] = 20
Dealer : [♣6, ♥K, ♥3] = 19
Playerの勝ち
Playerの所持チップは $1100
続けますか? y/n: y
残りカード枚数は 307
$100 賭けました
残りは $1000
Playerのターン
Player : [♠2, ♥K] = [12], soft card : False
Dealer : ♥3, ? = 3
Hit(h) or Stand(s) or Double down(d) or Surrender(r): h
Playerのターン
Player : [♠2, ♥K, ♥2] = [14], soft card : False
Dealer : ♥3, ? = 3
Hit(h) or Stand(s) or Double down(d) or Surrender(r): h
Playerのターン
Player : [♠2, ♥K, ♥2, ♠Q] = [24], soft card : False
Dealer : ♥3, ? = 3
Player BUST
Playerの負け
Playerの所持チップは $1000
続けますか? y/n: y
残りカード枚数は 301
$100 賭けました
残りは $900
Playerのターン
Player : [♥7, ♥5] = [12], soft card : False
Dealer : ♠8, ? = 8
Hit(h) or Stand(s) or Double down(d) or Surrender(r): d
Playerのターン
Player : [♥7, ♥5, ♠8] = [20], soft card : False
Dealer : ♠8, ? = 8
Double down が選択されました.掛け金を倍にしました
残りは $800
Dealerのターン
Player : [♥7, ♥5, ♠8] = 20
Dealer : [♠8, ♥2] = 10
Dealerのターン
Player : [♥7, ♥5, ♠8] = 20
Dealer : [♠8, ♥2, ♣7] = 17
Playerの勝ち
Playerの所持チップは $1200
続けますか? y/n: n
残りカード枚数は 295
BlackJackを終了します
3回ゲームをしました
コード
記録用に置いておきます.
以下コード(クリックで展開)
import random
import copy
# 定数
NUM_DECK = 6 # デッキ数
NUM_PLAYER = 1 # プレイヤー数
INITIAL_CHIP = 1000 # 初期チップ
MINIMUM_BET = 100
class Card:
'''
カードを生成
数字:A,2~10,J,Q,K
スート:スペード,ハート,ダイヤ,クラブ
'''
SUITS = '♠♥♦♣'
RANKS = range(1, 14) # 通常のRank
SYMBOLS = "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"
POINTS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10] # BlackJack用のポイント
def __init__(self, suit, rank):
self.suit = suit
self.rank = rank
self.index = suit + self.SYMBOLS[rank - self.RANKS[0]]
self.point = self.POINTS[rank - self.RANKS[0]]
def __repr__(self):
return self.index
class Deck:
'''
カードがシャッフルされたデッキ(山札を生成)
'''
def __init__(self):
self.cards = [Card(suit, rank) \
for suit in Card.SUITS \
for rank in Card.RANKS]
if NUM_DECK > 1:
temp_cards = copy.deepcopy(self.cards)
for i in range(NUM_DECK - 1):
self.cards.extend(temp_cards)
random.shuffle(self.cards)
def draw(self, n=1):
'''
デッキから指定した枚数分だけ引く関数
'''
cards = self.cards[:n]
del self.cards[:n] # 引いたカードを山札から削除
return cards
def shuffle(self):
'''
デッキをシャッフルする
'''
random.shuffle(self.cards)
return
def count_cards(self):
"""
デッキの残り枚数を返す
"""
count = len(self.cards)
return count
class Hand:
"""
手札クラス
"""
def __init__(self):
self.hand = []
self.is_soft_hand = False
def add_card(self, card):
self.hand.append(card)
def check_soft_hand(self):
"""
ソフトハンド(Aを含むハンド)かチェックする
"""
hand_list = []
for i in range(len(self.hand)):
hand_list.append(self.hand[i].point)
hand_list.sort() # 手札を昇順にソート
if hand_list[0] == 1 and sum(hand_list[1:]) < 11: # ソフトハンドなら
self.is_soft_hand = True
else:
self.is_soft_hand = False
def sum_point(self):
"""
ポイントの合計値を返す
"""
self.check_soft_hand()
hand_list = []
for i in range(len(self.hand)):
hand_list.append(self.hand[i].point)
hand_list.sort() # 手札を昇順にソート
s1 = 0 # Aを1とカウントする場合の初期値
for i in range(len(self.hand)):
s1 += self.hand[i].point
if self.is_soft_hand == True: # ソフトハンドなら
s2 = 11 # 1枚目のAを11としてカウント
for i in range(len(hand_list)-1):
s2 += hand_list[i+1]
s = [s1, s2]
else:
s = [s1]
return s
def calc_final_point(self):
"""
BUSTしていない最終的なポイントを返す
"""
temp_point = self.sum_point()
if max(temp_point) > 22:
p = temp_point[0] # ポイントの大きい方がBUSTなら小さい方
else:
p = max(temp_point)
return p
def is_bust(self):
"""
BUSTかどうか判定する
"""
if min(self.sum_point()) > 21: # ポイントの小さい方が21を超えていたら
return True
else:
return False
def deal(self, card):
"""
Dealされたカードを手札に加える
"""
for i in range(len(card)):
self.add_card(card[i])
def hit(self, card):
# 1枚ずつHitする
if len(card) == 1:
self.add_card(card[0])
else:
print("カードの枚数が正しくありません")
class Player:
def __init__(self):
self.hand = Hand()
self.chip = Chip()
self.done = False # Playerのターン終了を示すフラグ
self.hit_flag = False # Player が Hit を選択済みかどうか示すフラグ
self.is_human = True # True:人がプレイ,False:自動プレイ
def init_player(self):
self.hand = Hand()
self.done = False
self.hit_flag = False
def deal(self, card):
self.hand.deal(card)
def hit(self, card):
# カードを1枚手札に加える
self.hand.hit(card)
self.hit_flag = True
def stand(self):
# ターン終了
self.done = True
def double_down(self, card):
# betを2倍にして一度だけHitしてターン終了
self.chip.balance -= self.chip.bet
self.chip.bet = self.chip.bet * 2
self.hand.hit(card)
self.done = True # double down後は一度しかhitできないルールとする
def surrender(self):
# Betを半分にして(betの半分を手持ちに戻して)ターン終了
# self.chip.balance += int(self.chip.bet / 2)
self.chip.bet = int(self.chip.bet / 2)
self.chip.balance += self.chip.bet
self.done = True
def insurance(self):
# 未実装
pass
def split(self):
# 未実装
pass
class Dealer:
def __init__(self):
self.hand = Hand()
def init_dealer(self):
self.hand = Hand()
def deal(self, card):
self.hand.deal(card)
def hit(self, card):
self.hand.hit(card)
class Chip:
def __init__(self):
self.balance = INITIAL_CHIP
self.bet = 0
def bet_chip(self, bet):
# Chipを掛けたら手持ちから減らす
self.balance -= bet
self.bet = bet
def pay_chip_win(self):
# 勝った時,BETの2倍を得る
self.balance += self.bet * 2
def pay_chip_lose(self):
# 負けた時,BETを全額失う
self.balance = self.balance
def pay_chip_push(self):
# 引き分けのとき,BETした分だけ戻る
self.balance += self.bet
class AI:
def select_random1(self):
r = random.randint(0, 1)
if r > 0.5:
selection = 'h' # hit
else:
selection = 's' # stand
return selection
def select_random2(self, hand):
if hand <= 11:
selection = 'h'
else:
r = random.randint(0, 1)
if r > 0.5:
selection = 'h' # hit
else:
selection = 's' # stand
return selection
def select_random3(self, hand, n):
if hand < 11:
selection = 'h' # hit
elif hand == 11 and n == 2:
selection = 'd' # double down
elif hand == 16 and n == 2:
selection = 'r' # surrender
elif hand > 17:
selection = 's' # stand
else:
r = random.randint(0, 1)
if r > 0.5:
selection = 'h' # hit
else:
selection = 's' # stand
return selection
class Game:
def __init__(self):
self.game_mode = 0 # 0:開始待ち,1:ゲーム中, 2:ゲーム終了
self.deck = Deck()
self.player = Player()
self.dealer = Dealer()
self.judgment = 0
self.game_count = 0
self.start()
self.message_on = True #self.player.is_human # True:コンソールにメッセージ表示する,False:コンソールにメッセージ表示しない
def start(self):
self.deck.shuffle()
self.game_mode = 1
self.player = Player()
self.dealer = Dealer()
self.game_count = 0
def reset_game(self):
self.player.init_player()
self.dealer.init_dealer()
self.game_count += 1
def bet(self, bet):
self.player.chip.bet_chip(bet=bet)
if self.message_on:
print("$" + str(self.player.chip.bet) + " 賭けました")
print("残りは $" + str(self.player.chip.balance))
# カードを配る
def deal(self, n=2):
'''
カードを配る
'''
card = self.deck.draw(n)
self.player.deal(card)
# print(self.player.hand.hand)
card = self.deck.draw(n)
self.dealer.deal(card)
# print(self.dealer.hand.hand)
self.judgment = 0 # 勝敗の判定
self.player.done = False
self.show_card()
# Playerのターン
def player_turn(self):
'''
プレーヤーのターン
'''
if self.player.hand.calc_final_point() == 21: # 合計が21だったらすぐにDealerのターンへ
self.player.done = True
while not self.player.done and not self.player.hand.is_bust():
if self.player.is_human is True:
action = input("Hit(h) or Stand(s) or Double down(d) or Surrender(r): ")
elif self.player.is_human is True and self.player.hit_flag:
action = input("Hit(h) or Stand(s): ") # Hitの後はhit/standのみ
else:
action = AI().select_random3(hand=self.player.hand.calc_final_point(), n=len(self.player.hand.hand))
self.player_step(action=action)
def player_step(self, action):
if action == 'h': # Hit
card = self.deck.draw(1)
self.player.hit(card)
self.show_card()
if self.player.hand.calc_final_point() == 21: # 合計点が21になったらこれ以上Hitはできない
self.player.done = True
if self.player.hand.is_bust():
self.player.done = True
self.judgment = -1 # PlayerがBUSTしたら即負け
if self.message_on:
print("Player BUST")
elif action == 's': # Stand
self.player.stand()
elif action == 'd' and self.player.hit_flag is False: # Double down. Hit選択していない場合に可
card = self.deck.draw(1)
if self.player.chip.balance >= self.player.chip.bet: # 残額が賭けた額以上にあればDouble Down可
self.player.double_down(card)
self.show_card()
if self.message_on:
print("Double down が選択されました.掛け金を倍にしました")
print("残りは $" + str(self.player.chip.balance))
if self.player.hand.is_bust():
self.player.done = True
self.judgment = -1 # PlayerがBUSTしたら即負け
if self.message_on:
print("Player BUST")
else: # 残額が賭けた額未満ならばHitとする
print("チップが足りないためHitします")
self.player.hit(card)
self.show_card()
if self.player.hand.calc_final_point() == 21: # 合計点が21になったらこれ以上Hitはできない
self.player.done = True
if self.player.hand.is_bust():
self.player.done = True
self.judgment = -1 # PlayerがBUSTしたら即負け
if self.message_on:
print("Player BUST")
elif action == 'r' and self.player.hit_flag is False: # Surrender. Hit選択していない場合に可
self.player.surrender()
self.judgment = -1 # Surrenderを選択したので負け
if self.message_on:
print("Surrender が選択されました")
else:
if self.message_on:
print("正しい選択肢を選んでください")
def show_card(self):
'''
プレーヤーのカードを表示
'''
if self.message_on:
print("Playerのターン")
print("Player : " + str(self.player.hand.hand) + " = " +
str(self.player.hand.sum_point()) + ", soft card : " + str(self.player.hand.is_soft_hand))
print("Dealer : " + str(self.dealer.hand.hand[0].index) +
", ? = " + str(self.dealer.hand.hand[0].point))
else:
pass
def dealer_turn(self):
'''
ディーラーのターン
'''
if self.judgment == -1:
return
self.open_dealer()
while self.dealer.hand.calc_final_point() < 17 and self.judgment == 0:
card = self.deck.draw(1)
self.dealer.hit(card)
self.open_dealer()
if self.dealer.hand.calc_final_point() > 21:
self.judgment = 1
if self.message_on:
print("Dealer BUST")
def open_dealer(self):
'''
hole cardをオープンする
'''
if self.message_on:
print("Dealerのターン")
print("Player : " + str(self.player.hand.hand) + " = " +
str(self.player.hand.calc_final_point()))
print("Dealer : " + str(self.dealer.hand.hand) + " = " +
str(self.dealer.hand.calc_final_point()))
else:
pass
def judge(self):
'''
勝敗の判定
'''
if self.judgment == 0 and self.player.hand.calc_final_point() > \
self.dealer.hand.calc_final_point():
self.judgment = 1
elif self.judgment == 0 and self.player.hand.calc_final_point() < \
self.dealer.hand.calc_final_point():
self.judgment = -1
elif self.judgment == 0 and self.player.hand.calc_final_point() == \
self.dealer.hand.calc_final_point():
self.judgment = 0
if self.message_on:
self.show_judgement()
def pay_chip(self):
previous_chip = self.player.chip.balance
if self.judgment == 1: # Player win
self.player.chip.pay_chip_win()
elif self.judgment == -1: # Player lose
self.player.chip.pay_chip_lose()
elif self.judgment == 0: # Push
self.player.chip.pay_chip_push()
if self.message_on:
print("Playerの所持チップは $" + str(self.player.chip.balance))
reward = self.player.chip.balance - previous_chip # このゲームで得た報酬
return reward
def check_chip(self):
if self.player.chip.balance < MINIMUM_BET:
self.game_mode = 2
if self.message_on:
print("チップがMinimum Betを下回ったのでゲームを終了します")
def show_judgement(self):
'''
勝敗の表示
'''
if self.message_on:
print("")
if self.judgment == 1:
print("Playerの勝ち")
elif self.judgment == -1:
print("Playerの負け")
elif self.judgment == 0:
print("引き分け")
print("")
else:
pass
def ask_next_game(self):
'''
ゲームを続けるか尋ねる
'''
if self.player.is_human == True:
while self.game_mode == 1:
player_input = input("続けますか? y/n: ")
if player_input == 'y':
break
elif player_input == 'n':
self.game_mode = 2
break
else:
print('y/nを入力してください')
else:
pass # 自動プレイなら継続する
print('残りカード枚数は ' + str(self.deck.count_cards()))
print("")
def check_deck(self):
'''
カードの残り枚数をチェックし,少なければシャッフルする
'''
if self.deck.count_cards() < NUM_PLAYER * 10 + 5:
self.deck = Deck()
if self.message_on:
print("デッキを初期化しました")
print('残りカード枚数は ' + str(self.deck.count_cards()))
print("")
def main():
game = Game()
game.start()
while game.game_mode == 1:
game.reset_game() # いろいろをリセットする
game.bet(bet=100) # 賭ける
game.deal() # カードを配る
game.player_turn() # プレイヤーのターン
game.dealer_turn() # ディーラーのターン
game.judge() # 勝敗の判定
game.pay_chip() # チップの精算
game.check_chip() # プレイヤーの残額を確認
game.ask_next_game() # ゲームを続けるか尋ねる
game.check_deck() # 残りカード枚数の確認
print("BlackJackを終了します")
print(str(game.game_count) + "回ゲームをしました")
return game.player.chip, game.game_count
if __name__ == '__main__':
main()
終わりに
Pythonでブラックジャックを作ってみました.
ベーシックストラテジーになるべく近づけるため,Double downとSurrenderの実装にも挑戦してみました.
Splitもいつか入れたいです.
学習することを想定してBET機能を入れましたが,所持金がゼロなのにDouble downしてしまうなど,
バグが多々発見され,修正が大変でした.(まだバグがあったらご指摘ください)
次は今回作ったブラックジャックを自作の環境として, OpenAI のgymに登録します.
ブラックジャックの戦略を強化学習で作ってみる(②gymに環境を登録)