You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Python Tkinter的Simon Says游戏开发问题求助

问题解决与代码修改

问题1:CPU标签无法逐个切换图像

Tkinter中直接使用time.sleep()会阻塞主事件循环,导致界面无法实时更新,看不到图像切换效果。需要用Tkinter的after()方法实现延迟动作,让每个图像显示后等待一段时间再切换下一个。

修改思路:

  • 先生成完整的CPU动作列表
  • 用递归方式,通过after()逐个显示每个动作的图像,最后恢复初始图像

问题2:对比CPU与用户的动作列表

Python中列表支持直接用==判断是否完全一致(元素顺序和内容都相同)。需要在用户输入完所有动作后触发对比逻辑。

修改思路:

  • 添加check_answer()方法处理对比逻辑
  • 用户每次点击按钮后检查输入长度是否等于CPU动作长度,达到后自动触发对比

修改后的完整代码

import random
from tkinter import *
from PIL import ImageTk, Image


class Gui:

    def __init__(self, window):
        # Image variables
        self.listofdirect = ['up', 'down', 'left', 'right']
        self.player_image = ImageTk.PhotoImage(Image.open("images/mavs.png"))
        self.caller_img = ImageTk.PhotoImage(Image.open("images/durango.png"))
        self.right_image = ImageTk.PhotoImage(Image.open("images/right.png"))
        self.left_image = ImageTk.PhotoImage(Image.open("images/left.png"))
        self.up_image = ImageTk.PhotoImage(Image.open("images/up.png"))
        self.down_image = ImageTk.PhotoImage(Image.open("images/down.png"))
        self.window = window
        # Caller Frame
        self.frame_one = Frame(self.window)
        self.caller_lbl = Label(self.frame_one, image=self.caller_img, width=180)
        self.score_lbl = Label(self.frame_one, text="Score: 0")

        self.caller_lbl.pack(side='left')
        self.score_lbl.pack(side="top")
        self.frame_one.pack()

        self.frame_one2 = Frame(self.window)  # spacer
        self.label_age = Label(self.frame_one2, text="---------", width=6)
        self.label_age.pack(side='left')
        self.frame_one2.pack()

        # Age Frame
        self.frame_two = Frame(self.window)
        self.user_lbl = Label(self.frame_two, image=self.player_image, width=180)
        self.user_lbl.pack(side='left')
        self.frame_two.pack()
        # Arrow Keys
        self.direct_button = Frame(self.frame_two)
        self.label_stat = Label(self.direct_button, text="Options")
        """Buttons: Up, Down, Left, Right """
        self.upButton = Button(self.direct_button, text="⇧", command=self.upClick, state=DISABLED)
        self.downButton = Button(self.direct_button, text="⇩", command=self.downClick, state=DISABLED)
        self.leftButton = Button(self.direct_button, text="⇦", command=self.leftClick, state=DISABLED)
        self.rightButton = Button(self.direct_button, text="⇨", command=self.rightClick, state=DISABLED)
        self.upButton.pack(side="top")
        self.downButton.pack(side="bottom")
        self.leftButton.pack(side="left")
        self.rightButton.pack(side="right")
        self.direct_button.pack()
        # Save Button (Start Game)
        self.save_btn = Frame(self.window)
        self.button_save = Button(self.save_btn, text='Start Game', width=10, command=self.submit)
        self.button_save.grid(row=0, column=2)
        self.save_btn.pack()

        self.reset_btn = Frame(self.window)
        self.button_reset = Button(self.reset_btn, text="Reset", command=self.reset, state=DISABLED)
        self.reset_btn.pack()
        self.button_reset.pack()
        # Direction Label
        self.direct = Frame(self.window)
        self.label_direct = Label(self.direct, text='Click Start Game to begin')
        self.label_direct.pack(side='left')
        self.direct.pack()

        self.caller_list = []
        self.player_list = []
        self.DIRECTIONS = ["up", "down", "left", "right"]

        self.MOVE_LENGTH = random.randint(1, 5)
        self.WAIT_TIME = 1000  # 延迟时间,单位毫秒
        self.SCORE = 0
        self.ATTEMPT = 0

    def rightClick(self):
        self.user_lbl.config(image=self.right_image)
        self.player_list.append("right")
        self.check_input_length()

    def leftClick(self):
        self.user_lbl.config(image=self.left_image)
        self.player_list.append("left")
        self.check_input_length()

    def upClick(self):
        self.user_lbl.config(image=self.up_image)
        self.player_list.append("up")
        self.check_input_length()

    def downClick(self):
        self.user_lbl.config(image=self.down_image)
        self.player_list.append("down")
        self.check_input_length()

    def check_input_length(self):
        # 检查用户输入是否完成
        if len(self.player_list) == self.MOVE_LENGTH:
            self.check_answer()

    def show_cpu_move(self, moves, index=0):
        # 递归显示CPU的每个动作
        if index >= len(moves):
            # 所有动作显示完毕,恢复初始图像
            self.caller_lbl.config(image=self.caller_img)
            self.label_direct.config(text="Now repeat the sequence!")
            return
        move = moves[index]
        # 设置对应图像
        if move == "up":
            self.caller_lbl.config(image=self.up_image)
        elif move == "down":
            self.caller_lbl.config(image=self.down_image)
        elif move == "left":
            self.caller_lbl.config(image=self.left_image)
        elif move == "right":
            self.caller_lbl.config(image=self.right_image)
        # 延迟后显示下一个动作
        self.window.after(self.WAIT_TIME, self.show_cpu_move, moves, index+1)

    def game(self):
        self.computer_list = []
        # 生成随机动作列表
        for _ in range(self.MOVE_LENGTH):
            move = random.choice(self.DIRECTIONS)
            self.computer_list.append(move)
        print(f"CPU sequence: {self.computer_list}")
        # 开始显示动作序列
        self.show_cpu_move(self.computer_list)

    def check_answer(self):
        # 对比两个列表
        if self.player_list == self.computer_list:
            self.SCORE += 1
            self.label_direct.config(text=f"Correct! Score: {self.SCORE}")
            self.score_lbl.config(text=f"Score: {self.SCORE}")
            # 下一轮增加难度(最多5个动作)
            self.MOVE_LENGTH = min(self.MOVE_LENGTH + 1, 5)
        else:
            self.label_direct.config(text=f"Wrong! Correct sequence was: {self.computer_list}")
        # 禁用方向按钮,等待重置
        self.upButton.config(state=DISABLED)
        self.downButton.config(state=DISABLED)
        self.leftButton.config(state=DISABLED)
        self.rightButton.config(state=DISABLED)
        self.button_reset.config(state=NORMAL)

    def submit(self):
        self.button_save.config(state=DISABLED)
        self.button_reset.config(state=DISABLED)
        # 启用方向按钮
        self.upButton.config(state=NORMAL)
        self.downButton.config(state=NORMAL)
        self.leftButton.config(state=NORMAL)
        self.rightButton.config(state=NORMAL)
        self.player_list = []
        self.label_direct.config(text="Watch the sequence!")
        self.game()

    def reset(self):
        self.button_reset.config(state=DISABLED)
        self.button_save.config(state=NORMAL)
        self.player_list = []
        self.computer_list = []
        self.caller_lbl.config(image=self.caller_img)
        self.user_lbl.config(image=self.player_image)
        self.label_direct.config(text='Click Start Game to begin')
        # 禁用方向按钮直到下一轮开始
        self.upButton.config(state=DISABLED)
        self.downButton.config(state=DISABLED)
        self.leftButton.config(state=DISABLED)
        self.rightButton.config(state=DISABLED)


if __name__ == "__main__":
    window = Tk()
    window.title("Simon Says")
    app = Gui(window)
    window.mainloop()

关键修改说明

  1. CPU图像切换修复:

    • 新增show_cpu_move()递归方法,通过after()实现每个动作的延迟显示,避免阻塞主循环
    • 每个动作显示后等待1秒(可通过WAIT_TIME调整),自动切换下一个动作,最后恢复初始图像
  2. 列表对比逻辑:

    • 新增check_answer()方法,直接用==对比player_list和computer_list,判断顺序和内容是否完全一致
    • 新增check_input_length()方法,用户每次点击按钮后检查输入长度,达到CPU动作长度时自动触发对比
  3. 交互优化:

    • 游戏开始前禁用方向按钮,避免误操作
    • 对比完成后禁用方向按钮,需点击重置才能开始新游戏
    • 增加分数更新和提示信息,提升用户体验

内容的提问来源于stack exchange,提问作者Kawinthida Haase

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 03:40:00