这是一个基于Tkinter的图形界面应用程序,用于模拟约瑟夫环问题。约瑟夫环问题是一个经典的数学问题,描述的是N个人围成一圈,从第一个人开始报数,每数到第M个人就将其淘汰,然后从下一个人继续报数,直到剩下最后一个人。
实现可视化功能:
- 环形排列的人物图标
- 当前报数者高亮显示(橙色)
- 实时显示淘汰信息
- 动态更新剩余人数
- 胜利者弹窗提示
程序说明:
首先,在JosephusGame类的init_方法中,设置了主窗口的标题、大小,并创建了各种控件,如画布、标签、输入框和开始按钮。这些控件通过Frame进行布局,使得界面看起来整洁有序。这里需要注意的是,用户输入的人数和步长是通过Entry控件获取的,而开始按钮绑定了start_game方法。
然后是draw_circle方法,负责在画布上绘制当前存活的人物。这里使用三角函数计算每个位置的角度,将人物均匀地排列成一个圆环。存活的人物用天蓝色表示,当前报数的人用橙色高亮显示。每个角色用一个圆形表示,中间显示其编号。
接下来是start_game方法,处理游戏的初始化。这里会验证用户输入的人数和步长是否为正整数,如果无效则弹出错误提示。然后初始化存活列表、当前索引、步数等变量,并禁用开始按钮以防止重复点击。最后调用next_step方法开始淘汰过程。
在next_step方法中,执行每一轮的淘汰逻辑。根据当前索引和步长计算下一个要淘汰的人,更新存活列表,并在界面上更新显示。如果还有多于一人存活,使用after方法在1.5秒后自动进行下一步,否则结束游戏,显示胜利者。
import tkinter as tk
from math import cos, sin, pi
from tkinter import messagebox
class JosephusGame:
def __init__(self, master):
self.master = master
master.title("约瑟夫生死环小游戏")
master.geometry("800x600")
# 游戏控件
self.canvas = tk.Canvas(master, width=600, height=500, bg='white')
self.label = tk.Label(master, text="欢迎来到约瑟夫生死环游戏!", font=('微软雅黑', 12))
self.people_num = tk.Entry(master, width=10)
self.step_num = tk.Entry(master, width=10)
self.start_btn = tk.Button(master, text="开始游戏", command=self.start_game)
# 布局
controls = tk.Frame(master)
tk.Label(controls, text="人数:").pack(side=tk.LEFT)
self.people_num.pack(side=tk.LEFT, padx=5)
tk.Label(controls, text="步长:").pack(side=tk.LEFT)
self.step_num.pack(side=tk.LEFT, padx=5)
self.start_btn.pack(side=tk.LEFT, padx=10)
controls.pack(pady=10)
self.canvas.pack()
self.label.pack(pady=10)
# 游戏变量
self.players = []
self.current_index = 0
self.alive_players = []
self.step = 0
self.running = False
def draw_circle(self):
"""绘制环形排列的人物"""
n = len(self.alive_players)
radius = 200
center_x, center_y = 300, 250
self.canvas.delete("all")
for i in range(n):
angle = 2 * pi * i / n
x = center_x + radius * cos(angle)
y = center_y + radius * sin(angle)
# 绘制人物图标
color = 'skyblue' if i != self.current_index else 'orange'
self.canvas.create_oval(x-20, y-20, x+20, y+20, fill=color, tags=f"player{i}")
self.canvas.create_text(x, y, text=str(self.alive_players[i]+1),
font=('Arial', 12, 'bold'))
def start_game(self):
"""初始化游戏"""
try:
n = int(self.people_num.get())
m = int(self.step_num.get())
if n < 1 or m < 1:
raise ValueError
except:
messagebox.showerror("错误", "请输入有效的正整数")
return
self.alive_players = list(range(n))
self.current_index = 0
self.step = 0
self.running = True
self.start_btn.config(state=tk.DISABLED)
self.next_step(m)
def next_step(self, m):
"""执行下一步"""
if not self.running or len(self.alive_players) == 1:
return
self.step += 1
# 计算淘汰位置
self.current_index = (self.current_index + m - 1) % len(self.alive_players)
eliminated = self.alive_players.pop(self.current_index)
# 更新显示
self.label.config(text=f"第 {self.step} 轮:{eliminated+1}号被淘汰,剩余 {len(self.alive_players)} 人")
self.draw_circle()
# 继续游戏或结束
if len(self.alive_players) > 1:
self.master.after(1500, lambda: self.next_step(m))
else:
self.running = False
self.start_btn.config(state=tk.NORMAL)
winner = self.alive_players[0] + 1
messagebox.showinfo("游戏结束", f"胜利者是 {winner} 号!")
self.draw_circle()
if __name__ == "__main__":
root = tk.Tk()
game = JosephusGame(root)
root.mainloop()