8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

コンピュータ囲碁の作成 ルールの実装

Last updated at Posted at 2016-05-06

#コンピュータ囲碁
・コンピュータ囲碁の作成メモ。
・ルール(自殺手,コウ,眼,石の消去)を実装

今回もかなり苦戦しています。
前回頂いたコメントを参考にclassを作ってみましたが,(自殺手,コウ,眼)の実装は手探りです。

前前回 コンピュータ囲碁の作成
前回  コンピュータ囲碁の作成 ランダム打ちの実装

#結果動画
コンピュータ囲碁(YOUTUBE)

#ソースコード

# -*- coding:utf-8 -*-
import random
import time
import copy
# 碁盤
BOARD_SIZE = 9				# 碁盤の大きさ

# 盤上の種類
NONE,BLACK,WHITE,WALL = 0,1,2,3
VISUAL = ("","🔴 ","⚪️ ", " ")
DIR4 = (-1,0),(1,0),(0,-1),(0,1)

SUCCESS = 0 		# 打てる
KILL 	= 1 		# 自殺手
KO 		= 2 		# 劫
ME 		= 3 		# 眼
MISS 	= 4 		# すでに石がある
PASS 	= 5 		# パス


# デバッグ用
def error_move(err):
	if err == KILL:
		print "自殺手"
	if err == KO:
		print ""
	if err == ME:
		print ""
	if err == MISS:
		print "すでに石がある"
	if err == PASS:
		print "パス"

class Count_Joined_Liberty(object):

	def __init__(self,board):
		self.board = board

	def count(self,position,stone):
		return self.count_sub(position,stone,[])

	def  count_sub(self,position,stone,checked,joined=0,liberty=0):
		checked.append(position)
		joined += 1
		y,x = position
		for dy,dx in DIR4:
			adjacent = (y+dy,x+dx)
			if adjacent in checked:
				continue
			if self.board.get(adjacent) == NONE:
				checked.append(adjacent)
				liberty+=1
			elif self.board.get(adjacent) == stone:
				joined, liberty = self.count_sub(adjacent,stone,checked,joined,liberty)
		return joined, liberty


class Board(object):
	# 碁盤作成
	def __init__(self,size):
		self.size = size + 2 	# 上下左右に外枠を含めた碁盤
		self.data = data = [[NONE]*self.size for i in range(self.size)]
		# 外枠の作成
		for i in range(self.size):
			data[0][i] = data[-1][i] = data[i][0] = data[i][-1] = WALL

	# 石を取る
	def capture(self,position,color):
		y,x = position
		self.data[y][x] = NONE
		for dy,dx in DIR4:
			around = (y+dy,x+dx)
			if self.get(around) == color:
				self.capture(around,color)

	def get(self,position):
		y,x = position
		return self.data[y][x]

	# 石を打つ
	def move(self,position,color,ko_z):
		joined_liberty = Count_Joined_Liberty(self)
		if position == PASS:
			return PASS
		if self.get(position) != NONE:
			return MISS

		# positionに対して4方向の [呼吸点の数,連石の数,色]
		libertys = [0,0,0,0]
		joineds  = [0,0,0,0]
		colors   = [0,0,0,0]

		un_color = 3- color
		space = 0 			# 4方向の空白の数
		wall = 0 			# 4方向の壁の数
		mikata_safe = 0 	# 呼吸点が2以上の味方の数
		take_sum = 0 		# 取れる石の合計
		pre_ko = 0 			# 劫の候補 ※シャレじゃない

		# 打つ前に4方向を調べる
		y,x = position
		for i in range(4):
			(dy,dx) = DIR4[i]
			z = (y+dy,x+dx) 
			c = self.get(z)
			if c == NONE:
				space+=1
			if c == WALL:
				wall+=1
			if c==NONE or c==WALL:
				continue

			joineds[i],libertys[i] = joined_liberty.count(z,c)
			colors[i] = c

			# 石が取れるなら,劫の可能性があるので保持
			if(c==un_color) and (libertys[i]==1):
				take_sum += joineds[i]
				pre_ko = z
			# 味方の石があって呼吸点が2つ以上あるなら眼の可能性
			if(c==color) and (libertys[i]>=2):
				mikata_safe+=1


		# ルール違反の処理
		if(take_sum==0) and (space==0) and (mikata_safe==0):		# 味方の石以外で囲まれていて,石が取れないなら自殺手
			return KILL
		if position == ko_z[0]:	# 劫
			return KO
		if wall + mikata_safe == 4: # 眼 (ルール違反ではない)
			return ME

		# 石を取る処理
		for i in range(4):
			(dy,dx) = DIR4[i]
			tz = (y+dy,x+dx)
			if (colors[i] == un_color) and (libertys[i]==1) and (self.get(tz)!=NONE):
				self.capture(tz,un_color)

		# 石を打つ
		self.data[y][x] = color
		joined,liberty = joined_liberty.count(position,color)
		if(take_sum==1) and (joined==1) and (liberty==1):
			ko_z[0] = pre_ko
		else:
			ko_z[0] = 0
		
		return SUCCESS

	# 盤上の空の場所を配列で取得
	def getSuccessPositions(self,ko_z,color):
		array = []
		board_copy = copy.deepcopy(self.data)
		for y in range(1,self.size-1):
			for x in xrange(1,self.size-1):
				ko_z_copy = ko_z[:]
				err = self.move((y,x),color,ko_z_copy)
				if err != SUCCESS:
					continue
				array.append((y,x))
				self.data = copy.deepcopy(board_copy)
		return array

	# 碁盤描画
	def draw(self):
		print "  ", " ".join("%2d"%x for x in range(1,self.size-1))
		for y in range(1,self.size-1):
			print "%2d"%y, " ".join(VISUAL[data] for data in self.data[y][1:-1])

def main():
	# 碁盤
	board = Board(BOARD_SIZE)

	# 先手
	color = BLACK
	ko_z = [0]
	count_pass = 0

	# 対局開始
	while(1):
		positions = board.getSuccessPositions(ko_z,color)

		if len(positions) == 0:
			z = PASS
		else:
			count_pass = 0
			z = random.choice(positions)

		err = board.move(z,color,ko_z)
		if err != SUCCESS:
			print VISUAL[color],
			error_move(err)
			if err == PASS:
				color = 3-color
				count_pass+=1
			if count_pass == 2:
				print "対局終了"
				break
			continue
		print VISUAL[color], z
		board.draw()
		color = WHITE if color == BLACK else BLACK
		time.sleep(0.1)
		print ""

if __name__ == '__main__':
	main()

##github
https://github.com/Tsunehiko511/python_Go_origin
master:1次元配列
branch:2次元配列
#参考図書
コンピュータ囲碁 ―モンテカルロ法の理論と実践―

8
7
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?