easyAI入門

easyAI入門

1 概要

  • Negamax(αβ法の一種 αβ法はMINMAX法(全手検索)と同じ結果を少ない探索で可能なアルゴリズム)のフレームワーク
  • Pythonベース
  • MITライセンス

2 リンク

3 easyAIのインストール

3.1 以下の操作を行っている動画


3.2 easyAIのインストール 手順

3.2.1 イメージ起動

docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 mytensorflow

3.2.2 シェル起動

  • New から terminalを選択して、ターミナル起動

3.2.3 シェルで以下のコマンドを実行

sudo su - user
cd /tf/notebooks/

3.2.4 easyAIのインストール

sudo pip3 install easyAI

3.2.5 easyAIのgithubのダウンロード

mkdir easyAI
cd easyAI
git clone https://github.com/Zulko/easyAI.git

3.2.6 easyAIのサンプルプログラムを動かしてみる

python3 easyAI/games/GameOfBones.py

3.3 この章のまとめ

  • easyAIをダウンロードし動かしてみた

4 コネクトX(Xは数字)を作って動かしてみる

4.1 以下の操作を行っている動画


4.2 コネクト4を作って動かしてみる の手順

4.2.1 イメージ起動

docker run -it --rm -v $(realpath ~/notebooks):/tf/notebooks -p 8888:8888 mytensorflow

4.2.2 シェル起動

  • New から terminalを選択して、ターミナル起動

4.2.3 シェルで以下のコマンドを実行

sudo su - user
cd /tf/notebooks/

4.2.4 easyAIのインストール

  • 起動しなおす毎に消えてるので、再度インストール
sudo pip3 install easyAI

4.2.5 コネクトX用のディレクトリ掘り、ファイルを作成

mkdir -p easyAI/Connectx
cd  easyAI/Connectx

4.2.6 Connectx.pyファイルを以下の内容で作成

  • ホスト側だとホームディレクトリのnotebooks/easyAI/Connectxディレクトリに以下の内容で作成
  • Connect X の処理を行うクラス
  • BWIDTHで盤の幅
  • BHEIGHTで盤の高さ
  • NEEDLENで勝利条件の長さ(4なら4個以上同じ陣営のコマを縦横あるいは斜めに連続で並べたら勝ち)
BWIDTH=7                    # board width
BHEIGHT=6                   # board height
NEEDLEN=4                    # How many must be arranged to win

class Connectx(object):

    def __init__(self):
	self.color=[[2] * BWIDTH for i in range(BHEIGHT)]
	self.v=[" O "," X "," . "]
	self.turn=0
	self.history=[]
	self.isEnd=False
	self.winner=2

    def clear(self, stone=True):
	self.color=[[2] * BWIDTH for i in range(BHEIGHT)]
	self.turn=0
	self.history.clear()
	self.isEnd=False
	self.winner=2

    def showboard(self):
	print("     ",end="")
	for x in range(BWIDTH):
	    print("{0:2d}".format(x),end=" ")
	print()
	for y in range(BHEIGHT):
	    print("{0:2d}".format(y)+" | ",end="")
	    for x in range(BWIDTH):
		c=self.color[y][x]
		print(self.v[c] ,end="")  
	    print(" | "+"{0:2d}".format(y))
	print("     ",end="")
	for x in range(BWIDTH):
	    print("{0:2d}".format(x),end=" ")
	print()
	print("isEnd : "+str(self.isEnd))
	if self.isEnd:
	    print("game is over winner is "+str(self.winner))
	print(self.history)
	print()

    def legal(self, v):
	ans=False
	if self.color[0][v]==2:
	    ans=True
	return ans

    def isValidXY(self ,xy):
	v,y=xy
	return (v>=0 and v<BWIDTH and y>=0 and y<BHEIGHT)

    def getColor(self,xy):
	ans=3
	if self.isValidXY(xy):
	    v,y=xy
	    ans=self.color[y][v]
	return ans

    def check(self):
	ans=False
	for x in range(BWIDTH):
	    if ans:
		break
	    for y in reversed(range(BHEIGHT)):
		if ans:
		    break
		c=self.color[y][x]
		if c<2:
		    #print(">>>***************",end="")
		    #print((x,y))
		    if self.bcheck((x,y)):
			ans=True
			break
	return ans

    def bcheck(self,xy):
	x,y=xy
	ans=False
	c=self.color[y][x]
	if c<2:
	    for dx in [1,0,-1]:
		for dy in [1,0,-1]:
		    #print("*****(dx,dy)",end=" ")
		    #print((dx,dy))
		    if (not (dx==0 and dy==0))  and (not ans):
			c1=1
			for i in range(1,NEEDLEN):
			    nx=x+dx*i
			    ny=y+dy*i
			    #print("(nx,ny)",end=" ")
			    #print((nx,ny))
			    if self.isValidXY((nx,ny)):
				nc=self.getColor((nx,ny))
				if nc==c:
				    #print((nx,ny),end=" ")
				    c1+=1
				    #print(c1)
				    if c1>=NEEDLEN:
					#print("*** TRUE")
					ans=True
					break
			    else:
				break
	return ans

    def getEnableVs(self):
	ans=[]
	for i in range(BWIDTH):
	    if self.color[0][i]==2:
		ans.append(i)
	return ans

    def checkEnd(self):
	evs=self.getEnableVs()
	ans=len(evs)>0 or self.isEnd
	if ans:
	    self.isEnd=True
	return ans

    def play(self,v):
	ans=False
	if self.legal(v):
	    ans=True
	    for y in reversed(range(BHEIGHT)):
		if self.color[y][v]==2:
		    self.color[y][v]=self.turn
		    self.history.append([v,y])
		    #print(self.check())
		    if not self.isEnd:
			if self.check():
			    self.isEnd=True
			    self.winner=self.turn
			    # print("game is over winner is "+str(self.winner))
			    # print(self.history)
		    self.turn=int(self.turn==0)
		    break
	return ans

    def unmake_move(self, move): # optional method (speeds up the AI)
	if len(self.history)>0:
	    x,y=self.history[-1]
	    self.color[y][x]=2
	    #for i in range(BHEIGHT):
	    #    if self.color[y][i]<2:
	    #        self.color[y][i]=2
	    #        break
	    self.history=self.history[:-1]
	    self.turn=int(self.turn==0)
	    self.isEnd=False
	    self.winner=2

4.2.7 ConnectxEasyAI.py ファイルを以下の内容で作成

  • easyAI用
  • ホスト側だとホームディレクトリのnotebooks/easyAI/Connectxディレクトリに以下の内容で作成
from easyAI import TwoPlayersGame
from easyAI.Player import Human_Player
from Connectx import *

class ConnectxEasyAI( TwoPlayersGame ):
    def __init__(self, players):
	self.board=Connectx()
	self.players = players
	self.nplayer = 1

    def possible_moves(self):
	return self.board.getEnableVs()

    def make_move(self, move):
	self.board.play(move)

    def unmake_move(self, move): # optional method (speeds up the AI)
	self.board.unmake_move(move)

    def lose(self):
	ans=self.board.check()
	enemy=int(self.board.turn==0)
	return self.board.winner==enemy

    def is_over(self):
	self.board.check()
	return self.board.isEnd;

    def show(self):
	self.board.showboard()

    def scoring(self):
	return -100 if self.lose() else 0

if __name__ == "__main__":

    from easyAI import AI_Player, Negamax
    ai_algo = Negamax(6)
    ConnectxEasyAI( [Human_Player(),AI_Player(ai_algo)]).play()

4.2.8 ConnectxEasyAI1.py ファイルを以下の内容で作成

  • 先手人間、後手AI(読み深さ6)戦用
  • ホスト側だとホームディレクトリのnotebooks/easyAI/Connectxディレクトリに以下の内容で作成
from easyAI import TwoPlayersGame
from easyAI.Player import Human_Player
from Connectx import *
from ConnectxEasyAI import ConnectxEasyAI


if __name__ == "__main__":

    from easyAI import AI_Player, Negamax
    ai_algo = Negamax(6)
    ConnectxEasyAI( [Human_Player(),AI_Player(ai_algo)]).play()

4.2.9 ConnectxEasyAI2.py ファイルを以下の内容で作成

  • 総当りで調べる用(私のマシンで半日動かしたが、8->12手までしか探索できず。時間をかければ先手必勝の結果が得られると思われる)
  • ホスト側だとホームディレクトリのnotebooks/easyAI/Connectxディレクトリに以下の内容で作成
from easyAI import TwoPlayersGame
from easyAI.Player import Human_Player
from Connectx import *
from ConnectxEasyAI import ConnectxEasyAI


if __name__ == "__main__":

    from easyAI import id_solve, Human_Player, AI_Player
    from easyAI.AI import TT

    #r, d, m = id_solve(ConnectxEasyAI, range(NEEDLEN*2, BWIDTH*BHEIGHT+1), win_score = 100)
    #r, d, m = id_solve(ConnectxEasyAI, range(13, BWIDTH*BHEIGHT+1,2), win_score = 100)
    r, d, m = id_solve(ConnectxEasyAI, range(13, BWIDTH*BHEIGHT+1), win_score = 100)
    print(r, d, m)  # see the docs.

4.2.10 ConnectxEasyAI3.py ファイルを以下の内容で作成

  • 対人対人戦用
  • ホスト側だとホームディレクトリのnotebooks/easyAI/Connectxディレクトリに以下の内容で作成
from easyAI import TwoPlayersGame
from easyAI.Player import Human_Player
from Connectx import *
from ConnectxEasyAI import ConnectxEasyAI

if __name__ == "__main__":

    from easyAI import AI_Player, Negamax
    ai_algo = Negamax(6)
    #ConnectxEasyAI( [Human_Player(),AI_Player(ai_algo)]).play()
    ConnectxEasyAI( [Human_Player(),Human_Player()]).play()

4.2.11 対AI戦を行ってみる

  • 以下のコマンドを(docker内)ターミナルで実行
python3 ConnectxEasyAI1.py 

4.2.12 人対人戦を行ってみる

  • 以下のコマンドを(docker内)ターミナルで実行
python3 ConnectxEasyAI3.py 

4.2.13 人対人戦を行ってみる

  • 探索を行ってみる(時間かかりすぎるので、最後まで未調査、調査した方いたら結果を教えてもらえると嬉しい)
  • 半日やって8から12まで終わり、13手の処理中でした
python3 ConnectxEasyAI2.py 

4.3 この章のまとめ

  • easyAIをダウンロードし動かしてみた

5 今後

  • 今後も文書追加していきます。

6 この文書のチェンジログ

  • 2020/04/02 初版

著者: NM Max

Created: 2020-04-04 土 20:52

Validate

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です