プログラム完成
前回強化学習のQ学習を確認したが、これをPythonを使い三目並べに実装した。このプログラムを紹介する。
三目並べ
まずは三目並べのエンジン部分だ。ちなみにPythonに不慣れなためPythonらしい記述にはなっていないところは割り引いて見て欲しい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
import numpy as np import Const import itertools """棋盤クラス """ class Kiban: houkou = [ #勝利判定用方向データー 4方向×2方向 [ [-1,-1],[1,1] ], [ [-1,0],[1,0] ], [ [-1,1],[1,-1] ], [ [0,-1],[0,1] ] ] def __init__(self,masume): self.kiban = np.zeros((masume, masume),dtype=int) def setKiban(self,x, y,state): #手を打つ self.kiban[x][y] = state def checkFinal(self,x,y): #勝利判定 x,y:打った座標 kigou = self.kiban[x][y] """打った箇所から八方に探索し同じマークがいくつ並んでいるか確認 """ for key1,value1 in enumerate(self.houkou): #4方向 count = 1 for key2,value2 in enumerate(self.houkou[key1]): #2方向 x2 = x y2 = y while True: #棋盤を超える、違うマーク、誰も打っていない、までループ x2 = x2 + self.houkou[key1][key2][0] #打った座標から方向データ値分加算する y2 = y2 + self.houkou[key1][key2][1] if x2 < 0 or x2 >= Const.BANSU: #盤超えている? break if y2 < 0 or y2 >= Const.BANSU: #盤超えている? break if self.kiban[x2][y2] == Const.KUHAKU: #誰も打っていない? break if self.kiban[x2][y2] != kigou: #違うマーク? break count += 1 #同じマークがあったのでカウントアップ if count >= Const.NARABE: #同じマークの数により勝利判定 return kigou return Const.KUHAKU def disp(self): #棋盤表示 print("----------------------------") for key1,value1 in enumerate(self.kiban): str = "|" for key2,value2 in enumerate(value1): str += Const.KIGOU[value2] + "|" print(str) def serchBlank(self): #打てる場所を探す ret = [] for key1,value1 in enumerate(self.kiban): for key2,value2 in enumerate(value1): if value2 == Const.KUHAKU: ret.append([key1,key2]) return ret def kibanToString(self): #棋盤情報を辞書用のキーに変更 ret = "" for key1,value1 in enumerate(self.kiban): for key2,value2 in enumerate(value1): ret += str(value2) return ret def checkKiban(self,x,y): #手が打てるかチェック if self.kiban[x][y] != Const.KUHAKU: return False return True def clear(self,masume): #棋盤クリア self.kiban = np.zeros((masume, masume),dtype=int) |
マス目を3×3の二次元配列としたがプログラミングを進めるにつれ二次元配列より一次元配列の方がよかった?と疑問に思うようになた。なぜならPythonは一次元配列のハンドリングが非常に柔軟にできることがわかってきたからだ。他の言語なら二次元配列の方が楽にできるが、Pythonの場合は検討が必要なようだ。
18 |
self.kiban = np.zeros((masume, masume),dtype=int) |
配列作成時に配列の数を引数により決定している。これは四目、五目並べと機能拡張を考慮してのことだ。
エンジン部分で重要な機能は勝利判定だ。三目並べのようにマス目が少ないなら、力業でロジックが組める(JavaScriptのお勉強)。しかし今回は四目、五目並べ対応を行った。
入力された座標を起点として二方向×四方向に同じマークが何個存在しているか確認している。この走査方向を下記のようにデーター化している。
10 11 12 13 14 15 |
houkou = [ #勝利判定用方向データー 4方向×2方向 [ [-1,-1],[1,1] ], [ [-1,0],[1,0] ], [ [-1,1],[1,-1] ], [ [0,-1],[0,1] ] ] |
23行~51行目の関数checkFinal()がロジックだ。この辺もPythonらしいロジックなら、もっとスッキリしていたかもしれない。
三目並べの他機能として、手を打つsetKiban()、打てる場所を探すserchBlank()、手が打てるかのチェックcheckKiban()、棋盤を表示するdisplay()、棋盤をクリアするclear()関数を実装した。
このエンジン機能が出来上がれば、人対人の対戦なら容易に構築できるだろう。
Qテーブルのキー作成
エンジンにはQ学習用の関数も実装されている。それが、関数kibanToString()だ。この関数は棋盤情報を文字列することにより、Qテーブルのキーとしているのだ。
Pythonは間口広く、奥が深ーい
Pythonに慣れるにつれ初期に記述したこのクラスに不満を持つようになった。「もっとPythonらしく書けないか?」。一部機能を覚えたてのリスト処理を使い、書き直したのだが…実行速度が遅くなってしまった。Q学習で大量処理を行うので速度は注視しなければいけない。
恐らくPythonに慣れた人は実行速度を落とすことなく、Pythonらしいく書き換えることができるのだろう。Pythonは記述しやすく、奥の深ーい言語だと悟った。