周末午后,我盯着电脑屏幕上的五子棋残局发呆——这已经是第三次输给朋友了。作为程序员,突然萌生一个想法:能不能用代码教会电脑下棋?于是开始了这段用Python构建五子棋AI的奇妙旅程。本文将带你从棋盘绘制开始,逐步实现一个具备基础决策能力的AI对手,最终完成完整的人机对战系统。
首先确保安装必要的库:
bash复制pip install pygame numpy
创建基础窗口的代码骨架:
python复制import pygame
import numpy as np
def init_game():
pygame.init()
screen = pygame.display.set_mode((615, 615))
pygame.display.set_caption('五子棋AI')
return screen
screen = init_game()
标准五子棋采用19×19网格,我们通过精确计算实现视觉效果:
python复制def draw_board(screen):
# 棋盘底色
screen.fill("#DD954F")
# 三层边框设计
border_colors = ['#121010', "#DD954F", '#121010']
for i, color in enumerate(border_colors):
border = pygame.Surface((603-18*i, 603-18*i))
border.fill(color)
screen.blit(border, (6.5+6*i, 6.5+6*i))
# 绘制网格线
grid_size = 31
for i in range(19):
pygame.draw.line(screen, '#121010', (20, 20+32*i), (596, 20+32*i), 2)
pygame.draw.line(screen, '#121010', (20+32*i, 20), (20+32*i, 596), 2)
# 添加星位标记
star_points = [(3,3), (9,3), (15,3), (3,9), (9,9),
(15,9), (3,15), (9,15), (15,15)]
for x,y in star_points:
pygame.draw.circle(screen, '#121010', [20+32*x, 20+32*y], 5)
使用numpy数组记录棋盘状态:
python复制board_state = np.zeros((19, 19)) # 0=空 1=黑 2=白
def place_piece(x, y, player):
if board_state[x][y] == 0:
board_state[x][y] = 1 if player == 'black' else 2
return True
return False
四方向检测的优化实现:
python复制def check_win(x, y, player):
directions = [(1,0), (0,1), (1,1), (1,-1)] # 横竖斜四个方向
piece = 1 if player == 'black' else 2
for dx, dy in directions:
count = 1 # 当前落子
# 正向检测
nx, ny = x+dx, y+dy
while 0<=nx<19 and 0<=ny<19 and board_state[nx][ny]==piece:
count += 1
nx += dx
ny += dy
# 反向检测
nx, ny = x-dx, y-dy
while 0<=nx<19 and 0<=ny<19 and board_state[nx][ny]==piece:
count += 1
nx -= dx
ny -= dy
if count >= 5:
return True
return False
AI的核心是预定义的棋型模式库:
python复制PATTERNS = {
# 进攻模式
'five': [1,1,1,1,1],
'open_four': [0,1,1,1,1,0],
'half_four': [0,1,1,1,1,2],
# 防守模式
'block_four': [2,1,1,1,1,0],
'open_three': [0,1,1,1,0],
'half_three': [0,1,1,1,2]
}
基于模式匹配的位置评估:
python复制def evaluate_position():
score_map = np.zeros((19,19))
for i in range(19):
for j in range(19):
if board_state[i][j] != 0:
continue
# 模拟落子
board_state[i][j] = 2 # AI执白
# 四方向扫描
for dx, dy in [(1,0), (0,1), (1,1), (1,-1)]:
line = []
for k in range(-4, 5):
x, y = i + dx*k, j + dy*k
if 0 <= x < 19 and 0 <= y < 19:
line.append(board_state[x][y])
else:
line.append(-1) # 边界
# 模式匹配
for name, pattern in PATTERNS.items():
if match_pattern(line, pattern):
score_map[i][j] += PATTERN_SCORES[name]
# 恢复空位
board_state[i][j] = 0
return score_map
python复制def main():
screen = init_game()
draw_board(screen)
current_player = 'black' # 玩家先手
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
return
if event.type == pygame.MOUSEBUTTONDOWN and current_player == 'black':
# 玩家落子逻辑
x, y = get_click_position(event.pos)
if place_piece(x, y, 'black'):
draw_piece(screen, x, y, 'black')
if check_win(x, y, 'black'):
show_winner('玩家')
return
current_player = 'white'
# AI回合
if current_player == 'white':
pygame.time.delay(500) # 增加思考时间
x, y = find_best_move()
place_piece(x, y, 'white')
draw_piece(screen, x, y, 'white')
if check_win(x, y, 'white'):
show_winner('AI')
return
current_player = 'black'
pygame.display.flip()
python复制# 优化后的评估函数示例
def fast_evaluate(x, y):
directions = [(1,0),(0,1),(1,1),(1,-1)]
total_score = 0
for dx, dy in directions:
line = [board_state[x+dx*i][y+dy*i] for i in range(-4,5)
if 0<=x+dx*i<19 and 0<=y+dy*i<19]
total_score += pattern_score(line)
return total_score
python复制def minimax(depth, alpha, beta, maximizing_player):
if depth == 0 or game_over():
return evaluate_board()
if maximizing_player:
max_eval = -float('inf')
for move in get_valid_moves():
make_move(move, 'white')
eval = minimax(depth-1, alpha, beta, False)
undo_move(move)
max_eval = max(max_eval, eval)
alpha = max(alpha, eval)
if beta <= alpha:
break
return max_eval
else:
min_eval = float('inf')
for move in get_valid_moves():
make_move(move, 'black')
eval = minimax(depth-1, alpha, beta, True)
undo_move(move)
min_eval = min(min_eval, eval)
beta = min(beta, eval)
if beta <= alpha:
break
return min_eval
专业级AI通常会内置:
python复制OPENING_BOOK = {
"花月开局": [(9,9), (8,9), (9,8), (10,9)],
"云雨开局": [(9,9), (10,8), (8,10), (9,7)]
}
以下是整合所有模块的最终版本(关键部分节选):
python复制import pygame
import numpy as np
from collections import defaultdict
class GomokuAI:
def __init__(self):
self.board = np.zeros((19,19))
self.patterns = self._init_patterns()
def _init_patterns(self):
# 完整模式库初始化
patterns = defaultdict(list)
# [模式识别代码...]
return patterns
def find_best_move(self):
# [决策引擎代码...]
return best_x, best_y
def main():
# [主游戏循环代码...]
if __name__ == "__main__":
main()
在实现过程中,最让我意外的是AI会发展出独特的进攻风格——它特别擅长设置"双三"陷阱。有次测试时,AI在第15手突然下出一个看似无关的落子,三手之后这个位置竟同时形成两个活三,这种前瞻性思考让人工智能显得格外有趣。