目录
Python实例题
题目
代码实现
实现原理
游戏逻辑:
AI 算法:
界面渲染:
关键代码解析
游戏棋盘渲染
AI 决策算法
胜利条件检查
使用说明
安装依赖:
运行游戏:
游戏操作:
扩展建议
增强 AI:
界面改进:
功能扩展:
性能优化:
Python实例题
题目
人机对战初体验Python基于Pygame实现四子棋游戏
代码实现
import pygame
import sys
import numpy as np
import random
class ConnectFour:
def __init__(self):
# 游戏常量
self.ROWS = 6
self.COLUMNS = 7
self.SQUARE_SIZE = 100
self.WIDTH = self.COLUMNS * self.SQUARE_SIZE
self.HEIGHT = (self.ROWS + 1) * self.SQUARE_SIZE
self.SCREEN_SIZE = (self.WIDTH, self.HEIGHT)
self.RADIUS = int(self.SQUARE_SIZE / 2 - 5)
# 颜色定义
self.BLUE = (0, 0, 255)
self.BLACK = (0, 0, 0)
self.RED = (255, 0, 0)
self.YELLOW = (255, 255, 0)
self.WHITE = (255, 255, 255)
# 初始化游戏
pygame.init()
self.screen = pygame.display.set_mode(self.SCREEN_SIZE)
pygame.display.set_caption("四子棋")
self.font = pygame.font.SysFont("SimHei", 40)
self.small_font = pygame.font.SysFont("SimHei", 24)
# 游戏变量
self.board = np.zeros((self.ROWS, self.COLUMNS))
self.game_over = False
self.turn = 1 # 1: 玩家1/人类, 2: 玩家2/AI
self.player_mode = 1 # 1: 人机对战, 2: 双人对战
self.winner = 0
# 绘制初始界面
self.draw_board()
pygame.display.update()
def draw_board(self):
"""绘制游戏棋盘"""
# 绘制背景
self.screen.fill(self.BLUE)
# 绘制标题区域
title_rect = pygame.Rect(0, 0, self.WIDTH, self.SQUARE_SIZE)
pygame.draw.rect(self.screen, self.BLACK, title_rect)
# 显示标题和模式
title_text = self.font.render("四子棋", True, self.WHITE)
self.screen.blit(title_text, (self.WIDTH // 2 - title_text.get_width() // 2, 30))
mode_text = self.small_font.render(
"模式: 人机对战" if self.player_mode == 1 else "模式: 双人对战",
True, self.WHITE
)
self.screen.blit(mode_text, (20, 35))
# 绘制切换模式按钮
button_rect = pygame.Rect(self.WIDTH - 150, 25, 120, 50)
pygame.draw.rect(self.screen, self.RED if self.player_mode == 1 else self.YELLOW, button_rect)
button_text = self.small_font.render(
"切换双人" if self.player_mode == 1 else "切换人机",
True, self.WHITE
)
self.screen.blit(button_text, (button_rect.centerx - button_text.get_width() // 2,
button_rect.centery - button_text.get_height() // 2))
# 绘制棋盘格子
for c in range(self.COLUMNS):
for r in range(self.ROWS):
pygame.draw.rect(self.screen, self.BLACK,
(c * self.SQUARE_SIZE, (r + 1) * self.SQUARE_SIZE,
self.SQUARE_SIZE, self.SQUARE_SIZE))
pygame.draw.circle(self.screen, self.WHITE,
(int(c * self.SQUARE_SIZE + self.SQUARE_SIZE / 2),
int((r + 1) * self.SQUARE_SIZE + self.SQUARE_SIZE / 2)),
self.RADIUS)
# 绘制当前棋子
for c in range(self.COLUMNS):
for r in range(self.ROWS):
if self.board[r][c] == 1:
pygame.draw.circle(self.screen, self.RED,
(int(c * self.SQUARE_SIZE + self.SQUARE_SIZE / 2),
self.HEIGHT - int(r * self.SQUARE_SIZE + self.SQUARE_SIZE / 2)),
self.RADIUS)
elif self.board[r][c] == 2:
pygame.draw.circle(self.screen, self.YELLOW,
(int(c * self.SQUARE_SIZE + self.SQUARE_SIZE / 2),
self.HEIGHT - int(r * self.SQUARE_SIZE + self.SQUARE_SIZE / 2)),
self.RADIUS)
# 如果游戏结束,显示获胜信息
if self.game_over:
overlay = pygame.Surface(self.SCREEN_SIZE, pygame.SRCALPHA)
overlay.fill((0, 0, 0, 180))
self.screen.blit(overlay, (0, 0))
winner_text = self.font.render(
f"玩家 {'红方' if self.winner == 1 else '黄方'} 获胜!" if self.winner != 0 else "平局!",
True, self.WHITE
)
self.screen.blit(winner_text, (self.WIDTH // 2 - winner_text.get_width() // 2,
self.HEIGHT // 2 - 30))
restart_text = self.font.render("按R键重新开始", True, self.WHITE)
self.screen.blit(restart_text, (self.WIDTH // 2 - restart_text.get_width() // 2,
self.HEIGHT // 2 + 30))
def is_valid_location(self, col):
"""检查指定列是否可以放置棋子"""
return self.board[0][col] == 0
def get_next_open_row(self, col):
"""获取指定列中下一个可用的行"""
for r in range(self.ROWS - 1, -1, -1):
if self.board[r][col] == 0:
return r
def drop_piece(self, row, col, player):
"""在指定位置放置棋子"""
self.board[row][col] = player
def check_winning_move(self, player):
"""检查玩家是否获胜"""
# 检查水平方向
for c in range(self.COLUMNS - 3):
for r in range(self.ROWS):
if (self.board[r][c] == player and
self.board[r][c + 1] == player and
self.board[r][c + 2] == player and
self.board[r][c + 3] == player):
return True
# 检查垂直方向
for c in range(self.COLUMNS):
for r in range(self.ROWS - 3):
if (self.board[r][c] == player and
self.board[r + 1][c] == player and
self.board[r + 2][c] == player and
self.board[r + 3][c] == player):
return True
# 检查正对角线
for c in range(self.COLUMNS - 3):
for r in range(self.ROWS - 3):
if (self.board[r][c] == player and
self.board[r + 1][c + 1] == player and
self.board[r + 2][c + 2] == player and
self.board[r + 3][c + 3] == player):
return True
# 检查反对角线
for c in range(self.COLUMNS - 3):
for r in range(3, self.ROWS):
if (self.board[r][c] == player and
self.board[r - 1][c + 1] == player and
self.board[r - 2][c + 2] == player and
self.board[r - 3][c + 3] == player):
return True
return False
def is_board_full(self):
"""检查棋盘是否已满"""
for c in range(self.COLUMNS):
if self.is_valid_location(c):
return False
return True
def evaluate_window(self, window, player):
"""评估一个窗口(四个位置)的得分"""
score = 0
opponent = 1 if player == 2 else 2
if window.count(player) == 4:
score += 100
elif window.count(player) == 3 and window.count(0) == 1:
score += 10
elif window.count(player) == 2 and window.count(0) == 2:
score += 5
if window.count(opponent) == 3 and window.count(0) == 1:
score -= 80 # 阻止对手三连
return score
def score_position(self, player):
"""评估整个棋盘的得分"""
score = 0
# 评估中心列
center_array = [int(i) for i in list(self.board[:, self.COLUMNS // 2])]
center_count = center_array.count(player)
score += center_count * 3
# 评估水平方向
for r in range(self.ROWS):
row_array = [int(i) for i in list(self.board[r, :])]
for c in range(self.COLUMNS - 3):
window = row_array[c:c + 4]
score += self.evaluate_window(window, player)
# 评估垂直方向
for c in range(self.COLUMNS):
col_array = [int(i) for i in list(self.board[:, c])]
for r in range(self.ROWS - 3):
window = col_array[r:r + 4]
score += self.evaluate_window(window, player)
# 评估正对角线
for r in range(self.ROWS - 3):
for c in range(self.COLUMNS - 3):
window = [self.board[r + i][c + i] for i in range(4)]
score += self.evaluate_window(window, player)
# 评估反对角线
for r in range(self.ROWS - 3):
for c in range(self.COLUMNS - 3):
window = [self.board[r + 3 - i][c + i] for i in range(4)]
score += self.evaluate_window(window, player)
return score
def get_valid_locations(self):
"""获取所有可用的列"""
valid_locations = []
for col in range(self.COLUMNS):
if self.is_valid_location(col):
valid_locations.append(col)
return valid_locations
def minimax(self, depth, maximizingPlayer, alpha, beta):
"""使用Minimax算法和Alpha-Beta剪枝选择最佳移动"""
valid_locations = self.get_valid_locations()
is_terminal = self.is_board_full() or self.check_winning_move(1) or self.check_winning_move(2)
if depth == 0 or is_terminal:
if is_terminal:
if self.check_winning_move(2):
return (None, 10000000)
elif self.check_winning_move(1):
return (None, -10000000)
else: # 平局
return (None, 0)
else: # 深度为0
return (None, self.score_position(2))
if maximizingPlayer:
value = -float('inf')
column = random.choice(valid_locations)
for col in valid_locations:
row = self.get_next_open_row(col)
temp_board = self.board.copy()
self.drop_piece(row, col, 2)
new_score = self.minimax(depth - 1, False, alpha, beta)[1]
self.board = temp_board
if new_score > value:
value = new_score
column = col
alpha = max(alpha, value)
if alpha >= beta:
break
return column, value
else: # 最小化玩家
value = float('inf')
column = random.choice(valid_locations)
for col in valid_locations:
row = self.get_next_open_row(col)
temp_board = self.board.copy()
self.drop_piece(row, col, 1)
new_score = self.minimax(depth - 1, True, alpha, beta)[1]
self.board = temp_board
if new_score < value:
value = new_score
column = col
beta = min(beta, value)
if alpha >= beta:
break
return column, value
def ai_move(self):
"""AI移动逻辑"""
if not self.game_over:
# 使用minimax算法选择最佳列,深度为4
col, _ = self.minimax(4, True, -float('inf'), float('inf'))
if self.is_valid_location(col):
pygame.time.wait(500) # 让AI思考看起来更自然
row = self.get_next_open_row(col)
self.drop_piece(row, col, 2)
if self.check_winning_move(2):
self.game_over = True
self.winner = 2
elif self.is_board_full():
self.game_over = True
self.winner = 0
self.turn = 1 # 回到玩家1
self.draw_board()
pygame.display.update()
def restart_game(self):
"""重新开始游戏"""
self.board = np.zeros((self.ROWS, self.COLUMNS))
self.game_over = False
self.turn = 1
self.winner = 0
self.draw_board()
pygame.display.update()
def run(self):
"""运行游戏主循环"""
clock = pygame.time.Clock()
while True:
clock.tick(60)
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 and self.game_over:
self.restart_game()
if event.type == pygame.MOUSEBUTTONDOWN:
# 检查是否点击了模式切换按钮
button_rect = pygame.Rect(self.WIDTH - 150, 25, 120, 50)
if button_rect.collidepoint(event.pos):
self.player_mode = 2 if self.player_mode == 1 else 1
self.restart_game()
continue
# 游戏未结束且轮到人类玩家
if not self.game_over and (self.turn == 1 or self.player_mode == 2):
# 获取鼠标位置
pos_x = event.pos[0]
col = int(pos_x // self.SQUARE_SIZE)
# 检查列是否有效
if self.is_valid_location(col):
# 获取下一个可用行
row = self.get_next_open_row(col)
# 放置棋子
player = self.turn
self.drop_piece(row, col, player)
# 检查是否获胜
if self.check_winning_move(player):
self.game_over = True
self.winner = player
# 检查是否平局
elif self.is_board_full():
self.game_over = True
self.winner = 0
# 切换玩家
self.turn = 2 if self.turn == 1 else 1
# 绘制棋盘
self.draw_board()
pygame.display.update()
# AI移动(人机对战且轮到AI)
if not self.game_over and self.turn == 2 and self.player_mode == 1:
self.ai_move()
if __name__ == "__main__":
game = ConnectFour()
game.run()
实现原理
这个四子棋游戏基于以下核心技术实现:
-
游戏逻辑:
- 使用 numpy 数组表示游戏棋盘
- 实现棋子放置、胜利条件检查和棋盘状态评估
- 支持人机对战和双人对战模式
-
AI 算法:
- 使用 Minimax 算法进行决策
- 实现 Alpha-Beta 剪枝优化搜索效率
- 设计评分函数评估棋盘状态
-
界面渲染:
- 使用 Pygame 创建图形界面
- 实现棋盘、棋子和交互元素的绘制
- 添加游戏状态提示和模式切换功能
关键代码解析
游戏棋盘渲染
def draw_board(self):
# 绘制背景和标题
self.screen.fill(self.BLUE)
title_rect = pygame.Rect(0, 0, self.WIDTH, self.SQUARE_SIZE)
pygame.draw.rect(self.screen, self.BLACK, title_rect)
# 绘制棋盘格子和棋子
for c in range(self.COLUMNS):
for r in range(self.ROWS):
pygame.draw.rect(self.screen, self.BLACK,
(c * self.SQUARE_SIZE, (r + 1) * self.SQUARE_SIZE,
self.SQUARE_SIZE, self.SQUARE_SIZE))
pygame.draw.circle(self.screen, self.WHITE,
(int(c * self.SQUARE_SIZE + self.SQUARE_SIZE / 2),
int((r + 1) * self.SQUARE_SIZE + self.SQUARE_SIZE / 2)),
self.RADIUS)
# 绘制当前棋子状态
for c in range(self.COLUMNS):
for r in range(self.ROWS):
if self.board[r][c] == 1:
pygame.draw.circle(self.screen, self.RED,
(int(c * self.SQUARE_SIZE + self.SQUARE_SIZE / 2),
self.HEIGHT - int(r * self.SQUARE_SIZE + self.SQUARE_SIZE / 2)),
self.RADIUS)
elif self.board[r][c] == 2:
pygame.draw.circle(self.screen, self.YELLOW,
(int(c * self.SQUARE_SIZE + self.SQUARE_SIZE / 2),
self.HEIGHT - int(r * self.SQUARE_SIZE + self.SQUARE_SIZE / 2)),
self.RADIUS)
AI 决策算法
def minimax(self, depth, maximizingPlayer, alpha, beta):
valid_locations = self.get_valid_locations()
is_terminal = self.is_board_full() or self.check_winning_move(1) or self.check_winning_move(2)
if depth == 0 or is_terminal:
if is_terminal:
if self.check_winning_move(2):
return (None, 10000000)
elif self.check_winning_move(1):
return (None, -10000000)
else:
return (None, 0)
else:
return (None, self.score_position(2))
if maximizingPlayer:
value = -float('inf')
column = random.choice(valid_locations)
for col in valid_locations:
row = self.get_next_open_row(col)
temp_board = self.board.copy()
self.drop_piece(row, col, 2)
new_score = self.minimax(depth - 1, False, alpha, beta)[1]
self.board = temp_board
if new_score > value:
value = new_score
column = col
alpha = max(alpha, value)
if alpha >= beta:
break
return column, value
else:
value = float('inf')
column = random.choice(valid_locations)
for col in valid_locations:
row = self.get_next_open_row(col)
temp_board = self.board.copy()
self.drop_piece(row, col, 1)
new_score = self.minimax(depth - 1, True, alpha, beta)[1]
self.board = temp_board
if new_score < value:
value = new_score
column = col
beta = min(beta, value)
if alpha >= beta:
break
return column, value
胜利条件检查
def check_winning_move(self, player):
# 检查水平方向
for c in range(self.COLUMNS - 3):
for r in range(self.ROWS):
if (self.board[r][c] == player and
self.board[r][c + 1] == player and
self.board[r][c + 2] == player and
self.board[r][c + 3] == player):
return True
# 检查垂直方向
for c in range(self.COLUMNS):
for r in range(self.ROWS - 3):
if (self.board[r][c] == player and
self.board[r + 1][c] == player and
self.board[r + 2][c] == player and
self.board[r + 3][c] == player):
return True
# 检查正对角线
for c in range(self.COLUMNS - 3):
for r in range(self.ROWS - 3):
if (self.board[r][c] == player and
self.board[r + 1][c + 1] == player and
self.board[r + 2][c + 2] == player and
self.board[r + 3][c + 3] == player):
return True
# 检查反对角线
for c in range(self.COLUMNS - 3):
for r in range(3, self.ROWS):
if (self.board[r][c] == player and
self.board[r - 1][c + 1] == player and
self.board[r - 2][c + 2] == player and
self.board[r - 3][c + 3] == player):
return True
return False
使用说明
-
安装依赖:
pip install pygame numpy
-
运行游戏:
python connect_four.py
-
游戏操作:
- 人机对战:红方 (玩家) vs 黄方 (AI)
- 双人对战:红方 (玩家 1) vs 黄方 (玩家 2)
- 点击顶部按钮切换游戏模式
- 点击列顶部放置棋子
- 游戏结束后按 R 键重新开始
扩展建议
-
增强 AI:
- 优化评分函数,考虑更多策略因素
- 增加难度级别选择
- 实现蒙特卡洛树搜索算法
-
界面改进:
- 添加动画效果(棋子下落、胜利高亮)
- 设计更精美的 UI 元素
- 支持全屏模式和窗口调整
-
功能扩展:
- 实现游戏存档和回放功能
- 添加音效和背景音乐
- 支持局域网多人对战
-
性能优化:
- 使用位运算优化棋盘表示
- 实现多线程计算 AI 决策
- 添加游戏状态缓存机制