python八皇后游戏
程序功能:
- 用户通过点击棋盘格子放置/移除皇后
- 实时检测皇后冲突(同列/对角线)
- 提供自动求解功能(显示一个随机解)
- 支持新游戏开始
- 国际象棋棋盘配色(浅棕/深棕交替)
- 红色边框高亮冲突皇后
- 使用 Unicode 皇后符号 ♛ 表示棋子
- 实时显示已放置皇后数量
- 基于回溯算法的自动求解器
- 冲突检测算法(O(n²) 复杂度)
- 解决方案缓存机制
代码结构:
class EightQueensGame:
def __init__(self, master): # 初始化游戏界面和变量
def draw_board(self): # 绘制棋盘和棋子
def draw_queen(self): # 绘制皇后图标
def on_click(self): # 处理鼠标点击事件
def has_conflicts(self): # 冲突检测逻辑
def highlight_conflicts(self):# 高亮冲突棋子
def update_status(self): # 更新状态栏信息
def new_game(self): # 重置游戏状态
def show_solution(self): # 显示解决方案
def find_solutions(self): # 回溯算法求解所有解
代码分析:
棋盘绘制
# 交替颜色绘制棋盘
color = "#DDB88C" if (row + col) % 2 == 0 else "#A0522D"
self.canvas.create_rectangle(x1, y1, x2, y2, fill=color)
冲突检测算法
# 检查两个皇后是否在同一列或对角线上
if c1 == c2 or abs(r1 - r2) == abs(c1 - c2):
return True
回溯求解算法
def backtrack(row, cols, diag1, diag2):
if row == self.board_size:
self.solutions.append(cols[:])
return
for col in range(self.board_size):
d1 = row - col # 主对角线标识
d2 = row + col # 副对角线标识
if col not in cols and d1 not in diag1 and d2 not in diag2:
backtrack(row+1, cols+[col], diag1+[d1], diag2+[d2])
具体代码
import tkinter as tk
from tkinter import messagebox
import random
class EightQueensGame:
def __init__(self, master):
# 初始化主窗口
self.master = master
master.title("八皇后游戏")
master.geometry("520x600") # 设置窗口尺寸
# 游戏参数初始化
self.board_size = 8 # 棋盘尺寸8x8
self.cell_size = 60 # 每个格子像素大小
self.queens = [] # 存储已放置皇后坐标的列表
self.solutions = [] # 存储所有解决方案的列表
# 创建棋盘画布
self.canvas = tk.Canvas(master,
width=self.cell_size*self.board_size,
height=self.cell_size*self.board_size)
self.canvas.pack(pady=10) # 添加垂直间距
# 创建控制面板
control_frame = tk.Frame(master)
# 状态显示标签
self.status_label = tk.Label(control_frame,
text="已放置 0/8 个皇后",
font=('微软雅黑', 12))
# 新游戏按钮
self.new_game_btn = tk.Button(control_frame,
text="新游戏",
command=self.new_game)
# 显示答案按钮
self.solve_btn = tk.Button(control_frame,
text="显示答案",
command=self.show_solution)
# 布局控制面板组件
self.status_label.pack(side=tk.LEFT, padx=10)
self.new_game_btn.pack(side=tk.LEFT, padx=5)
self.solve_btn.pack(side=tk.LEFT, padx=5)
control_frame.pack(pady=10)
# 初始化棋盘绘制并绑定点击事件
self.draw_board()
self.canvas.bind("<Button-1>", self.on_click)
def draw_board(self):
"""绘制棋盘及棋子"""
self.canvas.delete("all") # 清空画布
for row in range(self.board_size):
for col in range(self.board_size):
# 计算格子坐标
x1 = col * self.cell_size
y1 = row * self.cell_size
x2 = x1 + self.cell_size
y2 = y1 + self.cell_size
# 交替格子颜色(国际象棋棋盘样式)
color = "#DDB88C" if (row + col) % 2 == 0 else "#A0522D"
self.canvas.create_rectangle(x1, y1, x2, y2,
fill=color,
tags=f"cell_{row}_{col}")
# 如果该位置有皇后则绘制
if (row, col) in self.queens:
self.draw_queen(row, col)
# 高亮显示冲突的皇后
self.highlight_conflicts()
def draw_queen(self, row, col):
"""在指定位置绘制皇后符号"""
x = col * self.cell_size + self.cell_size//2 # 计算中心坐标
y = row * self.cell_size + self.cell_size//2
self.canvas.create_text(x, y,
text="♛", # Unicode皇后符号
font=('Arial', 24), # 字体设置
fill='black') # 黑色填充
def on_click(self, event):
"""处理棋盘点击事件"""
# 计算点击的格子坐标
col = event.x // self.cell_size
row = event.y // self.cell_size
# 切换皇后状态(添加/移除)
if (row, col) in self.queens:
self.queens.remove((row, col))
else:
if len(self.queens) >= 8:
messagebox.showwarning("提示", "已经放置8个皇后了!")
return
self.queens.append((row, col))
# 更新界面和状态
self.update_status()
self.draw_board()
# 胜利条件检查
if len(self.queens) == 8 and not self.has_conflicts():
messagebox.showinfo("恭喜", "你成功解决了八皇后问题!🎉")
def has_conflicts(self):
"""检查当前皇后布局是否存在冲突"""
for i in range(len(self.queens)):
for j in range(i+1, len(self.queens)):
r1, c1 = self.queens[i]
r2, c2 = self.queens[j]
# 冲突条件:同一列 或 同一对角线(行差绝对值等于列差绝对值)
if c1 == c2 or abs(r1 - r2) == abs(c1 - c2):
return True
return False
def highlight_conflicts(self):
"""用红色边框标记冲突的皇后"""
conflict_pairs = []
# 找出所有冲突的皇后对
for i in range(len(self.queens)):
for j in range(i+1, len(self.queens)):
r1, c1 = self.queens[i]
r2, c2 = self.queens[j]
if c1 == c2 or abs(r1 - r2) == abs(c1 - c2):
conflict_pairs.extend([(r1,c1), (r2,c2)])
# 为每个冲突的皇后添加红色边框
for row, col in set(conflict_pairs):
x1 = col * self.cell_size
y1 = row * self.cell_size
x2 = x1 + self.cell_size
y2 = y1 + self.cell_size
self.canvas.create_rectangle(x1, y1, x2, y2,
outline="red",
width=3)
def update_status(self):
"""更新状态栏显示"""
self.status_label.config(text=f"已放置 {len(self.queens)}/8 个皇后")
# 根据冲突状态改变文字颜色
self.status_label.config(fg="red" if self.has_conflicts() else "black")
def new_game(self):
"""重置游戏状态"""
self.queens = []
self.solutions = []
self.draw_board()
self.update_status()
def show_solution(self):
"""显示一个随机解决方案"""
if not self.solutions:
self.find_solutions() # 如果还没有解,先计算
if self.solutions:
# 随机选择一个解并显示
solution = random.choice(self.solutions)
self.queens = [(i, col) for i, col in enumerate(solution)]
self.draw_board()
self.update_status()
else:
messagebox.showinfo("提示", "没有找到解法!")
def find_solutions(self):
"""使用回溯算法查找所有合法解"""
def backtrack(row, cols, diag1, diag2):
"""递归回溯函数
Args:
row: 当前处理的行
cols: 已占用的列
diag1: 主对角线特征值(row - col)
diag2: 副对角线特征值(row + col)
"""
if row == self.board_size:
self.solutions.append(cols[:]) # 找到合法解
return
for col in range(self.board_size):
d1 = row - col # 主对角线标识
d2 = row + col # 副对角线标识
# 检查列冲突和对角线冲突
if col not in cols and d1 not in diag1 and d2 not in diag2:
backtrack(row+1, cols+[col], diag1+[d1], diag2+[d2])
self.solutions = []
backtrack(0, [], [], []) # 从第0行开始搜索
return self.solutions
if __name__ == "__main__":
root = tk.Tk() # 创建主窗口
game = EightQueensGame(root) # 初始化游戏实例
root.mainloop() # 启动GUI事件循环