跳到内容

计算机围棋/处理落子

来自维基教科书,开放的书籍,为开放的世界

处理落子

[编辑 | 编辑源代码]

现在我们已经能够检测合法落子,下一步就是实际处理合法落子,通过将新棋子添加到棋盘上,移除任何被吃掉的棋子,并更新禁手点。我们已经能够检测到何时发生吃子

} else if (getColor(neighbor) == c.opposite()) {
	// if any neighbor is an enemy
	// and that enemy is in atari
	if (inAtari(neighbor)) {
		suicide = false;
	}
}

现在我们只需要更新这段代码以移除被吃掉的棋子。到目前为止,应该很明显,表示的方式将非常有用。让我们修改之前getLiberties()代码,以返回一个链而不是一组气

private Set<Point> getChainPoints(Board b, Point p) {
	Set<Point> stones = new HashSet<Point>();
	stones.add(p);
	
	Color myColor = b.getColor(p);
	Color floodfillColor = myColor.opposite();
	b.setColor(p, floodfillColor);
	
	List<Point> neighbors = b.getNeighbors(p);
	for (Point neighbor : neighbors) {
		if (b.getColor(neighbor) == myColor) {
			if (!stones.contains(neighbor)) {
				stones.addAll(getChainPoints(b, neighbor));
			}
		}
	}
	
	return stones;
}

给定构成特定链的一组棋子,我们也可以很容易地获得与该链相邻的空点的集合,并构造一个包含这两个集合的对象。

private Chain getChain(Point p) {
	Set<Point> stones = getChainPoints(clone(), p);

	Set<Point> liberties = new HashSet<Point>();
	for (Point stone : stones) {
		for (Point point : getNeighbors(stone)) {
			if (getColor(point) == EMPTY) {
				liberties.add(point);
			}
		}
	}
	
	return new Chain(stones, liberties);
}

修改后的从棋盘上移除被吃掉棋子的代码现在变得非常简单

} else if (getColor(neighbor) == c.opposite()) {
	// if any neighbor is an enemy
	// and that enemy is in atari
	
	Chain enemy = getChain(neighbor);
	if (enemy.inAtari()) {
		suicide = false;

		// remove the enemy stones from the board
		for (Point point : enemy) {
			setColor(point, EMPTY);
			capturedStones.add(point);
		}
	}
}

通过将被吃掉的棋子保存在一个集合中,我们现在可以轻松地更新禁手点。

// If this move captured exactly one stone, that stone is the new ko point
if (capturedStones.size() == 1) {
	koPoint = capturedStones.iterator().next();
} else {
	koPoint = null;
}

如果您想要本章中使用的所有源代码的副本,这些代码已准备好编译和运行,您可以从这里下载示例代码副本

华夏公益教科书