新增五子棋游戏
This commit is contained in:
286
games/gomoku_logic.py
Normal file
286
games/gomoku_logic.py
Normal file
@@ -0,0 +1,286 @@
|
||||
"""五子棋游戏逻辑模块"""
|
||||
from typing import Optional, Tuple, List, Dict, Any
|
||||
|
||||
|
||||
def create_empty_board() -> List[List[int]]:
|
||||
"""创建空棋盘
|
||||
|
||||
Returns:
|
||||
15x15的二维列表,0表示空位
|
||||
"""
|
||||
return [[0] * 15 for _ in range(15)]
|
||||
|
||||
|
||||
def parse_coord(coord_str: str) -> Optional[Tuple[int, int]]:
|
||||
"""解析坐标字符串
|
||||
|
||||
Args:
|
||||
coord_str: 如 "A1", "O15", "h8"
|
||||
|
||||
Returns:
|
||||
(row, col) 或 None
|
||||
"""
|
||||
coord_str = coord_str.strip().upper()
|
||||
|
||||
if len(coord_str) < 2:
|
||||
return None
|
||||
|
||||
# 解析列(A-O)
|
||||
col_char = coord_str[0]
|
||||
if not ('A' <= col_char <= 'O'):
|
||||
return None
|
||||
col = ord(col_char) - ord('A')
|
||||
|
||||
# 解析行(1-15)
|
||||
try:
|
||||
row = int(coord_str[1:]) - 1
|
||||
if not (0 <= row <= 14):
|
||||
return None
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
return (row, col)
|
||||
|
||||
|
||||
def format_coord(row: int, col: int) -> str:
|
||||
"""格式化坐标
|
||||
|
||||
Args:
|
||||
row: 0-14
|
||||
col: 0-14
|
||||
|
||||
Returns:
|
||||
如 "A1", "O15"
|
||||
"""
|
||||
col_char = chr(ord('A') + col)
|
||||
row_num = row + 1
|
||||
return f"{col_char}{row_num}"
|
||||
|
||||
|
||||
def is_valid_position(row: int, col: int) -> bool:
|
||||
"""检查坐标是否在棋盘范围内
|
||||
|
||||
Args:
|
||||
row: 行号
|
||||
col: 列号
|
||||
|
||||
Returns:
|
||||
是否有效
|
||||
"""
|
||||
return 0 <= row <= 14 and 0 <= col <= 14
|
||||
|
||||
|
||||
def count_consecutive(board: List[List[int]], row: int, col: int,
|
||||
direction: Tuple[int, int], player: int) -> int:
|
||||
"""统计某方向连续同色棋子数(包括当前位置)
|
||||
|
||||
Args:
|
||||
board: 棋盘状态
|
||||
row, col: 起始位置
|
||||
direction: 方向向量 (dr, dc)
|
||||
player: 玩家 (1:黑, 2:白)
|
||||
|
||||
Returns:
|
||||
连续棋子数
|
||||
"""
|
||||
dr, dc = direction
|
||||
count = 1 # 包括当前位置
|
||||
|
||||
# 正方向
|
||||
r, c = row + dr, col + dc
|
||||
while is_valid_position(r, c) and board[r][c] == player:
|
||||
count += 1
|
||||
r += dr
|
||||
c += dc
|
||||
|
||||
# 反方向
|
||||
r, c = row - dr, col - dc
|
||||
while is_valid_position(r, c) and board[r][c] == player:
|
||||
count += 1
|
||||
r -= dr
|
||||
c -= dc
|
||||
|
||||
return count
|
||||
|
||||
|
||||
def check_win(board: List[List[int]], row: int, col: int, player: int) -> bool:
|
||||
"""检查是否获胜(恰好五连珠)
|
||||
|
||||
Args:
|
||||
board: 棋盘状态
|
||||
row, col: 最后落子位置
|
||||
player: 玩家 (1:黑, 2:白)
|
||||
|
||||
Returns:
|
||||
是否五连珠获胜
|
||||
"""
|
||||
# 四个方向:横、竖、左斜、右斜
|
||||
directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
|
||||
|
||||
for direction in directions:
|
||||
count = count_consecutive(board, row, col, direction, player)
|
||||
if count == 5:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def analyze_line(board: List[List[int]], row: int, col: int,
|
||||
direction: Tuple[int, int], player: int) -> Dict[str, Any]:
|
||||
"""分析某方向的棋型
|
||||
|
||||
Args:
|
||||
board: 棋盘状态
|
||||
row, col: 待分析位置(假设已落子)
|
||||
direction: 方向向量
|
||||
player: 玩家
|
||||
|
||||
Returns:
|
||||
{
|
||||
"consecutive": int, # 连续数
|
||||
"left_open": bool, # 左侧是否开放
|
||||
"right_open": bool, # 右侧是否开放
|
||||
"pattern": str # 棋型类型
|
||||
}
|
||||
"""
|
||||
dr, dc = direction
|
||||
|
||||
# 统计正方向连续数
|
||||
right_count = 0
|
||||
r, c = row + dr, col + dc
|
||||
while is_valid_position(r, c) and board[r][c] == player:
|
||||
right_count += 1
|
||||
r += dr
|
||||
c += dc
|
||||
right_open = is_valid_position(r, c) and board[r][c] == 0
|
||||
|
||||
# 统计反方向连续数
|
||||
left_count = 0
|
||||
r, c = row - dr, col - dc
|
||||
while is_valid_position(r, c) and board[r][c] == player:
|
||||
left_count += 1
|
||||
r -= dr
|
||||
c -= dc
|
||||
left_open = is_valid_position(r, c) and board[r][c] == 0
|
||||
|
||||
# 总连续数(包括当前位置)
|
||||
consecutive = left_count + 1 + right_count
|
||||
|
||||
# 判定棋型
|
||||
pattern = "none"
|
||||
|
||||
if consecutive >= 6:
|
||||
pattern = "overline"
|
||||
elif consecutive == 5:
|
||||
pattern = "five"
|
||||
elif consecutive == 4:
|
||||
if left_open and right_open:
|
||||
pattern = "live_four"
|
||||
elif left_open or right_open:
|
||||
pattern = "rush_four"
|
||||
elif consecutive == 3:
|
||||
if left_open and right_open:
|
||||
pattern = "live_three"
|
||||
elif left_open or right_open:
|
||||
pattern = "sleep_three"
|
||||
|
||||
return {
|
||||
"consecutive": consecutive,
|
||||
"left_open": left_open,
|
||||
"right_open": right_open,
|
||||
"pattern": pattern
|
||||
}
|
||||
|
||||
|
||||
def check_forbidden(board: List[List[int]], row: int, col: int) -> Tuple[bool, str]:
|
||||
"""检查黑方禁手
|
||||
|
||||
Args:
|
||||
board: 棋盘状态(不包含待落子)
|
||||
row, col: 待落子位置
|
||||
|
||||
Returns:
|
||||
(是否禁手, 禁手类型)
|
||||
"""
|
||||
# 只有黑方(玩家1)有禁手
|
||||
player = 1
|
||||
|
||||
# 临时落子
|
||||
original_value = board[row][col]
|
||||
board[row][col] = player
|
||||
|
||||
# 四个方向
|
||||
directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
|
||||
|
||||
live_threes = 0
|
||||
fours = 0
|
||||
has_overline = False
|
||||
|
||||
for direction in directions:
|
||||
analysis = analyze_line(board, row, col, direction, player)
|
||||
|
||||
if analysis["pattern"] == "overline":
|
||||
has_overline = True
|
||||
elif analysis["pattern"] == "live_three":
|
||||
live_threes += 1
|
||||
elif analysis["pattern"] in ["live_four", "rush_four"]:
|
||||
fours += 1
|
||||
|
||||
# 恢复棋盘
|
||||
board[row][col] = original_value
|
||||
|
||||
# 判定禁手
|
||||
if has_overline:
|
||||
return True, "长连禁手"
|
||||
if live_threes >= 2:
|
||||
return True, "三三禁手"
|
||||
if fours >= 2:
|
||||
return True, "四四禁手"
|
||||
|
||||
return False, ""
|
||||
|
||||
|
||||
def render_board(board: List[List[int]], last_move: Optional[Tuple[int, int]] = None) -> str:
|
||||
"""渲染棋盘为字符串
|
||||
|
||||
Args:
|
||||
board: 棋盘状态
|
||||
last_move: 最后落子位置(可选,用于标记)
|
||||
|
||||
Returns:
|
||||
棋盘的字符串表示
|
||||
"""
|
||||
lines = []
|
||||
|
||||
# 列标题
|
||||
col_labels = " " + " ".join([chr(ord('A') + i) for i in range(15)])
|
||||
lines.append(col_labels)
|
||||
|
||||
# 绘制棋盘
|
||||
for row in range(15):
|
||||
row_num = f"{row + 1:2d}" # 右对齐行号
|
||||
row_cells = []
|
||||
|
||||
for col in range(15):
|
||||
cell = board[row][col]
|
||||
|
||||
# 标记最后落子
|
||||
if last_move and last_move == (row, col):
|
||||
if cell == 1:
|
||||
row_cells.append("⚫")
|
||||
elif cell == 2:
|
||||
row_cells.append("⚪")
|
||||
else:
|
||||
row_cells.append("➕")
|
||||
else:
|
||||
if cell == 0:
|
||||
row_cells.append("➕")
|
||||
elif cell == 1:
|
||||
row_cells.append("⚫")
|
||||
elif cell == 2:
|
||||
row_cells.append("⚪")
|
||||
|
||||
lines.append(f" {row_num} {' '.join(row_cells)}")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
Reference in New Issue
Block a user