|
|
我们继续完善这个程序。首先,根据你提供的代码片段,我发现了几个问题需要修复和补充:
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[x][y] != 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[nx][ny] == EMPTY:
- liberties.add((nx, ny))
- elif board[nx][ny] == 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[nx][ny] == color and (nx, ny) not in visited):
- stack.append((nx, ny))
-
- for rx, ry in to_remove:
- board[rx][ry] = 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[x][y] != EMPTY:
- return False
-
- # 尝试落子
- board[x][y] = color
-
- # 检查自己是否有气
- if count_liberties(board, x, y, color) > 0:
- board[x][y] = 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[nx][ny] == opponent):
- if count_liberties(board, nx, ny, opponent) == 0:
- # 能提子,是有效着法
- board[x][y] = EMPTY
- return True
-
- # 既没有气又不能提子,无效着法
- board[x][y] = EMPTY
- return False
- def make_move(board, x, y, color):
- """执行落子,返回提子数量"""
- board[x][y] = 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[nx][ny] == 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[i][j] == 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[i][j] == 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 小助理,如未能正确解答您的问题,请继续追问。 |
|