import pygame
import sys
import numpy as np
import time
from pygame.locals import QUIT, KEYDOWN, MOUSEBUTTONDOWN
import random
import threading
# 初始化pygame
pygame.init()
screen = pygame.display.set_mode((670, 670))
screen_color = [238, 154, 73] # 棋盘背景色
line_color = [0, 0, 0] # 棋盘线颜色
over_pos = [] # 已落子位置
white_color = [255, 255, 255] # 白棋(AI)
black_color = [0, 0, 0] # 黑棋(玩家)
# 游戏状态
game_over = False
winner = 0
thinking = False # AI思考标志
# 评分常量
EMPTY = 0
PLAYER = 1 # 玩家
AI = 2 # AI
INF = float('inf')
# 更精细的棋型评分表
FIVE = 10000000 # 五连
OPEN_FOUR = 100000 # 活四
FOUR = 10000 # 冲四
OPEN_THREE = 1000 # 活三
THREE = 200 # 眠三
OPEN_TWO = 100 # 活二
TWO = 10 # 眠二
BLOCKED = -1 # 被阻挡的位置
# 威胁级别
THREAT_LEVEL = {
FIVE: 100,
OPEN_FOUR: 90,
FOUR: 80,
OPEN_THREE: 70,
THREE: 40,
OPEN_TWO: 20,
TWO: 5
}
def check_win(over_pos):
"""检查是否有玩家获胜"""
mp = np.zeros([15, 15], dtype=int)
for val in over_pos:
x = int((val[0][0] - 27) / 44)
y = int((val[0][1] - 27) / 44)
if val[1] == white_color:
mp[x][y] = AI
else:
mp[x][y] = PLAYER
directions = [[1, 0], [0, 1], [1, 1], [1, -1]] # 水平、垂直、对角线、反对角线
for i in range(15):
for j in range(15):
if mp[i][j] == 0:
continue
player = mp[i][j]
for dx, dy in directions:
count = 1
line = [[i, j]]
# 正向检查
for k in range(1, 5):
x = i + k * dx
y = j + k * dy
if 0 <= x < 15 and 0 <= y < 15 and mp[x][y] == player:
count += 1
line.append([x, y])
else:
break
# 反向检查
for k in range(1, 5):
x = i - k * dx
y = j - k * dy
if 0 <= x < 15 and 0 <= y < 15 and mp[x][y] == player:
count += 1
line.insert(0, [x, y])
else:
break
if count >= 5:
return [player, line]
return [0, []]
def find_pos(x, y):
"""将鼠标位置转换为棋盘坐标"""
for i in range(27, 670, 44):
for j in range(27, 670, 44):
if abs(x - i) <= 22 and abs(y - j) <= 22:
return i, j
return x, y
def check_over_pos(x, y, over_pos):
"""检查位置是否已有棋子"""
for val in over_pos:
if val[0][0] == x and val[0][1] == y:
return False
return True
def get_line_score(line, player):
"""计算一行棋型的分数"""
score = 0
count = 0 # 连续棋子数
open_ends = 0 # 开放端数量
block_ends = 0 # 封闭端数量
# 检查连续性和开放端
for i in range(len(line)):
if line[i] == player:
count += 1
elif line[i] == EMPTY:
if i > 0 and i < len(line) - 1:
open_ends += 1
else:
block_ends += 1
else: # 对手棋子
block_ends += 1
break
# 根据棋型评分
if count >= 5:
return FIVE
elif count == 4:
if open_ends >= 2:
return OPEN_FOUR
elif open_ends == 1:
return FOUR
elif count == 3:
if open_ends >= 2:
return OPEN_THREE
elif open_ends == 1:
return THREE
elif count == 2:
if open_ends >= 2:
return OPEN_TWO
elif open_ends == 1:
return TWO
return score
def evaluate_position(mp, x, y, player):
"""评估位置的价值 - 改进版"""
if not (0 <= x < 15 and 0 <= y < 15) or mp[x][y] != EMPTY:
return 0
opponent = PLAYER if player == AI else AI
score = 0
# 检查四个方向: 水平、垂直、两条对角线
directions = [[(0, 1), (0, -1)], # 水平
[(1, 0), (-1, 0)], # 垂直
[(1, 1), (-1, -1)], # 主对角线
[(1, -1), (-1, 1)]] # 反对角线
for dir_pair in directions:
# 获取整个方向的棋型
line = []
for dx, dy in [(-1, -1), (0, 0), (1, 1)]: # 扩展为3个点的窗口
for i in range(-4, 5): # 检查9个点的窗口
nx, ny = x + dx * i, y + dy * i
if 0 <= nx < 15 and 0 <= ny < 15:
line.append(mp[nx][ny])
else:
line.append(BLOCKED) # 边界阻挡
# 计算该方向的分数
dir_score = get_line_score(line, player)
# 检查对手的威胁
opponent_score = get_line_score(line, opponent)
if opponent_score >= OPEN_THREE:
# 优先防守对手的威胁
dir_score += opponent_score * 1.5
score += dir_score
# 位置加成:中心位置更有价值
center_x, center_y = 7, 7
distance = abs(x - center_x) + abs(y - center_y)
center_bonus = max(0, 50 - distance * 5)
score += center_bonus
return score
def evaluate_board(mp):
"""评估整个棋盘状态"""
ai_score = 0
player_score = 0
# 评估AI的分数
for i in range(15):
for j in range(15):
if mp[i][j] == EMPTY:
ai_score += evaluate_position(mp, i, j, AI)
# 评估玩家的分数
for i in range(15):
for j in range(15):
if mp[i][j] == EMPTY:
player_score += evaluate_position(mp, i, j, PLAYER)
# AI进攻与防守的权重
return ai_score * 1.2 - player_score * 1.1
def get_valid_moves(mp):
"""获取有效的移动位置 - 改进版"""
moves = []
# 只考虑已落子周围的位置,减少搜索空间
if not over_pos:
# 若棋盘为空,返回中心位置
return [(27 + 44 * 7, 27 + 44 * 7)]
# 找到所有已落子位置
occupied = set()
for pos in over_pos:
x = int((pos[0][0] - 27) / 44)
y = int((pos[0][1] - 27) / 44)
occupied.add((x, y))
# 考虑已落子周围的空位
directions = [[-1, -1], [-1, 0], [-1, 1],
[0, -1], [0, 1],
[1, -1], [1, 0], [1, 1]]
candidate = set()
for (x, y) in occupied:
for dx, dy in directions:
nx, ny = x + dx, y + dy
if 0 <= nx < 15 and 0 <= ny < 15 and (nx, ny) not in occupied:
candidate.add((nx, ny))
# 转换为棋盘坐标并评估分数
scored_moves = []
for (x, y) in candidate:
# 评估进攻价值
attack_score = evaluate_position(mp, x, y, AI)
# 评估防守价值
defense_score = evaluate_position(mp, x, y, PLAYER)
# 综合评分:进攻和防守的平衡
total_score = attack_score + defense_score * 0.8
scored_moves.append((total_score, x, y))
# 按分数排序
scored_moves.sort(reverse=True)
# 取前12个最佳位置
return [(x * 44 + 27, y * 44 + 27) for (score, x, y) in scored_moves[:12]]
def minimax(mp, depth, alpha, beta, is_maximizing, start_time, time_limit=1.0):
"""带Alpha-Beta剪枝的Minimax算法 - 改进版"""
# 检查超时
if time.time() - start_time > time_limit:
return None, None
res = check_win(over_pos)
if res[0] == AI:
return INF, None
elif res[0] == PLAYER:
return -INF, None
if depth == 0:
return evaluate_board(mp), None
valid_moves = get_valid_moves(mp)
if not valid_moves:
return 0, None
best_move = None
if is_maximizing:
max_score = -INF
for move in valid_moves:
# 检查超时
if time.time() - start_time > time_limit:
return None, None
x = int((move[0] - 27) / 44)
y = int((move[1] - 27) / 44)
if mp[x][y] != EMPTY:
continue
mp[x][y] = AI
over_pos.append([move, white_color])
score, _ = minimax(mp, depth - 1, alpha, beta, False, start_time, time_limit)
mp[x][y] = EMPTY
over_pos.pop()
if score is None: # 超时
return None, None
if score > max_score:
max_score = score
best_move = move
alpha = max(alpha, score)
if beta <= alpha:
break # Beta剪枝
return max_score, best_move
else:
min_score = INF
for move in valid_moves:
# 检查超时
if time.time() - start_time > time_limit:
return None, None
x = int((move[0] - 27) / 44)
y = int((move[1] - 27) / 44)
if mp[x][y] != EMPTY:
continue
mp[x][y] = PLAYER
over_pos.append([move, black_color])
score, _ = minimax(mp, depth - 1, alpha, beta, True, start_time, time_limit)
mp[x][y] = EMPTY
over_pos.pop()
if score is None: # 超时
return None, None
if score < min_score:
min_score = score
best_move = move
beta = min(beta, score)
if beta <= alpha:
break # Alpha剪枝
return min_score, best_move
def ai_move(over_pos):
"""AI决策函数 - 改进版"""
if not over_pos:
# 第一步下在中心
return [(27 + 44 * 7, 27 + 44 * 7), white_color]
# 创建棋盘状态
mp = np.zeros([15, 15], dtype=int)
for val in over_pos:
x = int((val[0][0] - 27) / 44)
y = int((val[0][1] - 27) / 44)
if val[1] == white_color:
mp[x][y] = AI
else:
mp[x][y] = PLAYER
# 检查是否有立即获胜的机会
for i in range(15):
for j in range(15):
if mp[i][j] == EMPTY:
# 检查AI是否可以立即获胜
mp[i][j] = AI
res = check_win([[(i * 44 + 27, j * 44 + 27), white_color]] + over_pos)
mp[i][j] = EMPTY
if res[0] == AI:
return [(i * 44 + 27, j * 44 + 27), white_color]
# 检查玩家威胁
mp[i][j] = PLAYER
res = check_win([[(i * 44 + 27, j * 44 + 27), black_color]] + over_pos)
mp[i][j] = EMPTY
if res[0] == PLAYER:
# 必须防守这个位置
return [(i * 44 + 27, j * 44 + 27), white_color]
# 使用Minimax搜索最佳移动
depth = 4 # 搜索深度
start_time = time.time()
time_limit = 1.0 # 最多思考1秒
# 使用迭代加深搜索
best_move = None
best_score = -INF
for current_depth in range(1, depth + 1):
score, move = minimax(mp, current_depth, -INF, INF, True, start_time, time_limit)
# 检查是否超时
if score is None:
break
if score > best_score:
best_score = score
best_move = move
# 检查剩余时间
if time.time() - start_time > time_limit * 0.8:
break
if best_move:
return [best_move, white_color]
else:
# 如果找不到最佳移动,选择评分最高的位置
valid_moves = get_valid_moves(mp)
if valid_moves:
return [valid_moves[0], white_color]
return None
# 选择游戏模式
game_mode = None
while game_mode not in ['P_vs_P', 'P_vs_ai']:
print("请选择游戏模式:")
print("1. 人与人对战")
print("2. 人与 AI 对战")
choice = input("输入 1 或 2 选择模式:")
if choice == '1':
game_mode = 'P_vs_P'
elif choice == '2':
game_mode = 'P_vs_ai'
class Gomoku:
def __init__(self, mode):
self.mp = [[0] * 15 for _ in range(15)]
self.game_mode = mode
self.last_draw_time = time.time()
self.ai_thinking = False
self.ai_move_result = None
self.ai_thread = None
def draw_board(self):
"""绘制棋盘和棋子"""
screen.fill(screen_color)
# 绘制棋盘
for i in range(27, 670, 44):
pygame.draw.line(screen, line_color, [i, 27], [i, 670 - 27], 4 if i in [27, 670 - 27] else 2)
pygame.draw.line(screen, line_color, [27, i], [670 - 27, i], 4 if i in [27, 670 - 27] else 2)
pygame.draw.circle(screen, line_color, [27 + 44 * 7, 27 + 44 * 7], 8)
# 绘制棋子
for val in over_pos:
pygame.draw.circle(screen, val[1], val[0], 20)
# 判断胜负
if game_over and winner != 0:
for pos in winner_line:
x, y = pos[0] * 44 + 27, pos[1] * 44 + 27
pygame.draw.rect(screen, [238, 48, 167], [x - 22, y - 22, 44, 44], 2)
# 显示胜利信息
font = pygame.font.SysFont(None, 55)
if winner == PLAYER:
text = font.render("玩家胜利!", True, (255, 0, 0))
else:
text = font.render("AI胜利!", True, (255, 0, 0))
screen.blit(text, (250, 300))
# 显示AI思考状态
if self.ai_thinking:
font = pygame.font.SysFont(None, 36)
text = font.render("AI思考中...", True, (50, 50, 200))
screen.blit(text, (270, 10))
def handle_ai_turn(self):
"""处理AI回合"""
global over_pos, game_over, winner, winner_line
if not self.ai_thinking:
self.ai_thinking = True
# 创建新线程执行AI计算
self.ai_thread = threading.Thread(target=self.ai_thread_func)
self.ai_thread.start()
# 检查AI计算是否完成
if self.ai_move_result is not None:
over_pos.append(self.ai_move_result)
self.ai_move_result = None
self.ai_thinking = False
# 检查AI是否获胜
res = check_win(over_pos)
if res[0] != 0:
game_over = True
winner = res[0]
winner_line = res[1]
def ai_thread_func(self):
"""AI计算线程函数"""
self.ai_move_result = ai_move(over_pos)
def play(self):
global over_pos, game_over, winner, winner_line
clock = pygame.time.Clock()
while True:
# 处理事件队列
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
elif event.key == pygame.K_r: # 重新开始
over_pos = []
game_over = False
winner = 0
self.ai_thinking = False
self.ai_move_result = None
elif event.type == MOUSEBUTTONDOWN and event.button == 1 and not game_over:
# 玩家回合
if self.game_mode == 'P_vs_P' or (self.game_mode == 'P_vs_ai' and len(over_pos) % 2 == 0):
x, y = pygame.mouse.get_pos()
x, y = find_pos(x, y)
if check_over_pos(x, y, over_pos):
over_pos.append([[x, y], black_color if len(over_pos) % 2 == 0 else white_color])
# 检查玩家是否获胜
res = check_win(over_pos)
if res[0] != 0:
game_over = True
winner = res[0]
winner_line = res[1]
# 检查是否需要AI回合
if not game_over and self.game_mode == 'P_vs_ai' and len(over_pos) % 2 == 1:
self.handle_ai_turn()
# 绘制棋盘
self.draw_board()
pygame.display.update()
# 控制帧率
clock.tick(60)
# 全局变量
game_over = False
winner = 0
winner_line = []
# 创建游戏实例并开始游戏
game = Gomoku(game_mode)
game.play()
帮我完善ai,让他更加聪明,甚至比人还聪明,优化不足的地方,然后输出完整代码给我