#はじめに
はじめまして!将棋は二段、pythonは初心者の@cucumberと申します!
今回は自分への備忘録も兼ねて、ゴロゴロ将棋の局面を自動生成する方法についてまとめました。
#動作環境
本記事における動作環境はこちらです
- windows 10
- python 3.5.4
#概要
ゴロゴロ将棋の16枚の駒をランダムに配置するプログラムを作成しました。最終的にはDeep Learningにより学習させたプログラムを作成することを目標にし、それに適した形式で入力しました。より最適な記述方法があると思われますが、ご容赦いただけると幸いです(-_-;)
#本題
##ゴロゴロ将棋とは
ゴロゴロ将棋とは本将棋より小さい5×6マスの盤面で行われる将棋です。図のように双方8枚の駒を初期位置に配置して始める将棋です。本将棋と異なる点は各駒が成ることのできる陣地が3段目ではなく2段目になっているという点です。取った駒を使用できるなど、その他のルールは本将棋と同様です。
##局面の符号化
後々、この局面をニューラルネットワークに入れる可能性を考慮し、局面を駒の種類と手番ごとフィルタを区別し5×6×8の盤面×8枚のフィルタといった形式に二値化し符号化し入力します。
どういうことかというと、ゴロゴロ将棋の場合は駒が(玉・金・銀・歩)×(先手・後手)で8種類あります。それぞれを区別し、別々に表示してい区ということです。(今回は成り駒については考慮していません)例えば、先手の玉が存在するかどうかを5×6の盤面に対して01のに2bitで表すといった形です。言葉では伝わりづらいので初期局面の場合の入力次の図に示します。
※左から二枚目の画像説明は正しくは「先手の金についての入力」でした。
##局面を生成する
さて次は先程説明した局面になるようにPythonでコーディングしていきます。今回は先手後手の駒の枚数は初期と同様、持ち駒を考慮しないという条件でランダムに生成します。
import numpy as np
import numpy.random as nprand
# data生成,各要素を0で初期化
data = np.zeros((8, 6, 5))
# 駒の総数
piece_num = 16
# それぞれの駒のデータを何枚目のフィルタに格納するか
position_piece = [0, 4, 1, 1, 5, 5, 2, 2, 6, 6, 3, 3, 3, 7, 7, 7]
# 重複なしで0-29の乱数を生成しpositionに格納
position_list = range(30)
position = nprand.choice(position_list, 16, replace=False)
# 各駒の存在位置に対応する要素を0→1にする
for piece in range(piece_num):
data[position_piece[piece], int(position[piece] / 5), position[piece] % 5] = 1
print(data)
実行した結果は次のようになります。
[[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 1. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 1. 1. 0.]]
[[0. 0. 0. 0. 0.]
[0. 0. 1. 0. 0.]
[0. 1. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
[[0. 1. 0. 0. 0.]
[1. 0. 0. 0. 0.]
[0. 0. 0. 1. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
[[0. 0. 0. 0. 1.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
[[0. 0. 0. 1. 0.]
[0. 0. 0. 0. 1.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 1.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 1. 0.]
[0. 0. 0. 0. 0.]]
[[0. 0. 1. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[1. 1. 0. 0. 0.]]]
##局面を表示する
ここまででランダム生成した局面を5×6×8のデータに格納することができました。しかし、これだけでは我々人間が見たときになんのことか理解できません。よって次はこのデータを使用して、局面を表示します。
今は5×6×8の状態ですが、これを5×6の1枚のフィルタにまとめます。そのためには各フィルタ毎にインデックスをつけて、各フィルタでの1を表示している要素をインデックスの数字に変更します。
フィルタ名 | インデックス |
---|---|
先手・玉 | 1 |
先手・金 | 2 |
先手・銀 | 3 |
先手・歩 | 4 |
後手・玉 | 5 |
後手・金 | 6 |
後手・銀 | 7 |
後手・歩 | 8 |
最後に各インデックスに対応する文字を整形して表示させればOKです。
pythonでコーディングすると次のようになりました。
mydict_jp = {0:" ", 1:" 王", 2:" 金", 3:" 銀", 4:" 歩", 5:"v玉", 6:"v金", 7:"v銀", 8:"v歩"}
def view(data):
# 5×6のint型の一枚のフィルタ
position_view = np.zeros((6,5),dtype=int)
# 1枚のフィルタにまとめる
for i in range(8):
position_view = position_view + data[i]*(i+1)
print(position_view)
# 表示
for i in range(position_view.shape[0]):
print("|", end="")
for j in range(position_view.shape[1]):
if (position_view[i][j] in mydict_jp) == False:
print(" x |", end="")
else:
print(mydict_jp[position_view[i][j]]+"|", end="")
print()
view(data)
先ほど生成したデータを引数にとり実行すると次のように表示されます。
[[0. 4. 8. 6. 5.]
[4. 0. 3. 0. 6.]
[0. 3. 0. 4. 7.]
[0. 0. 0. 0. 0.]
[0. 1. 0. 7. 0.]
[8. 8. 2. 2. 0.]]
| | 歩|v歩|v金|v玉|
| 歩| | 銀| |v金|
| | 銀| | 歩|v銀|
| | | | | |
| | 王| |v銀| |
|v歩|v歩| 金| 金| |
駒の前にvがついている物が後手側の駒を表しています。
#最後に
今回はゴロゴロ将棋の局面をランダムで生成させてみました。
最下段に自身の歩がいる等、ルール上不可能な手が生成されてしまう点や成り駒について考慮していません。
今後はより厳密にルールに基づいた盤面の生成を行う予定です!