目次
1.ハイ&ロー(Hi-Lo)とは何か
2.使用したライブラリと手法
3.今回の特殊な条件
4.Q学習のプログラム
5.今後の展望
※ミスなどがありましたら報告願います
1. ハイ&ロー(Hi-Lo)とは何か
ハイ&ローは、トランプを用いるカードゲームで、名前の通り、高い(high)か低い(low)かを当てる単純なゲームです。
単純なだけに細かい所で色々ルールが派生したり違ったりすることもあります。
最近では、オンラインカジノサイトなどで有名なため、知っている方も多いと思います。
今回は、オンラインカジノでのハイ&ローのルールを採用していきます。
手順
1.jokerを除いた52枚のトランプをよくシャッフルし、山札を裏向きにしておく
2.ディーラーが山札の一番上を表にして前に置く
3.プレイヤーは次に山札から出るカードが今開示されているカードより高い(high)か低い(low)かを予想する
(カードの大きさは、小さい順に2,3,4,5,6,7,8,9,10,J,Q,K,A)
4.ディーラーは伏せられていたカードを開示する
5.(1)予想が正しかった場合は、オッズ表(リンクにあるものをそのまま使っています)に基づきディーラーがプレイヤーに報酬を支払う
(2)予想が外れた場合は、ディーラーがプレイヤーの賭け金額を没収
6.先ほど開示されたカードをもとに次のカードの予想を行う
7.52枚のカードがなくなるまで1→6を繰り返す
<注>カジノサイトによってはカードを3枚出して戻すというところもあります。
※手順をお借りしたサイト
https://www.casino-winnersclub.com/high-low.php#haiandorono_liure (このサイトのオッズ表です)
https://edgegram.hatenablog.jp/entry/2018/09/05/172349
使用したライブラリ
使用した言語はpythonです。環境にJupyter Notebookを使用しました。
- python 3
次にライブラリを紹介しましょう。
- numpy as np
- pandas as pd
pandasはデータをまとめるために使用しました。別にimportしなくても構いません
使用した手法
AIとは言ってもいくつかの手法のもとに成り立っています。
今回は、正解のデータがあるわけでもなく、明確な目的は所持金額を増やすことだけなので強化学習を使用。
強化学習の基本とされている「Q学習」を使用しました。もちろんε-greedy法はありです。
今回の特殊な条件
・今回はわかりやすいようにカードの大きい順を変えます。
本来:(2,3,4,5,6,7,8,9,10,J,Q,K,A)
今回:(A,2,3,4,5,6,7,8,9,10,J,Q,K)
・数字が同じだった場合について"Same"という選択肢のあるものや、"High"に含めるもの、"Low"に含めるものがありますが、今回"Same"は"High"に含めるものを採用します。
・スート(マーク)による大小(例:♠>❤など)はなしです。
・バーストはなしです
・賭けられる金額は1です。(読者の皆さんが変えて遊んでみてください)
Q学習のプログラム
Qテーブルの定義
num_actions = 2
num_total_values = 13
num_remaining_cards = 52
q_table_shape = (num_actions, num_total_values, num_remaining_cards)
q_table = np.ones(q_table_shape)
残りのカードの枚数が学習に大事なので三次元によるQ学習になっています。
オッズ表を定義
odds_dict = {
1: (1.00, 13.4),
2: (1.04, 6.30),
3: (1.10, 4.20),
4: (1.30, 3.30),
5: (1.45, 2.70),
6: (2.10, 1.50),
7: (1.80, 1.80),
8: (1.50, 2.10),
9: (2.70, 1.45),
10: (3.30, 1.30),
11: (4.20, 1.10),
12: (6.30, 1.04),
13: (13.4, 1.00)
}
ゲームをプレイする関数
def play_game(initial_bet, epsilon):
global bet
global total
global remaining_cards
deck = list(range(1, 14)) * 4 # AからKまでのジョーカー抜きのデッキ
np.random.shuffle(deck)
# カードの初期状態
total = deck.pop() # 初めに開示されるカード
action = 1 # 初期アクション
reward = 0 # 報酬の初期化
while deck:
# カードを引く前に状態を取得
state = (action, total-1, len(deck))
# ε-greedy法に基づいて次のアクションを決定
if np.random.rand() < epsilon:
next_action = np.random.randint(2) # ランダムに行動を選択
else:
next_action = 1 if q_table[1, total-1, len(deck)] > q_table[0, total-1, len(deck)] else 0 # Q値が最大となる行動を選択
# カードを引く
next_card = deck.pop()
# 次の状態の取得
next_state = (next_action, next_card-1, len(deck))
# プレイヤーの予測に基づいて勝敗判定
next_card_value = q_table[:, total-1, len(deck)]
max_next_card_value = next_card_value[next_action]
if (action == 1 and next_card >= total):
reward = initial_bet * odds_dict[total][0]
elif (action == 0 and next_card < total):
reward = initial_bet * odds_dict[total][1]
else:
reward = -initial_bet
# Q値の更新
q_table[state] = (1 - alpha) * q_table[state] + alpha * (reward + gamma * max_next_card_value)
# カードを更新
total = next_card
action = next_action
return reward
学習率、回数、εの値
epochs = 100000
bet = 1
epsilon = 0.1
alpha = 0.1
gamma = 0.9
alphaとgammaを書き忘れてました。すみません(2024/05/17)
モデルの作成
print(q_table)
for _ in range(epochs):
reward = play_game(bet, epsilon)
if _ % 100 == 0:
print(q_table)
print(q_table)
今後の展望
今度は、安全手をなるべく多くとれるように、もう一つの有名なものであるSARSAを行いたいと思います。また、賭け金を予測に基づいて変動させるAIを作ることもよいかと思います。