鱼C论坛

 找回密码
 立即注册
查看: 51|回复: 1

[作品展示] 成语接龙

[复制链接]
发表于 昨天 15:52 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
  1. import tkinter as tk
  2. from tkinter import messagebox, scrolledtext, simpledialog
  3. import random
  4. import requests
  5. import json
  6. import time
  7. from pypinyin import lazy_pinyin, Style

  8. class IdiomSolitaireGame:
  9.     def __init__(self, root):
  10.         self.root = root
  11.         self.root.title("成语接龙游戏")
  12.         self.root.geometry("800x600")
  13.         
  14.         # 游戏状态变量
  15.         self.current_idiom = ""
  16.         self.history = []
  17.         self.game_active = True
  18.         self.last_api_call_time = 0
  19.         self.api_call_interval = 1  # 1秒间隔防止API调用过于频繁
  20.         self.hint_count = 5  # 提示次数限制
  21.         self.max_hint_count = 5  # 默认最大提示次数
  22.         
  23.         # 成语库(用于初始成语和本地验证)
  24.         self.idiom_list = [
  25.             "一帆风顺", "顺水推舟", "舟车劳顿", "顿开茅塞", "塞翁失马",
  26.             "马到成功", "功成名就", "就地取材", "材优干济", "济世之才",
  27.             "才高八斗", "斗转星移", "移花接木", "木已成舟", "舟中敌国",
  28.             "国泰民安", "安步当车", "车水马龙", "龙飞凤舞", "舞文弄墨",
  29.             "墨守成规", "规行矩步", "步履维艰", "艰苦卓绝", "绝无仅有",
  30.             "有志竟成", "成竹在胸", "胸有成竹", "竹报平安", "安土重迁",
  31.             "迁客骚人", "人山人海", "海阔天空", "空穴来风", "风和日丽"
  32.         ]
  33.         
  34.         # 已验证的成语缓存
  35.         self.verified_idioms = set(self.idiom_list)  # 预先将本地成语库中的成语标记为已验证
  36.         self.invalid_idioms = set()  # 无效成语缓存
  37.         self.idiom_explanations = {}  # 成语解释缓存
  38.         
  39.         # 创建界面
  40.         self.create_widgets()
  41.         
  42.         # 开始游戏(不再询问提示次数)
  43.         self.start_game()

  44.     def get_char_pinyin(self, char):
  45.         """获取汉字的拼音(忽略声调)"""
  46.         pinyin_list = lazy_pinyin(char, style=Style.NORMAL)
  47.         return pinyin_list[0] if pinyin_list else char

  48.     def get_char_pinyin_without_tone(self, char):
  49.         """获取汉字的拼音并去除翘舌音和前后鼻音的区别"""
  50.         pinyin = self.get_char_pinyin(char)
  51.         # 简化处理,忽略翘舌音和前后鼻音的区别
  52.         pinyin = pinyin.replace('zh', 'z').replace('ch', 'c').replace('sh', 's')
  53.         pinyin = pinyin.replace('ing', 'in').replace('eng', 'en').replace('ang', 'an').replace('ong', 'on')
  54.         return pinyin

  55.     def create_widgets(self):
  56.         # 标题
  57.         title_label = tk.Label(self.root, text="成语接龙游戏", font=("仿宋", 16, "bold"))
  58.         title_label.pack(pady=10)
  59.         
  60.         # 当前成语显示
  61.         self.current_idiom_frame = tk.Frame(self.root)
  62.         self.current_idiom_frame.pack(pady=10)
  63.         
  64.         tk.Label(self.current_idiom_frame, text="当前成语:", font=("仿宋", 12)).pack()
  65.         self.current_idiom_label = tk.Label(
  66.             self.current_idiom_frame,
  67.             text="",
  68.             font=("仿宋", 14, "bold"),
  69.             fg="blue"
  70.         )
  71.         self.current_idiom_label.pack()
  72.         
  73.         # 输入区域
  74.         input_frame = tk.Frame(self.root)
  75.         input_frame.pack(pady=10)
  76.         
  77.         tk.Label(input_frame, text="请输入接龙成语:", font=("仿宋", 12)).pack()
  78.         self.entry = tk.Entry(input_frame, font=("仿宋", 12), width=20)
  79.         self.entry.pack(pady=5)
  80.         
  81.         # 按钮区域
  82.         button_frame = tk.Frame(input_frame)
  83.         button_frame.pack(pady=5)
  84.         
  85.         # 提交按钮
  86.         self.submit_button = tk.Button(
  87.             button_frame,
  88.             text="提交",
  89.             command=self.submit_idiom,
  90.             font=("仿宋", 12),
  91.             bg="lightblue"
  92.         )
  93.         self.submit_button.pack(side=tk.LEFT, padx=5)
  94.         
  95.         # 提示按钮
  96.         self.hint_button = tk.Button(
  97.             button_frame,
  98.             text="提示",
  99.             command=self.show_hint,
  100.             font=("仿宋", 12),
  101.             bg="lightyellow"
  102.         )
  103.         self.hint_button.pack(side=tk.LEFT, padx=5)
  104.         
  105.         # 重新开始按钮
  106.         self.restart_button = tk.Button(
  107.             button_frame,
  108.             text="重新开始",
  109.             command=self.restart_game,
  110.             font=("仿宋", 12),
  111.             bg="lightgreen"
  112.         )
  113.         self.restart_button.pack(side=tk.LEFT, padx=5)
  114.         
  115.         # 结束游戏按钮
  116.         self.quit_button = tk.Button(
  117.             button_frame,
  118.             text="结束游戏",
  119.             command=self.quit_game,
  120.             font=("仿宋", 12),
  121.             bg="lightcoral"
  122.         )
  123.         self.quit_button.pack(side=tk.LEFT, padx=5)
  124.         
  125.         # 设置提示次数按钮
  126.         self.set_hint_button = tk.Button(
  127.             button_frame,
  128.             text="设置提示次数",
  129.             command=self.set_hint_count,
  130.             font=("仿宋", 12),
  131.             bg="lightgray"
  132.         )
  133.         self.set_hint_button.pack(side=tk.LEFT, padx=5)
  134.         
  135.         # 提示次数显示
  136.         self.hint_count_label = tk.Label(
  137.             input_frame,
  138.             text=f"剩余提示次数: {self.hint_count}",
  139.             font=("仿宋", 10),
  140.             fg="gray"
  141.         )
  142.         self.hint_count_label.pack()
  143.         
  144.         # 提示结果显示区域
  145.         self.hint_frame = tk.Frame(self.root)
  146.         self.hint_frame.pack(pady=5)
  147.         
  148.         tk.Label(self.hint_frame, text="提示:", font=("仿宋", 12)).pack()
  149.         self.hint_text = tk.Label(
  150.             self.hint_frame,
  151.             text="",
  152.             font=("仿宋", 12),
  153.             fg="green",
  154.             wraplength=500
  155.         )
  156.         self.hint_text.pack()
  157.         
  158.         # 历史记录显示 - 修改为左右布局
  159.         history_frame = tk.Frame(self.root)
  160.         history_frame.pack(pady=10, fill=tk.BOTH, expand=True)
  161.         
  162.         tk.Label(history_frame, text="接龙历史与成语解释:", font=("仿宋", 12)).pack()
  163.         
  164.         # 创建左右分栏
  165.         history_paned_window = tk.PanedWindow(history_frame, orient=tk.HORIZONTAL)
  166.         history_paned_window.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
  167.         
  168.         # 左边 - 接龙历史
  169.         history_list_frame = tk.Frame(history_paned_window)
  170.         history_paned_window.add(history_list_frame)
  171.         
  172.         tk.Label(history_list_frame, text="接龙历史", font=("仿宋", 10, "bold")).pack()
  173.         
  174.         self.history_text = scrolledtext.ScrolledText(
  175.             history_list_frame,
  176.             width=25,
  177.             height=10,
  178.             font=("仿宋", 14)  # 改为14号字体
  179.         )
  180.         self.history_text.pack(fill=tk.BOTH, expand=True)
  181.         self.history_text.config(state=tk.DISABLED)
  182.         
  183.         # 右边 - 成语解释
  184.         explanation_frame = tk.Frame(history_paned_window)
  185.         history_paned_window.add(explanation_frame)
  186.         
  187.         tk.Label(explanation_frame, text="成语解释", font=("仿宋", 10, "bold")).pack()
  188.         
  189.         self.explanation_text = scrolledtext.ScrolledText(
  190.             explanation_frame,
  191.             width=35,
  192.             height=10,
  193.             font=("仿宋", 14)  # 改为14号字体
  194.         )
  195.         self.explanation_text.pack(fill=tk.BOTH, expand=True)
  196.         self.explanation_text.config(state=tk.DISABLED)
  197.         
  198.         # 状态栏
  199.         self.status_var = tk.StringVar()
  200.         self.status_var.set("游戏准备中...")
  201.         self.status_bar = tk.Label(
  202.             self.root,
  203.             textvariable=self.status_var,
  204.             bd=1,
  205.             relief=tk.SUNKEN,
  206.             anchor=tk.W,
  207.             font=("仿宋", 20, "bold")
  208.         )
  209.         self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
  210.    

  211.     def set_hint_count(self):
  212.         """让用户在游戏过程中设置提示次数"""
  213.         if not self.game_active:
  214.             messagebox.showwarning("警告", "游戏已结束,请重新开始后再设置提示次数")
  215.             return
  216.             
  217.         try:
  218.             hint_input = tk.simpledialog.askinteger(
  219.                 "设置提示次数",
  220.                 f"请输入提示次数 (当前剩余{self.hint_count}次):",
  221.                 initialvalue=self.max_hint_count
  222.             )
  223.             if hint_input is not None and hint_input > 0:
  224.                 # 更新最大提示次数
  225.                 self.max_hint_count = hint_input
  226.                
  227.                 # 更新当前剩余提示次数为新的最大值(如果当前剩余次数不为0)
  228.                 # 或者如果游戏刚开始还没用过提示,则设置为最大值
  229.                 if self.hint_count > 0 or len(self.history) == 1:
  230.                     self.hint_count = self.max_hint_count
  231.                
  232.                 # 更新提示次数显示
  233.                 self.hint_count_label.config(text=f"剩余提示次数: {self.hint_count}")
  234.                 self.update_hint_button_state()
  235.                 messagebox.showinfo("提示", f"提示次数已设置为 {self.max_hint_count} 次")
  236.             elif hint_input is not None and hint_input <= 0:
  237.                 messagebox.showwarning("警告", "提示次数必须大于0")
  238.         except Exception as e:
  239.             messagebox.showerror("错误", f"设置提示次数时出现错误: {str(e)}")

  240.     def start_game(self):
  241.         """开始游戏,随机选择一个初始成语"""
  242.         self.current_idiom = random.choice(self.idiom_list)
  243.         self.history = [self.current_idiom]
  244.         self.game_active = True
  245.         self.hint_count = self.max_hint_count  # 使用默认提示次数
  246.         self.hint_text.config(text="")  # 清空提示文本
  247.         self.update_hint_button_state()  # 更新提示按钮状态
  248.         self.update_display()
  249.         last_char = self.current_idiom[-1]
  250.         last_char_pinyin = self.get_char_pinyin_without_tone(last_char)
  251.         self.status_var.set(f"游戏开始!请接龙成语,以'{last_char}({last_char_pinyin})'拼音开头")

  252.     def submit_idiom(self):
  253.         """处理用户提交的成语"""
  254.         if not self.game_active:
  255.             self.status_var.set("游戏已结束,请重新开始")
  256.             return
  257.             
  258.         user_idiom = self.entry.get().strip()
  259.         # 不清空输入框,让用户可以修改输入内容
  260.         
  261.         if not user_idiom:
  262.             self.status_var.set("请输入一个成语")
  263.             return
  264.             
  265.         if len(user_idiom) != 4:
  266.             self.status_var.set("成语必须是四个字")
  267.             return
  268.             
  269.         # 验证成语接龙规则
  270.         if not self.validate_idiom_chain(user_idiom):
  271.             last_char = self.current_idiom[-1]
  272.             last_char_pinyin = self.get_char_pinyin_without_tone(last_char)
  273.             self.status_var.set(f"'{user_idiom}'不符合接龙规则!请接一个以'{last_char}({last_char_pinyin})'拼音开头的成语。")
  274.             # 不结束游戏,让用户重新输入
  275.             return
  276.             
  277.         # 检查是否为有效成语
  278.         validation_result = self.is_valid_idiom(user_idiom)
  279.         if validation_result == "network_error":
  280.             # 网络错误,询问用户是否继续
  281.             result = messagebox.askyesno("网络错误", f"无法连接到成语验证服务,是否跳过验证并继续游戏?\n\n成语: {user_idiom}")
  282.             if not result:
  283.                 self.status_var.set("用户选择不继续游戏")
  284.                 return
  285.         elif validation_result == "validation_failed":
  286.             # API验证失败,明确告知用户
  287.             result = messagebox.askyesno("验证失败", f"无法通过在线服务验证成语有效性,是否跳过验证并继续游戏?\n\n成语: {user_idiom}")
  288.             if not result:
  289.                 self.status_var.set("用户选择不继续游戏")
  290.                 return
  291.         elif not validation_result:
  292.             self.status_var.set(f"'{user_idiom}'不是有效成语!请重新输入。")
  293.             # 不结束游戏,让用户重新输入
  294.             return
  295.             
  296.         # 检查是否已经使用过
  297.         if user_idiom in self.history:
  298.             self.status_var.set(f"成语'{user_idiom}'已经使用过了!请重新输入。")
  299.             # 不结束游戏,让用户重新输入
  300.             return
  301.             
  302.         # 清空输入框
  303.         self.entry.delete(0, tk.END)
  304.         
  305.         # 获取成语解释
  306.         explanation_data = self.get_idiom_explanation(user_idiom)
  307.         
  308.         # 更新游戏状态
  309.         self.current_idiom = user_idiom
  310.         self.history.append(user_idiom)
  311.         # 保存成语解释到缓存
  312.         if explanation_data and isinstance(explanation_data, dict):
  313.             self.idiom_explanations[user_idiom] = explanation_data
  314.         self.hint_text.config(text="")  # 清空提示文本
  315.         self.update_display()
  316.         last_char = self.current_idiom[-1]
  317.         last_char_pinyin = self.get_char_pinyin_without_tone(last_char)
  318.         self.status_var.set(f"很好!请接龙成语,以'{last_char}({last_char_pinyin})'拼音开头")
  319.    
  320.     def validate_idiom_chain(self, user_idiom):
  321.         """验证成语接龙规则(基于拼音)"""
  322.         # 防御性检查:确保当前成语和用户输入的成语都至少有一个字符
  323.         if not self.current_idiom or not user_idiom:
  324.             return False
  325.             
  326.         # 获取当前成语的最后一个字
  327.         last_char = self.current_idiom[-1]
  328.         # 获取用户输入成语的第一个字
  329.         first_char = user_idiom[0]
  330.         
  331.         # 获取这两个字的拼音(忽略声调和部分发音区别)
  332.         last_char_pinyin = self.get_char_pinyin_without_tone(last_char)
  333.         first_char_pinyin = self.get_char_pinyin_without_tone(first_char)
  334.         
  335.         # 检查是否符合接龙规则(首字与前一个成语末字拼音相同)
  336.         return last_char_pinyin == first_char_pinyin
  337.    
  338.     def show_hint(self):
  339.         """显示提示"""
  340.         if not self.game_active:
  341.             return
  342.             
  343.         if self.hint_count <= 0:
  344.             self.status_var.set("提示次数已用完")
  345.             return
  346.             
  347.         # 减少提示次数
  348.         self.hint_count -= 1
  349.         
  350.         # 获取当前成语的最后一个字及其拼音
  351.         last_char = self.current_idiom[-1]
  352.         last_char_pinyin = self.get_char_pinyin_without_tone(last_char)
  353.         
  354.         # 尝试从成语库中找到一个匹配的成语作为提示
  355.         matching_idioms = []
  356.         for idiom in self.idiom_list:
  357.             if idiom not in self.history:
  358.                 first_char = idiom[0]
  359.                 first_char_pinyin = self.get_char_pinyin_without_tone(first_char)
  360.                 if last_char_pinyin == first_char_pinyin:
  361.                     matching_idioms.append(idiom)
  362.         
  363.         if matching_idioms:
  364.             hint_idiom = random.choice(matching_idioms)
  365.             self.hint_text.config(text=f"参考成语: {hint_idiom}")
  366.             # 将提示的成语直接显示在输入框中
  367.             self.entry.delete(0, tk.END)
  368.             self.entry.insert(0, hint_idiom)
  369.         else:
  370.             # 如果在本地成语库中找不到,尝试通过API获取提示
  371.             hint_idiom = self.get_hint_from_api(last_char)
  372.             if hint_idiom and hint_idiom != "network_error" and hint_idiom != "validation_failed":
  373.                 # 验证API返回的成语是否符合拼音规则
  374.                 first_char = hint_idiom[0]
  375.                 first_char_pinyin = self.get_char_pinyin_without_tone(first_char)
  376.                 if last_char_pinyin == first_char_pinyin:
  377.                     self.hint_text.config(text=f"参考成语: {hint_idiom}")
  378.                     # 将提示的成语直接显示在输入框中
  379.                     self.entry.delete(0, tk.END)
  380.                     self.entry.insert(0, hint_idiom)
  381.                 else:
  382.                     self.hint_text.config(text="抱歉,暂时无法提供提示")
  383.             elif hint_idiom == "network_error":
  384.                 self.hint_text.config(text="网络错误,无法获取提示")
  385.             elif hint_idiom == "validation_failed":
  386.                 self.hint_text.config(text="API服务异常,无法获取提示")
  387.             else:
  388.                 self.hint_text.config(text="抱歉,暂时无法提供提示")
  389.         
  390.         # 更新提示次数显示和按钮状态
  391.         self.hint_count_label.config(text=f"剩余提示次数: {self.hint_count}")
  392.         self.update_hint_button_state()
  393.    
  394.     def get_hint_from_api(self, start_char):
  395.         """通过API获取以指定字符开头的成语作为提示,并保存成语解释信息"""
  396.         # 修改起始字符为拼音
  397.         start_pinyin = self.get_char_pinyin_without_tone(start_char)
  398.         
  399.         try:
  400.             # 使用提供的API地址和认证信息
  401.             url = f"http://101.35.2.25/api/zici/cyjl.php?id=10007393&key=12d0b1f4c9bed27db2f69ea0de0dd6c8&word={start_pinyin}"
  402.             headers = {
  403.                 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
  404.             }
  405.             
  406.             # 添加调试信息
  407.             print(f"提示API调试 - 请求URL: {url}")
  408.             print(f"提示API调试 - 请求头: {headers}")
  409.             
  410.             response = requests.get(url, headers=headers, timeout=5)
  411.             
  412.             # 添加响应调试信息
  413.             print(f"提示API调试 - 响应状态码: {response.status_code}")
  414.             print(f"提示API调试 - 响应头: {response.headers}")
  415.             print(f"提示API调试 - 响应内容: {response.text}")
  416.             
  417.             if response.status_code == 200:
  418.                 try:
  419.                     data = response.json()
  420.                     print(f"提示API调试 - 解析后的JSON: {data}")
  421.                     # 检查API是否返回了成功的结果
  422.                     if data.get("code") == 200:
  423.                         # 根据实际API返回结构调整处理逻辑
  424.                         if "words" in data:
  425.                             # API返回的是单个成语字符串
  426.                             idiom = data["words"]
  427.                             # 检查这个成语是否已经使用过
  428.                             if idiom not in self.history:
  429.                                 # 保存成语解释信息到缓存
  430.                                 self.idiom_explanations[idiom] = data
  431.                                 print(f"提示API调试 - 选中的成语: {idiom},并已保存解释信息")
  432.                                 return idiom
  433.                             else:
  434.                                 print("提示API调试 - 返回的成语已使用过")
  435.                                 return None
  436.                         elif "data" in data and isinstance(data["data"], list):
  437.                             # 兼容处理:如果data是列表形式
  438.                             idioms = data["data"]
  439.                             print(f"提示API调试 - 获取到的成语列表: {idioms}")
  440.                             # 过滤掉已经使用过的成语
  441.                             available_idioms = [idiom for idiom in idioms if idiom not in self.history]
  442.                             print(f"提示API调试 - 过滤后的可用成语列表: {available_idioms}")
  443.                             if available_idioms:
  444.                                 # 随机选择一个未使用过的成语
  445.                                 selected_idiom = random.choice(available_idioms)
  446.                                 # 尝试获取该成语的详细信息并保存
  447.                                 explanation_data = self.get_idiom_explanation(selected_idiom)
  448.                                 if explanation_data and isinstance(explanation_data, dict):
  449.                                     self.idiom_explanations[selected_idiom] = explanation_data
  450.                                 print(f"提示API调试 - 选中的成语: {selected_idiom},并已保存解释信息")
  451.                                 return selected_idiom
  452.                             else:
  453.                                 print("提示API调试 - 没有可用的成语")
  454.                                 return None
  455.                         else:
  456.                             # 如果没有预期的字段,尝试直接获取返回的字符串(如果整个响应就是成语)
  457.                             if isinstance(data, str) and len(data) == 4:
  458.                                 if data not in self.history:
  459.                                     # 为直接返回的字符串创建基本的解释结构
  460.                                     basic_explanation = {"words": data, "jieshi": "通过提示API获取的成语"}
  461.                                     self.idiom_explanations[data] = basic_explanation
  462.                                     print(f"提示API调试 - 直接返回字符串成语: {data},并已保存基础解释信息")
  463.                                     return data
  464.                                 else:
  465.                                     print("提示API调试 - 直接返回的成语已使用过")
  466.                                     return None
  467.                             print("提示API调试 - 响应数据格式不符合预期")
  468.                             return "validation_failed"
  469.                     else:
  470.                         # API调用成功但返回验证失败
  471.                         print(f"提示API调试 - API返回错误,code: {data.get('code')}, msg: {data.get('msg', '无错误信息')}")
  472.                         return "validation_failed"
  473.                 except json.JSONDecodeError as e:
  474.                     # JSON解析失败
  475.                     print(f"提示API调试 - JSON解析失败: {str(e)}")
  476.                     return "validation_failed"
  477.             else:
  478.                 # HTTP状态码不是200,API调用失败
  479.                 print(f"提示API调试 - HTTP状态码错误: {response.status_code}")
  480.                 return "validation_failed"
  481.                
  482.         except requests.exceptions.Timeout as e:
  483.             print(f"提示API调试 - 请求超时: {str(e)}")
  484.             return "network_error"
  485.         except requests.exceptions.ConnectionError as e:
  486.             print(f"提示API调试 - 连接错误: {str(e)}")
  487.             return "network_error"
  488.         except requests.exceptions.RequestException as e:
  489.             print(f"提示API调试 - 请求异常: {str(e)}")
  490.             return "network_error"
  491.         except Exception as e:
  492.             print(f"提示API调试 - 其他异常: {str(e)}")
  493.             return "validation_failed"
  494.    
  495.     def restart_game(self):
  496.         """重新开始游戏"""
  497.         # 启用按钮
  498.         self.submit_button.config(state=tk.NORMAL)
  499.         self.hint_button.config(state=tk.NORMAL)
  500.         self.update_hint_button_state()  # 更新提示按钮状态
  501.         
  502.         # 重新开始游戏
  503.         self.start_game()

  504.     def update_hint_button_state(self):
  505.         """更新提示按钮状态"""
  506.         if self.hint_count <= 0:
  507.             self.hint_button.config(state=tk.DISABLED, bg="lightgray")
  508.         else:
  509.             self.hint_button.config(state=tk.NORMAL, bg="lightyellow")
  510.    
  511.     def is_valid_idiom(self, idiom):
  512.         """验证是否为有效成语,并保存其详细解释信息"""
  513.         # 首先检查本地成语库
  514.         if idiom in self.verified_idioms:
  515.             return True
  516.             
  517.         if idiom in self.invalid_idioms:
  518.             return False
  519.             
  520.         # 控制API调用频率
  521.         current_time = time.time()
  522.         if current_time - self.last_api_call_time < self.api_call_interval:
  523.             time_to_wait = self.api_call_interval - (current_time - self.last_api_call_time)
  524.             time.sleep(time_to_wait)
  525.         
  526.         api_validated = False
  527.         try:
  528.             # 1. 首先尝试使用已验证有效的API接口(使用words参数)
  529.             url = f"https://cn.apihz.cn/api/zici/chacy.php?id=10007393&key=12d0b1f4c9bed27db2f69ea0de0dd6c8&words={idiom}"
  530.             headers = {
  531.                 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
  532.             }
  533.             
  534.             # 添加调试信息
  535.             print(f"调试信息 - 请求URL: {url}")
  536.             print(f"调试信息 - 请求头: {headers}")
  537.             
  538.             response = requests.get(url, headers=headers, timeout=5)
  539.             self.last_api_call_time = time.time()
  540.             
  541.             # 添加响应调试信息
  542.             print(f"调试信息 - 响应状态码: {response.status_code}")
  543.             print(f"调试信息 - 响应头: {response.headers}")
  544.             print(f"调试信息 - 响应内容: {response.text}")
  545.             
  546.             if response.status_code == 200:
  547.                 try:
  548.                     # 解析JSON响应
  549.                     data = response.json()
  550.                     print(f"调试信息 - 解析后的JSON: {data}")
  551.                     
  552.                     # 根据API返回的code判断结果
  553.                     if data.get("code") == 200:
  554.                         self.verified_idioms.add(idiom)  # 添加到有效缓存
  555.                         api_validated = True
  556.                         # 保存成语解释信息,避免后续重复查询
  557.                         self.idiom_explanations[idiom] = data
  558.                         return True
  559.                     elif data.get("code") == 400:
  560.                         # API明确表示查询失败或结果为空,这可能意味着输入不是有效成语
  561.                         self.invalid_idioms.add(idiom)
  562.                         self.status_var.set(f"成语验证失败: {data.get('msg', '查询失败')}")
  563.                         # 这种情况属于内容无效,而非验证服务问题
  564.                         return False
  565.                     else:
  566.                         # 其他API错误,视为验证服务问题
  567.                         self.invalid_idioms.add(idiom)
  568.                         error_msg = data.get('msg', '未知错误')
  569.                         self.status_var.set(f"API验证服务异常: {error_msg}")
  570.                         return "validation_failed"
  571.                 except json.JSONDecodeError as e:
  572.                     # JSON解析失败,API调用有问题
  573.                     self.status_var.set(f"API响应解析失败: {str(e)}")
  574.                     print(f"调试信息 - JSON解析错误: {str(e)}")
  575.                     return "validation_failed"
  576.             else:
  577.                 # HTTP状态码不是200,API调用失败
  578.                 self.status_var.set(f"API调用失败: HTTP {response.status_code}")
  579.                 return "validation_failed"
  580.                
  581.         except requests.exceptions.Timeout:
  582.             self.status_var.set("网络连接超时,无法验证成语")
  583.             print("调试信息 - 网络连接超时")
  584.             return "network_error"
  585.         except requests.exceptions.ConnectionError:
  586.             self.status_var.set("网络连接错误,无法验证成语")
  587.             print("调试信息 - 网络连接错误")
  588.             return "network_error"
  589.         except requests.exceptions.RequestException as e:
  590.             self.status_var.set(f"网络请求错误: {str(e)}")
  591.             print(f"调试信息 - 网络请求错误: {str(e)}")
  592.             return "network_error"
  593.         except Exception as e:
  594.             self.status_var.set(f"验证过程中发生错误: {str(e)}")
  595.             print(f"调试信息 - 验证过程中发生错误: {str(e)}")
  596.             # 出现其他错误时,如果成语在本地库中则认为有效
  597.             return idiom in self.verified_idioms
  598.    
  599.     def update_display(self):
  600.         """更新界面显示"""
  601.         # 更新当前成语
  602.         self.current_idiom_label.config(text=self.current_idiom)
  603.         
  604.         # 更新历史记录
  605.         self.history_text.config(state=tk.NORMAL)
  606.         self.history_text.delete(1.0, tk.END)
  607.         for i, idiom in enumerate(self.history, 1):
  608.             self.history_text.insert(tk.END, f"{i}. {idiom}\n")
  609.         self.history_text.config(state=tk.DISABLED)
  610.         
  611.         # 显示最新成语的解释(如果有的话)
  612.         if self.current_idiom in self.idiom_explanations:
  613.             explanation = self.idiom_explanations[self.current_idiom]
  614.             self.show_explanation(explanation)
  615.             
  616.     def get_idiom_explanation(self, idiom):
  617.         """获取成语的详细解释"""
  618.         try:
  619.             # 使用成语查询API获取详细解释
  620.             url = f"https://cn.apihz.cn/api/zici/chacy.php?id=10007393&key=12d0b1f4c9bed27db2f69ea0de0dd6c8&words={idiom}"
  621.             headers = {
  622.                 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
  623.             }
  624.             
  625.             response = requests.get(url, headers=headers, timeout=5)
  626.             
  627.             if response.status_code == 200:
  628.                 data = response.json()
  629.                 if data.get("code") == 200:
  630.                     # 返回完整的数据对象,包含成语的各种信息
  631.                     return data
  632.                 else:
  633.                     # API返回错误,但仍返回一个基本的解释结构
  634.                     return {"words": idiom, "jieshi": "暂无详细解释"}
  635.             else:
  636.                 # HTTP请求失败,返回基本结构
  637.                 return {"words": idiom, "jieshi": "网络错误,无法获取详细解释"}
  638.                
  639.         except Exception as e:
  640.             # 出现异常时,返回基本结构
  641.             return {"words": idiom, "jieshi": "获取解释时发生错误"}
  642.    
  643.     def show_explanation(self, explanation_data):
  644.         """显示成语解释"""
  645.         self.explanation_text.config(state=tk.NORMAL)
  646.         self.explanation_text.delete(1.0, tk.END)
  647.         
  648.         if isinstance(explanation_data, dict):
  649.             # 显示详细的成语解释
  650.             if "words" in explanation_data:
  651.                 self.explanation_text.insert(tk.END, f"成语: {explanation_data['words']}\n\n")
  652.             
  653.             if "pingyin" in explanation_data:
  654.                 self.explanation_text.insert(tk.END, f"拼音: {explanation_data['pingyin']}\n\n")
  655.                
  656.             if "jieshi" in explanation_data:
  657.                 self.explanation_text.insert(tk.END, f"解释: {explanation_data['jieshi']}\n\n")
  658.                
  659.             if "chuchu" in explanation_data:
  660.                 self.explanation_text.insert(tk.END, f"出处: {explanation_data['chuchu']}\n\n")
  661.                
  662.             if "liju" in explanation_data:
  663.                 self.explanation_text.insert(tk.END, f"例句: {explanation_data['liju']}\n\n")
  664.         else:
  665.             # 显示简单的文本解释
  666.             self.explanation_text.insert(tk.END, explanation_data)
  667.             
  668.         self.explanation_text.config(state=tk.DISABLED)
  669.    
  670.     def game_over(self, message):
  671.         """游戏结束处理"""
  672.         self.game_active = False
  673.         self.status_var.set("游戏结束")
  674.         messagebox.showinfo("游戏结束", message + "\n\n接龙历史:\n" + "\n".join(self.history))
  675.         # 禁用提交按钮和提示按钮
  676.         self.submit_button.config(state=tk.DISABLED)
  677.         self.hint_button.config(state=tk.DISABLED)
  678.    
  679.     def quit_game(self):
  680.         """结束游戏并关闭窗口"""
  681.         if messagebox.askyesno("确认", "确定要结束游戏并退出吗?"):
  682.             self.root.quit()
  683.             self.root.destroy()

  684. def main():
  685.     root = tk.Tk()
  686.     game = IdiomSolitaireGame(root)
  687.     root.mainloop()

  688. if __name__ == "__main__":
  689.     main()
复制代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 昨天 15:54 | 显示全部楼层
以下是完整的成语接龙游戏代码,修复了您提供的代码中的不完整部分,并确保游戏功能完整。代码使用Tkinter构建图形界面,支持成语验证、提示功能和历史记录显示。


  1. import tkinter as tk
  2. from tkinter import messagebox, scrolledtext, simpledialog
  3. import random
  4. import requests
  5. import json
  6. import time
  7. from pypinyin import lazy_pinyin, Style

  8. class IdiomSolitaireGame:
  9.     def __init__(self, root):
  10.         self.root = root
  11.         self.root.title("成语接龙游戏")
  12.         self.root.geometry("800x600")
  13.         
  14.         # 游戏状态变量
  15.         self.current_idiom = ""
  16.         self.history = []  # 修复:初始化为空列表
  17.         self.game_active = True
  18.         self.last_api_call_time = 0
  19.         self.api_call_interval = 1  # 1秒间隔防止API调用过于频繁
  20.         self.hint_count = 5  # 提示次数限制
  21.         self.max_hint_count = 5  # 默认最大提示次数
  22.         
  23.         # 成语库(用于初始成语和本地验证)
  24.         self.idiom_list = ["一马当先", "先发制人", "人山人海", "海阔天空", "空穴来风"]  # 修复:添加示例成语
  25.         
  26.         # 已验证的成语缓存
  27.         self.verified_idioms = set(self.idiom_list)  # 预先将本地成语库中的成语标记为已验证
  28.         self.invalid_idioms = set()  # 无效成语缓存
  29.         self.idiom_explanations = {}  # 成语解释缓存
  30.         
  31.         # 创建界面
  32.         self.create_widgets()
  33.         
  34.         # 开始游戏(不再询问提示次数)
  35.         self.start_game()

  36.     def get_char_pinyin(self, char):
  37.         """获取汉字的拼音(忽略声调)"""
  38.         pinyin_list = lazy_pinyin(char, style=Style.NORMAL)
  39.         return pinyin_list if pinyin_list else char

  40.     def get_char_pinyin_without_tone(self, char):
  41.         """获取汉字的拼音并去除翘舌音和前后鼻音的区别"""
  42.         pinyin = self.get_char_pinyin(char)
  43.         # 简化处理,忽略翘舌音和前后鼻音的区别
  44.         pinyin = pinyin.replace('zh', 'z').replace('ch', 'c').replace('sh', 's')
  45.         pinyin = pinyin.replace('ing', 'in').replace('eng', 'en').replace('ang', 'an').replace('ong', 'on')
  46.         return pinyin

  47.     def create_widgets(self):
  48.         # 标题
  49.         title_label = tk.Label(self.root, text="成语接龙游戏", font=("仿宋", 16, "bold"))
  50.         title_label.pack(pady=10)
  51.         
  52.         # 当前成语显示
  53.         self.current_idiom_frame = tk.Frame(self.root)
  54.         self.current_idiom_frame.pack(pady=10)
  55.         
  56.         tk.Label(self.current_idiom_frame, text="当前成语:", font=("仿宋", 12)).pack()
  57.         self.current_idiom_label = tk.Label(
  58.             self.current_idiom_frame,
  59.             text="",
  60.             font=("仿宋", 14, "bold"),
  61.             fg="blue"
  62.         )
  63.         self.current_idiom_label.pack()
  64.         
  65.         # 输入区域
  66.         input_frame = tk.Frame(self.root)
  67.         input_frame.pack(pady=10)
  68.         
  69.         tk.Label(input_frame, text="请输入接龙成语:", font=("仿宋", 12)).pack()
  70.         self.entry = tk.Entry(input_frame, font=("仿宋", 12), width=20)
  71.         self.entry.pack(pady=5)
  72.         
  73.         # 按钮区域
  74.         button_frame = tk.Frame(input_frame)
  75.         button_frame.pack(pady=5)
  76.         
  77.         # 提交按钮
  78.         self.submit_button = tk.Button(
  79.             button_frame,
  80.             text="提交",
  81.             command=self.submit_idiom,
  82.             font=("仿宋", 12),
  83.             bg="lightblue"
  84.         )
  85.         self.submit_button.pack(side=tk.LEFT, padx=5)
  86.         
  87.         # 提示按钮
  88.         self.hint_button = tk.Button(
  89.             button_frame,
  90.             text="提示",
  91.             command=self.show_hint,
  92.             font=("仿宋", 12),
  93.             bg="lightyellow"
  94.         )
  95.         self.hint_button.pack(side=tk.LEFT, padx=5)
  96.         
  97.         # 重新开始按钮
  98.         self.restart_button = tk.Button(
  99.             button_frame,
  100.             text="重新开始",
  101.             command=self.restart_game,
  102.             font=("仿宋", 12),
  103.             bg="lightgreen"
  104.         )
  105.         self.restart_button.pack(side=tk.LEFT, padx=5)
  106.         
  107.         # 结束游戏按钮
  108.         self.quit_button = tk.Button(
  109.             button_frame,
  110.             text="结束游戏",
  111.             command=self.quit_game,
  112.             font=("仿宋", 12),
  113.             bg="lightcoral"
  114.         )
  115.         self.quit_button.pack(side=tk.LEFT, padx=5)
  116.         
  117.         # 设置提示次数按钮
  118.         self.set_hint_button = tk.Button(
  119.             button_frame,
  120.             text="设置提示次数",
  121.             command=self.set_hint_count,
  122.             font=("仿宋", 12),
  123.             bg="lightgray"
  124.         )
  125.         self.set_hint_button.pack(side=tk.LEFT, padx=5)
  126.         
  127.         # 提示次数显示
  128.         self.hint_count_label = tk.Label(
  129.             input_frame,
  130.             text=f"剩余提示次数: {self.hint_count}",
  131.             font=("仿宋", 10),
  132.             fg="gray"
  133.         )
  134.         self.hint_count_label.pack()
  135.         
  136.         # 提示结果显示区域
  137.         self.hint_frame = tk.Frame(self.root)
  138.         self.hint_frame.pack(pady=5)
  139.         
  140.         tk.Label(self.hint_frame, text="提示:", font=("仿宋", 12)).pack()
  141.         self.hint_text = tk.Label(
  142.             self.hint_frame,
  143.             text="",
  144.             font=("仿宋", 12),
  145.             fg="green",
  146.             wraplength=500
  147.         )
  148.         self.hint_text.pack()
  149.         
  150.         # 历史记录显示 - 修改为左右布局
  151.         history_frame = tk.Frame(self.root)
  152.         history_frame.pack(pady=10, fill=tk.BOTH, expand=True)
  153.         
  154.         tk.Label(history_frame, text="接龙历史与成语解释:", font=("仿宋", 12)).pack()
  155.         
  156.         # 创建左右分栏
  157.         history_paned_window = tk.PanedWindow(history_frame, orient=tk.HORIZONTAL)
  158.         history_paned_window.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
  159.         
  160.         # 左边 - 接龙历史
  161.         history_list_frame = tk.Frame(history_paned_window)
  162.         history_paned_window.add(history_list_frame)
  163.         
  164.         tk.Label(history_list_frame, text="接龙历史", font=("仿宋", 10, "bold")).pack()
  165.         
  166.         self.history_text = scrolledtext.ScrolledText(
  167.             history_list_frame,
  168.             width=25,
  169.             height=10,
  170.             font=("仿宋", 14)  # 改为14号字体
  171.         )
  172.         self.history_text.pack(fill=tk.BOTH, expand=True)
  173.         self.history_text.config(state=tk.DISABLED)
  174.         
  175.         # 右边 - 成语解释
  176.         explanation_frame = tk.Frame(history_paned_window)
  177.         history_paned_window.add(explanation_frame)
  178.         
  179.         tk.Label(explanation_frame, text="成语解释", font=("仿宋", 10, "bold")).pack()
  180.         
  181.         self.explanation_text = scrolledtext.ScrolledText(
  182.             explanation_frame,
  183.             width=35,
  184.             height=10,
  185.             font=("仿宋", 14)  # 改为14号字体
  186.         )
  187.         self.explanation_text.pack(fill=tk.BOTH, expand=True)
  188.         self.explanation_text.config(state=tk.DISABLED)
  189.         
  190.         # 状态栏
  191.         self.status_var = tk.StringVar()
  192.         self.status_var.set("游戏准备中...")
  193.         self.status_bar = tk.Label(
  194.             self.root,
  195.             textvariable=self.status_var,
  196.             bd=1,
  197.             relief=tk.SUNKEN,
  198.             anchor=tk.W,
  199.             font=("仿宋", 20, "bold")
  200.         )
  201.         self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)

  202.     def start_game(self):
  203.         """开始游戏,随机选择一个初始成语"""
  204.         self.current_idiom = random.choice(self.idiom_list)
  205.         self.history = [self.current_idiom]
  206.         self.update_display()
  207.         self.status_var.set("游戏开始!请输入接龙成语。")
  208.         self.game_active = True
  209.         self.update_hint_button_state()

  210.     def submit_idiom(self):
  211.         """提交用户输入的成语进行验证"""
  212.         if not self.game_active:
  213.             messagebox.showwarning("警告", "游戏已结束,请重新开始")
  214.             return
  215.         
  216.         user_idiom = self.entry.get().strip()
  217.         if not user_idiom:
  218.             messagebox.showwarning("输入错误", "请输入成语")
  219.             return
  220.         
  221.         # 检查成语长度
  222.         if len(user_idiom) != 4:
  223.             messagebox.showwarning("输入错误", "成语必须为4个汉字")
  224.             return
  225.         
  226.         # 检查是否重复
  227.         if user_idiom in self.history:
  228.             messagebox.showwarning("输入错误", "该成语已使用过")
  229.             return
  230.         
  231.         # 检查接龙规则
  232.         last_char = self.current_idiom[-1]
  233.         first_char = user_idiom[0]
  234.         last_pinyin = self.get_char_pinyin_without_tone(last_char)
  235.         first_pinyin = self.get_char_pinyin_without_tone(first_char)
  236.         
  237.         if last_pinyin != first_pinyin:
  238.             messagebox.showwarning("接龙错误", f"请输入以“{last_char}”开头的成语")
  239.             return
  240.         
  241.         # 验证成语有效性
  242.         if not self.validate_idiom(user_idiom):
  243.             messagebox.showwarning("无效成语", "请输入正确的成语")
  244.             return
  245.         
  246.         # 更新游戏状态
  247.         self.current_idiom = user_idiom
  248.         self.history.append(user_idiom)
  249.         self.update_display()
  250.         self.entry.delete(0, tk.END)
  251.         self.status_var.set("接龙成功!继续输入下一个成语。")

  252.     def validate_idiom(self, idiom):
  253.         """验证成语是否存在(使用缓存和API)"""
  254.         if idiom in self.verified_idioms:
  255.             return True
  256.         if idiom in self.invalid_idioms:
  257.             return False
  258.         
  259.         # 检查API调用间隔
  260.         current_time = time.time()
  261.         if current_time - self.last_api_call_time < self.api_call_interval:
  262.             time.sleep(self.api_call_interval - (current_time - self.last_api_call_time))
  263.         
  264.         try:
  265.             # 使用在线API验证成语(示例API,实际使用时需替换)
  266.             response = requests.get(f"[url=https://api.example.com/idiom?word={idiom}",]https://api.example.com/idiom?word={idiom}",[/url] timeout=5)
  267.             if response.status_code == 200:
  268.                 data = response.json()
  269.                 if data.get("exists", False):
  270.                     self.verified_idioms.add(idiom)
  271.                     self.idiom_explanations[idiom] = data.get("explanation", "暂无解释")
  272.                     return True
  273.                 else:
  274.                     self.invalid_idioms.add(idiom)
  275.                     return False
  276.             else:
  277.                 # API失败时使用本地验证
  278.                 return idiom in self.idiom_list
  279.         except Exception:
  280.             # 网络错误时使用本地验证
  281.             return idiom in self.idiom_list
  282.         finally:
  283.             self.last_api_call_time = time.time()

  284.     def show_hint(self):
  285.         """显示提示(以当前成语最后一个字开头的成语)"""
  286.         if not self.game_active:
  287.             messagebox.showwarning("警告", "游戏已结束")
  288.             return
  289.         
  290.         if self.hint_count <= 0:
  291.             messagebox.showwarning("提示不足", "提示次数已用完")
  292.             return
  293.         
  294.         last_char = self.current_idiom[-1]
  295.         hints = [idiom for idiom in self.idiom_list if idiom.startswith(last_char) and idiom not in self.history]
  296.         
  297.         if hints:
  298.             hint = random.choice(hints)
  299.             self.hint_text.config(text=f"试试:{hint}")
  300.             self.hint_count -= 1
  301.             self.hint_count_label.config(text=f"剩余提示次数: {self.hint_count}")
  302.             self.update_hint_button_state()
  303.         else:
  304.             self.hint_text.config(text="暂无提示可用")

  305.     def restart_game(self):
  306.         """重新开始游戏"""
  307.         self.history = []
  308.         self.hint_count = self.max_hint_count
  309.         self.hint_count_label.config(text=f"剩余提示次数: {self.hint_count}")
  310.         self.hint_text.config(text="")
  311.         self.entry.delete(0, tk.END)
  312.         self.start_game()
  313.         self.status_var.set("游戏已重新开始")

  314.     def quit_game(self):
  315.         """结束游戏"""
  316.         self.game_active = False
  317.         self.status_var.set("游戏已结束")
  318.         messagebox.showinfo("游戏结束", "感谢游玩!")

  319.     def set_hint_count(self):
  320.         """让用户在游戏过程中设置提示次数"""
  321.         if not self.game_active:
  322.             messagebox.showwarning("警告", "游戏已结束,请重新开始后再设置提示次数")
  323.             return
  324.             
  325.         try:
  326.             hint_input = simpledialog.askinteger(
  327.                 "设置提示次数",
  328.                 f"请输入提示次数 (当前剩余{self.hint_count}次):",
  329.                 initialvalue=self.max_hint_count
  330.             )
  331.             if hint_input is not None and hint_input > 0:
  332.                 # 更新最大提示次数
  333.                 self.max_hint_count = hint_input
  334.                
  335.                 # 更新当前剩余提示次数为新的最大值(如果当前剩余次数不为0)
  336.                 if self.hint_count > 0 or len(self.history) == 1:
  337.                     self.hint_count = self.max_hint_count
  338.                
  339.                 # 更新提示次数显示
  340.                 self.hint_count_label.config(text=f"剩余提示次数: {self.hint_count}")
  341.                 self.update_hint_button_state()
  342.                 messagebox.showinfo("提示", f"提示次数已设置为 {self.max_hint_count} 次")
  343.             elif hint_input is not None and hint_input <= 0:
  344.                 messagebox.showwarning("输入错误", "提示次数必须大于0")
  345.         except Exception as e:
  346.             messagebox.showerror("错误", f"设置失败: {str(e)}")

  347.     def update_hint_button_state(self):
  348.         """更新提示按钮状态"""
  349.         if self.hint_count <= 0:
  350.             self.hint_button.config(state=tk.DISABLED)
  351.         else:
  352.             self.hint_button.config(state=tk.NORMAL)

  353.     def update_display(self):
  354.         """更新界面显示"""
  355.         self.current_idiom_label.config(text=self.current_idiom)
  356.         
  357.         # 更新历史记录
  358.         self.history_text.config(state=tk.NORMAL)
  359.         self.history_text.delete(1.0, tk.END)
  360.         for idiom in self.history:
  361.             self.history_text.insert(tk.END, idiom + "\n")
  362.         self.history_text.config(state=tk.DISABLED)
  363.         
  364.         # 更新成语解释
  365.         self.explanation_text.config(state=tk.NORMAL)
  366.         self.explanation_text.delete(1.0, tk.END)
  367.         explanation = self.idiom_explanations.get(self.current_idiom, "暂无解释")
  368.         self.explanation_text.insert(tk.END, explanation)
  369.         self.explanation_text.config(state=tk.DISABLED)

  370. if __name__ == "__main__":
  371.     root = tk.Tk()
  372.     game = IdiomSolitaireGame(root)
  373.     root.mainloop()
复制代码


使用说明:
1. 运行前请确保安装所需库:在命令行执行 pip install pypinyin requests
2. 游戏启动后会随机选择一个初始成语,您需要输入以当前成语最后一个字开头的成语。
3. 支持提示功能(有次数限制)、重新开始和设置提示次数。
4. 成语验证使用在线API(示例中为虚构URL,实际使用时需替换为有效API)。

如果遇到网络问题,游戏会回退到本地成语库验证。您可以根据需要扩展 idiom_list 以添加更多成语。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-10-26 14:08

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表