气追踪器的编写
气追踪器类用于更新和记录棋盘上每颗棋子的气,以及群的信息。下面是其追踪器的几个属性:
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
气追踪器通过一个工厂方法生成对象,这个工厂方法会从棋盘上的局势来设置groupIndexMap和libertyCacheMap的值。
@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
气追踪器的deepcopy函数:
def __deepcopy__(self, memodict={}):
"""
深层拷贝
:param memodict:
:return: LibertyTracker
"""
newGroupIndexMap = np.copy(self.groupIndexMap)
newLibertyCacheMap = np.copy(self.libertyCacheMap)
newGroups = {
group.id: Group(group.id, set(group.stones), set(group.liberties), group.color)
for group in self.groups.values()
}
return LibertyTracker(newGroupIndexMap, newGroups, newLibertyCacheMap, maxGroupId=self.maxGroupId)
气追踪器还有其它的方法没有在这里介绍,可以用于普通围棋的行棋,这里贴上Gitee地址感兴趣的可以看看:
go_rules.py
Condition类的编写
"""
对棋面进行分析的类
baseBoard: 基础棋盘, 这里直接为我们的基础棋盘
"""
def __init__(self, baseBoard=None, libTracker=None, ourColor=None, opponentColor=None):
self.baseBoard = baseBoard if baseBoard is not None else gf.Board.getStaticBaseBoard()
self.libTracker = libTracker if libTracker is not None else LibertyTracker.newTrackerFromBaseBoard(self.baseBoard)
self.ourColor = ourColor if ourColor is not None else gf.GameStatus.ourColor
self.opponentColor = opponentColor if opponentColor is not None else gf.GameStatus.opponentColor
def __deepcopy__(self, memodict={}):
condition = Condition()
condition.baseBoard = np.copy(self.baseBoard)
condition.libTracker = copy.deepcopy(self.libTracker)
condition.ourColor = copy.copy(self.ourColor)
condition.opponentColor = copy.copy(self.opponentColor)
return condition
Condition类只有两个方法,用于判断是否为禁着点:
def isMoveSuicidal(self, move):
"""
判断该行棋点是否为禁着点
:param move: 行棋的位置(元组对象,或者Point对象)
:return: 如果是禁着点, 返回True, 否则返回False
"""
if isinstance(move, gf.Point):
move = move.toTuple()
potentialLibs = set()
for p in NEIGHBORS[move]:
neighborGroupId = self.libTracker.groupIndexMap[p]
if neighborGroupId == MISSING_GROUP_ID:
return False
neighborGroup = self.libTracker.groups[neighborGroupId]
if neighborGroup.color == self.ourColor:
potentialLibs |= neighborGroup.liberties
elif len(neighborGroup.liberties) == 1:
return False
potentialLibs -= set([move])
return not potentialLibs
isMoveSuicidal方法会计算下棋点的潜在气,也就是如果该点下了后能够提子,虽然该点本身气为0,但是可以下。
def isMoveLegal(self, move):
"""
判断下棋点是否合法
:param move: 下棋点(元组对象, 或者point对象)
:return:如果该下棋点合法,则返回True, 否则返回False
"""
if isinstance(move, gf.Point):
move = move.toTuple()
if move is None:
return True
if self.baseBoard[move] != EMPTY:
return False
# if move == self.ko:
# if self.koTimes >= gf.GameStatus.koTimes:
# return False
# else:
# return True
if self.isMoveSuicidal(move):
return False
return True
isMoveLegal是对isMoveSuicidal的进一步封装。