人工智能初探4:围棋ai篇2:较复杂规则的完善(含代码)

1.前文总结

存在的问题与改进方向

  1. 性能瓶颈

    • MCTS的每次迭代需要神经网络推理,速度较慢。
    • 解决方案:实现批量推理(Batch Inference)。
  2. 训练不稳定

    • 自我对弈初期策略随机,生成数据质量低。
    • 解决方案:先用人类棋谱进行预训练。
  3. 规则缺失

    • 未实现打劫、眼、禁着点等规则。
    • 解决方案:完善GoBoard类中的合法性检查。

通过以上简化模拟,可以看到程序的基本流程,但实际开发中需逐步完善细节和优化性能。

2.规则改进

实现围棋中的打劫、眼、禁着点等规则是围棋AI开发中的关键部分。以下是这些规则的详细解释和代码实现。


1. 禁着点(自杀规则)

禁着点是指落子后导致自己的棋子没有气的点。根据围棋规则,禁止在禁着点落子。

实现逻辑
  • 检查落子后是否会导致自己的棋子没有气。
  • 如果有气,则允许落子;否则禁止。
class GoBoard:
    def is_suicide(self, x, y, player):
        # 检查落子后是否会导致自己的棋子没有气
        self.board[x][y] = player
        if self.count_liberties(x, y) == 0:
            self.board[x][y] = 0  # 恢复棋盘状态
            return True
        self.board[x][y] = 0
        return False

    def count_liberties(self, x, y):
        # 计算(x,y)处棋子的气
        if self.board[x][y] == 0:
            return 0
        liberties = 0
        for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
            nx, ny = x + dx, y + dy
            if 0 <= nx < self.size and 0 <= ny < self.size:
                if self.board[nx][ny] == 0:
                    liberties += 1
        return liberties

2. 眼(真眼与假眼)

眼是指被同一方棋子完全包围的空点。真眼是活棋的关键,假眼则可能被对方破坏。

实现逻辑
  • 检查某个空点是否被同一方棋子完全包围。
  • 如果是,则认为是眼。
class GoBoard:
    def is_eye(self, x, y, player):
        # 检查(x,y)是否是player的眼
        if self.board[x][y] != 0:
            return False
        for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
            nx, ny = x + dx, y + dy
            if 0 <= nx < self.size and 0 <= ny < self.size:
                if self.board[nx][ny] != player:
                    return False
        return True

3. 打劫(劫争规则)

打劫是指双方反复争夺同一个点的规则。为了防止无限循环,围棋规定不能立即回提同一个点。

实现逻辑
  • 记录上一步的落子位置。
  • 检查当前落子是否是回提上一步的落子。
  • 如果是,则禁止落子。
class GoBoard:
    def __init__(self, size=19):
        self.size = size
        self.board = [[0] * size for _ in range(size)]
        self.last_move = None  # 记录上一步的落子
        self.ko = None  # 劫争点

    def place_stone(self, x, y, player):
        if self.is_suicide(x, y, player):
            return False  # 禁着点
        if (x, y) == self.ko:
            return False  # 打劫禁止
        self.board[x][y] = player
        self.last_move = (x, y)
        self.ko = None
        self.remove_dead_stones(x, y, player)
        return True

    def remove_dead_stones(self, x, y, player):
        # 移除被提掉的棋子
        opponent = 3 - player
        for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
            nx, ny = x + dx, y + dy
            if 0 <= nx < self.size and 0 <= ny < self.size:
                if self.board[nx][ny] == opponent and self.count_liberties(nx, ny) == 0:
                    self.capture_group(nx, ny)
                    if self.count_liberties(x, y) == 1:
                        self.ko = (nx, ny)  # 设置劫争点

    def capture_group(self, x, y):
        # 捕获一组棋子
        if self.board[x][y] == 0:
            return
        player = self.board[x][y]
        stack = [(x, y)]
        while stack:
            cx, cy = stack.pop()
            self.board[cx][cy] = 0
            for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
                nx, ny = cx + dx, cy + dy
                if 0 <= nx < self.size and 0 <= ny < self.size:
                    if self.board[nx][ny] == player:
                        stack.append((nx, ny))

4. 整合规则

将以上规则整合到GoBoard类中,确保每次落子都符合围棋规则。

class GoBoard:
    def __init__(self, size=19):
        self.size = size
        self.board = [[0] * size for _ in range(size)]
        self.last_move = None
        self.ko = None

    def place_stone(self, x, y, player):
        if self.board[x][y] != 0:
            return False  # 已有棋子
        if self.is_suicide(x, y, player):
            return False  # 禁着点
        if (x, y) == self.ko:
            return False  # 打劫禁止
        self.board[x][y] = player
        self.last_move = (x, y)
        self.ko = None
        self.remove_dead_stones(x, y, player)
        return True

    def is_suicide(self, x, y, player):
        self.board[x][y] = player
        if self.count_liberties(x, y) == 0:
            self.board[x][y] = 0
            return True
        self.board[x][y] = 0
        return False

    def count_liberties(self, x, y):
        if self.board[x][y] == 0:
            return 0
        liberties = 0
        for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
            nx, ny = x + dx, y + dy
            if 0 <= nx < self.size and 0 <= ny < self.size:
                if self.board[nx][ny] == 0:
                    liberties += 1
        return liberties

    def remove_dead_stones(self, x, y, player):
        opponent = 3 - player
        for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
            nx, ny = x + dx, y + dy
            if 0 <= nx < self.size and 0 <= ny < self.size:
                if self.board[nx][ny] == opponent and self.count_liberties(nx, ny) == 0:
                    self.capture_group(nx, ny)
                    if self.count_liberties(x, y) == 1:
                        self.ko = (nx, ny)

    def capture_group(self, x, y):
        if self.board[x][y] == 0:
            return
        player = self.board[x][y]
        stack = [(x, y)]
        while stack:
            cx, cy = stack.pop()
            self.board[cx][cy] = 0
            for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
                nx, ny = cx + dx, cy + dy
                if 0 <= nx < self.size and 0 <= ny < self.size:
                    if self.board[nx][ny] == player:
                        stack.append((nx, ny))

3.总结

通过以上代码,我们实现了围棋中的禁着点、眼、打劫等规则。这些规则是围棋AI的基础,确保AI能够合法、合理地落子。接下来,可以将这些规则整合到MCTS和神经网络中,进一步提升AI的棋力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值