围棋规则其实很简单,首先每个棋子会有气,相连的一片棋子共用气,那么基于这个规则我们可以构造这样一个Group类:
class Group(namedtuple(
'Group',
['id', 'stones', 'liberties', 'color']
)):
"""
++++++
++..++
++..++
+*++++
上面那些点就构成了一个群
群: 一个群就是一大片连着的相同颜色的棋子
:stones 群内棋子的集合
:liberties 群周围相邻且没有棋子的点的集合
:color 群内棋子的颜色
"""
def __eq__(self, other):
return self.stones == other.stones and self.liberties == other.liberties and self.color == other.color
这个群是一个命名元组类,Group是这个命名元组的名称,后面接了他的四个属性。
基于这个数据结构我们可以构造一个气追踪器类,用于记录和更新棋盘上棋子的气。
class LibertyTracker(object):
@staticmethod
def newTrackerFromBaseBoard(board=gf.Board.getStaticBaseBoard())
def __init__(self, groupIndexMap=None, groups=None, librtyCacheMap=None, maxGroupId=1)
def __deepcopy__(self, memodict={})
def addStone(self, color, point, phantom=True)
def _handleCaptures(self, capturedStones)
def _createGroup(self, color, point, liberties)
def _delGroup(self, groupId)
def _captureGroup(self, groupId, phantom)
def _mergeGroup(self, group1Id, group2Id)
def _updateLiberties(self, groupId, add=None, remove=None)
首先来看这个静态方法,这个静态方法用于根据当前棋面生产出LibertyTrakcer:
@staticmethod
def newTrackerFromBaseBoard(board=gf.Board.getStaticBaseBoard()):
"""
:param board 默认为基础棋盘。
从基础棋盘上创建自由度追踪器
:return: LibertyTracker
"""
baseBoard = np.copy(board)
curGroupId = 0
libTracker = LibertyTracker()
for color in (WHITE, BLACK):
while color in baseBoard:
curGroupId += 1
foundColor = np.where(baseBoard == color)
# point的值为第一个点
point = foundColor[0][0], foundColor[1][0]
chain, reached = findReached(point=point, baseBoard=baseBoard)
# 相邻且为EMPTY的点的集合
liberties = set(r for r in reached if baseBoard[r] == EMPTY)
newGroup = Group(curGroupId, chain, liberties, color)
libTracker.groups[curGroupId] = newGroup
for c in chain:
libTracker.groupIndexMap[c] = curGroupId
#在另一张图上标注这里已经有棋子了
placeStones(baseBoard, FILL, chain)
libTracker.maxGroupId = curGroupId
libertyCounts = np.zeros([SIZE, SIZE], dtype=np.uint8)
for group in libTracker.groups.values():
# 一个群的自由度
libNum = len(group.liberties)
for s in group.stones:
libertyCounts[s] = libNum
libTracker.libertyCacheMap = libertyCounts
return libTracker
该方法会遍历棋盘上的棋子,用findReached方法:
def findReached(point, baseBoard=gf.Board.baseBoard):
"""
深搜
返回当前点相同颜色(WHITE,BLACK,EMPTY)所连成的链以及相邻不同颜色的集合(WHITE,BLACK,EMPTY)
:param baseBoard:基础棋盘(二维数组)
:param point:当前点(元组对象)
:return: sameColorChain: 相同颜色连成的一片点的集合 diffColorReached: 相邻不同颜色的点的集合
"""
if isinstance(point, gf.Point):
point = point.toTuple()
color = baseBoard[point]
sameColorChain = set([point])
diffColorReached = set()
frontier = [point]
while frontier:
cur = frontier.pop()
sameColorChain.add(cur)
for p in NEIGHBORS[cur]:
if baseBoard[p] == color and not p in sameColorChain:
frontier.append(p)
elif baseBoard[p] != color:
diffColorReached.add(p)
return sameColorChain, diffColorReached
findReached方法用深搜的方法得到一个群的集合,以及群周围一圈位置的集合。
LibertyTrakcer的构造函数:
def __init__(self, groupIndexMap=None, groups=None, librtyCacheMap=None, maxGroupId=1):
"""
一个"自由度追踪器"类,
:param groupIndexMap: 一个棋盘(群的索引, 二维数组),上面用不同的数字(ID)标明不同的群 例如
1 1 1 1
1 2 2 1
1 2 1 1
:param groups: 一个字典, 根据群的ID返回群
:param librtyCacheMap: 记录每个群的自由度(周围相邻且为EMPTY的点的数量, 二维数组)
:param maxGroupId: 记录ID最大的群的ID
"""
self.groupIndexMap = groupIndexMap if groupIndexMap is not None else -np.ones([SIZE, SIZE], dtype=np.int16)
self.groups = groups or {}
self.libertyCacheMap = librtyCacheMap if librtyCacheMap is not None else np.zeros([SIZE, SIZE], dtype=np.uint8)
self.maxGroupId = maxGroupId