zshxsy/gomoku_game.py
st2411020112 c745693acb refactor: 重构项目结构并更新依赖配置
删除旧版AI应用文件及配置
添加.gitignore忽略规则
更新pyproject.toml依赖配置
迁移chainlit配置文件及翻译资源
2026-01-09 00:24:50 +08:00

392 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import pygame
import sys
# 初始化pygame
pygame.init()
# 游戏常量设置
SCREEN_SIZE = 600 # 窗口大小
GRID_SIZE = 30 # 每个格子的大小
LINE_WIDTH = 2 # 棋盘线宽度
BOARD_SIZE = 19 # 棋盘大小(19x19)
PIECE_RADIUS = 14 # 棋子半径
PIECE_WIDTH = 2 # 棋子边框宽度
# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BG_COLOR = (240, 220, 180) # 棋盘背景色(木纹色)
LINE_COLOR = (100, 100, 100)# 棋盘线颜色
# 计算棋盘起始位置(居中显示)
START_X = (SCREEN_SIZE - (BOARD_SIZE - 1) * GRID_SIZE) // 2
START_Y = (SCREEN_SIZE - (BOARD_SIZE - 1) * GRID_SIZE) // 2
# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_SIZE, SCREEN_SIZE))
pygame.display.set_caption("五子棋")
# 游戏模式0表示双人对战1表示AI对战
game_mode = 1 # 默认AI对战
mode_selected = False # 是否已选择游戏模式
# 初始化棋盘数据0表示空1表示黑子2表示白子
board = [[0 for _ in range(BOARD_SIZE)] for _ in range(BOARD_SIZE)]
current_player = 1 # 1表示黑方2表示白方
game_over = False
winner = None
# AI评估权重
WEIGHTS = {
'win': 100000, # 获胜
'block_win': 50000, # 阻挡对方获胜
'four': 10000, # 四子连珠
'block_four': 5000, # 阻挡对方四子
'three': 1000, # 三子连珠
'block_three': 500, # 阻挡对方三子
'two': 100, # 二子连珠
'block_two': 50, # 阻挡对方二子
'one': 10, # 一子
'block_one': 5 # 阻挡对方一子
}
def draw_board():
"""绘制棋盘"""
# 填充背景色
screen.fill(BG_COLOR)
# 绘制棋盘网格线
for i in range(BOARD_SIZE):
# 竖线
pygame.draw.line(
screen, LINE_COLOR,
(START_X + i * GRID_SIZE, START_Y),
(START_X + i * GRID_SIZE, START_Y + (BOARD_SIZE - 1) * GRID_SIZE),
LINE_WIDTH
)
# 横线
pygame.draw.line(
screen, LINE_COLOR,
(START_X, START_Y + i * GRID_SIZE),
(START_X + (BOARD_SIZE - 1) * GRID_SIZE, START_Y + i * GRID_SIZE),
LINE_WIDTH
)
# 绘制棋子
for row in range(BOARD_SIZE):
for col in range(BOARD_SIZE):
if board[row][col] != 0:
center_x = START_X + col * GRID_SIZE
center_y = START_Y + row * GRID_SIZE
color = BLACK if board[row][col] == 1 else WHITE
# 绘制棋子
pygame.draw.circle(screen, color, (center_x, center_y), PIECE_RADIUS)
# 绘制棋子边框(增加视觉效果)
pygame.draw.circle(screen, BLACK, (center_x, center_y), PIECE_RADIUS, PIECE_WIDTH)
def get_click_pos(pos):
"""将鼠标点击位置转换为棋盘坐标"""
x, y = pos
# 计算所在格子
col = (x - START_X + GRID_SIZE // 2) // GRID_SIZE
row = (y - START_Y + GRID_SIZE // 2) // GRID_SIZE
# 检查是否在棋盘范围内
if 0 <= row < BOARD_SIZE and 0 <= col < BOARD_SIZE:
return (row, col)
return None
def check_win(row, col):
"""检查落子后是否获胜"""
player = board[row][col]
directions = [
(0, 1), # 横向
(1, 0), # 纵向
(1, 1), # 正对角线
(1, -1) # 反对角线
]
for dr, dc in directions:
count = 1
# 正方向检查
r, c = row + dr, col + dc
while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and board[r][c] == player:
count += 1
r += dr
c += dc
# 反方向检查
r, c = row - dr, col - dc
while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and board[r][c] == player:
count += 1
r -= dr
c -= dc
# 五子连珠则获胜
if count >= 5:
return True
return False
def evaluate_position(row, col, player):
"""评估指定位置对玩家的价值"""
if board[row][col] != 0:
return -1000000 # 已经有棋子的位置
score = 0
opponent = 1 if player == 2 else 2
# 模拟落子
board[row][col] = player
# 检查是否获胜
if check_win(row, col):
score += WEIGHTS['win']
# 评估各个方向的连珠情况
directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
for dr, dc in directions:
# 检查当前玩家的连珠
count = 1
# 正方向
r, c = row + dr, col + dc
while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and board[r][c] == player:
count += 1
r += dr
c += dc
# 反方向
r, c = row - dr, col - dc
while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and board[r][c] == player:
count += 1
r -= dr
c -= dc
# 根据连珠数量加分
if count == 4:
score += WEIGHTS['four']
elif count == 3:
score += WEIGHTS['three']
elif count == 2:
score += WEIGHTS['two']
elif count == 1:
score += WEIGHTS['one']
# 撤销模拟落子
board[row][col] = 0
# 模拟对方落子,检查需要阻挡的情况
board[row][col] = opponent
if check_win(row, col):
score += WEIGHTS['block_win']
for dr, dc in directions:
# 检查对方的连珠
count = 1
# 正方向
r, c = row + dr, col + dc
while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and board[r][c] == opponent:
count += 1
r += dr
c += dc
# 反方向
r, c = row - dr, col - dc
while 0 <= r < BOARD_SIZE and 0 <= c < BOARD_SIZE and board[r][c] == opponent:
count += 1
r -= dr
c -= dc
# 根据连珠数量加分(阻挡)
if count == 4:
score += WEIGHTS['block_four']
elif count == 3:
score += WEIGHTS['block_three']
elif count == 2:
score += WEIGHTS['block_two']
elif count == 1:
score += WEIGHTS['block_one']
# 撤销模拟落子
board[row][col] = 0
# 中心位置加成
center_row, center_col = BOARD_SIZE // 2, BOARD_SIZE // 2
distance = abs(row - center_row) + abs(col - center_col)
score += (10 - distance) * 2
return score
def ai_move():
"""AI落子"""
best_score = -float('inf')
best_move = None
# 遍历棋盘上的所有空位
for row in range(BOARD_SIZE):
for col in range(BOARD_SIZE):
if board[row][col] == 0:
# 评估该位置的价值
score = evaluate_position(row, col, current_player)
if score > best_score:
best_score = score
best_move = (row, col)
# 执行最佳落子
if best_move:
row, col = best_move
board[row][col] = current_player
return (row, col)
return None
def show_winner():
"""显示获胜信息"""
# 尝试使用系统中文字体
try:
font = pygame.font.SysFont(["SimHei", "Microsoft YaHei", "Arial"], 60)
except:
font = pygame.font.Font(None, 60)
text = f"{'黑方' if winner == 1 else '白方'}获胜!"
text_surface = font.render(text, True, (255, 0, 0))
text_rect = text_surface.get_rect(center=(SCREEN_SIZE//2, SCREEN_SIZE//2))
screen.blit(text_surface, text_rect)
# 显示重新开始提示
try:
font_small = pygame.font.SysFont(["SimHei", "Microsoft YaHei", "Arial"], 30)
except:
font_small = pygame.font.Font(None, 30)
restart_text = "按R键重新开始 | 按Q键退出"
restart_surface = font_small.render(restart_text, True, BLACK)
restart_rect = restart_surface.get_rect(center=(SCREEN_SIZE//2, SCREEN_SIZE//2 + 50))
screen.blit(restart_surface, restart_rect)
def show_mode_selection():
"""显示游戏模式选择界面"""
# 填充背景色
screen.fill(BG_COLOR)
# 显示标题
try:
title_font = pygame.font.SysFont(["SimHei", "Microsoft YaHei", "Arial"], 48)
except:
title_font = pygame.font.Font(None, 48)
title_text = "五子棋"
title_surface = title_font.render(title_text, True, BLACK)
title_rect = title_surface.get_rect(center=(SCREEN_SIZE//2, SCREEN_SIZE//2 - 100))
screen.blit(title_surface, title_rect)
# 显示模式选择
try:
font = pygame.font.SysFont(["SimHei", "Microsoft YaHei", "Arial"], 36)
except:
font = pygame.font.Font(None, 36)
# 双人对战选项
pvp_text = "1. 双人对战"
pvp_surface = font.render(pvp_text, True, BLACK)
pvp_rect = pvp_surface.get_rect(center=(SCREEN_SIZE//2, SCREEN_SIZE//2))
screen.blit(pvp_surface, pvp_rect)
# AI对战选项
ai_text = "2. AI对战"
ai_surface = font.render(ai_text, True, BLACK)
ai_rect = ai_surface.get_rect(center=(SCREEN_SIZE//2, SCREEN_SIZE//2 + 60))
screen.blit(ai_surface, ai_rect)
# 显示操作提示
try:
hint_font = pygame.font.SysFont(["SimHei", "Microsoft YaHei", "Arial"], 24)
except:
hint_font = pygame.font.Font(None, 24)
hint_text = "请按数字键选择游戏模式"
hint_surface = hint_font.render(hint_text, True, BLACK)
hint_rect = hint_surface.get_rect(center=(SCREEN_SIZE//2, SCREEN_SIZE//2 + 120))
screen.blit(hint_surface, hint_rect)
pygame.display.update()
def restart_game():
"""重新开始游戏"""
global board, current_player, game_over, winner, mode_selected
board = [[0 for _ in range(BOARD_SIZE)] for _ in range(BOARD_SIZE)]
current_player = 1
game_over = False
winner = None
mode_selected = False # 重新开始时需要重新选择模式
def main():
"""游戏主循环"""
global current_player, game_over, winner, game_mode, mode_selected
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# 键盘事件处理
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r: # 按R重新开始
restart_game()
if event.key == pygame.K_q: # 按Q退出
pygame.quit()
sys.exit()
# 游戏模式选择
if not mode_selected:
if event.key == pygame.K_1:
game_mode = 0 # 双人对战
mode_selected = True
elif event.key == pygame.K_2:
game_mode = 1 # AI对战
mode_selected = True
# 鼠标点击落子(游戏未结束且已选择模式时)
if event.type == pygame.MOUSEBUTTONDOWN and not game_over and mode_selected:
pos = pygame.mouse.get_pos()
board_pos = get_click_pos(pos)
if board_pos:
row, col = board_pos
# 检查位置是否为空
if board[row][col] == 0:
board[row][col] = current_player
# 检查是否获胜
if check_win(row, col):
game_over = True
winner = current_player
else:
# 切换玩家
current_player = 2 if current_player == 1 else 1
# 如果是AI对战模式且当前玩家是AI白方则AI落子
if game_mode == 1 and current_player == 2:
ai_pos = ai_move()
if ai_pos:
ai_row, ai_col = ai_pos
# 检查AI落子后是否获胜
if check_win(ai_row, ai_col):
game_over = True
winner = current_player
else:
# 切换回玩家
current_player = 1
# 如果未选择模式,显示模式选择界面
if not mode_selected:
show_mode_selection()
else:
# 绘制游戏界面
draw_board()
# 如果游戏结束,显示获胜信息
if game_over:
show_winner()
# 更新屏幕显示
pygame.display.update()
clock.tick(60)
if __name__ == "__main__":
main()