鱼C论坛

 找回密码
 立即注册
查看: 55|回复: 6

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

[复制链接]
回帖奖励 18 鱼币 回复本帖可获得 2 鱼币奖励! 每人限 1 次
发表于 昨天 07:40 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
下围棋先手第一步走天元(中心点),先手第二步走后手第一步以中心点的180度旋转对称点,后面一直这么走,最后谁赢?
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 11 小时前 | 显示全部楼层

回帖奖励 +2 鱼币

这叫模仿棋,无需程序,输赢取决于贴目多少
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 3 小时前 | 显示全部楼层
假如不需贴目,没有棋规限制,无限循环的棋算和棋,谁会赢呢?如果太复杂,把棋盘缩小为11*11,结果如何?@FishC
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 3 小时前 | 显示全部楼层
ydwb 发表于 2025-12-10 07:51
假如不需贴目,没有棋规限制,无限循环的棋算和棋,谁 ...


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

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

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 3 小时前 | 显示全部楼层
  1. import numpy as np
  2. import random

  3. BOARD_SIZE = 11
  4. EMPTY = 0
  5. BLACK = 1
  6. WHITE = 2

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

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

  13. def count_liberties(board, x, y, color):
  14.     # 计算连通块的气
  15.     from collections import deque
  16.     visited = set()
  17.     q = deque()
  18.     q.append((x, y))
  19.     visited.add((x, y))
  20.     liberties = set()
  21.     while q:
  22.         cx, cy = q.popleft()
  23.         for dx, dy in [(1,0),(-1,0),(0,1),(0,-1)]:
  24.             nx, ny = cx + dx, cy + dy
  25.             if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE:
  26.                 if board[nx][ny] == EMPTY:
  27.                     liberties.add((nx, ny))
  28.                 elif board[nx][ny] == color and (nx, ny) not in visited:
  29.                     visited.add((nx, ny))
  30.                     q.append((nx, ny))
  31.     return len(liberties), visited

  32. def remove_dead_stones(board, color):
  33.     # 移除指定颜色的所有死子
  34.     to_remove = []
  35.     for i in range(BOARD_SIZE):
  36.         for j in range(BOARD_SIZE):
  37.             if board[i][j] == color:
  38.                 lib, group = count_liberties(board, i, j, color)
  39.                 if lib == 0:
  40.                     for (x, y) in group:
  41.                         to_remove.append((x, y))
  42.     for (x, y) in to_remove:
  43.         board[x][y] = EMPTY
  44.     return len(to_remove) > 0

  45. def compute_score(board):
  46.     # 计算黑棋和白棋的活子+围空的点数
  47.     # 先提掉死子
  48.     changed = True
  49.     while changed:
  50.         changed = False
  51.         changed |= remove_dead_stones(board, BLACK)
  52.         changed |= remove_dead_stones(board, WHITE)
  53.     # 现在棋盘上只有活子,然后计算各方控制的点
  54.     black_score = 0
  55.     white_score = 0
  56.     for i in range(BOARD_SIZE):
  57.         for j in range(BOARD_SIZE):
  58.             if board[i][j] == BLACK:
  59.                 black_score += 1
  60.             elif board[i][j] == WHITE:
  61.                 white_score += 1
  62.             else:
  63.                 # 空点,判断属于哪一方
  64.                 # 检查四个方向,如果只有一种颜色相邻,则属于该方;如果都有,则不计入任何一方(但实际可能双活)
  65.                 # 更精确的做法是使用洪水填充,但这里简单处理:如果空点相邻只有黑棋,则算黑棋;只有白棋则算白棋;都有则不计(或视为公共)
  66.                 black_adj = False
  67.                 white_adj = False
  68.                 for dx, dy in [(1,0),(-1,0),(0,1),(0,-1)]:
  69.                     nx, ny = i + dx, j + dy
  70.                     if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE:
  71.                         if board[nx][ny] == BLACK:
  72.                             black_adj = True
  73.                         elif board[nx][ny] == WHITE:
  74.                             white_adj = True
  75.                 if black_adj and not white_adj:
  76.                     black_score += 1
  77.                 elif white_adj and not black_adj:
  78.                     white_score += 1
  79.                 # 否则双方相邻,可能是双活,都不算
  80.     return black_score, white_score

  81. def simulate():
  82.     board = np.zeros((BOARD_SIZE, BOARD_SIZE), dtype=int)
  83.     # 黑棋第一手天元
  84.     center = BOARD_SIZE // 2
  85.     board[center][center] = BLACK
  86.     last_white_move = None
  87.     # 列出所有空点
  88.     empty_points = [(i, j) for i in range(BOARD_SIZE) for j in range(BOARD_SIZE) if board[i][j] == EMPTY]
  89.     # 白棋和黑棋交替下,白棋先下(全局第二手)
  90.     turn = WHITE
  91.     while empty_points:
  92.         if turn == WHITE:
  93.             # 白棋随机选择一个空点下
  94.             move = random.choice(empty_points)
  95.             board[move[0]][move[1]] = WHITE
  96.             last_white_move = move
  97.             turn = BLACK
  98.         else:
  99.             # 黑棋下
  100.             if last_white_move is not None:
  101.                 # 下对称点
  102.                 sym_move = symmetric_point(last_white_move[0], last_white_move[1])
  103.                 # 确保对称点是空的(根据推理应该为空)
  104.                 if board[sym_move[0]][sym_move[1]] != EMPTY:
  105.                     # 如果对称点不空,则随机下一个空点(但实际上不应该发生)
  106.                     # print("Warning: symmetric point not empty, random move.")
  107.                     move = random.choice(empty_points)
  108.                 else:
  109.                     move = sym_move
  110.             else:
  111.                 # 黑棋第一手已经下过,这里不会执行
  112.                 move = random.choice(empty_points)
  113.             board[move[0]][move[1]] = BLACK
  114.             turn = WHITE
  115.         # 更新空点列表
  116.         empty_points = [(i, j) for i in range(BOARD_SIZE) for j in range(BOARD_SIZE) if board[i][j] == EMPTY]
  117.     # 棋盘填满,计算胜负
  118.     black_score, white_score = compute_score(board)
  119.     # print(f"Black score: {black_score}, White score: {white_score}")
  120.     if black_score > white_score:
  121.         return BLACK
  122.     elif white_score > black_score:
  123.         return WHITE
  124.     else:
  125.         return 0  # 平局

  126. if __name__ == "__main__":
  127.     num_simulations = 1000
  128.     black_wins = 0
  129.     white_wins = 0
  130.     draws = 0
  131.     for i in range(num_simulations):
  132.         result = simulate()
  133.         if result == BLACK:
  134.             black_wins += 1
  135.         elif result == WHITE:
  136.             white_wins += 1
  137.         else:
  138.             draws += 1
  139.     print(f"Black wins: {black_wins}, White wins: {white_wins}, Draws: {draws}")
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 3 小时前 | 显示全部楼层
ydwb 发表于 2025-12-10 08:27
import numpy as np
import random

BOARD_SIZE =  ...


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

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

以下是完整的代码实现:

  1. import numpy as np
  2. import random

  3. BOARD_SIZE = 11
  4. EMPTY = 0
  5. BLACK = 1  # 先手
  6. WHITE = 2  # 后手

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

  10. def print_board(board):
  11.     """打印棋盘"""
  12.     print("  " + " ".join(str(i) for i in range(BOARD_SIZE)))
  13.     for i, row in enumerate(board):
  14.         row_str = []
  15.         for c in row:
  16.             if c == BLACK:
  17.                 row_str.append('X')
  18.             elif c == WHITE:
  19.                 row_str.append('O')
  20.             else:
  21.                 row_str.append('.')
  22.         print(f"{i} " + " ".join(row_str))
  23.     print()

  24. def count_liberties(board, x, y, color):
  25.     """计算指定位置连通块的气"""
  26.     from collections import deque
  27.    
  28.     if board[x][y] != color:
  29.         return 0
  30.    
  31.     visited = set()
  32.     q = deque()
  33.     q.append((x, y))
  34.     visited.add((x, y))
  35.     liberties = set()
  36.    
  37.     # 四个方向
  38.     directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
  39.    
  40.     while q:
  41.         cx, cy = q.popleft()
  42.         for dx, dy in directions:
  43.             nx, ny = cx + dx, cy + dy
  44.             if 0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE:
  45.                 if board[nx][ny] == EMPTY:
  46.                     liberties.add((nx, ny))
  47.                 elif board[nx][ny] == color and (nx, ny) not in visited:
  48.                     visited.add((nx, ny))
  49.                     q.append((nx, ny))
  50.    
  51.     return len(liberties)

  52. def remove_group(board, x, y, color):
  53.     """移除指定颜色的连通块"""
  54.     directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
  55.     to_remove = []
  56.     stack = [(x, y)]
  57.     visited = set()
  58.    
  59.     while stack:
  60.         cx, cy = stack.pop()
  61.         if (cx, cy) in visited:
  62.             continue
  63.         visited.add((cx, cy))
  64.         to_remove.append((cx, cy))
  65.         
  66.         for dx, dy in directions:
  67.             nx, ny = cx + dx, cy + dy
  68.             if (0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and
  69.                 board[nx][ny] == color and (nx, ny) not in visited):
  70.                 stack.append((nx, ny))
  71.    
  72.     for rx, ry in to_remove:
  73.         board[rx][ry] = EMPTY
  74.    
  75.     return len(to_remove)

  76. def is_valid_move(board, x, y, color):
  77.     """检查落子是否有效"""
  78.     if not (0 <= x < BOARD_SIZE and 0 <= y < BOARD_SIZE):
  79.         return False
  80.     if board[x][y] != EMPTY:
  81.         return False
  82.    
  83.     # 尝试落子
  84.     board[x][y] = color
  85.    
  86.     # 检查自己是否有气
  87.     if count_liberties(board, x, y, color) > 0:
  88.         board[x][y] = EMPTY
  89.         return True
  90.    
  91.     # 如果没有气,检查是否能提掉对方棋子
  92.     directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
  93.     opponent = WHITE if color == BLACK else BLACK
  94.    
  95.     for dx, dy in directions:
  96.         nx, ny = x + dx, y + dy
  97.         if (0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and
  98.             board[nx][ny] == opponent):
  99.             if count_liberties(board, nx, ny, opponent) == 0:
  100.                 # 能提子,是有效着法
  101.                 board[x][y] = EMPTY
  102.                 return True
  103.    
  104.     # 既没有气又不能提子,无效着法
  105.     board[x][y] = EMPTY
  106.     return False

  107. def make_move(board, x, y, color):
  108.     """执行落子,返回提子数量"""
  109.     board[x][y] = color
  110.     opponent = WHITE if color == BLACK else BLACK
  111.     total_captured = 0
  112.    
  113.     # 提掉无气的对方棋子
  114.     directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
  115.     to_check = []
  116.    
  117.     for dx, dy in directions:
  118.         nx, ny = x + dx, y + dy
  119.         if (0 <= nx < BOARD_SIZE and 0 <= ny < BOARD_SIZE and
  120.             board[nx][ny] == opponent):
  121.             to_check.append((nx, ny))
  122.    
  123.     for nx, ny in to_check:
  124.         if count_liberties(board, nx, ny, opponent) == 0:
  125.             total_captured += remove_group(board, nx, ny, opponent)
  126.    
  127.     # 检查自己是否还有气(理论上不可能,因为前面已验证)
  128.     if count_liberties(board, x, y, color) == 0:
  129.         remove_group(board, x, y, color)
  130.         return -1  # 自杀,不应发生
  131.    
  132.     return total_captured

  133. def get_empty_positions(board):
  134.     """获取所有空位置"""
  135.     positions = []
  136.     for i in range(BOARD_SIZE):
  137.         for j in range(BOARD_SIZE):
  138.             if board[i][j] == EMPTY:
  139.                 positions.append((i, j))
  140.     return positions

  141. def play_game():
  142.     """进行一局游戏"""
  143.     board = np.zeros((BOARD_SIZE, BOARD_SIZE), dtype=int)
  144.    
  145.     # 第一步:黑棋下天元
  146.     center = BOARD_SIZE // 2
  147.     make_move(board, center, center, BLACK)
  148.    
  149.     game_over = False
  150.     consecutive_passes = 0
  151.     turn = WHITE  # 白棋走第二步
  152.    
  153.     while not game_over:
  154.         # 检查是否还有有效着法
  155.         valid_moves = []
  156.         for i in range(BOARD_SIZE):
  157.             for j in range(BOARD_SIZE):
  158.                 if board[i][j] == EMPTY:
  159.                     if is_valid_move(board, i, j, turn):
  160.                         valid_moves.append((i, j))
  161.         
  162.         if not valid_moves:
  163.             consecutive_passes += 1
  164.             if consecutive_passes >= 2:  # 双方连续虚着
  165.                 game_over = True
  166.                 break
  167.             turn = WHITE if turn == BLACK else BLACK
  168.             continue
  169.         
  170.         consecutive_passes = 0
  171.         
  172.         if turn == WHITE:  # 白棋随机落子
  173.             x, y = random.choice(valid_moves)
  174.             make_move(board, x, y, WHITE)
  175.             
  176.             # 黑棋模仿策略
  177.             sym_x, sym_y = symmetric_point(x, y)
  178.             if (sym_x, sym_y) in valid_moves:
  179.                 make_move(board, sym_x, sym_y, BLACK)
  180.             else:
  181.                 # 对称点无效,尝试其他位置
  182.                 black_valid_moves = []
  183.                 for i, j in valid_moves:
  184.                     if is_valid_move(board, i, j, BLACK):
  185.                         black_valid_moves.append((i, j))
  186.                 if black_valid_moves:
  187.                     bx, by = random.choice(black_valid_moves)
  188.                     make_move(board, bx, by, BLACK)
  189.                 else:
  190.                     consecutive_passes += 1
  191.         
  192.         # 切换回合
  193.         turn = WHITE if turn == BLACK else BLACK
  194.    
  195.     # 计算胜负(简化版,只数子)
  196.     black_count = np.sum(board == BLACK)
  197.     white_count = np.sum(board == WHITE)
  198.    
  199.     if black_count > white_count:
  200.         return "BLACK"
  201.     elif white_count > black_count:
  202.         return "WHITE"
  203.     else:
  204.         return "DRAW"

  205. def main():
  206.     """主函数"""
  207.     num_games = 1000
  208.     black_wins = 0
  209.     white_wins = 0
  210.     draws = 0
  211.    
  212.     print(f"开始{num_games}局11x11围棋模拟...")
  213.     print("规则:黑棋使用模仿策略,白棋随机落子")
  214.     print("-" * 50)
  215.    
  216.     for i in range(num_games):
  217.         if i % 100 == 0:
  218.             print(f"已进行{i}局...")
  219.         
  220.         result = play_game()
  221.         if result == "BLACK":
  222.             black_wins += 1
  223.         elif result == "WHITE":
  224.             white_wins += 1
  225.         else:
  226.             draws += 1
  227.    
  228.     print("-" * 50)
  229.     print(f"统计结果(共{num_games}局):")
  230.     print(f"黑棋胜: {black_wins} ({black_wins/num_games*100:.1f}%)")
  231.     print(f"白棋胜: {white_wins} ({white_wins/num_games*100:.1f}%)")
  232.     print(f"平局: {draws} ({draws/num_games*100:.1f}%)")
  233.    
  234.     # 根据提问中的特殊规则分析
  235.     print("\n注意:这里使用了简化的胜负判定(数子法)")
  236.     print("实际围棋中,模仿策略通常会导致黑棋劣势")

  237. if __name__ == "__main__":
  238.     main()
复制代码


这个程序实现了:

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

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

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

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

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-12-10 11:31

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表