程序功能:
- 用户通过点击棋盘格子放置/移除皇后
- 实时检测皇后冲突(同列/对角线)
- 提供自动求解功能(显示一个随机解)
- 支持新游戏开始
- 国际象棋棋盘配色(浅棕/深棕交替)
- 红色边框高亮冲突皇后
- 使用 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[:])returnfor 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 randomclass EightQueensGame:def __init__(self, master):# 初始化主窗口self.master = mastermaster.title("八皇后游戏")master.geometry("520x600") # 设置窗口尺寸# 游戏参数初始化self.board_size = 8 # 棋盘尺寸8x8self.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_sizey1 = row * self.cell_sizex2 = x1 + self.cell_sizey2 = 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//2self.canvas.create_text(x, y, text="♛", # Unicode皇后符号font=('Arial', 24), # 字体设置fill='black') # 黑色填充def on_click(self, event):"""处理棋盘点击事件"""# 计算点击的格子坐标col = event.x // self.cell_sizerow = 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个皇后了!")returnself.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 Truereturn Falsedef 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_sizey1 = row * self.cell_sizex2 = x1 + self.cell_sizey2 = y1 + self.cell_sizeself.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[:]) # 找到合法解returnfor 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.solutionsif __name__ == "__main__":root = tk.Tk() # 创建主窗口game = EightQueensGame(root) # 初始化游戏实例root.mainloop() # 启动GUI事件循环