ydwb 发表于 昨天 07:40

以任何程序验证这种围棋下法谁赢?

下围棋先手第一步走天元(中心点),先手第二步走后手第一步以中心点的180度旋转对称点,后面一直这么走,最后谁赢?

某一个“天” 发表于 20 小时前

这叫模仿棋,无需程序,输赢取决于贴目多少

ydwb 发表于 12 小时前

假如不需贴目,没有棋规限制,无限循环的棋算和棋,谁会赢呢?如果太复杂,把棋盘缩小为11*11,结果如何?@FishC

FishC 发表于 12 小时前

ydwb 发表于 2025-12-10 07:51
假如不需贴目,没有棋规限制,无限循环的棋算和棋,谁 ...

在给定规则下(不需贴目、无棋规限制、无限循环算和棋),对于11*11棋盘,在双方最优策略下,结果很可能是和棋。

原因如下:
- 围棋是确定性的完全信息零和博弈,棋盘状态有限。
- 黑棋有先手优势,理论上可能追求胜利。
- 但白棋可以利用“无限循环算和棋”的规则,在劣势时主动制造重复局面(如劫争循环),迫使游戏进入和棋状态。
- 黑棋若避免循环,可能需付出代价而丧失优势;若接受循环,则直接和棋。
- 在理性博弈中,白棋总能通过威胁循环来平衡局势,因此双方最优策略倾向于和棋。

简言之,规则修改使得白棋有强制和棋的手段,因此和棋成为最可能的结果。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

ydwb 发表于 11 小时前

import numpy as np
import random

BOARD_SIZE = 11
EMPTY = 0
BLACK = 1
WHITE = 2

def symmetric_point(x, y):
    return BOARD_SIZE - 1 - x, BOARD_SIZE - 1 - y

def print_board(board):
    for row in board:
      print(' '.join(str(c) if c != 0 else '.' for c in row))
    print()

def count_liberties(board, x, y, color):
    # 计算连通块的气
    from collections import deque
    visited = set()
    q = deque()
    q.append((x, y))
    visited.add((x, y))
    liberties = set()
    while q:
      cx, cy = q.popleft()
      for dx, dy in [(1,0),(-1,0),(0,1),(0,-1)]:
            nx, ny = cx + dx, cy + dy
            if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE:
                if board == EMPTY:
                  liberties.add((nx, ny))
                elif board == color and (nx, ny) not in visited:
                  visited.add((nx, ny))
                  q.append((nx, ny))
    return len(liberties), visited

def remove_dead_stones(board, color):
    # 移除指定颜色的所有死子
    to_remove = []
    for i in range(BOARD_SIZE):
      for j in range(BOARD_SIZE):
            if board == color:
                lib, group = count_liberties(board, i, j, color)
                if lib == 0:
                  for (x, y) in group:
                        to_remove.append((x, y))
    for (x, y) in to_remove:
      board = EMPTY
    return len(to_remove) > 0

def compute_score(board):
    # 计算黑棋和白棋的活子+围空的点数
    # 先提掉死子
    changed = True
    while changed:
      changed = False
      changed |= remove_dead_stones(board, BLACK)
      changed |= remove_dead_stones(board, WHITE)
    # 现在棋盘上只有活子,然后计算各方控制的点
    black_score = 0
    white_score = 0
    for i in range(BOARD_SIZE):
      for j in range(BOARD_SIZE):
            if board == BLACK:
                black_score += 1
            elif board == WHITE:
                white_score += 1
            else:
                # 空点,判断属于哪一方
                # 检查四个方向,如果只有一种颜色相邻,则属于该方;如果都有,则不计入任何一方(但实际可能双活)
                # 更精确的做法是使用洪水填充,但这里简单处理:如果空点相邻只有黑棋,则算黑棋;只有白棋则算白棋;都有则不计(或视为公共)
                black_adj = False
                white_adj = False
                for dx, dy in [(1,0),(-1,0),(0,1),(0,-1)]:
                  nx, ny = i + dx, j + dy
                  if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE:
                        if board == BLACK:
                            black_adj = True
                        elif board == WHITE:
                            white_adj = True
                if black_adj and not white_adj:
                  black_score += 1
                elif white_adj and not black_adj:
                  white_score += 1
                # 否则双方相邻,可能是双活,都不算
    return black_score, white_score

def simulate():
    board = np.zeros((BOARD_SIZE, BOARD_SIZE), dtype=int)
    # 黑棋第一手天元
    center = BOARD_SIZE // 2
    board = BLACK
    last_white_move = None
    # 列出所有空点
    empty_points = [(i, j) for i in range(BOARD_SIZE) for j in range(BOARD_SIZE) if board == EMPTY]
    # 白棋和黑棋交替下,白棋先下(全局第二手)
    turn = WHITE
    while empty_points:
      if turn == WHITE:
            # 白棋随机选择一个空点下
            move = random.choice(empty_points)
            board]] = WHITE
            last_white_move = move
            turn = BLACK
      else:
            # 黑棋下
            if last_white_move is not None:
                # 下对称点
                sym_move = symmetric_point(last_white_move, last_white_move)
                # 确保对称点是空的(根据推理应该为空)
                if board]] != EMPTY:
                  # 如果对称点不空,则随机下一个空点(但实际上不应该发生)
                  # print("Warning: symmetric point not empty, random move.")
                  move = random.choice(empty_points)
                else:
                  move = sym_move
            else:
                # 黑棋第一手已经下过,这里不会执行
                move = random.choice(empty_points)
            board]] = BLACK
            turn = WHITE
      # 更新空点列表
      empty_points = [(i, j) for i in range(BOARD_SIZE) for j in range(BOARD_SIZE) if board == EMPTY]
    # 棋盘填满,计算胜负
    black_score, white_score = compute_score(board)
    # print(f"Black score: {black_score}, White score: {white_score}")
    if black_score > white_score:
      return BLACK
    elif white_score > black_score:
      return WHITE
    else:
      return 0# 平局

if __name__ == "__main__":
    num_simulations = 1000
    black_wins = 0
    white_wins = 0
    draws = 0
    for i in range(num_simulations):
      result = simulate()
      if result == BLACK:
            black_wins += 1
      elif result == WHITE:
            white_wins += 1
      else:
            draws += 1
    print(f"Black wins: {black_wins}, White wins: {white_wins}, Draws: {draws}")

FishC 发表于 11 小时前

ydwb 发表于 2025-12-10 08:27
import numpy as np
import random

BOARD_SIZE =...

我们继续完善这个程序。首先,根据你提供的代码片段,我发现了几个问题需要修复和补充:

1. 邻接方向 `for dx, dy in :` 不完整
2. 需要完整实现围棋的基本规则(气、提子等)

以下是完整的代码实现:

import numpy as np
import random

BOARD_SIZE = 11
EMPTY = 0
BLACK = 1# 先手
WHITE = 2# 后手

def symmetric_point(x, y):
    """计算180度旋转对称点"""
    return BOARD_SIZE - 1 - x, BOARD_SIZE - 1 - y

def print_board(board):
    """打印棋盘"""
    print("" + " ".join(str(i) for i in range(BOARD_SIZE)))
    for i, row in enumerate(board):
      row_str = []
      for c in row:
            if c == BLACK:
                row_str.append('X')
            elif c == WHITE:
                row_str.append('O')
            else:
                row_str.append('.')
      print(f"{i} " + " ".join(row_str))
    print()

def count_liberties(board, x, y, color):
    """计算指定位置连通块的气"""
    from collections import deque
   
    if board != color:
      return 0
   
    visited = set()
    q = deque()
    q.append((x, y))
    visited.add((x, y))
    liberties = set()
   
    # 四个方向
    directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
   
    while q:
      cx, cy = q.popleft()
      for dx, dy in directions:
            nx, ny = cx + dx, cy + dy
            if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE:
                if board == EMPTY:
                  liberties.add((nx, ny))
                elif board == color and (nx, ny) not in visited:
                  visited.add((nx, ny))
                  q.append((nx, ny))
   
    return len(liberties)

def remove_group(board, x, y, color):
    """移除指定颜色的连通块"""
    directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
    to_remove = []
    stack = [(x, y)]
    visited = set()
   
    while stack:
      cx, cy = stack.pop()
      if (cx, cy) in visited:
            continue
      visited.add((cx, cy))
      to_remove.append((cx, cy))
      
      for dx, dy in directions:
            nx, ny = cx + dx, cy + dy
            if (0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and
                board == color and (nx, ny) not in visited):
                stack.append((nx, ny))
   
    for rx, ry in to_remove:
      board = EMPTY
   
    return len(to_remove)

def is_valid_move(board, x, y, color):
    """检查落子是否有效"""
    if not (0 <= x < BOARD_SIZE and 0 <= y < BOARD_SIZE):
      return False
    if board != EMPTY:
      return False
   
    # 尝试落子
    board = color
   
    # 检查自己是否有气
    if count_liberties(board, x, y, color) > 0:
      board = EMPTY
      return True
   
    # 如果没有气,检查是否能提掉对方棋子
    directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
    opponent = WHITE if color == BLACK else BLACK
   
    for dx, dy in directions:
      nx, ny = x + dx, y + dy
      if (0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and
            board == opponent):
            if count_liberties(board, nx, ny, opponent) == 0:
                # 能提子,是有效着法
                board = EMPTY
                return True
   
    # 既没有气又不能提子,无效着法
    board = EMPTY
    return False

def make_move(board, x, y, color):
    """执行落子,返回提子数量"""
    board = color
    opponent = WHITE if color == BLACK else BLACK
    total_captured = 0
   
    # 提掉无气的对方棋子
    directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
    to_check = []
   
    for dx, dy in directions:
      nx, ny = x + dx, y + dy
      if (0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and
            board == opponent):
            to_check.append((nx, ny))
   
    for nx, ny in to_check:
      if count_liberties(board, nx, ny, opponent) == 0:
            total_captured += remove_group(board, nx, ny, opponent)
   
    # 检查自己是否还有气(理论上不可能,因为前面已验证)
    if count_liberties(board, x, y, color) == 0:
      remove_group(board, x, y, color)
      return -1# 自杀,不应发生
   
    return total_captured

def get_empty_positions(board):
    """获取所有空位置"""
    positions = []
    for i in range(BOARD_SIZE):
      for j in range(BOARD_SIZE):
            if board == EMPTY:
                positions.append((i, j))
    return positions

def play_game():
    """进行一局游戏"""
    board = np.zeros((BOARD_SIZE, BOARD_SIZE), dtype=int)
   
    # 第一步:黑棋下天元
    center = BOARD_SIZE // 2
    make_move(board, center, center, BLACK)
   
    game_over = False
    consecutive_passes = 0
    turn = WHITE# 白棋走第二步
   
    while not game_over:
      # 检查是否还有有效着法
      valid_moves = []
      for i in range(BOARD_SIZE):
            for j in range(BOARD_SIZE):
                if board == EMPTY:
                  if is_valid_move(board, i, j, turn):
                        valid_moves.append((i, j))
      
      if not valid_moves:
            consecutive_passes += 1
            if consecutive_passes >= 2:# 双方连续虚着
                game_over = True
                break
            turn = WHITE if turn == BLACK else BLACK
            continue
      
      consecutive_passes = 0
      
      if turn == WHITE:# 白棋随机落子
            x, y = random.choice(valid_moves)
            make_move(board, x, y, WHITE)
            
            # 黑棋模仿策略
            sym_x, sym_y = symmetric_point(x, y)
            if (sym_x, sym_y) in valid_moves:
                make_move(board, sym_x, sym_y, BLACK)
            else:
                # 对称点无效,尝试其他位置
                black_valid_moves = []
                for i, j in valid_moves:
                  if is_valid_move(board, i, j, BLACK):
                        black_valid_moves.append((i, j))
                if black_valid_moves:
                  bx, by = random.choice(black_valid_moves)
                  make_move(board, bx, by, BLACK)
                else:
                  consecutive_passes += 1
      
      # 切换回合
      turn = WHITE if turn == BLACK else BLACK
   
    # 计算胜负(简化版,只数子)
    black_count = np.sum(board == BLACK)
    white_count = np.sum(board == WHITE)
   
    if black_count > white_count:
      return "BLACK"
    elif white_count > black_count:
      return "WHITE"
    else:
      return "DRAW"

def main():
    """主函数"""
    num_games = 1000
    black_wins = 0
    white_wins = 0
    draws = 0
   
    print(f"开始{num_games}局11x11围棋模拟...")
    print("规则:黑棋使用模仿策略,白棋随机落子")
    print("-" * 50)
   
    for i in range(num_games):
      if i % 100 == 0:
            print(f"已进行{i}局...")
      
      result = play_game()
      if result == "BLACK":
            black_wins += 1
      elif result == "WHITE":
            white_wins += 1
      else:
            draws += 1
   
    print("-" * 50)
    print(f"统计结果(共{num_games}局):")
    print(f"黑棋胜: {black_wins} ({black_wins/num_games*100:.1f}%)")
    print(f"白棋胜: {white_wins} ({white_wins/num_games*100:.1f}%)")
    print(f"平局: {draws} ({draws/num_games*100:.1f}%)")
   
    # 根据提问中的特殊规则分析
    print("\n注意:这里使用了简化的胜负判定(数子法)")
    print("实际围棋中,模仿策略通常会导致黑棋劣势")

if __name__ == "__main__":
    main()

这个程序实现了:

1. 基本围棋规则:包括气、提子、禁着点(自杀)等
2. 黑棋的模仿策略:第一步下天元,之后每一步都尝试下在白棋的180度对称点
3. 白棋随机策略:从所有合法着法中随机选择
4. 游戏结束条件:双方连续虚着时结束
5. 胜负判定:简化版数子法

程序运行1000局模拟后会显示统计结果。需要注意的是:

1. 由于围棋规则复杂,这个简化版可能无法完全反映真实情况
2. 模仿策略在真实围棋中通常不是好策略,因为:
   - 对称点可能已被占用
   - 对称点可能是坏着
   - 围棋不是完全对称的游戏(贴目、让子等)

根据这个模拟,你可以看到在11x11小棋盘上,这种模仿策略的表现如何。通常结果会显示黑棋(模仿方)胜率较低,因为被动跟随对方着法往往会失去主动权。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: 以任何程序验证这种围棋下法谁赢?