You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

215 lines
7.9 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import tkinter as tk
from tkinter import messagebox
class NumberChess:
def __init__(self, root):
self.root = root
self.root.title("数字棋")
self.board = [[None for _ in range(3)] for _ in range(3)]
self.current_player = ""
self.buttons = [[None for _ in range(3)] for _ in range(3)]
self.selected_cell = None
self.penalty_highlight = None
self.is_penalty_window_open = False
self.create_board()
def create_board(self):
for i in range(3):
for j in range(3):
button = tk.Button(self.root, text="", width=10, height=3, bg="white",
command=lambda i=i, j=j: self.on_click(i, j))
button.grid(row=i, column=j)
self.buttons[i][j] = button
def on_click(self, i, j):
cell = self.board[i][j]
if self.selected_cell is None:
if cell is None:
self.board[i][j] = (1, self.current_player)
self.update_button(i, j)
if self.check_win():
messagebox.showinfo("游戏结束", f"{self.current_player} 方获胜!")
self.reset_game()
else:
punishment_triggered = self.check_special_rule()
if not punishment_triggered:
self.switch_player()
else:
number, player = cell
if player == self.current_player:
self.selected_cell = (i, j)
self.highlight_selected(i, j)
else:
if self.move_selected_to(i, j):
if self.check_win():
messagebox.showinfo("游戏结束", f"{self.current_player} 方获胜!")
self.reset_game()
else:
punishment_triggered = self.check_special_rule()
if not punishment_triggered:
self.switch_player()
self.clear_selection()
def move_selected_to(self, i, j):
si, sj = self.selected_cell
if abs(si - i) + abs(sj - j) != 1:
return False
selected_number, selected_player = self.board[si][sj]
target_cell = self.board[i][j]
if (target_cell is None or target_cell[1] != selected_player) and (abs(i - si) + abs(j - sj) == 1):
new_number = selected_number
if target_cell is not None:
new_number += target_cell[0]
self.board[i][j] = (new_number, selected_player)
self.board[si][sj] = None
self.update_button(si, sj)
self.update_button(i, j)
return True
return False
def highlight_selected(self, i, j):
for x in range(3):
for y in range(3):
if (x, y) == (i, j):
self.buttons[x][y].config(bg="yellow")
else:
self.update_button(x, y)
def clear_selection(self):
self.selected_cell = None
for i in range(3):
for j in range(3):
self.update_button(i, j)
def update_button(self, i, j):
cell = self.board[i][j]
if cell is None:
self.buttons[i][j].config(text="", bg="white")
else:
number, player = cell
bg_color = "red" if player == "" else "blue"
fg_color = "black"
cell_text = str(number)
if self.penalty_highlight and (i, j) in self.penalty_highlight:
index = self.penalty_highlight.index((i, j)) + 1
cell_text += f"_{index}"
bg_color = "lightgreen" # 使用绿色背景突出显示
self.buttons[i][j].config(text=cell_text, bg=bg_color, fg=fg_color)
def switch_player(self):
self.current_player = "" if self.current_player == "" else ""
def check_win(self):
for row in self.board:
for cell in row:
if cell and cell[0] >= 10:
return True
return False
def check_special_rule(self):
if not self.has_empty_cell():
self.apply_special_rule()
return True
return False
def has_empty_cell(self):
for row in self.board:
if None in row:
return True
return False
def apply_special_rule(self):
current_player_cells = []
for i in range(3):
for j in range(3):
cell = self.board[i][j]
if cell and cell[1] == self.current_player:
current_player_cells.append(cell)
if not current_player_cells:
return
max_number = max(cell[0] for cell in current_player_cells)
max_cells = [(i,j) for i in range(3) for j in range(3)
if self.board[i][j] and
self.board[i][j][1] == self.current_player and
self.board[i][j][0] == max_number]
if len(max_cells) == 1:
i, j = max_cells[0]
self.apply_number_reduction(i, j, None) # 传入 None 表示无窗口
else:
self._max_cells = max_cells.copy()
self.penalty_highlight = self._max_cells.copy()
self.ask_player_to_choose(max_cells)
def ask_player_to_choose(self, max_cells):
if self.is_penalty_window_open:
return
self.is_penalty_window_open = True
self._max_cells = max_cells
self.ask_window = tk.Toplevel(self.root)
self.ask_window.title("选择一个数字减1")
self.ask_window.grab_set()
self.ask_window.protocol("WM_DELETE_WINDOW", self.on_window_close)
label_text = f"请选择 {self.current_player} 方要减1的数字"
label = tk.Label(self.ask_window, text=label_text)
label.pack(padx=10, pady=10)
for idx, (i, j) in enumerate(max_cells):
cell = self.board[i][j]
color = "red" if cell[1] == "" else "blue"
frame = tk.Frame(self.ask_window,
highlightbackground=color,
highlightthickness=2)
coord_label = tk.Label(frame, text=f"({i+1}, {j+1})")
coord_label.pack()
button = tk.Button(frame,
text=str(cell[0]),
width=5,
height=2,
command=lambda i=i, j=j: self.apply_number_reduction(i, j, self.ask_window))
button.pack(padx=2, pady=2)
frame.pack(side=tk.LEFT, padx=5, pady=5)
def on_window_close(self):
messagebox.showwarning("警告", "必须选择一个棋子才能继续操作!", parent=self.ask_window)
self.ask_window.grab_set()
def apply_number_reduction(self, i, j, window):
number, player = self.board[i][j]
if number == 1:
self.board[i][j] = None
else:
self.board[i][j] = (number - 1, player)
self.penalty_highlight = None
self.update_button(i, j)
# 只有当 window 存在时才销毁
if window:
window.destroy()
self.is_penalty_window_open = False
self.switch_player()
def reset_game(self):
self.board = [[None for _ in range(3)] for _ in range(3)]
for i in range(3):
for j in range(3):
self.buttons[i][j].config(text="", bg="white")
self.current_player = ""
self.penalty_highlight = None
self.is_penalty_window_open = False
if __name__ == "__main__":
root = tk.Tk()
game = NumberChess(root)
root.mainloop()