larinui的Python 代码集合

迷宫地图代码

import random
import heapq
import os
import time
import json
import math
import numpy as np
from datetime import datetime
class InvalidMapError(Exception):
    """自定义异常,用于表示地图设置无效"""
    pass
# -------------------------- 柏林噪声核心代码 --------------------------
def generate_permutation(seed=None):
    """生成带种子的置换表,长度为256"""
    permutation = list(range(256))
    random.seed(seed)
    for i in range(255, 0, -1):
        j = random.randint(0, i)
        permutation[i], permutation[j] = permutation[j], permutation[i]
    return permutation
def fade(t):
    return t * t * t * (t * (t * 6 - 15) + 10)
def lerp(t, a, b):
    return a + t * (b - a)
def grad(hash_val, x, y):
    h = hash_val & 3
    if h == 0:
        return x + y
    elif h == 1:
        return -x + y
    elif h == 2:
        return x - y
    else:
        return -x - y
def perlin_noise_2d(x, y, permutation):
    p = permutation * 2
    X = math.floor(x) & 255
    Y = math.floor(y) & 255
    x -= math.floor(x)
    y -= math.floor(y)
    u = fade(x)
    v = fade(y)
    A = p[X] + Y
    B = p[X + 1] + Y
    n0 = grad(p[A], x, y)
    n1 = grad(p[B], x - 1, y)
    nx0 = lerp(u, n0, n1)
    n2 = grad(p[A + 1], x, y - 1)
    n3 = grad(p[B + 1], x - 1, y - 1)
    nx1 = lerp(u, n2, n3)
    return lerp(v, nx0, nx1)
def octave_perlin_2d(x, y, permutation, octaves=4, persistence=0.5, lacunarity=2.0):
    total = 0
    frequency = 1
    amplitude = 1
    max_value = 0
    for _ in range(octaves):
        total += perlin_noise_2d(x * frequency, y * frequency, permutation) * amplitude
        max_value += amplitude
        amplitude *= persistence
        frequency *= lacunarity
    return total / max_value
# -------------------------- 迷宫地图类 --------------------------
class CharacterMap:
    def __init__(self, width, a, height, sections, obstacles=None, special_obstacles=None, goal=None, player_position=None, use_file_settings=False, auto_save=False, noise_seed=123):
        print("正在生成地图,设置数据. . .")
        self.width = width
        self.height = a
        self.section_width = sections
        self.section_height = height
        self.view_center = [self.section_width // 2, self.section_height // 2]
        self.map = [['.' for _ in range(width)] for _ in range(a)]
        self.player_position = player_position if player_position else [random.randint(0, self.view_center[0]), random.randint(0, self.view_center[1])]
        self.goal = goal if goal else [random.randint(0, width - 1), random.randint(0, a - 1)]
        while self.goal == self.player_position:
            self.goal = [random.randint(0, width - 1), random.randint(0, a - 1)]
        self.steps = 0
        self.obstacles = obstacles if obstacles else []
        self.special_obstacles = special_obstacles if special_obstacles else []
        self.path = []
        self.auto_save = auto_save
        self.noise_seed = noise_seed  # 柏林噪声种子
        self.permutation = generate_permutation(noise_seed)  # 生成置换表
        if not use_file_settings:
            while not self.generate_obstacles():
                
                pass
        else:
            if not self.a_star(tuple(self.player_position), tuple(self.goal)):
                print("%--警告:从文件加载的地图无法到达终点!--%")
            try:
                self.update_map()
            except:
                print('此文件更新错误')
                raise InvalidMapError("地图设置无效")
        print("完成")
        time.sleep(0.5)
        self.update_map()
    def generate_obstacles(self):
        """使用柏林噪声生成自然分布的障碍物"""
        self.map = [['.' for _ in range(self.width)] for _ in range(self.height)]
        self.obstacles.clear()
        self.special_obstacles.clear()
        # ========== 已调好的参数 ==========
        noise_scale = 15.0       # 控制纹理粗细
        octaves = 3              # 减少细节,避免过密
        obstacle_threshold = 0.5 # 普通障碍物阈值
        special_threshold = 0.7  # 特殊障碍物阈值
        # 遍历地图生成障碍物
        for y in range(self.height):
            for x in range(self.width):
                noise_val = octave_perlin_2d(
                    x / noise_scale, 
                    y / noise_scale, 
                    self.permutation, 
                    octaves=octaves
                )
                noise_val = (noise_val + 1) / 2  # 归一化到0-1
                if [x, y] == self.player_position or [x, y] == self.goal:
                    continue
                if noise_val < obstacle_threshold:
                    self.obstacles.append([x, y])
                elif noise_val > special_threshold:
                    self.special_obstacles.append([x, y])
        # ========== 新增的障碍物保底机制 ==========
        min_obstacle_count = int(self.width * self.height * 0.50)
        if len(self.obstacles) < min_obstacle_count:
            while len(self.obstacles) < min_obstacle_count:
                x = random.randint(0, self.width-1)
                y = random.randint(0, self.height-1)
                if [x,y] not in self.obstacles and [x,y] != self.player_position and [x,y] != self.goal:
                    self.obstacles.append([x,y])
        # 检查路径是否可行
        path = self.a_star(tuple(self.player_position), tuple(self.goal))
        return path is not None
    def zdyd(self):
        if self.path == []:
            self.show_shortest_path()
        szx = len(self.path)
        szx_pd = 0
        for x, y in self.path:
            print('自动寻路中...')
            os.system('clear')
            if szx_pd == szx - 1:
                self.path = []
                self.map[self.player_position[1]][self.player_position[0]] = '♛'
                self.update_map()
                break
            self.player_position = [x, y]
            self.map = [['.' for _ in range(self.width)] for _ in range(self.height)]
            for x, y in self.obstacles:
                self.map[y][x] = '#'
            for x, y in self.special_obstacles:
                self.map[y][x] = 'ᐃ'
            self.map[self.player_position[1]][self.player_position[0]] = '●'
            self.map[self.goal[1]][self.goal[0]] = '♞'
            self.print_map()
            self.steps += 1
            szx_pd += 1
            time.sleep(0.2)
        print('完成')
    def update_map(self):
        self.map = [['.' for _ in range(self.width)] for _ in range(self.height)]
        for x, y in self.obstacles:
            self.map[y][x] = '#'
        for x, y in self.special_obstacles:
            self.map[y][x] = 'ᐃ'
        for x, y in self.path:
            self.map[y][x] = '■'
        self.map[self.player_position[1]][self.player_position[0]] = '♛'
        self.map[self.goal[1]][self.goal[0]] = '♞'
    def print_map(self):
        start_x = max(0, self.player_position[0] - self.view_center[0])
        end_x = start_x + self.section_width
        if end_x > self.width:
            end_x = self.width
            start_x = self.width - self.section_width
        start_y = max(0, self.player_position[1] - self.view_center[1])
        end_y = start_y + self.section_height
        if end_y > self.height:
            end_y = self.height
            start_y = self.height - self.section_height
        top_border = '╔' + '═' * int((self.section_width) * 2) + '╗'
        print(top_border)
        for row in self.map[start_y:end_y]:
            print('║ ' + ' '.join(row[start_x:end_x]) + '║')
        bottom_border = '╚' + '═' * int((self.section_width) * 2) + '╝'
        print(bottom_border)
        print(f"步数:{self.steps}")
        print()
    def move(self, directionx):
        x, y = self.player_position
        new_x, new_y = x, y
        for direction in directionx:
            if direction == '4':
                new_x -= 1
            elif direction == '8':
                new_y += 1
            elif direction == '6':
                new_x += 1
            elif direction == '2':
                new_y -= 1
            elif direction == '1':
                new_x -= 1
                new_y -= 1
            elif direction == '3':
                new_x += 1
                new_y -= 1
            elif direction == '7':
                new_x -= 1
                new_y += 1
            elif direction == '9':
                new_x += 1
                new_y += 1
            else:
                print("无效的方向!")
                return
            if not (0 <= new_x < self.width and 0 <= new_y < self.height):
                print("你不能走出地图边界!")
                return
            if [new_x, new_y] in self.obstacles:
                print("前面有障碍物,不能通过!")
                return
            if [new_x, new_y] in self.special_obstacles:
                print("碰到特殊障碍物,你被弹回了!")
                self.player_position = [random.randint(0, self.view_center[0]), random.randint(0, self.view_center[1])]
                self.update_map()
                self.steps += 1
                return
            self.player_position = [new_x, new_y]
            self.steps += 1
            if self.player_position == self.goal:
                print("恭喜你到达终点!游戏结束!")
                print(f"总步数:{self.steps}")
                return self.steps
            self.random_move_goal()
            self.path = []
            self.update_map()
            self.print_map()
            time.sleep(0.1)
        os.system('clear')
    def random_move_goal(self):
        directions = [
            (-1, -1), (-1, 0), (-1, 1),
            (0, -1), (0, 1),
            (1, -1), (1, 0), (1, 1)
        ]
        possible_positions = []
        for dx, dy in directions:
            new_goal_x = self.goal[0] + dx
            new_goal_y = self.goal[1] + dy
            if 0 <= new_goal_x < self.width and 0 <= new_goal_y < self.height:
                if [new_goal_x, new_goal_y] not in self.obstacles and \
                   [new_goal_x, new_goal_y] not in self.special_obstacles and \
                   [new_goal_x, new_goal_y] != self.player_position:
                    possible_positions.append([new_goal_x, new_goal_y])
        if possible_positions:
            self.goal = random.choice(possible_positions)
    def run(self):
        print("欢迎来到迷宫地图!")
        print("使用数字控制方向:")
        print("1 - 左上,2 - 上,3 - 右上,4 - 左,6 - 右,7 - 左下,8 - 下,9 - 右下")
        print("输入'0'退出游戏。")
        print("输入'5'获取当前位置到终点的最短路径。")
        print("输入'@'自动寻路到终点。")
        while True:
            self.print_map()
            direction = input("请输入方向:").strip().lower()
            os.system('clear')
            if direction == '0':
                print("退出游戏。")
                return -1
            elif direction == '5':
                self.show_shortest_path()
            elif direction == '@':
                self.zdyd()
            else:
                bs = self.move(direction)
                if bs is not None:
                    if self.auto_save:
                        self.save_map_data()
                    return bs
    def save_map_data(self):
        current_time = datetime.now().strftime("%Y%m%d_%H%M%S")
        file_name = f"{current_time}.json"
        file_path = f"/storage/emulated/0/Download/python.wj/gwzm_wj/{file_name}"
        os.makedirs(os.path.dirname(file_path), exist_ok=True)
        data = {
            "width": self.width,
            "a": self.height,
            "height": self.section_height,
            "sections": self.section_width,
            "obstacles": self.obstacles,
            "special_obstacles": self.special_obstacles,
            "player_position": self.player_position,
            "goal": self.goal,
            "noise_seed": self.noise_seed  # 保存噪声种子
        }
        with open(file_path, 'w') as file:
            json.dump(data, file, indent=4)
        print(f"地图数据已保存到 {file_path}")
    def show_shortest_path(self):
        start = tuple(self.player_position)
        goal = tuple(self.goal)
        self.path = self.a_star(start, goal)
        if self.path:
            self.update_map()
            self.print_map()
            print("已显示从当前位置到终点的最短路径。")
        else:
            self.path = []
            self.update_map()
            self.print_map()
            print("无法到达终点!")
    def a_star(self, start, goal):
        open_set = []
        heapq.heappush(open_set, (0, start))
        came_from = {}
        g_score = {start: 0}
        f_score = {start: self.heuristic(start, goal)}
        while open_set:
            # 弹出f_score最小的节点
            current_f, current = heapq.heappop(open_set)
            # 避免重复处理已最优的节点
            if current in f_score and current_f > f_score[current]:
                continue
            # 到达终点,重构路径
            if current == goal:
                return self.reconstruct_path(came_from, current)
            # 遍历所有邻居并校验合法性
            for neighbor in self.get_neighbors(current):
                # 跳过障碍物和特殊障碍物
                if list(neighbor) in self.obstacles or list(neighbor) in self.special_obstacles:
                    continue
                # 计算移动代价:斜向√2≈1.414,正交1
                dx = abs(neighbor[0] - current[0])
                dy = abs(neighbor[1] - current[1])
                move_cost = 1.414 if dx == 1 and dy == 1 else 1
                # 计算从起点到邻居的总代价
                tentative_g_score = g_score[current] + move_cost
                # 仅当新路径更优时,才更新节点信息
                if neighbor not in g_score or tentative_g_score < g_score[neighbor]:
                    came_from[neighbor] = current
                    g_score[neighbor] = tentative_g_score
                    f_score[neighbor] = tentative_g_score + self.heuristic(neighbor, goal)
                    heapq.heappush(open_set, (f_score[neighbor], neighbor))
        # 无路径时返回空列表
        return []
    def heuristic(self, a, b):
        # 切比雪夫距离:适配8方向移动,更精准
        dx = abs(a[0] - b[0])
        dy = abs(a[1] - b[1])
        return max(dx, dy)
    def get_neighbors(self, position):
        x, y = position
        # 8方向邻居
        directions = [(-1,-1), (-1,0), (-1,1),
                      (0,-1),          (0,1),
                      (1,-1),  (1,0), (1,1)]
        valid_neighbors = []
        for dx, dy in directions:
            nx = x + dx
            ny = y + dy
            # 严格校验边界
            if 0 <= nx < self.width and 0 <= ny < self.height:
                valid_neighbors.append((nx, ny))
        return valid_neighbors
    def reconstruct_path(self, came_from, current):
        path = []
        # 从终点回溯到起点
        while current in came_from:
            path.append(list(current))
            current = came_from[current]
        # 添加起点
        path.append(list(current))
        # 反转路径,变为 起点→终点 顺序
        path.reverse()
        # 去重(防止回溯时的重复节点)
        path = [list(item) for item in list(dict.fromkeys(tuple(p) for p in path))]
        return path
# -------------------------- 原有辅助函数 --------------------------
def 初始设置():
    settings = {
        "width": {"default": 60, "prompt": "地图总宽,默认60>>>", "validator": lambda x: int(x) > 0},
        "a": {"default": 60, "prompt": "地图总高,默认60>>>", "validator": lambda x: int(x) > 0},
        "sections": {"default": 19, "prompt": "可视图宽,此项不建议更改,默认19>>>", "validator": lambda x: int(x) <= settings["width"]["value"]},
        "height": {"default": 15, "prompt": "可视图高,此项不建议更改,默认15>>>", "validator": lambda x: int(x) <= settings["a"]["value"]}
    }
    for key, config in settings.items():
        while True:
            os.system('clear')
            print("         欢迎\n让我们来做一些基础设置,回车使用默认")
            value = input(config["prompt"])
            if value == "":
                value = str(config["default"])
            if config["validator"](value):
                settings[key]["value"] = int(value)
                break
            else:
                print("注意,此设置设置不符合要求")
                time.sleep(0.5)
    return settings["width"]["value"], settings["a"]["value"], settings["height"]["value"], settings["sections"]["value"]
def 从文件加载设置(file_path):
    try:
        with open(file_path, 'r') as file:
            data = json.load(file)
            width = data.get('width', 60)
            a = data.get('a', 60)
            if int(width) < 0 or int(a) < 0:
                print("地图总不为负数")
                return
            height = data.get('height', 15)
            sections = data.get('sections', 19)
            if int(height) > width or int(sections) > a:
                print("可视图大小大于地图")
                return
            obstacles = data.get('obstacles', [])
            special_obstacles = data.get('special_obstacles', [])
            player_position = data.get('player_position', [random.randint(0, sections // 2), random.randint(0, height // 2)])
            goal = data.get('goal', [random.randint(0, width - 1), random.randint(0, a - 1)])
            noise_seed = data.get('noise_seed', 123)
            return width, a, height, sections, obstacles, special_obstacles, goal, player_position, noise_seed
    except FileNotFoundError:
        return -1
    except json.JSONDecodeError:
        return -2
    except:
        return -3
def yrun(bcmr, auto_save):
    if bcmr:
        print("已使用默认设置")
        width, a, height, sections, obstacles, special_obstacles, goal, player_position, noise_seed = 60, 60, 15, 19, [], [], [random.randint(0, 59), random.randint(0, 59)], [random.randint(0, 9), random.randint(0, 7)], 123
        use_file_settings = False
    else:
        use_file_settings = False
        width, a, height, sections = 初始设置()
        os.system('clear')
        noise_seed = random.randint(0, 9999)  # 随机生成噪声种子
    print(f"加载完成: \n宽度={width}\n高度={a}\n可视图高={height}\n可视图宽={sections}\n噪声种子={noise_seed}")
    os.system('clear')
    times, bs = zrun(width, a, height, sections, obstacles=None, special_obstacles=None, goal=None, player_position=None, use_file_settings=use_file_settings, auto_save=auto_save, noise_seed=noise_seed)
    return times, bs
def zrun(width, a, height, sections, obstacles, special_obstacles, goal, player_position, use_file_settings, auto_save, noise_seed=123):
    try:
        timea = time.time()
        game_map = CharacterMap(width, a, height, sections, obstacles, special_obstacles, goal, player_position, use_file_settings, auto_save, noise_seed)
        bs = game_map.run()
        timeb = time.time() - timea
    except InvalidMapError as e:
        print("错误", e)
        return None, None
    return timeb, bs
def 设置(bcmr, auto_save):
    while True:
        print('''
    ╔══════════════════···
    ║1.保持地图默认设置:{}
    ║2.自动保存地图:{}
    ║回车.保存并退出
    ╚══════════════════···'''.format(bcmr, auto_save))
        srsz = input('请选择>>>')
        if srsz == "1":
            os.system('clear')
            bcmr = not bcmr
        elif srsz == "2":
            os.system('clear')
            auto_save = not auto_save
        elif srsz == "":
            os.system('clear')
            break
        else:
            os.system('clear')
            print("输入错误")
    return bcmr, auto_save
def kgx(bs):
    if bs > -1:
        kgx = len(str(bs))
        if kgx == 1:
            kgy = 2
        elif kgx == 2:
            kgy = 1
        elif kgx == 3:
            kgy = 0
        kg = " " * kgy
        return kg
    return "  "
def 选择文件界面():
    print('''
    ╔══════════════════════╗
    ║  1.手动输入路径      ║
    ╠══════════════════════╣
    ''')
    file_path = "/storage/emulated/0/Download/python.wj/gwzm_wj/"
    if not os.path.exists(file_path):
        os.makedirs(file_path)
    files = os.listdir(file_path)
    json_files = [f for f in files if f.endswith('.json')]
    for idx, file_name in enumerate(json_files, start=2):
        print(f"║ {idx}. {file_name}{' ' * (30 - len(file_name))}║")
    print('''
    ╚══════════════════════╝
    ''')
    return json_files
def xrun():
    bs = -1
    kg = " "
    bcmr = False
    auto_save = False
    times = -1
    os.system('clear')
    while True:
        print('''
          ╔══════════════════╗
          ║ 1.开始游戏       ║
          ║ 2.进入设置       ║
          ║ 3.从文件加载地图 ║
          ╠══════════════════╣
          ║上一局步数:{}{}    ║
          ║上一局时间:{}s
          ╚══════════════════╝'''.format(bs, kg, round(times, 3)))
        xzxz = input("\n请输入你的选择>>>")
        if xzxz == "1":
            os.system('clear')
            times, bs = yrun(bcmr, auto_save)
            kg = kgx(bs)
        elif xzxz == "2":
            os.system('clear')
            bcmr, auto_save = 设置(bcmr, auto_save)
        elif xzxz == "3":
            os.system('clear')
            json_files = 选择文件界面()
            choice = input("请选择一个选项>>>")
            if choice == "1":
                file_name = input("请输入文件路径>>>")
                file_path = file_name
                if not file_name.endswith('.json'):
                    file_path += ".json"
            else:
                try:
                    choice = int(choice) - 2
                    if 0 <= choice < len(json_files):
                        file_name = json_files[choice]
                        file_path = os.path.join("/storage/emulated/0/Download/python.wj/gwzm_wj/", file_name)
                    else:
                        print("无效的选项")
                        continue
                except ValueError:
                    print("无效的选项")
                    continue
            try:
                path_sc = 从文件加载设置(file_path)
                if path_sc == -3:
                    print("输入错误")
                    continue
                elif path_sc == -1:
                    print("文件未找到")
                    continue
                elif path_sc == -2:
                    print("文件格式错误")
                    continue
                width, a, height, sections, obstacles, special_obstacles, goal, player_position, noise_seed = path_sc
                print(f"设置完成: \n宽度={width}\n高度={a}\n可视图高={height}\n可视图宽={sections}\n噪声种子={noise_seed}")
                times, bs = zrun(width, a, height, sections, obstacles, special_obstacles, goal, player_position, True, auto_save, noise_seed)
            except Exception as e:
                print(f"加载失败: {e}")
                times = None
            if times is None:
                times, bs = -1, -1
            kg = kgx(bs)
            if kg is None:
                kg = " "
        else:
            os.system('clear')
            print("输入错误")
# 开始运行
xrun()

抽签程序代码

import random
import os
import json
import tempfile
import ctypes
import subprocess
import tkinter as tk
from tkinter import messagebox
print('要开始喽!')
# 存放配置/数据的目录(统一放在 D:\Python\wenjian)
STORAGE_DIR = r'D:\Python\wenjian'
os.makedirs(STORAGE_DIR, exist_ok=True)
def set_hidden(path):
    """在 Windows 上将文件设为隐藏。尝试使用 WinAPI,失败时回退到 attrib 命令。"""
    try:
        # FILE_ATTRIBUTE_HIDDEN = 0x02
        res = ctypes.windll.kernel32.SetFileAttributesW(str(path), 0x02)
        if res:
            return True
    except Exception:
        pass
    try:
        # 回退到 attrib 命令(Windows)
        subprocess.check_call(['attrib', '+h', str(path)], shell=True)
        return True
    except Exception:
        return False
def randomm(x,z):
    if z: # 当此变量为是则认为传入的是不是数组
        a=[]
        for i in range(len(x)):
            for _ in range(x[i][1]):
                a.append(int(x[i][0]))
        #print(a)        
        b=random.choice(a)         
    else:  
        b=random.choice(x)
    return b    
    
def ttxt():
    # 使用统一的 storage 目录
    path = os.path.join(STORAGE_DIR, 'name.json')
    if os.path.exists(path):
        try:
            with open(path, 'r', encoding='utf-8') as f:
                data = json.load(f)
            return data
        except Exception:
            pass
    data = [[i, 10] for i in range(70)]
    # 原子写入初始文件
    atomic_write(path, data)
    try:
        set_hidden(path)
    except Exception:
        pass
    return data
    
def run_gui():
    base = os.path.dirname(__file__)
    root = tk.Tk()
    namee = ttxt()
    root.title('抽签程序')
    selected_idx = tk.IntVar(value=-1)
    lbl = tk.Label(root, text='点击 "抽取" 开始', font=('Arial', 24))
    lbl.pack(padx=12, pady=8)
    weight_lbl = tk.Label(root, text='', font=('Arial', 18))
    weight_lbl.pack(padx=8, pady=4)
    def draw():
        idx = randomm(namee, True)
        selected_idx.set(idx)
        lbl.config(text=f'这次抽到的人是: {idx+1} 号')
        weight_lbl.config(text=f'当前权重:{namee[idx][1]}')
        print(f'抽到的是:{idx+1} 号')
        # 抽取完成后启用按钮
        try:
            enable_buttons()
        except Exception:
            pass
    def correct():
        idx = selected_idx.get()
        if idx == -1:
            return
        #######
        if namee[idx][0]==6:
            namee[idx][1]=0
        #######
        if namee[idx][1] > 1:
            namee[idx][1] -= 1
            weight_lbl.config(text=f'当前权重:{namee[idx][1]}')
            print(f'{namee[idx][0]+1}号当前权重:{namee[idx][1]}')
            
        # 保存并在 1 秒后抽取下一位(期间禁用按钮)
        disable_buttons()
        save_data()
        root.after(300, draw)
    def skip():
        idx = selected_idx.get()
        if idx == -1:
            return
        # 不更改权重,仅保存并抽取下一位
        # 显示短暂提示,保存并几乎立即抽取下一位(几毫秒延迟以便呈现提示)
        lbl.config(text='跳过,抽取下一位...')
        print(f'{namee[idx][0]+1}号当前权重:{namee[idx][1]}')
        disable_buttons()
        save_data()
        root.after(300, draw)
    
    def save_data():
        path = os.path.join(STORAGE_DIR, 'name.json')
        try:
            atomic_write(path, namee)
            try:
                set_hidden(path)
            except Exception:
                pass
        except Exception as e:
            messagebox.showerror('错误', f'保存失败:{e}')
    btn_frame = tk.Frame(root)
    btn_frame.pack(pady=10)
    btn_font = ('Arial', 16)
    btn_correct = tk.Button(btn_frame, text='回答对了', width=12, font=btn_font, command=correct)
    btn_correct.grid(row=0, column=0, padx=8)
    btn_skip = tk.Button(btn_frame, text='跳过', width=12, font=btn_font, command=skip)
    btn_skip.grid(row=0, column=1, padx=8)
    def disable_buttons():
        btn_correct.config(state='disabled')
        btn_skip.config(state='disabled')
    def enable_buttons():
        btn_correct.config(state='normal')
        btn_skip.config(state='normal')
    def on_close():
        # 关闭时直接保存并退出(不询问)
        try:
            save_data()
        finally:
            root.destroy()
    root.protocol('WM_DELETE_WINDOW', on_close)
    # 启动时禁用按钮,随后立即抽取一次(在事件循环开始后立刻执行)
    disable_buttons()
    root.after(0, draw)
    root.mainloop()
def atomic_write(path, data):
    """原子地将 JSON 数据写入 `path`:先写入临时文件,然后用 os.replace 原子替换。"""
    dirpath = os.path.dirname(path) or '.'
    # 使用 mkstemp 获取文件描述符以避免竞态
    fd, tmp_path = tempfile.mkstemp(dir=dirpath, prefix='.tmp_', suffix='.json')
    try:
        with os.fdopen(fd, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
            f.flush()
            try:
                os.fsync(f.fileno())
            except Exception:
                # 在某些平台或文件系统上 fsync 可能失败,忽略但继续
                pass
        # 原子替换(Windows 和 POSIX 都支持 os.replace)
        os.replace(tmp_path, path)
        # 尝试设置为隐藏属性(仅在 Windows 有意义)
        try:
            set_hidden(path)
        except Exception:
            pass
    except Exception:
        try:
            os.remove(tmp_path)
        except Exception:
            pass
        raise
if __name__ == '__main__':
    run_gui()

猜数字游戏代码 (图形化版本)

import tkinter as tk
import random
class GuessNumberGame:
    def __init__(self, root):
        self.root = root
        self.root.title("猜数字游戏")
        self.target = random.randint(1, 100)
        self.attempts = 0
        
        self.label = tk.Label(root, text="猜一个1到100之间的数字", font=("Arial", 14))
        self.label.pack(pady=10)
        
        self.entry = tk.Entry(root, font=("Arial", 14))
        self.entry.pack(pady=5)
        
        self.button = tk.Button(root, text="猜测", command=self.guess, font=("Arial", 14))
        self.button.pack(pady=10)
        
        self.result_label = tk.Label(root, text="", font=("Arial", 12))
        self.result_label.pack(pady=10)
    
    def guess(self):
        try:
            guess = int(self.entry.get())
            self.attempts += 1
            if guess == self.target:
                self.result_label.config(text=f"恭喜你,猜对了!你猜了{self.attempts}次。")
                self.button.config(state="disabled")
            elif guess < self.target:
                self.result_label.config(text="猜的数字太小了,请再试一次!")
            else:
                self.result_label.config(text="猜的数字太大了,请再试一次!")
            if self.attempts == 5:
                self.result_label.config(text=f"提示: {self.target * 2}")
        except ValueError:
            self.result_label.config(text="请输入有效的数字!")
if __name__ == "__main__":
    root = tk.Tk()
    game = GuessNumberGame(root)
    root.mainloop()

圣诞树制造机代码 (图形化版本)

import tkinter as tk
def generate_tree(height):
    tree = ""
    b = 50  # 中心位置
    tree += " " * b + "☆\n"
    c = 0
    d = 1
    while c < height:
        tree += " " * b + "*" * d + "\n"
        b -= 1
        d += 2
        c += 1
    tree += " " * 50 + "|\n"
    return tree
class ChristmasTreeApp:
    def __init__(self, root):
        self.root = root
        self.root.title("圣诞树制造机")
        
        self.label = tk.Label(root, text="输入树的高度:", font=("Arial", 14))
        self.label.pack(pady=10)
        
        self.entry = tk.Entry(root, font=("Arial", 14))
        self.entry.pack(pady=5)
        
        self.button = tk.Button(root, text="生成圣诞树", command=self.make_tree, font=("Arial", 14))
        self.button.pack(pady=10)
        
        self.text = tk.Text(root, height=20, width=60, font=("Courier", 12))
        self.text.pack(pady=10)
    
    def make_tree(self):
        try:
            height = int(self.entry.get())
            tree = generate_tree(height)
            self.text.delete(1.0, tk.END)
            self.text.insert(tk.END, tree)
        except ValueError:
            self.text.delete(1.0, tk.END)
            self.text.insert(tk.END, "请输入有效的数字!")
if __name__ == "__main__":
    root = tk.Tk()
    app = ChristmasTreeApp(root)
    root.mainloop()

多功能合集代码 (图形化版本)

import tkinter as tk
from tkinter import messagebox
import random
class MultifuncApp:
    def __init__(self, root):
        self.root = root
        self.root.title("多功能合集")
        
        self.label = tk.Label(root, text="选择一个功能:", font=("Arial", 16))
        self.label.pack(pady=20)
        
        self.button1 = tk.Button(root, text="井字棋", command=self.start_tic_tac_toe, font=("Arial", 14), width=20)
        self.button1.pack(pady=10)
        
        self.button2 = tk.Button(root, text="剪刀石头布", command=self.start_rock_paper_scissors, font=("Arial", 14), width=20)
        self.button2.pack(pady=10)
        
        self.button3 = tk.Button(root, text="计算器", command=self.start_calculator, font=("Arial", 14), width=20)
        self.button3.pack(pady=10)
    
    def start_tic_tac_toe(self):
        # 简单井字棋实现
        TicTacToeWindow(tk.Toplevel(self.root))
    
    def start_rock_paper_scissors(self):
        RockPaperScissorsWindow(tk.Toplevel(self.root))
    
    def start_calculator(self):
        CalculatorWindow(tk.Toplevel(self.root))
class TicTacToeWindow:
    def __init__(self, root):
        self.root = root
        self.root.title("井字棋")
        self.board = [['' for _ in range(3)] for _ in range(3)]
        self.current_player = 'X'
        self.buttons = [[None for _ in range(3)] for _ in range(3)]
        
        for i in range(3):
            for j in range(3):
                self.buttons[i][j] = tk.Button(root, text='', font=('Arial', 20), width=5, height=2,
                                               command=lambda r=i, c=j: self.click(r, c))
                self.buttons[i][j].grid(row=i, column=j)
        
        self.status_label = tk.Label(root, text="轮到 X", font=('Arial', 14))
        self.status_label.grid(row=3, column=0, columnspan=3)
    
    def click(self, r, c):
        if self.board[r][c] == '':
            self.board[r][c] = self.current_player
            self.buttons[r][c].config(text=self.current_player)
            if self.check_winner():
                messagebox.showinfo("游戏结束", f"{self.current_player} 赢了!")
                self.root.destroy()
            elif self.is_full():
                messagebox.showinfo("游戏结束", "平局!")
                self.root.destroy()
            else:
                self.current_player = 'O' if self.current_player == 'X' else 'X'
                self.status_label.config(text=f"轮到 {self.current_player}")
    
    def check_winner(self):
        for i in range(3):
            if self.board[i][0] == self.board[i][1] == self.board[i][2] != '':
                return True
            if self.board[0][i] == self.board[1][i] == self.board[2][i] != '':
                return True
        if self.board[0][0] == self.board[1][1] == self.board[2][2] != '':
            return True
        if self.board[0][2] == self.board[1][1] == self.board[2][0] != '':
            return True
        return False
    
    def is_full(self):
        return all(self.board[i][j] != '' for i in range(3) for j in range(3))
class RockPaperScissorsWindow:
    def __init__(self, root):
        self.root = root
        self.root.title("剪刀石头布")
        self.choices = ['剪刀', '石头', '布']
        
        self.label = tk.Label(root, text="选择你的:", font=('Arial', 14))
        self.label.pack(pady=10)
        
        self.var = tk.StringVar()
        self.var.set('剪刀')
        for choice in self.choices:
            tk.Radiobutton(root, text=choice, variable=self.var, value=choice, font=('Arial', 12)).pack()
        
        self.button = tk.Button(root, text="出拳", command=self.play, font=('Arial', 14))
        self.button.pack(pady=10)
        
        self.result_label = tk.Label(root, text="", font=('Arial', 12))
        self.result_label.pack(pady=10)
    
    def play(self):
        user = self.var.get()
        computer = random.choice(self.choices)
        result = self.determine_winner(user, computer)
        self.result_label.config(text=f"你: {user}\n电脑: {computer}\n结果: {result}")
    
    def determine_winner(self, user, computer):
        if user == computer:
            return "平局"
        elif (user == '剪刀' and computer == '布') or \
             (user == '石头' and computer == '剪刀') or \
             (user == '布' and computer == '石头'):
            return "你赢了"
        else:
            return "电脑赢了"
class CalculatorWindow:
    def __init__(self, root):
        self.root = root
        self.root.title("计算器")
        
        self.entry = tk.Entry(root, font=('Arial', 16), justify='right')
        self.entry.pack(fill=tk.X, padx=10, pady=10)
        
        frame = tk.Frame(root)
        frame.pack()
        
        buttons = [
            '7', '8', '9', '/',
            '4', '5', '6', '*',
            '1', '2', '3', '-',
            '0', '.', '=', '+'
        ]
        
        row = 0
        col = 0
        for button in buttons:
            cmd = lambda x=button: self.click(x)
            tk.Button(frame, text=button, font=('Arial', 14), width=5, height=2, command=cmd).grid(row=row, column=col)
            col += 1
            if col > 3:
                col = 0
                row += 1
        
        tk.Button(frame, text='C', font=('Arial', 14), width=5, height=2, command=self.clear).grid(row=row, column=4)
    
    def click(self, key):
        if key == '=':
            try:
                result = eval(self.entry.get())
                self.entry.delete(0, tk.END)
                self.entry.insert(tk.END, str(result))
            except:
                self.entry.delete(0, tk.END)
                self.entry.insert(tk.END, "错误")
        else:
            self.entry.insert(tk.END, key)
    
    def clear(self):
        self.entry.delete(0, tk.END)
if __name__ == "__main__":
    root = tk.Tk()
    app = MultifuncApp(root)
    root.mainloop()

数字炸弹游戏代码 (图形化版本)

import tkinter as tk
import random
class BombGame:
    def __init__(self, root):
        self.root = root
        self.root.title("数字炸弹游戏")
        self.reset_game()
        
        self.label = tk.Label(root, text=f"炸弹范围: 2-{self.d}", font=("Arial", 14))
        self.label.pack(pady=10)
        
        self.status_label = tk.Label(root, text="轮到你了", font=("Arial", 12))
        self.status_label.pack(pady=5)
        
        self.entry = tk.Entry(root, font=("Arial", 14))
        self.entry.pack(pady=5)
        
        self.button = tk.Button(root, text="提交", command=self.player_guess, font=("Arial", 14))
        self.button.pack(pady=10)
        
        self.history_text = tk.Text(root, height=10, width=50, font=("Courier", 12))
        self.history_text.pack(pady=10)
        
        self.new_game_button = tk.Button(root, text="新游戏", command=self.reset_game, font=("Arial", 14))
        self.new_game_button.pack(pady=10)
    
    def reset_game(self):
        self.d = random.randint(2, 99)
        self.b = random.randint(1, self.d)
        self.win = 0
        self.player_turn = True
        self.history_text.delete(1.0, tk.END)
        self.history_text.insert(tk.END, f"机器人: {self.b}\n")
        self.status_label.config(text="轮到你了")
    
    def player_guess(self):
        try:
            c = int(self.entry.get())
            if c <= self.b:
                self.history_text.insert(tk.END, "请输入比机器人大的数\n")
                return
            self.win += 1
            if c >= self.d:
                self.history_text.insert(tk.END, f"你: {c}\n你输了,炸弹数字为{self.d}\n你们一共猜了{self.win}次\n")
                self.button.config(state="disabled")
                return
            self.history_text.insert(tk.END, f"你: {c}\n")
            self.player_turn = False
            self.root.after(1000, self.robot_guess)
        except ValueError:
            self.history_text.insert(tk.END, "请输入有效的数字!\n")
    
    def robot_guess(self):
        while True:
            b1 = random.randint(self.b + 1, self.d)
            if b1 != self.b:
                break
        self.win += 1
        self.history_text.insert(tk.END, f"机器人: {b1}\n")
        if b1 >= self.d:
            self.history_text.insert(tk.END, f"机器人输了,炸弹数字为{self.d}\n你们一共猜了{self.win}次\n")
            self.button.config(state="disabled")
        else:
            self.player_turn = True
            self.status_label.config(text="轮到你了")
if __name__ == "__main__":
    root = tk.Tk()
    game = BombGame(root)
    root.mainloop()