import tkinter as tk from tkinter import ttk, messagebox import numpy as np from game.reversi import Board class ReversiGUI: def __init__(self, master): self.master = master self.master.title("黑白棋 (Reversi)") self.master.geometry("1000x600") self.master.resizable(True, True) # 创建棋盘实例 (8x8) self.board = Board(8, 8) # 棋子颜色和符号 self.colors = { 0: "#228B22", # 空位 - 绿色 1: "#000000", # 黑棋 - 黑色 -1: "#FFFFFF" # 白棋 - 白色 } self.bg_colors = { 0: "#228B22", # 空位 - 绿色 1: "#000000", # 黑棋 - 黑色 -1: "#FFFFFF" # 白棋 - 白色 } self.symbols = { 1: "●", -1: "●", 0: "" } # 创建主框架 self.main_frame = ttk.Frame(self.master) self.main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 创建左侧主棋盘框架 self.board_frame = ttk.LabelFrame(self.main_frame, text="主棋盘") self.board_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5) # 创建右侧通道可视化框架 self.channels_frame = ttk.LabelFrame(self.main_frame, text="通道可视化") self.channels_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5) # 状态标签 self.status_var = tk.StringVar() self.status_label = ttk.Label(self.master, textvariable=self.status_var, font=('Arial', 12)) self.status_label.pack(pady=5) # 初始化棋盘按钮 self.board_buttons = [] self.setup_board() # 初始化通道可视化 self.channel_labels = { "board_b": [], # 黑棋位置 "board_w": [], # 白棋位置 "board_move": [], # 合法走法 "player": [] # 当前玩家 } self.setup_channels() # 更新显示 self.update_display() # 重置按钮 self.reset_button = ttk.Button(self.master, text="重置游戏", command=self.reset_game) self.reset_button.pack(pady=10) def setup_board(self): """设置主棋盘界面""" # 创建行列标签 col_frame = ttk.Frame(self.board_frame) col_frame.pack(fill=tk.X) # 空白格用于对齐 ttk.Label(col_frame, text="", width=2).pack(side=tk.LEFT) # 列标签 (A-H) for c in range(8): ttk.Label(col_frame, text=chr(65 + c), width=4).pack(side=tk.LEFT) # 创建棋盘按钮 for r in range(8): row_frame = ttk.Frame(self.board_frame) row_frame.pack(fill=tk.X) # 行标签 (1-8) ttk.Label(row_frame, text=str(r+1), width=2).pack(side=tk.LEFT) row_buttons = [] for c in range(8): btn = tk.Button( row_frame, width=3, height=1, font=('Arial', 14, 'bold'), command=lambda r=r, c=c: self.make_move(r, c) ) btn.pack(side=tk.LEFT, padx=1, pady=1) row_buttons.append(btn) self.board_buttons.append(row_buttons) def setup_channels(self): """设置通道可视化界面""" # 创建通道标签和网格 channels = [ ("黑棋位置", "board_b"), ("白棋位置", "board_w"), ("合法走法", "board_move"), ("当前玩家", "player") ] for idx, (title, key) in enumerate(channels): # 为每个通道创建框架 channel_frame = ttk.LabelFrame(self.channels_frame, text=title) channel_frame.grid(row=idx//2, column=idx%2, padx=5, pady=5, sticky="nsew") # 创建网格 grid_frame = ttk.Frame(channel_frame) grid_frame.pack(padx=5, pady=5) # 创建小格子 cell_labels = [] for r in range(8): row_labels = [] for c in range(8): lbl = tk.Label( grid_frame, width=2, height=1, relief=tk.RIDGE, borderwidth=1 ) lbl.grid(row=r, column=c, sticky="nsew") row_labels.append(lbl) cell_labels.append(row_labels) self.channel_labels[key] = cell_labels # 使行列权重相等 for i in range(2): self.channels_frame.grid_columnconfigure(i, weight=1) self.channels_frame.grid_rowconfigure(i, weight=1) def update_display(self): """更新所有显示元素""" # 更新主棋盘 for r in range(8): for c in range(8): value = self.board.board[r, c] btn = self.board_buttons[r][c] # 设置按钮颜色和文本 btn.config( text=self.symbols[value], fg="#FFFFFF" if value == 1 else "#000000", # 黑棋白字,白棋黑字 bg=self.bg_colors[value], # 使用对应的背景色 state=tk.NORMAL if self.board.board_move[r, c] == 1 else tk.DISABLED ) # 更新通道可视化 # 黑棋位置通道 self._update_channel_display("board_b", self.board.board_b) # 白棋位置通道 self._update_channel_display("board_w", self.board.board_w) # 合法走法通道 self._update_channel_display("board_move", self.board.board_move) # 当前玩家通道 self._update_channel_display("player", self.board.player_channel) # 更新状态信息 player_name = "黑棋" if self.board.player == 1 else "白棋" if self.board.is_game_over(): winner = self.board.get_winner() if winner == 1: status = "游戏结束!黑棋获胜!" elif winner == -1: status = "游戏结束!白棋获胜!" else: status = "游戏结束!平局!" else: black_count = np.sum(self.board.board == 1) white_count = np.sum(self.board.board == -1) status = f"当前玩家: {player_name} | 黑棋: {black_count} | 白棋: {white_count}" self.status_var.set(status) def _update_channel_display(self, channel_key, data): """更新特定通道的显示""" for r in range(8): for c in range(8): value = data[r, c] label = self.channel_labels[channel_key][r][c] # 设置颜色强度 if channel_key == "board_b": # 黑棋通道: 黑色 intensity = int(value * 255) color = f"#{intensity:02x}{intensity:02x}{intensity:02x}" elif channel_key == "board_w": # 白棋通道: 白色 intensity = int(255 - value * 255) color = f"#{intensity:02x}{intensity:02x}{intensity:02x}" elif channel_key == "board_move": # 合法走法通道: 蓝色 intensity = int(value * 255) color = f"#00{intensity:02x}ff" else: # 当前玩家通道: 红色(黑棋)/黄色(白棋) if value > 0: color = f"#ff0000" # 红色表示黑棋 else: color = f"#ffff00" # 黄色表示白棋 label.config(bg=color) def make_move(self, r, c): """执行走棋操作""" try: self.board.play(r, c) self.update_display() # 检查游戏是否结束 if self.board.is_game_over(): winner = self.board.get_winner() if winner == 1: messagebox.showinfo("游戏结束", "黑棋获胜!") elif winner == -1: messagebox.showinfo("游戏结束", "白棋获胜!") else: messagebox.showinfo("游戏结束", "平局!") except ValueError as e: messagebox.showerror("错误", str(e)) def reset_game(self): """重置游戏""" self.board.reset() self.update_display() if __name__ == "__main__": root = tk.Tk() app = ReversiGUI(root) root.mainloop()