|
|
|
@ -0,0 +1,215 @@
|
|
|
|
|
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()
|