タンヤオか七対子どっちの戦略をとれば良いかニューラルネットワークで判断させる

# ※この記事は2020年に作成しました
#概要
大量の手牌と捨牌のデータがあれば、それが七対子を狙っているのか、タンヤオを狙っているのかは判断できるが、手牌1つだけを与えられたときは難しい。
しかし、手牌1つだけでも打牌を考えると最大で14パターンにすることができる。
打牌は必ず手牌からしか選ばないので、手牌+打牌で最大で14パターンに分けられる。最大14というのは、重なってる牌がある場合は14から減っていくからだ。

森本の作成したタンヤオだけを狙っていくエージェントと、七対子だけを狙っていくエージェントから手牌と捨牌のデータを取り、手牌と捨牌を入力、狙っている役を正解ラベルとしてニューラルネットワークで学習させる。

学習させたモデルを使えば、手牌と捨牌の組1つだけでタンヤオを狙っている確率と七対子を狙っている確率を出すことができる。
これで1つの手牌を最大で14パターンに分けてそれぞれの確率の合計を出すことにより、タンヤオか七対子のどっちを狙っているかわかる。

#結果・考察
ニューラルネットワークのデータ数はタンヤオと七対子、両方とも1万9000個ずつである。
ニューラルネットワークの結果は約98%と思っていたよりもかなり高かった。
この理由は、タンヤオは么九牌から切っていくが、七対子は3枚以上ある牌や2枚以外の牌では前から切っていくようになっているので、そこで違いが生まれたからだと思う。

タンヤオと七対子のそれぞれの手牌を使ってどっちの確率が高くなるかいくつか調べた結果、タンヤオを打牌してる途中の手牌ではタンヤオの確率が高くなり、七対子を打牌してる途中の手牌では七対子の確率が高くなった。
役とデータ数をもっと増やせば、1つの手牌だけでどの戦略を取っているのかがわかるようになる。

#作成したプログラム1
ニューラルネットワークで学習させるプログラム。

```python
# coding: UTF-8
import csv
import numpy as np
from keras.utils import to_categorical
from keras.models import Sequential,Model
from keras.layers import Dense,Conv2D,MaxPooling2D,Dropout,Flatten,Activation,BatchNormalization
from keras.optimizers import Adam
from keras.layers import Dense,Input
from keras.callbacks import TensorBoard
from keras import optimizers,regularizers

#前処理　ここから
data = 19000
col = 34
x_train34_tan = np.zeros((data,col), dtype='float32')
with open("C:/sqlite/tanyao_tehai.csv", 'r') as fr:
    for i,row in enumerate(fr.readlines(),start=0):
        if i >= data:
            break
        x_train34_tan[i] += np.array(list(map(np.float,row[:col])))

y_train_tan = np.loadtxt("C:/sqlite/tanyao_dahai.csv",delimiter=",")
y_train_tan = np.delete(y_train_tan,slice(data,None),0)

x_train34_chi = np.zeros((data,col), dtype='float32')
with open("C:/sqlite/Chitoi_tehai.csv", 'r') as fr:
    for i,row in enumerate(fr.readlines(),start=0):
        if i >= data:
            break
        x_train34_chi[i] += np.array(list(map(np.float,row[:col])))

y_train_chi = np.loadtxt("C:/sqlite/Chitoi_dahai.csv",delimiter=",")
y_train_chi = np.delete(y_train_chi,slice(data,None),0)


x_train = np.ndarray((data*2,204))
for i in range(data):
    hai = int(y_train_tan[i])
    x_train[i,(hai*6)+5] +=1
    for j in range(34):
        if x_train34_tan[i,j] == 0:
            x_train[i,j*6] += 1
        elif x_train34_tan[i,j] == 1:
            x_train[i,(j*6)+1] += 1
        elif x_train34_tan[i,j] == 2:
            x_train[i,(j*6)+2] += 1
        elif x_train34_tan[i,j] == 3:
            x_train[i,(j*6)+3] += 1
        elif x_train34_tan[i,j] == 4:
            x_train[i,(j*6)+4] += 1

for i in range(data):
    hai = int(y_train_chi[i])
    x_train[(i+data),(hai*6)+5] +=1
    for j in range(34):
        if x_train34_chi[i,j] == 0:
            x_train[(i+data),j*6] += 1
        elif x_train34_chi[i,j] == 1:
            x_train[(i+data),(j*6)+1] += 1
        elif x_train34_chi[i,j] == 2:
            x_train[(i+data),(j*6)+2] += 1
        elif x_train34_chi[i,j] == 3:
            x_train[(i+data),(j*6)+3] += 1
        elif x_train34_chi[i,j] == 4:
            x_train[(i+data),(j*6)+4] += 1

y_train  = np.zeros((data*2,1))
for i in range(data):
    y_train[i+data] +=1
#y_train = to_categorical(y_train,2)
#print('x_train.shape:',x_train.shape)
#print('y_train.shape:',ｙ_train.shape)

train = np.hstack((x_train,y_train))
np.random.shuffle(train)

lavel = np.zeros((data*2))
for i in range(data*2):
    if train[i,204] == 1:
        lavel[i] += 1

train = np.delete(train,204, 1)
lavel= to_categorical(lavel,2)

#前処理ここまで
model = Sequential()

input_data = Input(shape=(204,))#入力層
hidden_layer = Dense(100, activation='relu')(input_data)#中間層
output_layer = Dense(2, activation='softmax',kernel_regularizer=regularizers.l2(1e-4))(hidden_layer)#出力層
#Hidden_output = Model(input = input_data , output = hidden_layer) #中間出力用
model = Model(input = input_data , output = output_layer)#入力から出力

#最適化アルゴリズムAdam、損失関数
model.compile(
    optimizer=Adam(lr=0.01),
    loss='categorical_crossentropy',
    metrics=['accuracy'],
)
#http://localhost:6006/
#tensorboard --logdir=./logs
#tsb = TensorBoard(log_dir='./logs')
history_adam=model.fit(
    train,
    lavel,
    batch_size=256,
    epochs=50,
    verbose=1,
    shuffle = True,
    validation_split=0.2,
    #callbacks=[tsb]
)

model.save('tan_chi.h5')#, include_optimizer=False)
```

#作成したプログラム2
1つの手牌からどっちの確率が高いか調べるプログラム。

```python
# coding: UTF-8
import numpy as np
from keras.models import load_model
import copy

label = [0,1]
model = load_model('tan_chi.h5')

data = 10000
col =34
x_train34_tan = np.zeros((data,col), dtype='float32')
with open("C:/sqlite/Chitoi_tehai.csv", 'r') as fr:
    for i,row in enumerate(fr.readlines(),start=0):
        if i >= data:
            break
        x_train34_tan[i] += np.array(list(map(np.float,row[:col])))

x_train = np.zeros((1,204))
tehai = copy.deepcopy(x_train34_tan[1000,])#ここを変えたら手牌を変えられる
for i in range(34):
    if tehai[i] == 0:
        x_train[0,i*6] += 1
    elif tehai[i] == 1:
        x_train[0,(i*6)+1] += 1
    elif tehai[i] == 2:
        x_train[0,(i*6)+2] += 1
    elif tehai[i] == 3:
        x_train[0,(i*6)+3] += 1
    elif tehai[i] == 4:
        x_train[0,(i*6)+4] += 1

tan = 0
chi = 0
for i in range(34):
    if tehai[i]>=1:
        sutehai = i
        x_train[0,(sutehai*6)+5] +=1
        pred = model.predict(x_train, batch_size=1, verbose=1)
        tan += pred[0,0]
        chi += pred[0,1]
        x_train[0,(sutehai*6)+5] -=1

print('タンヤオ:%f , 七対子:%f'%(tan,chi))
```