diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index eadd33c..73a4c53 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -24,13 +24,13 @@ jobs: run: uv sync --group dev - name: Build with PyInstaller - run: uv run src/tools/package.py + run: uv run tools/package.py - name: Upload build artifact uses: actions/upload-artifact@v7 with: name: cannotmax-build - path: build/dist/main/ + path: output/main/ retention-days: 1 release: diff --git a/.gitignore b/.gitignore index 14e3469..5781d3d 100644 --- a/.gitignore +++ b/.gitignore @@ -30,17 +30,27 @@ __pycache__/ # 5. 模型权重与构建产物 # =========================== # 模型文件 -/models/ +models/*.png +*.pth +*.onnx +*.onnx.data # 构建与输出目录 -/build/ +build/ +output/ # =========================== # 6. 数据集与媒体资源 # =========================== # 基础数据目录 -src/resources/assets/images/nums/ -/data/ +data/images/ +data/[0-9][0-9][0-9][0-9]_[0-1][0-9]_[0-3][0-9]__[0-2][0-9]_[0-5][0-9]_[0-5][0-9]/ +images/nums/ + +# 训练相关数据 +data_train/tmp/ +data_train/package/*.zip +data_train/images/ # 单独的截图文件 screenshot.png @@ -58,4 +68,5 @@ tmp # =========================== # 8. 其他杂项文件 # =========================== +arknights.csv multi_ports.txt diff --git a/WinningRate_Statistics.py b/WinningRate_Statistics.py new file mode 100644 index 0000000..c6d9aad --- /dev/null +++ b/WinningRate_Statistics.py @@ -0,0 +1,942 @@ +import pandas as pd +import numpy as np +from pathlib import Path +from math import sqrt +import csv +from collections import defaultdict +from config import MONSTER_COUNT, FIELD_FEATURE_COUNT, MONSTER_DATA + +FIELD_FEATURE_COUNT=0 +def load_data(): + """加载数据""" + df = pd.read_csv('arknights.csv', header=None, low_memory=False) + # 设置列名 + monster_cols_left = [f'L{i+1}' for i in range(MONSTER_COUNT)] + field_cols_left = [f'FL{i+1}' for i in range(FIELD_FEATURE_COUNT)] + monster_cols_right = [f'R{i+1}' for i in range(MONSTER_COUNT)] + field_cols_right = [f'FR{i+1}' for i in range(FIELD_FEATURE_COUNT)] + + df.columns = monster_cols_left + field_cols_left + monster_cols_right + field_cols_right + ['Result', 'ImgPath'] + return df + + +def get_monster_name(monster_id): + """根据怪物ID获取怪物名称""" + if monster_id in MONSTER_DATA.index: + return MONSTER_DATA.loc[monster_id]['名称'] + return f'怪物{monster_id}' + + +def get_monster_original_name(monster_id): + """根据怪物ID获取怪物原始名称(用于匹配图片)""" + if monster_id in MONSTER_DATA.index: + return MONSTER_DATA.loc[monster_id]['原始名称'] + return f'怪物{monster_id}' + + +def calculate_all_monster_win_rates(df): + """计算所有怪物的胜率""" + monster_stats = {} + total_matches = len(df) + + for i in range(1, MONSTER_COUNT + 1): + try: + # 转换数据类型并过滤 + df[f'L{i}'] = pd.to_numeric(df[f'L{i}'], errors='coerce').fillna(0) + df[f'R{i}'] = pd.to_numeric(df[f'R{i}'], errors='coerce').fillna(0) + + # 左方统计 + left_games = df[df[f'L{i}'] != 0] + left_wins = len(left_games[left_games['Result'] == 'L']) + left_total = len(left_games) + + # 右方统计 + right_games = df[df[f'R{i}'] != 0] + right_wins = len(right_games[right_games['Result'] == 'R']) + right_total = len(right_games) + except Exception as e: + print(f"处理怪物{i}时出错: {e}") + continue + + # 合并统计 + total_games = left_total + right_total + total_wins = left_wins + right_wins + + if total_games > 0: + monster_name = get_monster_name(i) + win_rate = total_wins / total_games + participation_rate = total_games / total_matches if total_matches > 0 else 0 + monster_stats[monster_name] = { + '怪物ID': i, + '胜场': total_wins, + '总场数': total_games, + '胜率': win_rate, + '参战率': participation_rate + } + + return pd.DataFrame(monster_stats).T.sort_values('胜率', ascending=False) + + +def analyze_monster_combinations(df): + """分析怪物配合效果""" + # 初始化数据结构 + single_stats = defaultdict(lambda: {'appearances': 0, 'wins': 0}) + pair_stats = defaultdict(lambda: {'co_occurrences': 0, 'co_wins': 0}) + + for _, record in df.iterrows(): + victory_side = record['Result'] + + # 获取左右两方的怪物 + left_monsters = [] + right_monsters = [] + + for i in range(1, MONSTER_COUNT + 1): + try: + left_val = float(record[f'L{i}']) if pd.notna(record[f'L{i}']) else 0 + right_val = float(record[f'R{i}']) if pd.notna(record[f'R{i}']) else 0 + + if left_val > 0: + left_monsters.append(i) + if right_val > 0: + right_monsters.append(i) + except (ValueError, TypeError): + continue + + # 确定胜利队伍和失败队伍 + if victory_side == 'L': + win_team, lose_team = left_monsters, right_monsters + else: + win_team, lose_team = right_monsters, left_monsters + + # 更新单怪统计(胜利方) + for monster in win_team: + single_stats[monster]['appearances'] += 1 + single_stats[monster]['wins'] += 1 + + # 更新单怪统计(失败方) + for monster in lose_team: + single_stats[monster]['appearances'] += 1 + + # 更新双怪组合统计(胜利方) + for i in range(len(win_team)): + for j in range(i+1, len(win_team)): + x, y = sorted((win_team[i], win_team[j])) + pair_stats[(x, y)]['co_occurrences'] += 1 + pair_stats[(x, y)]['co_wins'] += 1 + + # 更新双怪组合统计(失败方) + for i in range(len(lose_team)): + for j in range(i+1, len(lose_team)): + x, y = sorted((lose_team[i], lose_team[j])) + pair_stats[(x, y)]['co_occurrences'] += 1 + + # 计算最佳配合 + results = [] + total_battles = len(df) + + for (x, y), stats in pair_stats.items(): + if stats['co_occurrences'] < 10: # 过滤低频组合 + continue + + # 组合胜率 + xy_win_rate = stats['co_wins'] / stats['co_occurrences'] + + # 单怪胜率 + if single_stats[x]['appearances'] > 0 and single_stats[y]['appearances'] > 0: + x_win_rate = single_stats[x]['wins'] / single_stats[x]['appearances'] + y_win_rate = single_stats[y]['wins'] / single_stats[y]['appearances'] + + # 提升度 - 简化计算,不使用卡方检验 + expected_win_rate = sqrt(x_win_rate * y_win_rate) + lift = xy_win_rate / expected_win_rate if expected_win_rate > 0 else 0 + + if lift > 1.1 and xy_win_rate > max(x_win_rate, y_win_rate) and stats['co_occurrences'] >= 20: + x_name = get_monster_name(x) + y_name = get_monster_name(y) + results.append({ + '组合': f'{x_name}+{y_name}', + '怪物1': x_name, + '怪物2': y_name, + 'ID1': x, + 'ID2': y, + '提升度': lift, + '组合胜率': xy_win_rate, + '出场次数': stats['co_occurrences'], + '获胜次数': stats['co_wins'] + }) + + # 按提升度排序 + results.sort(key=lambda x: -x['提升度']) + return pd.DataFrame(results) + + +def find_countered_monsters(df): + """寻找被克制的怪物前五个""" + counter_stats = defaultdict(lambda: {'total_matchups': 0, 'losses': 0}) + + for _, record in df.iterrows(): + victory_side = record['Result'] + + # 获取左右两方的怪物 + left_monsters = [] + right_monsters = [] + + for i in range(1, MONSTER_COUNT + 1): + try: + left_val = float(record[f'L{i}']) if pd.notna(record[f'L{i}']) else 0 + right_val = float(record[f'R{i}']) if pd.notna(record[f'R{i}']) else 0 + + if left_val > 0: + left_monsters.append(i) + if right_val > 0: + right_monsters.append(i) + except (ValueError, TypeError): + continue + + # 分析对战情况 + for left_monster in left_monsters: + for right_monster in right_monsters: + # 左方怪物的统计 + counter_stats[left_monster]['total_matchups'] += 1 + if victory_side == 'R': # 左方败北 + counter_stats[left_monster]['losses'] += 1 + + # 右方怪物的统计 + counter_stats[right_monster]['total_matchups'] += 1 + if victory_side == 'L': # 右方败北 + counter_stats[right_monster]['losses'] += 1 + + # 计算被克制率 + countered_results = [] + for monster_id, stats in counter_stats.items(): + if stats['total_matchups'] >= 20: # 至少20场对战 + loss_rate = stats['losses'] / stats['total_matchups'] + monster_name = get_monster_name(monster_id) + countered_results.append({ + '怪物': monster_name, + '怪物ID': monster_id, + '被克制率': loss_rate, + '败场': stats['losses'], + '总对战数': stats['total_matchups'] + }) + + # 按被克制率排序(降序) + countered_results.sort(key=lambda x: -x['被克制率']) + return pd.DataFrame(countered_results[:5]) + + +def analyze_individual_monster_relations(df): + """分析每个怪物的详细关系:最佳队友、克制关系、被克制关系""" + monster_relations = {} + + # 初始化数据结构 + single_stats = defaultdict(lambda: {'appearances': 0, 'wins': 0}) + pair_stats = defaultdict(lambda: {'co_occurrences': 0, 'co_wins': 0}) + counter_stats = defaultdict(lambda: defaultdict(lambda: {'matchups': 0, 'wins': 0})) + + for _, record in df.iterrows(): + victory_side = record['Result'] + + # 获取左右两方的怪物 + left_monsters = [] + right_monsters = [] + + for i in range(1, MONSTER_COUNT + 1): + try: + left_val = float(record[f'L{i}']) if pd.notna(record[f'L{i}']) else 0 + right_val = float(record[f'R{i}']) if pd.notna(record[f'R{i}']) else 0 + + if left_val > 0: + left_monsters.append(i) + if right_val > 0: + right_monsters.append(i) + except (ValueError, TypeError): + continue + + # 确定胜利队伍和失败队伍 + if victory_side == 'L': + win_team, lose_team = left_monsters, right_monsters + else: + win_team, lose_team = right_monsters, left_monsters + + # 更新单怪统计 + for monster in win_team: + single_stats[monster]['appearances'] += 1 + single_stats[monster]['wins'] += 1 + + for monster in lose_team: + single_stats[monster]['appearances'] += 1 + + # 更新队友统计 + for i in range(len(win_team)): + for j in range(i+1, len(win_team)): + x, y = sorted((win_team[i], win_team[j])) + pair_stats[(x, y)]['co_occurrences'] += 1 + pair_stats[(x, y)]['co_wins'] += 1 + + for i in range(len(lose_team)): + for j in range(i+1, len(lose_team)): + x, y = sorted((lose_team[i], lose_team[j])) + pair_stats[(x, y)]['co_occurrences'] += 1 + + # 更新克制关系统计 + for winner in win_team: + for loser in lose_team: + counter_stats[winner][loser]['matchups'] += 1 + counter_stats[winner][loser]['wins'] += 1 + counter_stats[loser][winner]['matchups'] += 1 + + # 为每个怪物分析关系 + for monster_id in range(1, MONSTER_COUNT + 1): + monster_name = get_monster_name(monster_id) + + if single_stats[monster_id]['appearances'] < 10: # 数据量太少 + continue + + # 分析最佳队友 + best_teammates = [] + for (x, y), stats in pair_stats.items(): + if x == monster_id or y == monster_id: + partner_id = y if x == monster_id else x + if stats['co_occurrences'] >= 5: # 至少5次合作 + combo_win_rate = stats['co_wins'] / stats['co_occurrences'] + + # 计算提升度 + if (single_stats[monster_id]['appearances'] > 0 and + single_stats[partner_id]['appearances'] > 0): + monster_win_rate = single_stats[monster_id]['wins'] / single_stats[monster_id]['appearances'] + partner_win_rate = single_stats[partner_id]['wins'] / single_stats[partner_id]['appearances'] + expected_win_rate = sqrt(monster_win_rate * partner_win_rate) + + if expected_win_rate > 0: + lift = combo_win_rate / expected_win_rate + if lift > 1.0: + best_teammates.append({ + 'partner_id': partner_id, + 'partner_name': get_monster_name(partner_id), + 'lift': lift, + 'combo_win_rate': combo_win_rate, + 'occurrences': stats['co_occurrences'] + }) + + best_teammates.sort(key=lambda x: -x['lift']) + + # 分析克制关系 + counters = [] # 该怪物克制的 + countered_by = [] # 克制该怪物的 + + for opponent_id in counter_stats[monster_id]: + stats = counter_stats[monster_id][opponent_id] + if stats['matchups'] >= 5: + win_rate = stats['wins'] / stats['matchups'] + if win_rate > 0.6: # 胜率超过60%认为克制 + counters.append({ + 'opponent_id': opponent_id, + 'opponent_name': get_monster_name(opponent_id), + 'win_rate': win_rate, + 'matchups': stats['matchups'] + }) + + for opponent_id in range(1, MONSTER_COUNT + 1): + if opponent_id in counter_stats and monster_id in counter_stats[opponent_id]: + stats = counter_stats[opponent_id][monster_id] + if stats['matchups'] >= 5: + lose_rate = stats['wins'] / stats['matchups'] + if lose_rate > 0.6: # 对方胜率超过60%认为被克制 + countered_by.append({ + 'opponent_id': opponent_id, + 'opponent_name': get_monster_name(opponent_id), + 'lose_rate': lose_rate, + 'matchups': stats['matchups'] + }) + + counters.sort(key=lambda x: -x['win_rate']) + countered_by.sort(key=lambda x: -x['lose_rate']) + + monster_relations[monster_id] = { + 'name': monster_name, + 'best_teammates': best_teammates[:3], + 'counters': counters[:3], + 'countered_by': countered_by[:3] + } + + return monster_relations + + +def get_terrain_feature_columns(): + """获取地形特征列名""" + import json + import re + from collections import defaultdict + + try: + # 加载类别映射 + class_map_path = "tools/battlefield_recognize/class_to_idx.json" + with open(class_map_path, 'r', encoding='utf-8') as f: + class_to_idx = json.load(f) + + # 使用与data_cleaning_with_field_recognize_gpu.py相同的逻辑 + grouped_elements = defaultdict(list) + for class_name in class_to_idx.keys(): + if class_name.endswith('_none'): + continue + condensed_name = re.sub(r'_left_', '_', class_name) + condensed_name = re.sub(r'_right_', '_', condensed_name) + grouped_elements[condensed_name].append(class_name) + + # 返回排序后的特征列名 + return sorted(grouped_elements.keys()) + except Exception as e: + print(f"无法获取地形特征列名,使用默认值: {e}") + # 如果无法获取,返回默认列表 + return [ + "altar_vertical_altar", "block_parallel_block", "block_vertical_altar_shape1", + "block_vertical_altar_shape2", "block_vertical_block_shape1", "block_vertical_block_shape2", + "coil_narrow_coil", "coil_wide_coil", "crossbow_top_crossbow", + "fire_side_crossbow", "fire_side_fire", "fire_top_fire" + ] + + +def analyze_terrain_effects(df): + """分析地形对怪物的影响""" + terrain_effects = [] + + # 获取实际的地形特征列名 + terrain_feature_columns = get_terrain_feature_columns() + + # 地形显示名称映射 + terrain_display_mapping = { + "altar_vertical_altar": "垂直祭坛", + "block_parallel_block": "平行方块阻挡", + "block_vertical_altar_shape1": "垂直祭坛形阻挡1", + "block_vertical_altar_shape2": "垂直祭坛形阻挡2", + "block_vertical_block_shape1": "垂直方块阻挡1", + "block_vertical_block_shape2": "垂直方块阻挡2", + "coil_narrow_coil": "窄型线圈装置", + "coil_wide_coil": "宽型线圈装置", + "crossbow_top_crossbow": "顶部弩炮", + "fire_side_crossbow": "侧边弩炮", + "fire_side_fire": "侧边火炮", + "fire_top_fire": "顶部火炮" + } + + for terrain_idx, terrain_key in enumerate(terrain_feature_columns): + terrain_name = terrain_display_mapping.get(terrain_key, terrain_key) + + for monster_idx in range(1, MONSTER_COUNT + 1): + monster_name = get_monster_name(monster_idx) + + # 转换数据类型 + df[f'FL{terrain_idx+1}'] = pd.to_numeric(df[f'FL{terrain_idx+1}'], errors='coerce').fillna(0) + df[f'FR{terrain_idx+1}'] = pd.to_numeric(df[f'FR{terrain_idx+1}'], errors='coerce').fillna(0) + df[f'L{monster_idx}'] = pd.to_numeric(df[f'L{monster_idx}'], errors='coerce').fillna(0) + df[f'R{monster_idx}'] = pd.to_numeric(df[f'R{monster_idx}'], errors='coerce').fillna(0) + + # 有地形时的表现 + terrain_left_games = df[(df[f'FL{terrain_idx+1}'] == 1) & (df[f'L{monster_idx}'] > 0)] + terrain_right_games = df[(df[f'FR{terrain_idx+1}'] == 1) & (df[f'R{monster_idx}'] > 0)] + + terrain_total = len(terrain_left_games) + len(terrain_right_games) + if terrain_total < 5: # 数据量太少 + continue + + terrain_wins = len(terrain_left_games[terrain_left_games['Result'] == 'L']) + \ + len(terrain_right_games[terrain_right_games['Result'] == 'R']) + terrain_win_rate = terrain_wins / terrain_total + + # 无地形时的表现 + normal_left_games = df[(df[f'FL{terrain_idx+1}'] == 0) & (df[f'L{monster_idx}'] > 0)] + normal_right_games = df[(df[f'FR{terrain_idx+1}'] == 0) & (df[f'R{monster_idx}'] > 0)] + + normal_total = len(normal_left_games) + len(normal_right_games) + if normal_total < 5: + continue + + normal_wins = len(normal_left_games[normal_left_games['Result'] == 'L']) + \ + len(normal_right_games[normal_right_games['Result'] == 'R']) + normal_win_rate = normal_wins / normal_total + + # 计算影响程度 + effect = terrain_win_rate - normal_win_rate + + if abs(effect) >= 0.05: # 胜率差异超过5%才记录 + terrain_effects.append({ + '地形': terrain_name, + '怪物': monster_name, + '怪物ID': monster_idx, + '地形胜率': terrain_win_rate, + '普通胜率': normal_win_rate, + '影响程度': effect, + '地形场次': terrain_total, + '普通场次': normal_total + }) + + # 按影响程度绝对值排序 + terrain_effects.sort(key=lambda x: -abs(x['影响程度'])) + return pd.DataFrame(terrain_effects[:20]) # 增加到前20个 + + +def analyze_device_counter_effects(df): + """分析五个装置对怪物的克制效果""" + device_counter_results = {} + + # 获取实际的地形特征列名 + terrain_feature_columns = get_terrain_feature_columns() + + # 定义五个装置类别及其对应的地形特征 + device_categories = { + 'altar': { + 'name': '祭坛', + 'features': [f for f in terrain_feature_columns if 'altar' in f], + 'description': '祭坛类装置' + }, + 'block': { + 'name': '箱子/阻挡', + 'features': [f for f in terrain_feature_columns if 'block' in f], + 'description': '方块阻挡类装置' + }, + 'coil': { + 'name': '电桩', + 'features': [f for f in terrain_feature_columns if 'coil' in f], + 'description': '线圈电桩装置' + }, + 'crossbow': { + 'name': '弩箭', + 'features': [f for f in terrain_feature_columns if 'crossbow' in f], + 'description': '弩炮装置' + }, + 'fire': { + 'name': '火炮', + 'features': [f for f in terrain_feature_columns if 'fire' in f], + 'description': '火炮装置' + } + } + + for device_key, device_info in device_categories.items(): + device_name = device_info['name'] + device_features = device_info['features'] + + if not device_features: + continue + + device_effects = [] + + # 对每个怪物分析该装置的克制效果 + for monster_idx in range(1, MONSTER_COUNT + 1): + monster_name = get_monster_name(monster_idx) + + # 收集该装置所有特征的统计数据 + total_device_games = 0 + total_device_wins = 0 + total_normal_games = 0 + total_normal_wins = 0 + + for terrain_key in device_features: + if terrain_key not in terrain_feature_columns: + continue + + terrain_idx = terrain_feature_columns.index(terrain_key) + + # 转换数据类型 + df[f'FL{terrain_idx+1}'] = pd.to_numeric(df[f'FL{terrain_idx+1}'], errors='coerce').fillna(0) + df[f'FR{terrain_idx+1}'] = pd.to_numeric(df[f'FR{terrain_idx+1}'], errors='coerce').fillna(0) + df[f'L{monster_idx}'] = pd.to_numeric(df[f'L{monster_idx}'], errors='coerce').fillna(0) + df[f'R{monster_idx}'] = pd.to_numeric(df[f'R{monster_idx}'], errors='coerce').fillna(0) + + # 有该装置时的表现 + device_left_games = df[(df[f'FL{terrain_idx+1}'] == 1) & (df[f'L{monster_idx}'] > 0)] + device_right_games = df[(df[f'FR{terrain_idx+1}'] == 1) & (df[f'R{monster_idx}'] > 0)] + + device_games_count = len(device_left_games) + len(device_right_games) + device_wins_count = len(device_left_games[device_left_games['Result'] == 'L']) + \ + len(device_right_games[device_right_games['Result'] == 'R']) + + # 无该装置时的表现 + normal_left_games = df[(df[f'FL{terrain_idx+1}'] == 0) & (df[f'L{monster_idx}'] > 0)] + normal_right_games = df[(df[f'FR{terrain_idx+1}'] == 0) & (df[f'R{monster_idx}'] > 0)] + + normal_games_count = len(normal_left_games) + len(normal_right_games) + normal_wins_count = len(normal_left_games[normal_left_games['Result'] == 'L']) + \ + len(normal_right_games[normal_right_games['Result'] == 'R']) + + total_device_games += device_games_count + total_device_wins += device_wins_count + total_normal_games += normal_games_count + total_normal_wins += normal_wins_count + + # 计算整体效果 + if total_device_games >= 10 and total_normal_games >= 10: # 确保有足够的数据 + device_win_rate = total_device_wins / total_device_games + normal_win_rate = total_normal_wins / total_normal_games + effect = device_win_rate - normal_win_rate + + # 计算克制程度(负值表示被该装置克制) + counter_effect = -effect # 装置对怪物的克制效果 + + if abs(effect) >= 0.05: # 胜率差异超过5%才记录 + device_effects.append({ + '怪物': monster_name, + '怪物ID': monster_idx, + '装置胜率': device_win_rate, + '普通胜率': normal_win_rate, + '克制程度': counter_effect, # 正值表示被该装置克制 + '装置场次': total_device_games, + '普通场次': total_normal_games, + '效果类型': '被克制' if counter_effect > 0 else '克制装置' + }) + + # 按克制程度排序(被克制程度最高的在前) + device_effects.sort(key=lambda x: -x['克制程度']) + device_counter_results[device_key] = { + 'name': device_name, + 'description': device_info['description'], + 'features': device_features, + 'effects': device_effects[:10] # 取前10个被克制最严重的怪物 + } + + return device_counter_results + + +def create_html_table(df, columns, title, is_combo=False, monster_relations=None): + """创建带有怪物头像的HTML表格""" + html = f"

{title}

\n\n" + + # 表头 + if is_combo: + html += "" + else: + html += "" + + for col in columns: + html += f"" + + # 如果是胜率表且有关系数据,添加额外的列 + if not is_combo and monster_relations and title == '所有怪物胜率排行榜': + html += "" + + html += "\n" + + # 表格内容 + row_number = 1 + for idx, row in df.iterrows(): + html += "" + + # 怪物图片和名称 + monster_id = None + if is_combo and 'ID1' in row and 'ID2' in row: + monster1_name = get_monster_name(row['ID1']) + monster2_name = get_monster_name(row['ID2']) + monster1_orig = get_monster_original_name(row['ID1']) + monster2_orig = get_monster_original_name(row['ID2']) + html += f"""""" + elif '怪物ID' in row: + monster_name = get_monster_name(row['怪物ID']) + monster_orig = get_monster_original_name(row['怪物ID']) + display_name = row.get('怪物', monster_name) + monster_id = row['怪物ID'] + html += f"""""" + else: + # 对于胜率表,使用索引作为怪物名称 + monster_name = idx + # 尝试从怪物数据中获取ID + monster_orig = monster_name + for mid in range(1, MONSTER_COUNT + 1): + if get_monster_name(mid) == monster_name: + monster_id = mid + monster_orig = get_monster_original_name(mid) + break + html += f"""""" + + # 数据列 + for col in columns: + value = row[col] + if isinstance(value, float): + if '率' in col or '程度' in col: + html += f"" + else: + html += f"" + else: + html += f"" + + # 如果是胜率表且有关系数据,添加关系信息 + if not is_combo and monster_relations and title == '所有怪物胜率排行榜' and monster_id: + relations = monster_relations.get(int(monster_id), {}) + + # 最佳队友 + html += "" + + # 克制关系 + html += "" + + # 被克制关系 + html += "" + + html += "\n" + row_number += 1 + + html += "
组合怪物{col}最佳队友克制被克制
+ {row_number}. + + {monster1_name}
+ + {monster2_name} +
+ {row_number}. + + {display_name} + + {row_number}. + + {monster_name} + {value:.2%}{value:.2f}{value}" + if relations and 'best_teammates' in relations and relations['best_teammates']: + teammates = [] + for teammate in relations['best_teammates']: + teammate_orig = get_monster_original_name(teammate['partner_id']) + teammates.append(f"""
+ + {teammate['partner_name']} ({teammate['lift']:.2f}x) +
""") + html += "".join(teammates) + else: + html += "暂无数据" + html += "
" + if relations and 'counters' in relations and relations['counters']: + counters = [] + for counter in relations['counters']: + counter_orig = get_monster_original_name(counter['opponent_id']) + counters.append(f"""
+ + {counter['opponent_name']} ({counter['win_rate']:.0%}) +
""") + html += "".join(counters) + else: + html += "暂无数据" + html += "
" + if relations and 'countered_by' in relations and relations['countered_by']: + countered = [] + for counter in relations['countered_by']: + counter_orig = get_monster_original_name(counter['opponent_id']) + countered.append(f"""
+ + {counter['opponent_name']} ({counter['lose_rate']:.0%}) +
""") + html += "".join(countered) + else: + html += "暂无数据" + html += "
\n" + return html + + +def create_device_counter_html(device_counter_effects): + """创建装置克制效果的HTML表格""" + html = "

装置克制效果统计

\n" + + for device_key, device_data in device_counter_effects.items(): + if not device_data['effects']: + continue + + device_name = device_data['name'] + device_description = device_data['description'] + effects = device_data['effects'] + + html += f"

{device_name}({device_description})

\n" + html += "\n" + html += "" + html += "\n" + + row_number = 1 + for effect in effects: + monster_name = effect['怪物'] + monster_orig = get_monster_original_name(effect['怪物ID']) + html += f""" + + + + + + + + \n""" + row_number += 1 + + html += "
怪物克制程度装置胜率普通胜率装置场次普通场次效果类型
+ {row_number}. + + {monster_name} + {effect['克制程度']:.2%}{effect['装置胜率']:.2%}{effect['普通胜率']:.2%}{effect['装置场次']}{effect['普通场次']}{effect['效果类型']}
\n
\n" + + return html + + +def generate_comprehensive_report(): + """生成综合统计报告""" + print("正在加载数据...") + df = load_data() + + print("正在计算怪物胜率...") + win_rates = calculate_all_monster_win_rates(df) + + print("正在分析怪物配合...") + combinations = analyze_monster_combinations(df) + + print("正在分析被克制关系...") + countered = find_countered_monsters(df) + + if FIELD_FEATURE_COUNT > 0: + print("正在分析地形效果...") + terrain_effects = analyze_terrain_effects(df) + + print("正在分析装置克制效果...") + device_counter_effects = analyze_device_counter_effects(df) + else: + print("地形特征数量为0,跳过地形分析...") + terrain_effects = pd.DataFrame() + device_counter_effects = {} + + print("正在分析个体怪物关系...") + monster_relations = analyze_individual_monster_relations(df) + + # 创建HTML报告 + total_battles = len(df) + monster_count = MONSTER_COUNT + field_count = FIELD_FEATURE_COUNT + + html = f""" + + + + + + +

明日方舟争锋频道绿藤城

+
+

数据概览:

+ +
+""" + + # 1. 所有怪物胜率 + if not win_rates.empty: + html += create_html_table(win_rates, ['胜场', '总场数', '胜率', '参战率'], '所有怪物胜率排行榜', monster_relations=monster_relations) + else: + html += "

所有怪物胜率排行榜

暂无数据

" + + # 2. 最佳配合 + if not combinations.empty: + html += create_html_table(combinations.head(20), ['提升度', '组合胜率', '出场次数'], '最佳怪物配合TOP20', is_combo=True) + else: + html += "

最佳怪物配合

暂无足够的配合数据

" + + + # 4. 地形效果 + if not terrain_effects.empty: + html += create_html_table(terrain_effects, ['地形', '地形胜率', '普通胜率', '影响程度'], '地形影响最大的怪物TOP20') + else: + html += "

地形影响

暂无足够的地形数据

" + + # 5. 装置克制效果 + if device_counter_effects: + html += create_device_counter_html(device_counter_effects) + else: + html += "

装置克制效果统计

暂无足够的装置数据

" + + timestamp = pd.Timestamp.now().strftime('%Y-%m-%d %H:%M:%S') + html += f""" +
+

报告生成时间:{timestamp}

+

注:数据基于历史战斗记录,仅供参考

+
+ + +""" + + # 保存报告 + with open('comprehensive_monster_report.html', 'w', encoding='utf-8') as f: + f.write(html) + + print("统计报告已生成:comprehensive_monster_report.html") + + # 也输出到控制台 + print("\n=== 怪物胜率TOP10 ===") + print(win_rates.head(10).to_string()) + + if not combinations.empty: + print("\n=== 最佳配合TOP10 ===") + print(combinations.head(10)[['组合', '提升度', '组合胜率', '出场次数']].to_string()) + + # 输出装置克制效果 + if device_counter_effects: + print("\n=== 装置克制效果统计 ===") + for device_key, device_data in device_counter_effects.items(): + if device_data['effects']: + print(f"\n{device_data['name']}({device_data['description']})最克制的怪物TOP5:") + for i, effect in enumerate(device_data['effects'][:5]): + print(f" {i+1}. {effect['怪物']} - 克制程度: {effect['克制程度']:.2%} ({effect['效果类型']})") + + if not terrain_effects.empty: + print("\n=== 地形影响TOP10 ===") + print(terrain_effects.head(10)[['地形', '怪物', '影响程度', '地形胜率', '普通胜率']].to_string()) + + + +if __name__ == "__main__": + generate_comprehensive_report() diff --git a/src/game/auto_fetch.py b/auto_fetch.py similarity index 74% rename from src/game/auto_fetch.py rename to auto_fetch.py index 9dc6f04..a17cf02 100644 --- a/src/game/auto_fetch.py +++ b/auto_fetch.py @@ -1,7 +1,6 @@ import os - # 设置 OpenCV 日志级别为 ERROR,减少 libpng 警告 -os.environ["OPENCV_LOG_LEVEL"] = "ERROR" +os.environ['OPENCV_LOG_LEVEL'] = 'ERROR' import csv import datetime @@ -10,19 +9,19 @@ from pathlib import Path import threading import time +from typing import Literal import cv2 import numpy as np -from src.recognition.recognize import INTELLIGENT_WORKERS_DEBUG -from src.core.config import MONSTER_COUNT, FIELD_FEATURE_COUNT -from src.core.paths import PROJECT_ROOT, process_image_path, simulation_path +import loadData +from recognize import intelligent_workers_debug +from config import MONSTER_COUNT, FIELD_FEATURE_COUNT from collections.abc import Callable from collections import deque -from .login import LoginManager +from login import LoginManager logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) - class GameState(Enum): MAIN_MENU = auto() MODE_SELECTION_UNSELECTED = auto() @@ -33,7 +32,6 @@ class GameState(Enum): FINISHED = auto() UNKNOWN = auto() - class AutoFetch: def __init__( self, @@ -49,7 +47,7 @@ def __init__( recognizer=None, cannot_model=None, field_recognizer=None, - start_timestamp=None, + start_timestamp=None, ): self.connector = connector self.game_mode = game_mode # 游戏模式(30人或自娱自乐) @@ -68,14 +66,10 @@ def __init__( self.monster_image = None # 当前轮次怪物图片 self.auto_fetch_running = False # 自动获取数据的状态 self.auto_fetch_thread = None # 线程引用 - self.start_time = ( - start_timestamp if start_timestamp is not None else time.time() - ) # 使用预先确定的时间戳 + self.start_time = start_timestamp if start_timestamp is not None else time.time() # 使用预先确定的时间戳 self.training_duration = training_duration # 训练时长 - self.data_folder = PROJECT_ROOT / "data" # 数据文件夹路径 - self.image_buffer = deque( - maxlen=5 - ) # 图片缓存队列,设置队列长短来保存结算前的图片 + self.data_folder = Path(f"data") # 数据文件夹路径 + self.image_buffer = deque(maxlen=5) # 图片缓存队列,设置队列长短来保存结算前的图片 self.recognizer = recognizer # 使用传入的识别器 self.cannot_model = cannot_model # 使用传入的模型 self.last_state = GameState.UNKNOWN @@ -85,24 +79,22 @@ def __init__( # 初始化状态匹配模板,缩小匹配尺寸提高速度 self.MATCH_WIDTH = 1920 // 4 self.MATCH_HEIGHT = 1080 // 4 // 4 - + # 初始化模板 self.processed_template = [] self._init_templates() - + # 根据 FIELD_FEATURE_COUNT 决定是否启用场地识别器(使用传入的实例) if FIELD_FEATURE_COUNT > 0: if self.field_recognizer is not None: logger.info(f"场地识别已启用,特征数量: {FIELD_FEATURE_COUNT}") else: - logger.warning( - f"FIELD_FEATURE_COUNT={FIELD_FEATURE_COUNT} > 0 但未传入 field_recognizer,场地识别将被禁用" - ) + logger.warning(f"FIELD_FEATURE_COUNT={FIELD_FEATURE_COUNT} > 0 但未传入 field_recognizer,场地识别将被禁用") self.field_recognizer = None else: self.field_recognizer = None logger.info("场地识别已禁用,仅收集怪物数据") - + def _log(self, level, message): """生成带有设备序列号的日志消息""" serial = getattr(self.connector, "device_serial", None) @@ -113,14 +105,10 @@ def _log(self, level, message): def _init_templates(self): for i in range(16): - img = cv2.imread(str(process_image_path(i))) + img = cv2.imread(f"images/process/{i}.png") if img is not None: # 使用最近邻插值缩放模板,速度最快 - img_resized = cv2.resize( - img, - (self.MATCH_WIDTH, self.MATCH_HEIGHT * 4), - interpolation=cv2.INTER_NEAREST, - ) + img_resized = cv2.resize(img, (self.MATCH_WIDTH, self.MATCH_HEIGHT * 4), interpolation=cv2.INTER_NEAREST) img_quarter = img_resized[self.MATCH_HEIGHT * 3 :, :] self.processed_template.append(img_quarter) else: @@ -131,31 +119,18 @@ def match_images(self, screenshot): # 裁剪底部 1/4 ROI y_start = int(h * 3 / 4) screenshot_quarter = screenshot[y_start:, :] - screenshot_quarter = cv2.resize( - screenshot_quarter, - (self.MATCH_WIDTH, self.MATCH_HEIGHT), - interpolation=cv2.INTER_NEAREST, - ) - + screenshot_quarter = cv2.resize(screenshot_quarter, (self.MATCH_WIDTH, self.MATCH_HEIGHT), interpolation=cv2.INTER_NEAREST) + results = [] for idx, template in enumerate(self.processed_template): if template is None: continue - res = cv2.matchTemplate( - screenshot_quarter, template, cv2.TM_CCOEFF_NORMED - ) + res = cv2.matchTemplate(screenshot_quarter, template, cv2.TM_CCOEFF_NORMED) _, max_val, _, _ = cv2.minMaxLoc(res) results.append((idx, max_val)) return results - def fill_data( - self, - battle_result, - recognize_results, - monster_image, - result_image, - field_recognize_result, - ): + def fill_data(self, battle_result, recognize_results, monster_image, result_image, field_recognize_result): # 获取队列头的图片 if self.image_buffer: _, previous_image, _ = self.image_buffer[0] # 获取队列头的图片 @@ -167,9 +142,7 @@ def fill_data( logger.error("未找到2秒前的图片,无法保存") return - image_name = self.get_image_name( - recognize_results, battle_result - ) # 生成图片名称 + image_name = self.get_image_name(recognize_results, battle_result) # 生成图片名称 # 确保images文件夹存在 images_folder = self.data_folder / "images" @@ -179,20 +152,12 @@ def fill_data( except Exception as e: logger.error(f"创建images文件夹失败: {e}") - if ( - INTELLIGENT_WORKERS_DEBUG - ): # 如果处于debug模式,保存人工审核图片到本地 + if intelligent_workers_debug: # 如果处于debug模式,保存人工审核图片到本地 if monster_image is not None: try: - resized_monster_img = cv2.resize( - monster_image, (960, 540) - ) # 调整分辨率为 960x540 + resized_monster_img = cv2.resize(monster_image, (960, 540)) # 调整分辨率为 960x540 image_path = images_folder / (image_name + ".jpg") - cv2.imwrite( - image_path, - resized_monster_img, - [int(cv2.IMWRITE_JPEG_QUALITY), 80], - ) + cv2.imwrite(image_path, resized_monster_img, [int(cv2.IMWRITE_JPEG_QUALITY), 80]) # logger.info(f"保存怪物图片到 {image_path}") except Exception as e: logger.error(f"保存怪物图片失败: {e}") @@ -202,17 +167,15 @@ def fill_data( try: result_image_name = image_name + "_result.jpg" # 缩放到128像素高度 - h, w = result_image.shape[:2] + (h, w) = result_image.shape[:2] new_height = 128 - resized_image = cv2.resize( - result_image, (int(w * (new_height / h)), new_height) - ) + resized_image = cv2.resize(result_image, (int(w * (new_height / h)), new_height)) image_path = images_folder / result_image_name cv2.imwrite(image_path, resized_image) logger.info(f"保存结果图片到 {image_path}") except Exception as e: logger.error(f"保存结果图片失败: {e}") - + # 原始怪物数据 left_monster_data = np.zeros(MONSTER_COUNT) right_monster_data = np.zeros(MONSTER_COUNT) @@ -238,8 +201,8 @@ def fill_data( field_feature_columns = self.field_recognizer.get_feature_columns() field_data_values = [] for col in field_feature_columns: - if col in field_recognize_result: - field_data_values.append(field_recognize_result[col]) + if col in field_recoginze_result: + field_data_values.append(field_recoginze_result[col]) else: field_data_values.append(0) # 默认值 @@ -260,9 +223,9 @@ def fill_data( logger.info("仅收集怪物数据,跳过场地特征") data_row.extend(left_monster_data.tolist()) # 左侧怪物数据 data_row.extend(right_monster_data.tolist()) # 右侧怪物数据 - + data_row.append(battle_result) # Result - + # 替换所有NaN为-1 for i, x in enumerate(data_row): if isinstance(x, (int, float)) and np.isnan(x): @@ -273,9 +236,7 @@ def fill_data( r"%Y_%m_%d__%H_%M_%S" ) - if ( - INTELLIGENT_WORKERS_DEBUG - ): # 如果处于debug模式,保存人工审核图片到本地 + if intelligent_workers_debug: # 如果处于debug模式,保存人工审核图片到本地 data_row.append(image_name) with open(self.data_folder / "arknights.csv", "a", newline="") as file: @@ -288,26 +249,24 @@ def build_terrain_features(self, left_counts, right_counts): # 获取场地特征列数 field_feature_columns = self.field_recognizer.get_feature_columns() num_field_features = len(field_feature_columns) - + # 构建地形特征向量(基于当前场地识别结果) terrain_features = np.zeros(num_field_features) - + if self.field_recognize_result: # 将场地识别结果转换为特征向量 for i, col in enumerate(field_feature_columns): if col in self.field_recognize_result: terrain_features[i] = self.field_recognize_result[col] - + # 按照data_cleaning_with_field_recognize.py的格式组织数据 - full_features = np.concatenate( - [ - left_counts, # 1L-77L - terrain_features, # 78L-83L - right_counts, # 1R-77R - terrain_features, # 78R-83R - ] - ) - + full_features = np.concatenate([ + left_counts, # 1L-77L + terrain_features, # 78L-83L + right_counts, # 1R-77R + terrain_features # 78R-83R + ]) + return full_features @staticmethod @@ -318,9 +277,7 @@ def get_saturation(bgr): cmax = max(r, g, b) cmin = min(r, g, b) delta = cmax - cmin - return ( - (delta / cmax) * 255 if cmax != 0 else 0 - ) # 返回0-255范围的饱和度值 + return (delta / cmax) * 255 if cmax != 0 else 0 # 返回0-255范围的饱和度值 if image is None: logger.error("图像加载失败") @@ -335,14 +292,14 @@ def get_saturation(bgr): (0.9, 0.1), # 右上区域 (0.9, 0.5), # 右中区域 ] - + sample_size = 20 # 增大采样区域 left_saturations = [] right_saturations = [] - + for y_ratio, x_ratio in sample_points: y_offset = int(height * y_ratio) - + # 左侧采样点 x_left_offset = int(width * 0.1) y_end = min(y_offset + sample_size, height) @@ -351,28 +308,26 @@ def get_saturation(bgr): left_region = image[y_offset:y_end, x_left_offset:x_left_end] left_mean = left_region.mean(axis=(0, 1)) left_saturations.append(get_saturation(left_mean)) - + # 右侧采样点 x_right_offset = int(width * 0.9 - sample_size) x_right_end = min(x_right_offset + sample_size, width) if y_end > y_offset and x_right_end > x_right_offset: - right_region = image[ - y_offset:y_end, x_right_offset:x_right_end - ] + right_region = image[y_offset:y_end, x_right_offset:x_right_end] right_mean = right_region.mean(axis=(0, 1)) right_saturations.append(get_saturation(right_mean)) - + if not left_saturations or not right_saturations: logger.error("无法获取有效的采样区域") return None - + # 计算平均饱和度 avg_sat_left = sum(left_saturations) / len(left_saturations) avg_sat_right = sum(right_saturations) / len(right_saturations) - + # 计算饱和度差值 saturation_diff = avg_sat_left - avg_sat_right - + # 使用自适应阈值,根据整体饱和度水平调整 base_threshold = 15 # 如果整体饱和度较低,降低阈值 @@ -383,51 +338,49 @@ def get_saturation(bgr): threshold = 12 else: threshold = base_threshold - + # 检查差值是否符合要求 if abs(saturation_diff) <= threshold: - logger.warning( - f"饱和度差值不足 (左:{avg_sat_left:.1f} vs 右:{avg_sat_right:.1f}, 阈值:{threshold})" - ) + logger.warning(f"饱和度差值不足 (左:{avg_sat_left:.1f} vs 右:{avg_sat_right:.1f}, 阈值:{threshold})") # 尝试使用亮度差异作为备选方案 return AutoFetch.calculate_brightness_diff(image) # 返回左侧是否比右侧饱和度更高 return saturation_diff > 0 - + @staticmethod def calculate_brightness_diff(image): """使用亮度差异作为胜负识别的备选方案""" if image is None: return None - + height, width, _ = image.shape - + # 转换为灰度图 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) - + # 定义左侧和右侧区域 - left_region = gray[:, : width // 2] - right_region = gray[:, width // 2 :] - + left_region = gray[:, :width//2] + right_region = gray[:, width//2:] + # 计算平均亮度 left_brightness = left_region.mean() right_brightness = right_region.mean() - + # 计算亮度差值 brightness_diff = left_brightness - right_brightness - + # 使用亮度阈值 brightness_threshold = 10 if abs(brightness_diff) <= brightness_threshold: - logger.warning( - f"亮度差值不足 (左:{left_brightness:.1f} vs 右:{right_brightness:.1f})" - ) + logger.warning(f"亮度差值不足 (左:{left_brightness:.1f} vs 右:{right_brightness:.1f})") return None - + # 返回左侧是否比右侧亮 return brightness_diff > 0 + + @staticmethod def get_image_name(recognize_results, battle_result=None): # 处理结果 @@ -457,37 +410,23 @@ def save_statistics_to_log(self): with open("log.txt", "a", encoding="utf-8") as log_file: log_file.write(stats_text) - def recognize_and_predict(self, screenshot=None): + def recognize_and_predict(self, screenshot = None): if screenshot is None: screenshot = self.connector.capture_screenshot() self.recognize_results = self.recognizer.process_regions(screenshot) - + # 场地识别 if self.field_recognizer is not None: - self.field_recognize_result = ( - self.field_recognizer.recognize_field_elements(screenshot) - ) - + self.field_recognize_result = self.field_recognizer.recognize_field_elements(screenshot) + # 输出场地识别结果日志 if self.field_recognize_result: - detected_elements = [ - key - for key, value in self.field_recognize_result.items() - if value == 1 - ] - partial_detected = [ - key - for key, value in self.field_recognize_result.items() - if value == -1 - ] + detected_elements = [key for key, value in self.field_recognize_result.items() if value == 1] + partial_detected = [key for key, value in self.field_recognize_result.items() if value == -1] if detected_elements: - logger.info( - f"场地识别检测到元素: {', '.join(detected_elements)}" - ) + logger.info(f"场地识别检测到元素: {', '.join(detected_elements)}") if partial_detected: - logger.info( - f"场地识别部分检测到元素: {', '.join(partial_detected)}" - ) + logger.info(f"场地识别部分检测到元素: {', '.join(partial_detected)}") if not detected_elements and not partial_detected: logger.info("场地识别: 未检测到任何特殊元素") else: @@ -496,73 +435,57 @@ def recognize_and_predict(self, screenshot=None): # 场地识别被禁用,设置为空结果 self.field_recognize_result = {} logger.debug("场地识别已禁用,跳过场地识别") - + # 获取预测结果 self.update_monster_callback(self.recognize_results) left_counts = np.zeros(MONSTER_COUNT, dtype=np.int16) right_counts = np.zeros(MONSTER_COUNT, dtype=np.int16) for res in self.recognize_results: - if "error" not in res: - region_id = res["region_id"] - matched_id = res["matched_id"] - number = res["number"] + if 'error' not in res: + region_id = res['region_id'] + matched_id = res['matched_id'] + number = res['number'] if matched_id == 0: continue if region_id < 3: - left_counts[matched_id - 1] = number + left_counts[matched_id -1] = number else: - right_counts[matched_id - 1] = number + right_counts[matched_id -1] = number else: logger.error("识别结果有错误,本轮跳过") # 选择预测方法 if self.cannot_model.is_model_loaded: if self.field_recognizer is not None: # 构建包含地形的完整特征向量 - full_features = self.build_terrain_features( - left_counts, right_counts - ) - self.current_prediction = ( - self.cannot_model.get_prediction_with_terrain( - full_features - ) - ) + full_features = self.build_terrain_features(left_counts, right_counts) + self.current_prediction = self.cannot_model.get_prediction_with_terrain(full_features) else: # 仅使用怪物数据进行预测 - self.current_prediction = self.cannot_model.get_prediction( - left_counts, right_counts - ) + self.current_prediction = self.cannot_model.get_prediction(left_counts, right_counts) self.update_prediction_callback(self.current_prediction) else: logger.warning("模型未加载,无法进行预测") # 人工审核保存测试用截图 - if INTELLIGENT_WORKERS_DEBUG: # 如果处于debug模式且处于自动模式 - self.monster_image = screenshot + if intelligent_workers_debug: # 如果处于debug模式且处于自动模式 + self.monster_image=screenshot def battle_result(self, result_image): result = self.calculate_average_yellow(result_image) if result is None: logger.warning("战斗结果识别失败,需要重试") return False - + if result: self.fill_data( - "L", - self.recognize_results, - self.monster_image, - result_image, - self.field_recognize_result, + "L", self.recognize_results, self.monster_image, result_image, self.field_recognize_result ) if self.current_prediction > 0.5: self.incorrect_fill_count += 1 self._log(logging.INFO, "填写数据左赢") else: self.fill_data( - "R", - self.recognize_results, - self.monster_image, - result_image, - self.field_recognize_result, + "R", self.recognize_results, self.monster_image, result_image, self.field_recognize_result ) if self.current_prediction < 0.5: self.incorrect_fill_count += 1 @@ -572,6 +495,7 @@ def battle_result(self, result_image): self._log(logging.INFO, "下一轮") return True + def auto_fetch_data(self): relative_points = [ (0.9297, 0.8833), # 右ALL、返回主页、加入赛事、开始游戏 @@ -584,14 +508,12 @@ def auto_fetch_data(self): screenshot = self.connector.capture_screenshot() if screenshot is None: self._log(logging.ERROR, "截图失败,尝试自动登录") - + # 使用 LoginManager 的自动登录(带重启重试) - if not self.login_manager.auto_login_with_restart( - lambda: self.auto_fetch_running - ): + if not self.login_manager.auto_login_with_restart(lambda: self.auto_fetch_running): self._log(logging.ERROR, "自动登录失败,无法继续操作") return - + # 检查是否已经收到停止信号 if not self.auto_fetch_running: self._log(logging.INFO, "检测到停止信号,取消后续操作") @@ -602,9 +524,7 @@ def auto_fetch_data(self): self._log(logging.INFO, "重新获取截图") screenshot = self.connector.capture_screenshot() if screenshot is None: - self._log( - logging.ERROR, "登录后仍然无法获取截图,无法继续操作" - ) + self._log(logging.ERROR, "登录后仍然无法获取截图,无法继续操作") return # 保存当前截图及其信息到缓冲区 @@ -638,9 +558,7 @@ def auto_fetch_data(self): elif best_idx in [12, 13]: current_state = GameState.FINISHED if self.last_state != current_state: - logger.info( - f"匹配到状态: {self.last_state.name} -> {current_state.name}, score:{best_score:.4f}" - ) + logger.info(f"匹配到状态: {self.last_state.name} -> {current_state.name}, score:{best_score:.4f}") else: # logger.info(f"状态机匹配置信度过低: idx:{best_idx}, score:{best_score:.4f}") pass @@ -650,68 +568,38 @@ def auto_fetch_data(self): old_state = self.last_state self.last_state = current_state elapsed = time.time() - self.state_start_time - + # 不记录 PRE_BATTLE -> IN_BATTLE 的状态变化 - if not ( - old_state == GameState.PRE_BATTLE - and current_state == GameState.IN_BATTLE - ): - self._log( - logging.INFO, - f"游戏状态变化: {old_state.name} -> {current_state.name}, 持续时间: {elapsed:.2f} 秒", - ) - + if not (old_state == GameState.PRE_BATTLE and current_state == GameState.IN_BATTLE): + self._log(logging.INFO, f"游戏状态变化: {old_state.name} -> {current_state.name}, 持续时间: {elapsed:.2f} 秒") + # 如果成功进入稳定状态且重启计数器非零,重置重启计数器 - _stable_states = { - GameState.MAIN_MENU, - GameState.IN_BATTLE, - GameState.SETTLEMENT, - GameState.FINISHED, - } - if ( - current_state in _stable_states - and self.login_manager.restart_count > 0 - ): + _stable_states = {GameState.MAIN_MENU, GameState.IN_BATTLE, GameState.SETTLEMENT, GameState.FINISHED} + if current_state in _stable_states and self.login_manager.restart_count > 0: self.login_manager.reset_restart_count() - + self.state_start_time = time.time() # 重置状态开始时间 - + # 全局超时检测:无论什么状态,只要超过时间都可能触发重启 # 非战斗状态:超过 50 秒触发重启 # 战斗流程状态:超过 120 秒触发重启(防止战斗卡死) elapsed_time = time.time() - self.state_start_time - is_battle_state = self.last_state in [ - GameState.PRE_BATTLE, - GameState.IN_BATTLE, - GameState.SETTLEMENT, - GameState.FINISHED, - ] + is_battle_state = self.last_state in [GameState.PRE_BATTLE, GameState.IN_BATTLE, GameState.SETTLEMENT, GameState.FINISHED] timeout_threshold = 120.0 if is_battle_state else 50.0 - + # 检查是否超时 if elapsed_time > timeout_threshold: state_name = self.last_state.name if self.last_state else "NONE" - self._log( - logging.WARNING, - f"在状态 '{state_name}' 停留超过 {elapsed_time:.2f} 秒(阈值: {timeout_threshold:.0f} 秒),触发重启", - ) - + self._log(logging.WARNING, f"在状态 '{state_name}' 停留超过 {elapsed_time:.2f} 秒(阈值: {timeout_threshold:.0f} 秒),触发重启") + # 使用 LoginManager 的重启登录方法 if not self.login_manager.can_restart(): - self._log( - logging.ERROR, - f"已达到最大重启次数 {self.login_manager.max_restart_count} 次,停止运行", - ) + self._log(logging.ERROR, f"已达到最大重启次数 {self.login_manager.max_restart_count} 次,停止运行") self.auto_fetch_running = False self.stop_callback() - elif not self.login_manager.restart_and_login( - first_start=False, - stop_callback=lambda: self.auto_fetch_running, - ): - self._log( - logging.WARNING, "本次重启登录失败,将在下次超时后重试" - ) - + elif not self.login_manager.restart_and_login(first_start=False, stop_callback=lambda: self.auto_fetch_running): + self._log(logging.WARNING, "本次重启登录失败,将在下次超时后重试") + # 检测完毕后,无论结果如何,重置计时器,避免频繁阻塞 self.state_start_time = time.time() self._log(logging.INFO, "重置状态计时器") @@ -769,9 +657,7 @@ def auto_fetch_data(self): if not self._sleep_with_check(3): return if self.game_mode == "30人": - self._log( - logging.INFO, "30人模式下,投资后需要等待20秒" - ) + self._log(logging.INFO, "30人模式下,投资后需要等待20秒") if not self._sleep_with_check(5): return else: # 不投资 @@ -786,9 +672,7 @@ def auto_fetch_data(self): case GameState.SETTLEMENT: if not self.battle_result(screenshot): new_screenshot = self.connector.capture_screenshot() - if new_screenshot is not None and not self.battle_result( - new_screenshot - ): + if new_screenshot is not None and not self.battle_result(new_screenshot): self._log(logging.ERROR, "战斗结果识别失败,跳过本轮") if not self._sleep_with_check(5): return @@ -806,33 +690,26 @@ def auto_fetch_loop(self): # 每次循环开始时检查状态 if not self.auto_fetch_running: break - - # 刷新当前预测显示(心跳):不要写入固定0,避免把GUI错误覆盖成“左方100%” - self.update_prediction_callback(self.current_prediction) - + + self.updater() # 多开器如果不更新会强制停止 self.auto_fetch_data() # 每次循环结束时检查状态 if not self.auto_fetch_running: break - + elapsed_time = time.time() - self.start_time - if ( - self.training_duration != -1 - and elapsed_time >= self.training_duration - ): + if self.training_duration != -1 and elapsed_time >= self.training_duration: self._log(logging.INFO, "已达到设定时长,结束自动获取") break # 检测一次间隔时间—————————————————————————————————— - time.sleep(0.1) + time.sleep(0.2) except Exception as e: self._log(logging.ERROR, f"自动获取数据出错:\n{e}") break else: - self._log( - logging.INFO, "auto_fetch_running is False, exiting loop" - ) + self._log(logging.INFO, "auto_fetch_running is False, exiting loop") return # 不通过按钮结束自动获取 self._log(logging.INFO, "break auto_fetch_loop") @@ -842,57 +719,33 @@ def start_auto_fetch(self): if not self.auto_fetch_running: self.auto_fetch_running = True # 使用初始化时设置的时间戳,不重新获取当前时间 - start_time = datetime.datetime.fromtimestamp( - self.start_time - ).strftime(r"%Y_%m_%d__%H_%M_%S") - self.data_folder = PROJECT_ROOT / "data" / start_time + start_time = datetime.datetime.fromtimestamp(self.start_time).strftime( + r"%Y_%m_%d__%H_%M_%S" + ) + self.data_folder = Path(f"data/{start_time}") self._log(logging.INFO, f"创建文件夹: {self.data_folder}") self.data_folder.mkdir(parents=True, exist_ok=True) # 创建文件夹 (self.data_folder / "images").mkdir(parents=True, exist_ok=True) - with open( - self.data_folder / "arknights.csv", "w", newline="" - ) as file: + with open(self.data_folder / "arknights.csv", "w", newline="") as file: # 创建CSV表头 if self.field_recognizer is not None: # 获取场地特征列数 - num_field_features = len( - self.field_recognizer.get_feature_columns() - ) - + num_field_features = len(self.field_recognizer.get_feature_columns()) + # 按照data_cleaning_with_field_recognize_gpu.py的格式创建表头 - header = [ - f"{i+1}L" for i in range(MONSTER_COUNT) - ] # 1L-77L - header += [ - f"{i+1}LF" - for i in range( - MONSTER_COUNT, MONSTER_COUNT + num_field_features - ) - ] # 78LF-83LF (场地特征) - header += [ - f"{i+1}R" for i in range(MONSTER_COUNT) - ] # 1R-77R - header += [ - f"{i+1}RF" - for i in range( - MONSTER_COUNT, MONSTER_COUNT + num_field_features - ) - ] # 78RF-83RF (场地特征) + header = [f"{i+1}L" for i in range(MONSTER_COUNT)] # 1L-77L + header += [f"{i+1}LF" for i in range(MONSTER_COUNT, MONSTER_COUNT + num_field_features)] # 78LF-83LF (场地特征) + header += [f"{i+1}R" for i in range(MONSTER_COUNT)] # 1R-77R + header += [f"{i+1}RF" for i in range(MONSTER_COUNT, MONSTER_COUNT + num_field_features)] # 78RF-83RF (场地特征) header += ["Result", "ImgPath"] - logger.info( - f"创建包含场地特征的CSV表头,场地特征数: {num_field_features}" - ) + logger.info(f"创建包含场地特征的CSV表头,场地特征数: {num_field_features}") else: # 仅怪物数据的格式 - header = [ - f"{i+1}L" for i in range(MONSTER_COUNT) - ] # 左侧怪物数据 - header += [ - f"{i+1}R" for i in range(MONSTER_COUNT) - ] # 右侧怪物数据 + header = [f"{i+1}L" for i in range(MONSTER_COUNT)] # 左侧怪物数据 + header += [f"{i+1}R" for i in range(MONSTER_COUNT)] # 右侧怪物数据 header += ["Result", "ImgPath"] logger.info("创建仅包含怪物数据的CSV表头") - + writer = csv.writer(file) writer.writerow(header) self.log_file_handler = logging.FileHandler( @@ -904,11 +757,9 @@ def start_auto_fetch(self): self.log_file_handler.setFormatter(file_formatter) self.log_file_handler.setLevel(logging.INFO) logger.addHandler(self.log_file_handler) - + # 启动自动获取数据线程 - self.auto_fetch_thread = threading.Thread( - target=self.auto_fetch_loop - ) + self.auto_fetch_thread = threading.Thread(target=self.auto_fetch_loop) self.auto_fetch_thread.start() logger.info("自动获取数据已启动") self.start_callback() @@ -923,14 +774,14 @@ def _sleep_with_check(self, seconds): return False time.sleep(0.1) return True - + def stop_auto_fetch(self): if not self.auto_fetch_running: return # 强制设置停止标志,不等待线程退出 self.auto_fetch_running = False self._log(logging.INFO, "强制停止自动获取") - + # 不等待线程退出,让线程在下一次循环时自己检测到停止标志 self.save_statistics_to_log() self.stop_callback() diff --git a/src/core/config.py b/config.py similarity index 54% rename from src/core/config.py rename to config.py index 819cea0..31acae5 100644 --- a/src/core/config.py +++ b/config.py @@ -1,14 +1,13 @@ +from pathlib import Path import cv2 import numpy as np import pandas as pd import logging -from .paths import DATA_DIR, IMAGES_DIR - logger = logging.getLogger(__name__) -FIELD_FEATURE_COUNT = 0 - +# 全局地形特征数量常量 +FIELD_FEATURE_COUNT = 0 # 默认值 def load_images() -> dict[str, np.ndarray]: """ @@ -16,13 +15,13 @@ def load_images() -> dict[str, np.ndarray]: returns: dict - 图片字典,键为文件名(不含扩展名),值为numpy.ndarray对象 """ images = {} - images_path = IMAGES_DIR - for image_file in images_path.glob("*.*"): - if image_file.suffix.lower() in (".png", ".jpg", ".jpeg", ".bmp"): + images_path = Path('images') + # 遍历images目录下的所有文件 + for image_file in images_path.glob('*.*'): + if image_file.suffix.lower() in ('.png', '.jpg', '.jpeg', '.bmp'): try: - img = cv2.imdecode( - np.fromfile(image_file, dtype=np.uint8), cv2.IMREAD_COLOR - ) + # img = cv2.imread(str(image_file), cv2.IMREAD_COLOR) + img = cv2.imdecode(np.fromfile(image_file, dtype=np.uint8), cv2.IMREAD_COLOR) if img is None: logger.error(f"无法加载图片: {image_file}") continue @@ -31,19 +30,13 @@ def load_images() -> dict[str, np.ndarray]: logger.error(f"加载图片出错 {image_file}: {str(e)}") return images - MONSTER_IMAGES = load_images() - def load_monster_data(): - monster_data = pd.read_csv( - DATA_DIR / "monster_greenvine.csv", - index_col="id", - encoding="utf-8-sig", - ) + monster_data = pd.read_csv('monster_greenvine.csv', index_col="id", encoding='utf-8-sig') return monster_data - MONSTER_DATA = load_monster_data() -MONSTER_COUNT = len(MONSTER_DATA) +# 全局变量 +MONSTER_COUNT = len(MONSTER_DATA) # 根据怪物数据自动设置数量 diff --git a/src/core/constants.py b/constants.py similarity index 89% rename from src/core/constants.py rename to constants.py index a1a2590..60d3adc 100644 --- a/src/core/constants.py +++ b/constants.py @@ -7,10 +7,10 @@ "health": 1390, "magic_resist": 0, "attack_interval": 3.3, - "move_speed": 1 / 2, # 除2是因为方舟就是要除2 + "move_speed": 1 / 2, # 除2是因为方舟就是要除2 "attack_radius": 2.75, "effect": "破甲15", - "icon": "", + "icon": "images/1.png" }, 2: { "name": "灼热源石虫", @@ -23,7 +23,7 @@ "move_speed": 0.8 / 2, "attack_radius": 2.8, "effect": "灼燃", - "icon": "", + "icon": "images/2.png" }, 3: { "name": "狂暴的猎狗pro", @@ -36,7 +36,7 @@ "move_speed": 1.9 / 2, "attack_radius": 0.8, "effect": "", - "icon": "", + "icon": "images/3.png" }, 4: { "name": "炮击组长", @@ -49,7 +49,7 @@ "move_speed": 0.8 / 2, "attack_radius": 7, "effect": "溅射", - "icon": "", + "icon": "images/4.png" }, 5: { "name": "萨卡兹大剑手", @@ -62,7 +62,7 @@ "move_speed": 0.85 / 2, "attack_radius": 0.8, "effect": "", - "icon": "", + "icon": "images/5.png" }, 6: { "name": "宿主流浪者", @@ -75,7 +75,7 @@ "move_speed": 0.65 / 2, "attack_radius": 0.8, "effect": "再生", - "icon": "", + "icon": "images/6.png" }, 7: { "name": "重装防御者", @@ -88,7 +88,7 @@ "move_speed": 0.75 / 2, "attack_radius": 0.8, "effect": "", - "icon": "", + "icon": "images/7.png" }, 8: { "name": "复仇者", @@ -101,7 +101,7 @@ "move_speed": 0.65 / 2, "attack_radius": 0.8, "effect": "火刀", - "icon": "", + "icon": "images/8.png" }, 9: { "name": "狂暴宿主组长", @@ -114,7 +114,7 @@ "move_speed": 1.2 / 2, "attack_radius": 0.8, "effect": "掉血", - "icon": "", + "icon": "images/9.png" }, 10: { "name": "巧克力流心虫虫", @@ -127,7 +127,7 @@ "move_speed": 0.8 / 2, "attack_radius": 2.8, "effect": "灼燃", - "icon": "", + "icon": "images/2.png" }, 11: { "name": "巧克力流心虫虫", @@ -140,7 +140,7 @@ "move_speed": 0.8 / 2, "attack_radius": 2.8, "effect": "灼燃", - "icon": "", + "icon": "images/2.png" }, 12: { "name": "泥岩巨像", @@ -153,7 +153,7 @@ "move_speed": 0.4 / 2, "attack_radius": 0.8, "effect": "", - "icon": "", + "icon": "images/12.png" }, 13: { "name": "高塔术师", @@ -166,7 +166,7 @@ "move_speed": 0.6 / 2, "attack_radius": 3.2, "effect": "打2 溅射", - "icon": "", + "icon": "images/13.png" }, 14: { "name": "巧克力流心虫虫", @@ -179,7 +179,7 @@ "move_speed": 0.8 / 2, "attack_radius": 2.8, "effect": "灼燃", - "icon": "", + "icon": "images/2.png" }, 15: { "name": "巧克力流心虫虫", @@ -192,7 +192,7 @@ "move_speed": 0.8 / 2, "attack_radius": 2.8, "effect": "灼燃", - "icon": "", + "icon": "images/2.png" }, 16: { "name": "冰原术师", @@ -205,7 +205,7 @@ "move_speed": 0.7 / 2, "attack_radius": 3.2, "effect": "打2 寒冷", - "icon": "", + "icon": "images/16.png" }, 17: { "name": "巧克力流心虫虫", @@ -218,7 +218,7 @@ "move_speed": 0.8 / 2, "attack_radius": 2.8, "effect": "灼燃", - "icon": "", + "icon": "images/2.png" }, 18: { "name": "弧光锋卫长", @@ -231,7 +231,7 @@ "move_speed": 0.75 / 2, "attack_radius": 0.8, "effect": "", - "icon": "", + "icon": "images/18.png" }, 19: { "name": "巧克力流心虫虫", @@ -244,7 +244,7 @@ "move_speed": 0.8 / 2, "attack_radius": 2.8, "effect": "灼燃", - "icon": "", + "icon": "images/2.png" }, 20: { "name": "提亚卡乌好战者", @@ -257,7 +257,7 @@ "move_speed": 0.8 / 2, "attack_radius": 0.8, "effect": "破甲10", - "icon": "", + "icon": "images/20.png" }, 21: { "name": "矿脉守卫", @@ -270,7 +270,7 @@ "move_speed": 0.6 / 2, "attack_radius": 0.8, "effect": "反伤", - "icon": "", + "icon": "images/21.png" }, 22: { "name": "巧克力流心虫虫", @@ -283,7 +283,7 @@ "move_speed": 0.8 / 2, "attack_radius": 2.8, "effect": "灼燃", - "icon": "", + "icon": "images/2.png" }, 23: { "name": "巧克力流心虫虫", @@ -296,7 +296,7 @@ "move_speed": 0.8 / 2, "attack_radius": 2.8, "effect": "灼燃", - "icon": "", + "icon": "images/2.png" }, 24: { "name": "巧克力流心虫虫", @@ -309,7 +309,7 @@ "move_speed": 0.8 / 2, "attack_radius": 2.8, "effect": "灼燃", - "icon": "", + "icon": "images/2.png" }, 25: { "name": "巧克力流心虫虫", @@ -322,7 +322,7 @@ "move_speed": 0.8 / 2, "attack_radius": 2.8, "effect": "灼燃", - "icon": "", + "icon": "images/2.png" }, 26: { "name": "巧克力流心虫虫", @@ -335,6 +335,6 @@ "move_speed": 0.8 / 2, "attack_radius": 2.8, "effect": "灼燃", - "icon": "", - }, -} + "icon": "images/2.png" + } +} \ No newline at end of file diff --git a/src/ui/dark_mode_style_fix.py b/dark_mode_style_fix.py similarity index 100% rename from src/ui/dark_mode_style_fix.py rename to dark_mode_style_fix.py diff --git a/src/data/data_package.py b/data_package.py similarity index 96% rename from src/data/data_package.py rename to data_package.py index 79fe590..dbc90b5 100644 --- a/src/data/data_package.py +++ b/data_package.py @@ -36,11 +36,10 @@ def create_zip_package(output_zip_path): shutil.rmtree(folder) print(f"已删除文件夹:{folder}") except Exception as e: - print(f"删除文件夹 {folder} 时出错:{e}") + print(f"删除文件夹 {folder} 时出错:{e}") print(f"压缩包已创建:{output_zip_path}") - def package_data(): # 使用当前时间生成输出文件名 current_time = datetime.now().strftime("%Y_%m_%d__%H_%M_%S") @@ -50,6 +49,5 @@ def package_data(): create_zip_package(output_zip) return output_zip - if __name__ == "__main__": package_data() diff --git a/src/__init__.py "b/data_train/package/\346\225\260\346\215\256\345\214\205\346\224\276\345\234\250\346\255\244\350\267\257\345\276\204.md" similarity index 100% rename from src/__init__.py rename to "data_train/package/\346\225\260\346\215\256\345\214\205\346\224\276\345\234\250\346\255\244\350\267\257\345\276\204.md" diff --git a/src/tools/merge_data.py "b/data_train/\346\225\260\346\215\256\345\220\210\345\271\266.py" similarity index 69% rename from src/tools/merge_data.py rename to "data_train/\346\225\260\346\215\256\345\220\210\345\271\266.py" index 879b10b..4c31aa0 100644 --- a/src/tools/merge_data.py +++ "b/data_train/\346\225\260\346\215\256\345\220\210\345\271\266.py" @@ -14,16 +14,12 @@ if str(project_root) not in sys.path: sys.path.insert(0, str(project_root)) -# from config import MONSTER_COUNT, FIELD_FEATURE_COUNT config会读取图片导致非常慢 - +#from config import MONSTER_COUNT, FIELD_FEATURE_COUNT config会读取图片导致非常慢 def load_monster_data(): - monster_data = pd.read_csv( - "monster_greenvine.csv", index_col="id", encoding="utf-8-sig" - ) + monster_data = pd.read_csv('monster_greenvine.csv', index_col="id", encoding='utf-8-sig') return monster_data - MONSTER_DATA = load_monster_data() # 全局变量 @@ -35,15 +31,9 @@ def get_expected_header(): """根据配置生成预期表头""" if FIELD_FEATURE_COUNT > 0: header = [f"{i + 1}L" for i in range(MONSTER_COUNT)] - header += [ - f"{i + 1}LF" - for i in range(MONSTER_COUNT, MONSTER_COUNT + FIELD_FEATURE_COUNT) - ] + header += [f"{i + 1}LF" for i in range(MONSTER_COUNT, MONSTER_COUNT + FIELD_FEATURE_COUNT)] header += [f"{i + 1}R" for i in range(MONSTER_COUNT)] - header += [ - f"{i + 1}RF" - for i in range(MONSTER_COUNT, MONSTER_COUNT + FIELD_FEATURE_COUNT) - ] + header += [f"{i + 1}RF" for i in range(MONSTER_COUNT, MONSTER_COUNT + FIELD_FEATURE_COUNT)] header += ["Result", "ImgPath"] else: header = [f"{i + 1}L" for i in range(MONSTER_COUNT)] @@ -54,12 +44,12 @@ def get_expected_header(): def read_csv_from_zip(zip_ref, csv_filename): """从 ZIP 文件流中直接读取 CSV 数据,尝试多种编码""" - encodings = ["utf-8-sig", "utf-8", "gbk", "gb18030", "big5", "latin1"] + encodings = ['utf-8-sig', 'utf-8', 'gbk', 'gb18030', 'big5', 'latin1'] for encoding in encodings: try: with zip_ref.open(csv_filename) as f: - text_f = io.TextIOWrapper(f, encoding=encoding, newline="") + text_f = io.TextIOWrapper(f, encoding=encoding, newline='') reader = csv.reader(text_f) try: header = next(reader) @@ -75,8 +65,8 @@ def read_csv_from_zip(zip_ref, csv_filename): def process_archives(merge_images=True, extract_result_images=False): package_dir = base_dir / "package" - target_images_dir = base_dir / "images" - target_csv_path = base_dir / "arknights.csv" + target_images_dir = base_dir / 'images' + target_csv_path = base_dir / 'arknights.csv' # 1. 目录准备 (移除旧的清空逻辑,保证增量更新) if not package_dir.exists(): @@ -92,16 +82,12 @@ def process_archives(merge_images=True, extract_result_images=False): # 2. 构建现有 CSV 数据的索引集合 seen_csv_img_paths = set() - is_csv_initialized = False # 用于判断是否需要写入表头 + is_csv_initialized = False # 用于判断是否需要写入表头 if target_csv_path.exists(): - print( - f"检测到已存在的 {target_csv_path.name},正在读取历史记录构建索引..." - ) + print(f"检测到已存在的 {target_csv_path.name},正在读取历史记录构建索引...") try: - with open( - target_csv_path, "r", encoding="utf-8-sig", newline="" - ) as f: + with open(target_csv_path, 'r', encoding='utf-8-sig', newline='') as f: reader = csv.reader(f) try: header = next(reader) @@ -110,14 +96,10 @@ def process_archives(merge_images=True, extract_result_images=False): for row in reader: if len(row) > img_path_idx: seen_csv_img_paths.add(row[img_path_idx]) - print( - f"-> 成功加载 {len(seen_csv_img_paths)} 条历史记录的索引。" - ) + print(f"-> 成功加载 {len(seen_csv_img_paths)} 条历史记录的索引。") else: - print( - "-> 警告:已存在 CSV 的表头与配置不符,将创建新文件或覆写。" - ) - target_csv_path.unlink() # 表头不对则删除重建 + print("-> 警告:已存在 CSV 的表头与配置不符,将创建新文件或覆写。") + target_csv_path.unlink() # 表头不对则删除重建 except StopIteration: # 文件为空 pass @@ -126,7 +108,7 @@ def process_archives(merge_images=True, extract_result_images=False): target_csv_path.unlink(missing_ok=True) # 定义可能的文件后缀,涵盖常见大小写 - possible_extensions = [".jpg", ".png", ".jpeg", ".JPG", ".PNG", ".JPEG"] + possible_extensions = ['.jpg', '.png', '.jpeg', '.JPG', '.PNG', '.JPEG'] zip_files = list(package_dir.glob("*.zip")) print(f"\n找到 {len(zip_files)} 个压缩包,准备进行增量处理...") @@ -139,19 +121,17 @@ def process_archives(merge_images=True, extract_result_images=False): print(f"\n正在处理压缩包: {zip_path.name}") try: - with zipfile.ZipFile(zip_path, "r") as zf: + with zipfile.ZipFile(zip_path, 'r') as zf: # 建立 namelist 的 O(1) 查找集合 zip_namelist_set = set(zf.namelist()) - + # ========================================== # 任务 1:完全独立处理 CSV 文件 # ========================================== - csv_members = [ - m for m in zip_namelist_set if m.endswith("arknights.csv") - ] + csv_members = [m for m in zip_namelist_set if m.endswith('arknights.csv')] zip_added_csv_count = 0 - + for csv_member in csv_members: header, data, encoding = read_csv_from_zip(zf, csv_member) @@ -173,24 +153,17 @@ def process_archives(merge_images=True, extract_result_images=False): # 追加写入 CSV if zip_new_csv_rows: - mode = "a" if is_csv_initialized else "w" - with open( - target_csv_path, - mode, - newline="", - encoding="utf-8-sig", - ) as f: + mode = 'a' if is_csv_initialized else 'w' + with open(target_csv_path, mode, newline='', encoding='utf-8-sig') as f: writer = csv.writer(f) if not is_csv_initialized: writer.writerow(expected_header) is_csv_initialized = True writer.writerows(zip_new_csv_rows) - + zip_added_csv_count += len(zip_new_csv_rows) print(f" -> {csv_member} (编码: {encoding})") - print( - f" CSV: 新增 {len(zip_new_csv_rows)} 条,重复跳过 {skip_csv_count} 条" - ) + print(f" CSV: 新增 {len(zip_new_csv_rows)} 条,重复跳过 {skip_csv_count} 条") total_added_rows += zip_added_csv_count @@ -207,39 +180,29 @@ def process_archives(merge_images=True, extract_result_images=False): # 排除 Mac 系统压缩可能产生的隐藏文件干扰 if "__MACOSX" in member: continue - + filename = Path(member).name - is_result_img = filename.rsplit(".", 1)[ - 0 - ].endswith("_result") + is_result_img = filename.rsplit('.', 1)[0].endswith('_result') # 根据参数决定是否跳过 result 图 if is_result_img and not extract_result_images: continue target_img_path = target_images_dir / filename - + # 增量判断:如果本地没有,则解压提取 if target_img_path.exists(): zip_skip_img_count += 1 else: try: with zf.open(member) as source_file: - with open( - target_img_path, "wb" - ) as target_file: - shutil.copyfileobj( - source_file, target_file - ) + with open(target_img_path, 'wb') as target_file: + shutil.copyfileobj(source_file, target_file) zip_extracted_img_count += 1 except Exception as e: - print( - f" [错误] 提取图片 {member} 失败: {e}" - ) - - print( - f" IMG: 提取新图 {zip_extracted_img_count} 张,已存在跳过 {zip_skip_img_count} 张" - ) + print(f" [错误] 提取图片 {member} 失败: {e}") + + print(f" IMG: 提取新图 {zip_extracted_img_count} 张,已存在跳过 {zip_skip_img_count} 张") total_extracted_imgs += zip_extracted_img_count except zipfile.BadZipFile: @@ -253,9 +216,7 @@ def process_archives(merge_images=True, extract_result_images=False): print(f"总计提取新图片: {total_extracted_imgs} 张") -if __name__ == "__main__": - merge_imgs = False # 设置为 True 则提取阵容图 +if __name__ == '__main__': + merge_imgs = False # 设置为 True 则提取阵容图 extract_res_imgs = False # 设置为 True 则同时提取带有 _result 的结果图 - process_archives( - merge_images=merge_imgs, extract_result_images=extract_res_imgs - ) + process_archives(merge_images=merge_imgs, extract_result_images=extract_res_imgs) diff --git a/src/recognition/field_recognition.py b/field_recognition.py similarity index 68% rename from src/recognition/field_recognition.py rename to field_recognition.py index c179e1c..59344bb 100644 --- a/src/recognition/field_recognition.py +++ b/field_recognition.py @@ -6,6 +6,7 @@ from collections import defaultdict from PIL import Image import cv2 +import numpy as np import torch import torch.nn as nn from torchvision import models, transforms @@ -17,22 +18,22 @@ "altar_vertical": [ {"x": 910, "y": 174, "width": 95, "height": 104}, {"x": 910, "y": 429, "width": 102, "height": 108}, - {"x": 900, "y": 755, "width": 120, "height": 108}, + {"x": 900, "y": 755, "width": 120, "height": 108} ], "block_parallel": [ {"x": 694, "y": 240, "width": 530, "height": 122}, - {"x": 651, "y": 614, "width": 620, "height": 143}, + {"x": 651, "y": 614, "width": 620, "height": 143} ], "block_vertical": [ {"x": 647, "y": 233, "width": 153, "height": 523}, - {"x": 1112, "y": 239, "width": 159, "height": 514}, + {"x": 1112, "y": 239, "width": 159, "height": 514} ], "coil_narrow": [ {"x": 915, "y": 110, "width": 85, "height": 89}, {"x": 815, "y": 257, "width": 86, "height": 98}, {"x": 1024, "y": 258, "width": 79, "height": 98}, {"x": 790, "y": 643, "width": 97, "height": 102}, - {"x": 1031, "y": 639, "width": 102, "height": 108}, + {"x": 1031, "y": 639, "width": 102, "height": 108} ], "coil_wide": [ {"x": 719, "y": 181, "width": 81, "height": 89}, @@ -42,18 +43,23 @@ {"x": 1159, "y": 757, "width": 93, "height": 92}, {"x": 1257, "y": 533, "width": 94, "height": 102}, {"x": 1236, "y": 344, "width": 85, "height": 97}, - {"x": 1120, "y": 180, "width": 75, "height": 91}, + {"x": 1120, "y": 180, "width": 75, "height": 91} + ], + "crossbow_top": [ + {"x": 718, "y": 13, "width": 484, "height": 106} + ], + "fire_side_left": [ + {"x": 98, "y": 246, "width": 184, "height": 281} + ], + "fire_side_right": [ + {"x": 1656, "y": 430, "width": 235, "height": 315} ], - "crossbow_top": [{"x": 718, "y": 13, "width": 484, "height": 106}], - "fire_side_left": [{"x": 98, "y": 246, "width": 184, "height": 281}], - "fire_side_right": [{"x": 1656, "y": 430, "width": 235, "height": 315}], "fire_top": [ {"x": 532, "y": 17, "width": 188, "height": 97}, - {"x": 1325, "y": 14, "width": 60, "height": 100}, - ], + {"x": 1325, "y": 14, "width": 60, "height": 100} + ] } - class FieldRecognizer: def __init__(self): self.field_model = None @@ -63,7 +69,7 @@ def __init__(self): self.grouped_elements = {} self.image_feature_columns = [] self.is_initialized = False - + # 初始化场地识别模型 self._init_field_recognition() @@ -71,23 +77,19 @@ def _init_field_recognition(self): """初始化场地识别模型和相关组件""" try: # 设置设备 - self.field_device = torch.device( - "cuda" if torch.cuda.is_available() else "cpu" - ) + self.field_device = torch.device("cuda" if torch.cuda.is_available() else "cpu") logger.info(f"场地识别将使用设备: {self.field_device}") - + # 加载类别映射 model_dir = Path("tools/battlefield_recognize") class_map_path = model_dir / "class_to_idx.json" pth_model_path = model_dir / "field_recognize.pth" - + if not class_map_path.exists(): - logger.warning( - "找不到场地识别类别映射文件,跳过场地识别初始化" - ) + logger.warning("找不到场地识别类别映射文件,跳过场地识别初始化") return - with open(class_map_path, "r", encoding="utf-8") as f: + with open(class_map_path, 'r', encoding='utf-8') as f: class_to_idx = json.load(f) self.idx_to_class = {v: k for k, v in class_to_idx.items()} num_classes = len(class_to_idx) @@ -95,45 +97,35 @@ def _init_field_recognition(self): # 准备特征列 self.grouped_elements = defaultdict(list) for class_name in class_to_idx.keys(): - if class_name.endswith("_none"): + if class_name.endswith('_none'): continue - condensed_name = re.sub(r"_left_", "_", class_name) - condensed_name = re.sub(r"_right_", "_", condensed_name) + condensed_name = re.sub(r'_left_', '_', class_name) + condensed_name = re.sub(r'_right_', '_', condensed_name) self.grouped_elements[condensed_name].append(class_name) self.image_feature_columns = sorted(self.grouped_elements.keys()) - + if not pth_model_path.exists(): logger.warning("找不到场地识别模型文件,跳过场地识别初始化") return # 加载模型 - self.field_model = self._load_pytorch_model( - str(pth_model_path), num_classes, self.field_device - ) - + self.field_model = self._load_pytorch_model(str(pth_model_path), num_classes, self.field_device) + # 设置图像变换 - self.field_transform = transforms.Compose( - [ - transforms.Resize((224, 224)), - transforms.ToTensor(), - transforms.Normalize( - [0.485, 0.456, 0.406], [0.229, 0.224, 0.225] - ), - ] - ) - + self.field_transform = transforms.Compose([ + transforms.Resize((224, 224)), + transforms.ToTensor(), + transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) + ]) + self.is_initialized = True - logger.info( - f"场地识别初始化成功,将生成 {len(self.image_feature_columns)} 个特征列" - ) - + logger.info(f"场地识别初始化成功,将生成 {len(self.image_feature_columns)} 个特征列") + except Exception as e: logger.error(f"场地识别初始化失败: {e}") self.is_initialized = False - def _load_pytorch_model( - self, model_path: str, num_classes: int, device: torch.device - ): + def _load_pytorch_model(self, model_path: str, num_classes: int, device: torch.device): """加载 PyTorch 模型并设置为评估模式""" logger.info(f"正在加载 PyTorch 模型: {model_path}") model = models.mobilenet_v3_small(weights=None) @@ -145,12 +137,10 @@ def _load_pytorch_model( logger.info("模型加载成功并已切换到评估模式。") return model - def _predict_scene_pytorch( - self, image_path: str, threshold: float = 0.5 - ) -> list[str]: + def _predict_scene_pytorch(self, image_path: str, threshold: float = 0.5) -> list[str]: """使用 PyTorch 模型对给定图片的所有 ROI 进行分类预测""" try: - full_image = Image.open(image_path).convert("RGB") + full_image = Image.open(image_path).convert('RGB') except Exception: return [] @@ -161,27 +151,18 @@ def _predict_scene_pytorch( with torch.no_grad(): for location, boxes in ROI_COORDINATES.items(): for i, box in enumerate(boxes): - x, y, w, h = ( - box["x"], - box["y"], - box["width"], - box["height"], - ) + x, y, w, h = box['x'], box['y'], box['width'], box['height'] roi_pil = full_image.crop((x, y, x + w, y + h)) input_tensor = self.field_transform(roi_pil).unsqueeze(0) input_tensor = input_tensor.to(self.field_device) outputs = self.field_model(input_tensor) - probabilities = torch.nn.functional.softmax( - outputs, dim=1 - )[0] - max_prob, predicted_index_tensor = torch.max( - probabilities, 0 - ) + probabilities = torch.nn.functional.softmax(outputs, dim=1)[0] + max_prob, predicted_index_tensor = torch.max(probabilities, 0) predicted_index = predicted_index_tensor.item() if max_prob.item() >= threshold: predicted_class = self.idx_to_class[predicted_index] - if not predicted_class.endswith("_none"): + if not predicted_class.endswith('_none'): detected_classes.append(predicted_class) return detected_classes @@ -190,37 +171,31 @@ def recognize_field_elements(self, screenshot): if not self.is_initialized or self.field_model is None: logger.debug("场地识别模型未初始化,跳过场地识别") return {} - + try: # 将OpenCV图像转换为PIL图像 screenshot_rgb = cv2.cvtColor(screenshot, cv2.COLOR_BGR2RGB) pil_image = Image.fromarray(screenshot_rgb) - + # 保存临时文件用于识别 temp_image_path = "temp_screenshot.png" pil_image.save(temp_image_path) - + # 进行场地识别 - detected_full_names = set( - self._predict_scene_pytorch(temp_image_path, threshold=0.5) - ) - + detected_full_names = set(self._predict_scene_pytorch(temp_image_path, threshold=0.5)) + # 删除临时文件 if os.path.exists(temp_image_path): os.remove(temp_image_path) - + # 处理识别结果 field_data = {} for condensed_name, full_names in self.grouped_elements.items(): num_positions = len(full_names) if num_positions == 1: - field_data[condensed_name] = ( - 1 if full_names[0] in detected_full_names else 0 - ) + field_data[condensed_name] = 1 if full_names[0] in detected_full_names else 0 else: - detections_in_group = [ - fn in detected_full_names for fn in full_names - ] + detections_in_group = [fn in detected_full_names for fn in full_names] num_detected = sum(detections_in_group) if num_detected == num_positions: field_data[condensed_name] = 1 @@ -228,12 +203,10 @@ def recognize_field_elements(self, screenshot): field_data[condensed_name] = 0 else: field_data[condensed_name] = -1 - - logger.debug( - f"场地识别完成,检测到元素: {list(detected_full_names)}" - ) + + logger.debug(f"场地识别完成,检测到元素: {list(detected_full_names)}") return field_data - + except Exception as e: logger.error(f"场地识别失败: {e}") return {} diff --git a/src/recognition/find_monster_zone.py b/find_monster_zone.py similarity index 58% rename from src/recognition/find_monster_zone.py rename to find_monster_zone.py index b837bba..8d3b273 100644 --- a/src/recognition/find_monster_zone.py +++ b/find_monster_zone.py @@ -2,12 +2,9 @@ import cv2 import numpy as np -from src.core.paths import ensure_tmp_images_dir - logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) - def custom_least_squares(fun, x0, args=()): """ A simple linear least squares solver to replace scipy.optimize.least_squares. @@ -16,13 +13,10 @@ def custom_least_squares(fun, x0, args=()): x = np.array(x0, dtype=float) r = np.array(fun(x, *args)) if r.size == 0: - class Result: - def __init__(self, x): - self.x = x - + def __init__(self, x): self.x = x return Result(x) - + n = len(x) J = np.zeros((len(r), n)) eps = 1e-6 @@ -31,16 +25,13 @@ def __init__(self, x): x_eps[i] += eps r_eps = np.array(fun(x_eps, *args)) J[:, i] = (r_eps - r) / eps - + delta, _, _, _ = np.linalg.lstsq(J, -r, rcond=None) - + class Result: - def __init__(self, x): - self.x = x - + def __init__(self, x): self.x = x return Result(x + delta) - # 类伽马变换函数 def adjust_quasi_gamma(image): c = np.arange(256.0 / 255, step=1.0 / 255) @@ -139,9 +130,7 @@ def find_big(crop, x_ratio, minR, maxR, width, p1=30, p2=35): results.append(j) logger.debug(f"big circle: {j}") else: - logger.warning( - f"section{x_ratio.index(i)} big circle not detected" - ) + logger.warning(f"section{x_ratio.index(i)} big circle not detected") results = np.array(results) return results @@ -162,18 +151,14 @@ def find_small(crop_small, x_ratio_small, x_ratio, minR, maxR, width): ) if circles_small is not None: circles_small_bias = circles_small[0].copy() - circles_small_bias[:, 0] = circles_small[0][:, 0] + np.round( - i * width - ) + circles_small_bias[:, 0] = circles_small[0][:, 0] + np.round(i * width) for m in circles_small_bias: j = np.append(m, x_ratio.index(i)) results.append(j) logger.debug(f"small circle: {j}") else: - logger.warning( - f"section{x_ratio.index(i)} small circle not detected" - ) + logger.warning(f"section{x_ratio.index(i)} small circle not detected") results = np.array(results) return results @@ -202,9 +187,7 @@ def detect_outliers(coords, threshold=0.1): std_avg_distance = np.std(avg_distances) # 找出距离均值超过阈值倍标准差的点 - outliers = np.where( - avg_distances > mean_avg_distance + threshold * std_avg_distance - )[0] + outliers = np.where(avg_distances > mean_avg_distance + threshold * std_avg_distance)[0] # 剔除异常点 filtered_coords = np.delete(coords, outliers, axis=0) @@ -214,191 +197,46 @@ def detect_outliers(coords, threshold=0.1): # 框架创建 def create_frame(cx, cy, r, high_tol=False): - k = 1.0401189 # 修正因子 - m = 4.7102526 # 中部padding - nums_bias = 0.9 - nums_bias_inn = 0.3 - nums_y = cy - 0.5 * r - - if high_tol == False: - t = 0.025 # 容差因子 - avatar = np.round( - np.array( - [ - [ - cx - r * t, - cy + r * t, - cx + 2 * k * r + r * t, - cy - 2 * k * r - r * t, - ], - [ - cx + 2 * k * r - r * t, - cy - 2 * k * r - r * t, - cx + 4 * k * r + r * t, - cy + r * t, - ], - [ - cx + 4 * k * r - r * t, - cy + r * t, - cx + 6 * k * r + r * t, - cy - 2 * k * r - r * t, - ], - [ - cx + (6 * k + m) * r - r * t, - cy + r * t, - cx + (8 * k + m) * r + r * t, - cy - 2 * k * r - r * t, - ], - [ - cx + (8 * k + m) * r - r * t, - cy - 2 * k * r - r * t, - cx + (10 * k + m) * r + r * t, - cy + r * t, - ], - [ - cx + (10 * k + m) * r - r * t, - cy + r * t, - cx + (12 * k + m) * r + r * t, - cy - 2 * k * r - r * t, - ], - ] - ) - ).astype("int") - nums = np.round( - np.array( - [ - [ - cx + (nums_bias + 0 * k) * r - r * t, - cy + r * t, - cx + (nums_bias_inn + 2 * k) * r + r * t, - nums_y, - ], - [ - cx + (nums_bias + 2 * k) * r - r * t, - nums_y, - cx + (nums_bias_inn + 4 * k) * r + r * t, - cy + r * t, - ], - [ - cx + (nums_bias + 4 * k) * r - r * t, - cy + r * t, - cx + (nums_bias_inn + 6 * k) * r + r * t, - nums_y, - ], - [ - cx + (-nums_bias_inn + 6 * k + m) * r - r * t, - cy + r * t, - cx + (-nums_bias + 8 * k + m) * r + r * t, - nums_y, - ], - [ - cx + (-nums_bias_inn + 8 * k + m) * r - r * t, - nums_y, - cx + (-nums_bias + 10 * k + m) * r + r * t, - cy + r * t, - ], - [ - cx + (-nums_bias_inn + 10 * k + m) * r - r * t, - cy + r * t, - cx + (-nums_bias + 12 * k + m) * r + r * t, - nums_y, - ], - ] - ) - ).astype("int") - - return avatar, nums - - if high_tol == True: - t = 0.17 # 容差因子 - avatar = np.round( - np.array( - [ - [ - cx - r * t, - cy + r * t, - cx + 2 * k * r + r * t, - cy - 2 * k * r - r * t, - ], - [ - cx + 2 * k * r - r * t, - cy - 2 * k * r - r * t, - cx + 4 * k * r + r * t, - cy + r * t, - ], - [ - cx + 4 * k * r - r * t, - cy + r * t, - cx + 6 * k * r + r * t, - cy - 2 * k * r - r * t, - ], - [ - cx + (6 * k + m) * r - r * t, - cy + r * t, - cx + (8 * k + m) * r + r * t, - cy - 2 * k * r - r * t, - ], - [ - cx + (8 * k + m) * r - r * t, - cy - 2 * k * r - r * t, - cx + (10 * k + m) * r + r * t, - cy + r * t, - ], - [ - cx + (10 * k + m) * r - r * t, - cy + r * t, - cx + (12 * k + m) * r + r * t, - cy - 2 * k * r - r * t, - ], - ] - ) - ).astype("int") - nums = np.round( - np.array( - [ - [ - cx + (nums_bias + 0 * k) * r - r * t, - cy + r * t, - cx + (nums_bias_inn + 2 * k) * r + r * t, - nums_y, - ], - [ - cx + (nums_bias + 2 * k) * r - r * t, - nums_y, - cx + (nums_bias_inn + 4 * k) * r + r * t, - cy + r * t, - ], - [ - cx + (nums_bias + 4 * k) * r - r * t, - cy + r * t, - cx + (nums_bias_inn + 6 * k) * r + r * t, - nums_y, - ], - [ - cx + (-nums_bias_inn + 6 * k + m) * r - r * t, - cy + r * t, - cx + (-nums_bias + 8 * k + m) * r + r * t, - nums_y, - ], - [ - cx + (-nums_bias_inn + 8 * k + m) * r - r * t, - nums_y, - cx + (-nums_bias + 10 * k + m) * r + r * t, - cy + r * t, - ], - [ - cx + (-nums_bias_inn + 10 * k + m) * r - r * t, - cy + r * t, - cx + (-nums_bias + 12 * k + m) * r + r * t, - nums_y, - ], - ] - ) - ).astype("int") - - return avatar, nums - - + k = 1.0401189 #修正因子 + m = 4.7102526 #中部padding + nums_bias=0.9 + nums_bias_inn=0.3 + nums_y=cy-0.5*r + + if high_tol==False: + t = 0.025 #容差因子 + avatar = np.round(np.array([[cx -r*t, cy +r*t, cx+2*k*r+r*t, cy-2*k*r-r*t], + [cx+2*k*r-r*t, cy-2*k*r-r*t, cx+4*k*r+r*t, cy +r*t], + [cx+4*k*r-r*t, cy +r*t, cx+6*k*r+r*t, cy-2*k*r-r*t], + [cx+(6 *k+m)*r-r*t, cy +r*t, cx+(8 *k+m)*r+r*t, cy-2*k*r-r*t], + [cx+(8 *k+m)*r-r*t, cy-2*k*r-r*t, cx+(10*k+m)*r+r*t, cy +r*t], + [cx+(10*k+m)*r-r*t, cy +r*t, cx+(12*k+m)*r+r*t, cy-2*k*r-r*t]])).astype("int") + nums = np.round(np.array([[cx+(nums_bias+0*k)*r-r*t, cy+r*t, cx+(nums_bias_inn+2*k)*r+r*t, nums_y], + [cx+(nums_bias+2*k)*r-r*t, nums_y, cx+(nums_bias_inn+4*k)*r+r*t, cy+r*t], + [cx+(nums_bias+4*k)*r-r*t, cy+r*t, cx+(nums_bias_inn+6*k)*r+r*t, nums_y], + [cx+(-nums_bias_inn+6 *k+m)*r-r*t, cy+r*t, cx+(-nums_bias+8 *k+m)*r+r*t, nums_y], + [cx+(-nums_bias_inn+8 *k+m)*r-r*t, nums_y, cx+(-nums_bias+10*k+m)*r+r*t, cy+r*t], + [cx+(-nums_bias_inn+10*k+m)*r-r*t, cy+r*t, cx+(-nums_bias+12*k+m)*r+r*t, nums_y]])).astype("int") + + return avatar,nums + + if high_tol==True: + t = 0.17 #容差因子 + avatar = np.round(np.array([[cx -r*t, cy +r*t, cx+2*k*r+r*t, cy-2*k*r-r*t], + [cx+2*k*r-r*t, cy-2*k*r-r*t, cx+4*k*r+r*t, cy +r*t], + [cx+4*k*r-r*t, cy +r*t, cx+6*k*r+r*t, cy-2*k*r-r*t], + [cx+(6 *k+m)*r-r*t, cy +r*t, cx+(8 *k+m)*r+r*t, cy-2*k*r-r*t], + [cx+(8 *k+m)*r-r*t, cy-2*k*r-r*t, cx+(10*k+m)*r+r*t, cy +r*t], + [cx+(10*k+m)*r-r*t, cy +r*t, cx+(12*k+m)*r+r*t, cy-2*k*r-r*t]])).astype("int") + nums = np.round(np.array([[cx+(nums_bias+0*k)*r-r*t, cy+r*t, cx+(nums_bias_inn+2*k)*r+r*t, nums_y], + [cx+(nums_bias+2*k)*r-r*t, nums_y, cx+(nums_bias_inn+4*k)*r+r*t, cy+r*t], + [cx+(nums_bias+4*k)*r-r*t, cy+r*t, cx+(nums_bias_inn+6*k)*r+r*t, nums_y], + [cx+(-nums_bias_inn+6 *k+m)*r-r*t, cy+r*t, cx+(-nums_bias+8 *k+m)*r+r*t, nums_y], + [cx+(-nums_bias_inn+8 *k+m)*r-r*t, nums_y, cx+(-nums_bias+10*k+m)*r+r*t, cy+r*t], + [cx+(-nums_bias_inn+10*k+m)*r-r*t, cy+r*t, cx+(-nums_bias+12*k+m)*r+r*t, nums_y]])).astype("int") + + return avatar,nums + def filter(results_big, results_small, height): high_tol = 0 big_key = 0 @@ -436,9 +274,7 @@ def filter(results_big, results_small, height): filtered_big = [] logger.warning("仅使用小圆进入最小二乘") else: - r_refer = ( - np.abs(filtered_small[1, 0] - filtered_small[0, 0]) / 16.39 - ) # 大圆的参考半径 + r_refer = np.abs(filtered_small[1, 0] - filtered_small[0, 0]) / 16.39 # 大圆的参考半径 diff_r = np.abs(results_big[:, 2] - r_refer) filtered_big = results_big[diff_r <= 0.05 * r_refer] # y筛选 @@ -447,9 +283,7 @@ def filter(results_big, results_small, height): # 如果数组为空,报错 if filtered_big.size == 0: logger.error(results_big) - raise IndexError( - "std_y筛选出现问题,请检查以上数据输入是否合法" - ) + raise IndexError("std_y筛选出现问题,请检查以上数据输入是否合法") mean_value = np.mean(filtered_big[:, 1]) abs_diff = np.abs(filtered_big[:, 1] - mean_value) @@ -464,9 +298,7 @@ def filter(results_big, results_small, height): if n in [0, 1, 2]: p_cx.append(x - ((2 * n + 1) * k * r_refer)) elif n in [3, 4, 5]: - p_cx.append( - x - ((2 * n + 1) * k * r_refer + 4.710 * r_refer) - ) + p_cx.append(x - ((2 * n + 1) * k * r_refer + 4.710 * r_refer)) filtered_big_p = np.column_stack((filtered_big, p_cx)) std_x = np.std(filtered_big_p[:, -1]) @@ -474,16 +306,12 @@ def filter(results_big, results_small, height): # 如果数组为空,报错 if filtered_big_p.size == 0: logger.error(results_big) - raise IndexError( - "std_x筛选出现问题,请检查以上数据输入是否合法" - ) + raise IndexError("std_x筛选出现问题,请检查以上数据输入是否合法") mean_value = np.mean(filtered_big_p[:, -1]) abs_diff = np.abs(filtered_big_p[:, -1] - mean_value) outlier_index = np.argmax(abs_diff) - filtered_big_p = np.delete( - filtered_big_p, outlier_index, axis=0 - ) + filtered_big_p = np.delete(filtered_big_p, outlier_index, axis=0) std_x = np.std(filtered_big_p[:, -1]) filtered_big = filtered_big_p[:, :-1] @@ -505,14 +333,10 @@ def filter(results_big, results_small, height): if n in [0, 1, 2]: a_cx = x - ((2 * n + 1) * k * r_refer) elif n in [3, 4, 5]: - a_cx = x - ( - (2 * n + 1) * k * r_refer + 4.710 * r_refer - ) + a_cx = x - ((2 * n + 1) * k * r_refer + 4.710 * r_refer) a_cy = y + radius std.append([a_cx, a_cy]) - _, out_index = detect_outliers( - std, threshold=0.02 * np.mean(results_big[:, 2]) - ) + _, out_index = detect_outliers(std, threshold=0.02 * np.mean(results_big[:, 2])) filtered_big = np.delete(results_big, out_index, axis=0) high_tol = 1 @@ -531,14 +355,10 @@ def filter(results_big, results_small, height): if n in [0, 1, 2]: a_cx = x - ((2 * n + 1) * k * r_refer) elif n in [3, 4, 5]: - a_cx = x - ( - (2 * n + 1) * k * r_refer + 4.710 * r_refer - ) + a_cx = x - ((2 * n + 1) * k * r_refer + 4.710 * r_refer) a_cy = y + radius std.append([a_cx, a_cy]) - _, out_index = detect_outliers( - std, threshold=0.02 * np.mean(results_big[:, 2]) - ) + _, out_index = detect_outliers(std, threshold=0.02 * np.mean(results_big[:, 2])) filtered_big = np.delete(results_big, out_index, axis=0) else: filtered_big = [] @@ -559,55 +379,25 @@ def cutFrame(image, high_tol=False): R_sets = flex_pixel(image) try: - crop_blur, crop_small, x_ratio, x_ratio_small = preprocess( - image, blur=11 - ) + crop_blur, crop_small, x_ratio, x_ratio_small = preprocess(image, blur=11) results_big = find_big( - crop_blur, - x_ratio, - minR=R_sets[0], - maxR=R_sets[1], - width=width, - p1=21, - p2=28, + crop_blur, x_ratio, minR=R_sets[0], maxR=R_sets[1], width=width, p1=21, p2=28 ) results_small = find_small( - crop_small, - x_ratio_small, - x_ratio, - minR=R_sets[2], - maxR=R_sets[3], - width=width, - ) - filtered_big, filtered_small, high_tol = filter( - results_big, results_small, height + crop_small, x_ratio_small, x_ratio, minR=R_sets[2], maxR=R_sets[3], width=width ) + filtered_big, filtered_small, high_tol = filter(results_big, results_small, height) except IndexError: try: - crop_blur, crop_small, x_ratio, x_ratio_small = preprocess( - image, blur=7, spare=1 - ) + crop_blur, crop_small, x_ratio, x_ratio_small = preprocess(image, blur=7, spare=1) results_big = find_big( - crop_blur, - x_ratio, - minR=R_sets[0], - maxR=R_sets[1], - width=width, - p1=18, - p2=24, + crop_blur, x_ratio, minR=R_sets[0], maxR=R_sets[1], width=width, p1=18, p2=24 ) results_small = find_small( - crop_small, - x_ratio_small, - x_ratio, - minR=R_sets[2], - maxR=R_sets[3], - width=width, - ) - filtered_big, filtered_small, high_tol = filter( - results_big, results_small, height + crop_small, x_ratio_small, x_ratio, minR=R_sets[2], maxR=R_sets[3], width=width ) + filtered_big, filtered_small, high_tol = filter(results_big, results_small, height) except IndexError: logger.error("备用参数捕捉失败!请重新框选试试") @@ -644,12 +434,8 @@ def residuals(params, large_circles, small_circles): # 定义目标函数 initial_guess = [0, 200, 60] # 使用最小二乘法求解 - result = custom_least_squares( - residuals, initial_guess, args=(filtered_big, filtered_small) - ) - avatar, nums = create_frame( - result.x[0], result.x[1], result.x[2], high_tol - ) + result = custom_least_squares(residuals, initial_guess, args=(filtered_big, filtered_small)) + avatar, nums = create_frame(result.x[0], result.x[1], result.x[2], high_tol) divisors = np.array([width, height, width, height]) d_avatar = avatar / divisors @@ -659,7 +445,7 @@ def residuals(params, large_circles, small_circles): # 定义目标函数 if __name__ == "__main__": - image = cv2.imread(str(ensure_tmp_images_dir() / "zone1.png")) + image = cv2.imread("images/tmp/zone1.png") height, width, _ = image.shape @@ -667,21 +453,10 @@ def residuals(params, large_circles, small_circles): # 定义目标函数 R_sets = flex_pixel(image) results_big = find_big( - crop_blur, - x_ratio, - minR=R_sets[0], - maxR=R_sets[1], - width=width, - p1=21, - p2=32, + crop_blur, x_ratio, minR=R_sets[0], maxR=R_sets[1], width=width, p1=21, p2=32 ) results_small = find_small( - crop_small, - x_ratio_small, - x_ratio, - minR=R_sets[2], - maxR=R_sets[3], - width=width, + crop_small, x_ratio_small, x_ratio, minR=R_sets[2], maxR=R_sets[3], width=width ) circles = np.round(results_big).astype("int") diff --git a/src/resources/assets/icons/background.png b/ico/background.png similarity index 100% rename from src/resources/assets/icons/background.png rename to ico/background.png diff --git a/src/resources/assets/icons/icon.ico b/ico/icon.ico similarity index 100% rename from src/resources/assets/icons/icon.ico rename to ico/icon.ico diff --git a/src/resources/assets/icons/icon_64x64.ico b/ico/icon_64x64.ico similarity index 100% rename from src/resources/assets/icons/icon_64x64.ico rename to ico/icon_64x64.ico diff --git "a/src/resources/assets/images/R-11\347\252\201\345\207\273\345\212\250\345\212\233\350\243\205\347\224\262.png" "b/images/R-11\347\252\201\345\207\273\345\212\250\345\212\233\350\243\205\347\224\262.png" similarity index 100% rename from "src/resources/assets/images/R-11\347\252\201\345\207\273\345\212\250\345\212\233\350\243\205\347\224\262.png" rename to "images/R-11\347\252\201\345\207\273\345\212\250\345\212\233\350\243\205\347\224\262.png" diff --git "a/src/resources/assets/images/R-31\351\207\215\345\236\213\345\212\250\345\212\233\350\243\205\347\224\262.png" "b/images/R-31\351\207\215\345\236\213\345\212\250\345\212\233\350\243\205\347\224\262.png" similarity index 100% rename from "src/resources/assets/images/R-31\351\207\215\345\236\213\345\212\250\345\212\233\350\243\205\347\224\262.png" rename to "images/R-31\351\207\215\345\236\213\345\212\250\345\212\233\350\243\205\347\224\262.png" diff --git a/src/resources/assets/images/eg.png b/images/eg.png similarity index 100% rename from src/resources/assets/images/eg.png rename to images/eg.png diff --git a/src/resources/assets/images/empty.png b/images/empty.png similarity index 100% rename from src/resources/assets/images/empty.png rename to images/empty.png diff --git a/src/resources/assets/images/login/announcement_close.png b/images/login/announcement_close.png similarity index 100% rename from src/resources/assets/images/login/announcement_close.png rename to images/login/announcement_close.png diff --git a/src/resources/assets/images/login/competition_page.png b/images/login/competition_page.png similarity index 100% rename from src/resources/assets/images/login/competition_page.png rename to images/login/competition_page.png diff --git a/src/resources/assets/images/login/event_claim_close.png b/images/login/event_claim_close.png similarity index 100% rename from src/resources/assets/images/login/event_claim_close.png rename to images/login/event_claim_close.png diff --git a/src/resources/assets/images/login/login_button.png b/images/login/login_button.png similarity index 100% rename from src/resources/assets/images/login/login_button.png rename to images/login/login_button.png diff --git a/src/resources/assets/images/login/login_off.png b/images/login/login_off.png similarity index 100% rename from src/resources/assets/images/login/login_off.png rename to images/login/login_off.png diff --git a/src/resources/assets/images/process/0.png b/images/process/0.png similarity index 100% rename from src/resources/assets/images/process/0.png rename to images/process/0.png diff --git a/src/resources/assets/images/process/1.png b/images/process/1.png similarity index 100% rename from src/resources/assets/images/process/1.png rename to images/process/1.png diff --git a/src/resources/assets/images/process/10.png b/images/process/10.png similarity index 100% rename from src/resources/assets/images/process/10.png rename to images/process/10.png diff --git a/src/resources/assets/images/process/11.png b/images/process/11.png similarity index 100% rename from src/resources/assets/images/process/11.png rename to images/process/11.png diff --git a/src/resources/assets/images/process/12.png b/images/process/12.png similarity index 100% rename from src/resources/assets/images/process/12.png rename to images/process/12.png diff --git a/src/resources/assets/images/process/13.png b/images/process/13.png similarity index 100% rename from src/resources/assets/images/process/13.png rename to images/process/13.png diff --git a/src/resources/assets/images/process/14.png b/images/process/14.png similarity index 100% rename from src/resources/assets/images/process/14.png rename to images/process/14.png diff --git a/src/resources/assets/images/process/15.png b/images/process/15.png similarity index 100% rename from src/resources/assets/images/process/15.png rename to images/process/15.png diff --git a/src/resources/assets/images/process/1746774840_28_5.png1s.png b/images/process/1746774840_28_5.png1s.png similarity index 100% rename from src/resources/assets/images/process/1746774840_28_5.png1s.png rename to images/process/1746774840_28_5.png1s.png diff --git a/src/resources/assets/images/process/2.png b/images/process/2.png similarity index 100% rename from src/resources/assets/images/process/2.png rename to images/process/2.png diff --git a/src/resources/assets/images/process/3.png b/images/process/3.png similarity index 100% rename from src/resources/assets/images/process/3.png rename to images/process/3.png diff --git a/src/resources/assets/images/process/4.png b/images/process/4.png similarity index 100% rename from src/resources/assets/images/process/4.png rename to images/process/4.png diff --git a/src/resources/assets/images/process/5.png b/images/process/5.png similarity index 100% rename from src/resources/assets/images/process/5.png rename to images/process/5.png diff --git a/src/resources/assets/images/process/6.png b/images/process/6.png similarity index 100% rename from src/resources/assets/images/process/6.png rename to images/process/6.png diff --git a/src/resources/assets/images/process/7.png b/images/process/7.png similarity index 100% rename from src/resources/assets/images/process/7.png rename to images/process/7.png diff --git a/src/resources/assets/images/process/8.png b/images/process/8.png similarity index 100% rename from src/resources/assets/images/process/8.png rename to images/process/8.png diff --git a/src/resources/assets/images/process/9.png b/images/process/9.png similarity index 100% rename from src/resources/assets/images/process/9.png rename to images/process/9.png diff --git "a/src/resources/assets/images/\342\200\234\345\244\215\344\273\207\350\200\205\342\200\235.png" "b/images/\342\200\234\345\244\215\344\273\207\350\200\205\342\200\235.png" similarity index 100% rename from "src/resources/assets/images/\342\200\234\345\244\215\344\273\207\350\200\205\342\200\235.png" rename to "images/\342\200\234\345\244\215\344\273\207\350\200\205\342\200\235.png" diff --git "a/src/resources/assets/images/\342\200\234\345\246\222\342\200\235.png" "b/images/\342\200\234\345\246\222\342\200\235.png" similarity index 100% rename from "src/resources/assets/images/\342\200\234\345\246\222\342\200\235.png" rename to "images/\342\200\234\345\246\222\342\200\235.png" diff --git "a/src/resources/assets/images/\342\200\234\345\267\242\347\251\264\342\200\235.png" "b/images/\342\200\234\345\267\242\347\251\264\342\200\235.png" similarity index 100% rename from "src/resources/assets/images/\342\200\234\345\267\242\347\251\264\342\200\235.png" rename to "images/\342\200\234\345\267\242\347\251\264\342\200\235.png" diff --git "a/src/resources/assets/images/\342\200\234\345\272\236\350\264\235\342\200\235.png" "b/images/\342\200\234\345\272\236\350\264\235\342\200\235.png" similarity index 100% rename from "src/resources/assets/images/\342\200\234\345\272\236\350\264\235\342\200\235.png" rename to "images/\342\200\234\345\272\236\350\264\235\342\200\235.png" diff --git "a/src/resources/assets/images/\342\200\234\346\212\225\347\237\263\346\234\272\342\200\235.png" "b/images/\342\200\234\346\212\225\347\237\263\346\234\272\342\200\235.png" similarity index 100% rename from "src/resources/assets/images/\342\200\234\346\212\225\347\237\263\346\234\272\342\200\235.png" rename to "images/\342\200\234\346\212\225\347\237\263\346\234\272\342\200\235.png" diff --git "a/src/resources/assets/images/\342\200\234\347\233\233\346\200\222\342\200\235.png" "b/images/\342\200\234\347\233\233\346\200\222\342\200\235.png" similarity index 100% rename from "src/resources/assets/images/\342\200\234\347\233\233\346\200\222\342\200\235.png" rename to "images/\342\200\234\347\233\233\346\200\222\342\200\235.png" diff --git "a/src/resources/assets/images/\342\200\234\350\207\252\345\234\250\342\200\235.png" "b/images/\342\200\234\350\207\252\345\234\250\342\200\235.png" similarity index 100% rename from "src/resources/assets/images/\342\200\234\350\207\252\345\234\250\342\200\235.png" rename to "images/\342\200\234\350\207\252\345\234\250\342\200\235.png" diff --git "a/src/resources/assets/images/\342\200\234\350\220\250\347\261\263\347\232\204\346\204\217\345\277\227\342\200\235.png" "b/images/\342\200\234\350\220\250\347\261\263\347\232\204\346\204\217\345\277\227\342\200\235.png" similarity index 100% rename from "src/resources/assets/images/\342\200\234\350\220\250\347\261\263\347\232\204\346\204\217\345\277\227\342\200\235.png" rename to "images/\342\200\234\350\220\250\347\261\263\347\232\204\346\204\217\345\277\227\342\200\235.png" diff --git "a/src/resources/assets/images/\342\200\234\351\222\263\351\222\263\347\224\237\351\243\216\342\200\235.png" "b/images/\342\200\234\351\222\263\351\222\263\347\224\237\351\243\216\342\200\235.png" similarity index 100% rename from "src/resources/assets/images/\342\200\234\351\222\263\351\222\263\347\224\237\351\243\216\342\200\235.png" rename to "images/\342\200\234\351\222\263\351\222\263\347\224\237\351\243\216\342\200\235.png" diff --git "a/src/resources/assets/images/\342\200\234\351\227\250\342\200\235.png" "b/images/\342\200\234\351\227\250\342\200\235.png" similarity index 100% rename from "src/resources/assets/images/\342\200\234\351\227\250\342\200\235.png" rename to "images/\342\200\234\351\227\250\342\200\235.png" diff --git "a/src/resources/assets/images/\342\200\234\351\230\277\345\222\254\342\200\235.png" "b/images/\342\200\234\351\230\277\345\222\254\342\200\235.png" similarity index 100% rename from "src/resources/assets/images/\342\200\234\351\230\277\345\222\254\342\200\235.png" rename to "images/\342\200\234\351\230\277\345\222\254\342\200\235.png" diff --git "a/src/resources/assets/images/\344\271\214\350\220\250\346\226\257\347\252\201\350\242\255\345\274\251\346\211\213.png" "b/images/\344\271\214\350\220\250\346\226\257\347\252\201\350\242\255\345\274\251\346\211\213.png" similarity index 100% rename from "src/resources/assets/images/\344\271\214\350\220\250\346\226\257\347\252\201\350\242\255\345\274\251\346\211\213.png" rename to "images/\344\271\214\350\220\250\346\226\257\347\252\201\350\242\255\345\274\251\346\211\213.png" diff --git "a/src/resources/assets/images/\345\205\250\345\260\201\351\227\255\346\262\231\346\273\251\350\275\246.png" "b/images/\345\205\250\345\260\201\351\227\255\346\262\231\346\273\251\350\275\246.png" similarity index 100% rename from "src/resources/assets/images/\345\205\250\345\260\201\351\227\255\346\262\231\346\273\251\350\275\246.png" rename to "images/\345\205\250\345\260\201\351\227\255\346\262\231\346\273\251\350\275\246.png" diff --git "a/src/resources/assets/images/\345\206\260\345\216\237\345\215\253\346\263\225\350\200\205.png" "b/images/\345\206\260\345\216\237\345\215\253\346\263\225\350\200\205.png" similarity index 100% rename from "src/resources/assets/images/\345\206\260\345\216\237\345\215\253\346\263\225\350\200\205.png" rename to "images/\345\206\260\345\216\237\345\215\253\346\263\225\350\200\205.png" diff --git "a/src/resources/assets/images/\345\206\260\345\216\237\346\234\257\345\270\210.png" "b/images/\345\206\260\345\216\237\346\234\257\345\270\210.png" similarity index 100% rename from "src/resources/assets/images/\345\206\260\345\216\237\346\234\257\345\270\210.png" rename to "images/\345\206\260\345\216\237\346\234\257\345\270\210.png" diff --git "a/src/resources/assets/images/\345\206\260\347\210\206\346\272\220\347\237\263\350\231\253.png" "b/images/\345\206\260\347\210\206\346\272\220\347\237\263\350\231\253.png" similarity index 100% rename from "src/resources/assets/images/\345\206\260\347\210\206\346\272\220\347\237\263\350\231\253.png" rename to "images/\345\206\260\347\210\206\346\272\220\347\237\263\350\231\253.png" diff --git "a/src/resources/assets/images/\345\207\213\351\233\266\351\252\221\345\243\253.png" "b/images/\345\207\213\351\233\266\351\252\221\345\243\253.png" similarity index 100% rename from "src/resources/assets/images/\345\207\213\351\233\266\351\252\221\345\243\253.png" rename to "images/\345\207\213\351\233\266\351\252\221\345\243\253.png" diff --git "a/src/resources/assets/images/\345\207\266\350\261\225\345\205\275.png" "b/images/\345\207\266\350\261\225\345\205\275.png" similarity index 100% rename from "src/resources/assets/images/\345\207\266\350\261\225\345\205\275.png" rename to "images/\345\207\266\350\261\225\345\205\275.png" diff --git "a/src/resources/assets/images/\345\217\215\350\243\205\347\224\262\346\255\245\345\205\265.png" "b/images/\345\217\215\350\243\205\347\224\262\346\255\245\345\205\265.png" similarity index 100% rename from "src/resources/assets/images/\345\217\215\350\243\205\347\224\262\346\255\245\345\205\265.png" rename to "images/\345\217\215\350\243\205\347\224\262\346\255\245\345\205\265.png" diff --git "a/src/resources/assets/images/\345\217\230\345\274\202\345\267\250\345\262\251\350\233\233.png" "b/images/\345\217\230\345\274\202\345\267\250\345\262\251\350\233\233.png" similarity index 100% rename from "src/resources/assets/images/\345\217\230\345\274\202\345\267\250\345\262\251\350\233\233.png" rename to "images/\345\217\230\345\274\202\345\267\250\345\262\251\350\233\233.png" diff --git "a/src/resources/assets/images/\345\221\274\345\225\270\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222.png" "b/images/\345\221\274\345\225\270\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222.png" similarity index 100% rename from "src/resources/assets/images/\345\221\274\345\225\270\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222.png" rename to "images/\345\221\274\345\225\270\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222.png" diff --git "a/src/resources/assets/images/\345\233\272\346\265\267\345\207\277\347\237\263\350\200\205.png" "b/images/\345\233\272\346\265\267\345\207\277\347\237\263\350\200\205.png" similarity index 100% rename from "src/resources/assets/images/\345\233\272\346\265\267\345\207\277\347\237\263\350\200\205.png" rename to "images/\345\233\272\346\265\267\345\207\277\347\237\263\350\200\205.png" diff --git "a/src/resources/assets/images/\345\244\215\344\273\207\350\200\205.png" "b/images/\345\244\215\344\273\207\350\200\205.png" similarity index 100% rename from "src/resources/assets/images/\345\244\215\344\273\207\350\200\205.png" rename to "images/\345\244\215\344\273\207\350\200\205.png" diff --git "a/src/resources/assets/images/\345\245\216\351\232\206\357\274\214\346\221\251\350\257\203\350\220\250\345\237\265\346\235\203\345\214\226.png" "b/images/\345\245\216\351\232\206\357\274\214\346\221\251\350\257\203\350\220\250\345\237\265\346\235\203\345\214\226.png" similarity index 100% rename from "src/resources/assets/images/\345\245\216\351\232\206\357\274\214\346\221\251\350\257\203\350\220\250\345\237\265\346\235\203\345\214\226.png" rename to "images/\345\245\216\351\232\206\357\274\214\346\221\251\350\257\203\350\220\250\345\237\265\346\235\203\345\214\226.png" diff --git "a/src/resources/assets/images/\345\256\277\344\270\273\346\265\201\346\265\252\350\200\205.png" "b/images/\345\256\277\344\270\273\346\265\201\346\265\252\350\200\205.png" similarity index 100% rename from "src/resources/assets/images/\345\256\277\344\270\273\346\265\201\346\265\252\350\200\205.png" rename to "images/\345\256\277\344\270\273\346\265\201\346\265\252\350\200\205.png" diff --git "a/src/resources/assets/images/\345\257\273\350\267\257\350\200\205\344\277\241\344\275\277.png" "b/images/\345\257\273\350\267\257\350\200\205\344\277\241\344\275\277.png" similarity index 100% rename from "src/resources/assets/images/\345\257\273\350\267\257\350\200\205\344\277\241\344\275\277.png" rename to "images/\345\257\273\350\267\257\350\200\205\344\277\241\344\275\277.png" diff --git "a/src/resources/assets/images/\345\261\261\346\265\267\344\274\227\347\252\245\351\255\205\344\272\272.png" "b/images/\345\261\261\346\265\267\344\274\227\347\252\245\351\255\205\344\272\272.png" similarity index 100% rename from "src/resources/assets/images/\345\261\261\346\265\267\344\274\227\347\252\245\351\255\205\344\272\272.png" rename to "images/\345\261\261\346\265\267\344\274\227\347\252\245\351\255\205\344\272\272.png" diff --git "a/src/resources/assets/images/\345\262\201\347\233\270.png" "b/images/\345\262\201\347\233\270.png" similarity index 100% rename from "src/resources/assets/images/\345\262\201\347\233\270.png" rename to "images/\345\262\201\347\233\270.png" diff --git "a/src/resources/assets/images/\345\262\251\345\206\240\345\205\275.png" "b/images/\345\262\251\345\206\240\345\205\275.png" similarity index 100% rename from "src/resources/assets/images/\345\262\251\345\206\240\345\205\275.png" rename to "images/\345\262\251\345\206\240\345\205\275.png" diff --git "a/src/resources/assets/images/\345\274\247\345\205\211\351\224\213\345\215\253\351\225\277.png" "b/images/\345\274\247\345\205\211\351\224\213\345\215\253\351\225\277.png" similarity index 100% rename from "src/resources/assets/images/\345\274\247\345\205\211\351\224\213\345\215\253\351\225\277.png" rename to "images/\345\274\247\345\205\211\351\224\213\345\215\253\351\225\277.png" diff --git "a/src/resources/assets/images/\346\213\263\346\211\213\345\233\232\347\212\257.png" "b/images/\346\213\263\346\211\213\345\233\232\347\212\257.png" similarity index 100% rename from "src/resources/assets/images/\346\213\263\346\211\213\345\233\232\347\212\257.png" rename to "images/\346\213\263\346\211\213\345\233\232\347\212\257.png" diff --git "a/src/resources/assets/images/\346\217\220\344\272\232\345\215\241\344\271\214\345\245\275\346\210\230\350\200\205.png" "b/images/\346\217\220\344\272\232\345\215\241\344\271\214\345\245\275\346\210\230\350\200\205.png" similarity index 100% rename from "src/resources/assets/images/\346\217\220\344\272\232\345\215\241\344\271\214\345\245\275\346\210\230\350\200\205.png" rename to "images/\346\217\220\344\272\232\345\215\241\344\271\214\345\245\275\346\210\230\350\200\205.png" diff --git "a/src/resources/assets/images/\346\217\220\344\272\232\345\215\241\344\271\214\347\240\264\345\235\217\347\216\213.png" "b/images/\346\217\220\344\272\232\345\215\241\344\271\214\347\240\264\345\235\217\347\216\213.png" similarity index 100% rename from "src/resources/assets/images/\346\217\220\344\272\232\345\215\241\344\271\214\347\240\264\345\235\217\347\216\213.png" rename to "images/\346\217\220\344\272\232\345\215\241\344\271\214\347\240\264\345\235\217\347\216\213.png" diff --git "a/src/resources/assets/images/\346\225\243\345\215\216\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222.png" "b/images/\346\225\243\345\215\216\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222.png" similarity index 100% rename from "src/resources/assets/images/\346\225\243\345\215\216\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222.png" rename to "images/\346\225\243\345\215\216\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222.png" diff --git "a/src/resources/assets/images/\346\227\272\350\264\242.png" "b/images/\346\227\272\350\264\242.png" similarity index 100% rename from "src/resources/assets/images/\346\227\272\350\264\242.png" rename to "images/\346\227\272\350\264\242.png" diff --git "a/src/resources/assets/images/\346\232\264\350\265\260\351\243\237\344\272\272\350\212\261.png" "b/images/\346\232\264\350\265\260\351\243\237\344\272\272\350\212\261.png" similarity index 100% rename from "src/resources/assets/images/\346\232\264\350\265\260\351\243\237\344\272\272\350\212\261.png" rename to "images/\346\232\264\350\265\260\351\243\237\344\272\272\350\212\261.png" diff --git "a/src/resources/assets/images/\346\232\264\350\265\260\351\243\237\350\231\253\350\212\261.png" "b/images/\346\232\264\350\265\260\351\243\237\350\231\253\350\212\261.png" similarity index 100% rename from "src/resources/assets/images/\346\232\264\350\265\260\351\243\237\350\231\253\350\212\261.png" rename to "images/\346\232\264\350\265\260\351\243\237\350\231\253\350\212\261.png" diff --git "a/src/resources/assets/images/\346\234\227\345\247\206\351\205\222\346\216\250\350\215\220\350\200\205.png" "b/images/\346\234\227\345\247\206\351\205\222\346\216\250\350\215\220\350\200\205.png" similarity index 100% rename from "src/resources/assets/images/\346\234\227\345\247\206\351\205\222\346\216\250\350\215\220\350\200\205.png" rename to "images/\346\234\227\345\247\206\351\205\222\346\216\250\350\215\220\350\200\205.png" diff --git "a/src/resources/assets/images/\346\235\260\346\226\257\351\241\277\302\267\345\250\201\345\273\211\345\247\206\346\226\257.png" "b/images/\346\235\260\346\226\257\351\241\277\302\267\345\250\201\345\273\211\345\247\206\346\226\257.png" similarity index 100% rename from "src/resources/assets/images/\346\235\260\346\226\257\351\241\277\302\267\345\250\201\345\273\211\345\247\206\346\226\257.png" rename to "images/\346\235\260\346\226\257\351\241\277\302\267\345\250\201\345\273\211\345\247\206\346\226\257.png" diff --git "a/src/resources/assets/images/\346\236\201\346\270\251\350\222\270\346\261\275\346\210\230\350\275\246.png" "b/images/\346\236\201\346\270\251\350\222\270\346\261\275\346\210\230\350\275\246.png" similarity index 100% rename from "src/resources/assets/images/\346\236\201\346\270\251\350\222\270\346\261\275\346\210\230\350\275\246.png" rename to "images/\346\236\201\346\270\251\350\222\270\346\261\275\346\210\230\350\275\246.png" diff --git "a/src/resources/assets/images/\346\236\243\345\244\247\345\210\200.png" "b/images/\346\236\243\345\244\247\345\210\200.png" similarity index 100% rename from "src/resources/assets/images/\346\236\243\345\244\247\345\210\200.png" rename to "images/\346\236\243\345\244\247\345\210\200.png" diff --git "a/src/resources/assets/images/\346\236\257\346\234\275\344\271\213\347\247\215.png" "b/images/\346\236\257\346\234\275\344\271\213\347\247\215.png" similarity index 100% rename from "src/resources/assets/images/\346\236\257\346\234\275\344\271\213\347\247\215.png" rename to "images/\346\236\257\346\234\275\344\271\213\347\247\215.png" diff --git "a/src/resources/assets/images/\346\243\230\345\205\275.png" "b/images/\346\243\230\345\205\275.png" similarity index 100% rename from "src/resources/assets/images/\346\243\230\345\205\275.png" rename to "images/\346\243\230\345\205\275.png" diff --git "a/src/resources/assets/images/\346\256\213\345\205\232\344\271\220\345\233\242\351\274\223\346\211\213.png" "b/images/\346\256\213\345\205\232\344\271\220\345\233\242\351\274\223\346\211\213.png" similarity index 100% rename from "src/resources/assets/images/\346\256\213\345\205\232\344\271\220\345\233\242\351\274\223\346\211\213.png" rename to "images/\346\256\213\345\205\232\344\271\220\345\233\242\351\274\223\346\211\213.png" diff --git "a/src/resources/assets/images/\346\256\213\345\205\232\350\220\250\345\205\213\346\226\257\346\211\213.png" "b/images/\346\256\213\345\205\232\350\220\250\345\205\213\346\226\257\346\211\213.png" similarity index 100% rename from "src/resources/assets/images/\346\256\213\345\205\232\350\220\250\345\205\213\346\226\257\346\211\213.png" rename to "images/\346\256\213\345\205\232\350\220\250\345\205\213\346\226\257\346\211\213.png" diff --git "a/src/resources/assets/images/\346\260\264\346\211\213\351\207\215\350\211\207.png" "b/images/\346\260\264\346\211\213\351\207\215\350\211\207.png" similarity index 100% rename from "src/resources/assets/images/\346\260\264\346\211\213\351\207\215\350\211\207.png" rename to "images/\346\260\264\346\211\213\351\207\215\350\211\207.png" diff --git "a/src/resources/assets/images/\346\260\264\351\201\201\345\277\215\350\200\205.png" "b/images/\346\260\264\351\201\201\345\277\215\350\200\205.png" similarity index 100% rename from "src/resources/assets/images/\346\260\264\351\201\201\345\277\215\350\200\205.png" rename to "images/\346\260\264\351\201\201\345\277\215\350\200\205.png" diff --git "a/src/resources/assets/images/\346\262\211\346\262\231.png" "b/images/\346\262\211\346\262\231.png" similarity index 100% rename from "src/resources/assets/images/\346\262\211\346\262\231.png" rename to "images/\346\262\211\346\262\231.png" diff --git "a/src/resources/assets/images/\346\262\270\350\241\200\351\252\221\345\243\253\345\233\242\347\262\276\351\224\220.png" "b/images/\346\262\270\350\241\200\351\252\221\345\243\253\345\233\242\347\262\276\351\224\220.png" similarity index 100% rename from "src/resources/assets/images/\346\262\270\350\241\200\351\252\221\345\243\253\345\233\242\347\262\276\351\224\220.png" rename to "images/\346\262\270\350\241\200\351\252\221\345\243\253\345\233\242\347\262\276\351\224\220.png" diff --git "a/src/resources/assets/images/\346\263\245\345\262\251\345\260\217\351\230\237\350\267\265\350\241\214\350\200\205.png" "b/images/\346\263\245\345\262\251\345\260\217\351\230\237\350\267\265\350\241\214\350\200\205.png" similarity index 100% rename from "src/resources/assets/images/\346\263\245\345\262\251\345\260\217\351\230\237\350\267\265\350\241\214\350\200\205.png" rename to "images/\346\263\245\345\262\251\345\260\217\351\230\237\350\267\265\350\241\214\350\200\205.png" diff --git "a/src/resources/assets/images/\346\263\245\345\262\251\345\267\250\345\203\217.png" "b/images/\346\263\245\345\262\251\345\267\250\345\203\217.png" similarity index 100% rename from "src/resources/assets/images/\346\263\245\345\262\251\345\267\250\345\203\217.png" rename to "images/\346\263\245\345\262\251\345\267\250\345\203\217.png" diff --git "a/src/resources/assets/images/\346\267\261\346\272\237\350\243\202\347\244\201\350\200\205.png" "b/images/\346\267\261\346\272\237\350\243\202\347\244\201\350\200\205.png" similarity index 100% rename from "src/resources/assets/images/\346\267\261\346\272\237\350\243\202\347\244\201\350\200\205.png" rename to "images/\346\267\261\346\272\237\350\243\202\347\244\201\350\200\205.png" diff --git "a/src/resources/assets/images/\346\270\251\351\241\272\347\232\204\346\255\246\350\243\205\351\251\256\345\205\275.png" "b/images/\346\270\251\351\241\272\347\232\204\346\255\246\350\243\205\351\251\256\345\205\275.png" similarity index 100% rename from "src/resources/assets/images/\346\270\251\351\241\272\347\232\204\346\255\246\350\243\205\351\251\256\345\205\275.png" rename to "images/\346\270\251\351\241\272\347\232\204\346\255\246\350\243\205\351\251\256\345\205\275.png" diff --git "a/src/resources/assets/images/\346\270\270\345\207\273\351\230\237\347\233\276\345\215\253.png" "b/images/\346\270\270\345\207\273\351\230\237\347\233\276\345\215\253.png" similarity index 100% rename from "src/resources/assets/images/\346\270\270\345\207\273\351\230\237\347\233\276\345\215\253.png" rename to "images/\346\270\270\345\207\273\351\230\237\347\233\276\345\215\253.png" diff --git "a/src/resources/assets/images/\346\271\226\347\225\224\345\277\227\346\204\277\350\200\205.png" "b/images/\346\271\226\347\225\224\345\277\227\346\204\277\350\200\205.png" similarity index 100% rename from "src/resources/assets/images/\346\271\226\347\225\224\345\277\227\346\204\277\350\200\205.png" rename to "images/\346\271\226\347\225\224\345\277\227\346\204\277\350\200\205.png" diff --git "a/src/resources/assets/images/\346\272\220\347\237\263\347\225\270\345\217\230\344\275\223.png" "b/images/\346\272\220\347\237\263\347\225\270\345\217\230\344\275\223.png" similarity index 100% rename from "src/resources/assets/images/\346\272\220\347\237\263\347\225\270\345\217\230\344\275\223.png" rename to "images/\346\272\220\347\237\263\347\225\270\345\217\230\344\275\223.png" diff --git "a/src/resources/assets/images/\347\201\274\347\203\255\346\272\220\347\237\263\350\231\253.png" "b/images/\347\201\274\347\203\255\346\272\220\347\237\263\350\231\253.png" similarity index 100% rename from "src/resources/assets/images/\347\201\274\347\203\255\346\272\220\347\237\263\350\231\253.png" rename to "images/\347\201\274\347\203\255\346\272\220\347\237\263\350\231\253.png" diff --git "a/src/resources/assets/images/\347\202\255\351\225\277\347\237\233.png" "b/images/\347\202\255\351\225\277\347\237\233.png" similarity index 100% rename from "src/resources/assets/images/\347\202\255\351\225\277\347\237\233.png" rename to "images/\347\202\255\351\225\277\347\237\233.png" diff --git "a/src/resources/assets/images/\347\202\256\345\207\273\347\273\204\351\225\277.png" "b/images/\347\202\256\345\207\273\347\273\204\351\225\277.png" similarity index 100% rename from "src/resources/assets/images/\347\202\256\345\207\273\347\273\204\351\225\277.png" rename to "images/\347\202\256\345\207\273\347\273\204\351\225\277.png" diff --git "a/src/resources/assets/images/\347\202\275\347\204\260\346\272\220\347\237\263\350\231\253.png" "b/images/\347\202\275\347\204\260\346\272\220\347\237\263\350\231\253.png" similarity index 100% rename from "src/resources/assets/images/\347\202\275\347\204\260\346\272\220\347\237\263\350\231\253.png" rename to "images/\347\202\275\347\204\260\346\272\220\347\237\263\350\231\253.png" diff --git "a/src/resources/assets/images/\347\213\202\346\232\264\345\256\277\344\270\273\347\273\204\351\225\277.png" "b/images/\347\213\202\346\232\264\345\256\277\344\270\273\347\273\204\351\225\277.png" similarity index 100% rename from "src/resources/assets/images/\347\213\202\346\232\264\345\256\277\344\270\273\347\273\204\351\225\277.png" rename to "images/\347\213\202\346\232\264\345\256\277\344\270\273\347\273\204\351\225\277.png" diff --git "a/src/resources/assets/images/\347\213\202\346\232\264\347\232\204\347\214\216\347\213\227pro.png" "b/images/\347\213\202\346\232\264\347\232\204\347\214\216\347\213\227pro.png" similarity index 100% rename from "src/resources/assets/images/\347\213\202\346\232\264\347\232\204\347\214\216\347\213\227pro.png" rename to "images/\347\213\202\346\232\264\347\232\204\347\214\216\347\213\227pro.png" diff --git "a/src/resources/assets/images/\347\213\231\345\207\273\346\255\245\345\205\265.png" "b/images/\347\213\231\345\207\273\346\255\245\345\205\265.png" similarity index 100% rename from "src/resources/assets/images/\347\213\231\345\207\273\346\255\245\345\205\265.png" rename to "images/\347\213\231\345\207\273\346\255\245\345\205\265.png" diff --git "a/src/resources/assets/images/\347\216\211\345\217\214\345\211\221.png" "b/images/\347\216\211\345\217\214\345\211\221.png" similarity index 100% rename from "src/resources/assets/images/\347\216\211\345\217\214\345\211\221.png" rename to "images/\347\216\211\345\217\214\345\211\221.png" diff --git "a/src/resources/assets/images/\347\224\260\351\274\267.png" "b/images/\347\224\260\351\274\267.png" similarity index 100% rename from "src/resources/assets/images/\347\224\260\351\274\267.png" rename to "images/\347\224\260\351\274\267.png" diff --git "a/src/resources/assets/images/\347\225\270\345\217\230\350\265\230\347\224\237\347\211\251.png" "b/images/\347\225\270\345\217\230\350\265\230\347\224\237\347\211\251.png" similarity index 100% rename from "src/resources/assets/images/\347\225\270\345\217\230\350\265\230\347\224\237\347\211\251.png" rename to "images/\347\225\270\345\217\230\350\265\230\347\224\237\347\211\251.png" diff --git "a/src/resources/assets/images/\347\230\264.png" "b/images/\347\230\264.png" similarity index 100% rename from "src/resources/assets/images/\347\230\264.png" rename to "images/\347\230\264.png" diff --git "a/src/resources/assets/images/\347\237\277\350\204\211\345\256\210\345\215\253.png" "b/images/\347\237\277\350\204\211\345\256\210\345\215\253.png" similarity index 100% rename from "src/resources/assets/images/\347\237\277\350\204\211\345\256\210\345\215\253.png" rename to "images/\347\237\277\350\204\211\345\256\210\345\215\253.png" diff --git "a/src/resources/assets/images/\347\240\201\345\244\264\346\260\264\346\211\213.png" "b/images/\347\240\201\345\244\264\346\260\264\346\211\213.png" similarity index 100% rename from "src/resources/assets/images/\347\240\201\345\244\264\346\260\264\346\211\213.png" rename to "images/\347\240\201\345\244\264\346\260\264\346\211\213.png" diff --git "a/src/resources/assets/images/\347\241\254\347\224\262\347\210\252\345\205\275.png" "b/images/\347\241\254\347\224\262\347\210\252\345\205\275.png" similarity index 100% rename from "src/resources/assets/images/\347\241\254\347\224\262\347\210\252\345\205\275.png" rename to "images/\347\241\254\347\224\262\347\210\252\345\205\275.png" diff --git "a/src/resources/assets/images/\347\251\272\351\231\215\345\205\265.png" "b/images/\347\251\272\351\231\215\345\205\265.png" similarity index 100% rename from "src/resources/assets/images/\347\251\272\351\231\215\345\205\265.png" rename to "images/\347\251\272\351\231\215\345\205\265.png" diff --git "a/src/resources/assets/images/\347\273\210\346\233\262\345\220\210\345\243\260.png" "b/images/\347\273\210\346\233\262\345\220\210\345\243\260.png" similarity index 100% rename from "src/resources/assets/images/\347\273\210\346\233\262\345\220\210\345\243\260.png" rename to "images/\347\273\210\346\233\262\345\220\210\345\243\260.png" diff --git "a/src/resources/assets/images/\350\205\220\350\264\245\351\252\221\345\243\253.png" "b/images/\350\205\220\350\264\245\351\252\221\345\243\253.png" similarity index 100% rename from "src/resources/assets/images/\350\205\220\350\264\245\351\252\221\345\243\253.png" rename to "images/\350\205\220\350\264\245\351\252\221\345\243\253.png" diff --git "a/src/resources/assets/images/\350\207\252\347\224\261\344\275\243\345\205\265\342\200\234\344\270\273\351\237\263\345\220\211\344\273\226\342\200\235.png" "b/images/\350\207\252\347\224\261\344\275\243\345\205\265\342\200\234\344\270\273\351\237\263\345\220\211\344\273\226\342\200\235.png" similarity index 100% rename from "src/resources/assets/images/\350\207\252\347\224\261\344\275\243\345\205\265\342\200\234\344\270\273\351\237\263\345\220\211\344\273\226\342\200\235.png" rename to "images/\350\207\252\347\224\261\344\275\243\345\205\265\342\200\234\344\270\273\351\237\263\345\220\211\344\273\226\342\200\235.png" diff --git "a/src/resources/assets/images/\350\207\252\347\224\261\344\275\243\345\205\265\342\200\234\350\264\235\346\226\257\342\200\235.png" "b/images/\350\207\252\347\224\261\344\275\243\345\205\265\342\200\234\350\264\235\346\226\257\342\200\235.png" similarity index 100% rename from "src/resources/assets/images/\350\207\252\347\224\261\344\275\243\345\205\265\342\200\234\350\264\235\346\226\257\342\200\235.png" rename to "images/\350\207\252\347\224\261\344\275\243\345\205\265\342\200\234\350\264\235\346\226\257\342\200\235.png" diff --git "a/src/resources/assets/images/\350\215\222\345\216\237\345\212\253\346\216\240\350\200\205.png" "b/images/\350\215\222\345\216\237\345\212\253\346\216\240\350\200\205.png" similarity index 100% rename from "src/resources/assets/images/\350\215\222\345\216\237\345\212\253\346\216\240\350\200\205.png" rename to "images/\350\215\222\345\216\237\345\212\253\346\216\240\350\200\205.png" diff --git "a/src/resources/assets/images/\350\220\250\345\215\241\345\205\271\345\244\247\345\211\221\346\211\213.png" "b/images/\350\220\250\345\215\241\345\205\271\345\244\247\345\211\221\346\211\213.png" similarity index 100% rename from "src/resources/assets/images/\350\220\250\345\215\241\345\205\271\345\244\247\345\211\221\346\211\213.png" rename to "images/\350\220\250\345\215\241\345\205\271\345\244\247\345\211\221\346\211\213.png" diff --git "a/src/resources/assets/images/\350\220\250\345\215\241\345\205\271\345\256\277\344\270\273\345\215\253\345\267\242\347\231\276\345\244\253\351\225\277.png" "b/images/\350\220\250\345\215\241\345\205\271\345\256\277\344\270\273\345\215\253\345\267\242\347\231\276\345\244\253\351\225\277.png" similarity index 100% rename from "src/resources/assets/images/\350\220\250\345\215\241\345\205\271\345\256\277\344\270\273\345\215\253\345\267\242\347\231\276\345\244\253\351\225\277.png" rename to "images/\350\220\250\345\215\241\345\205\271\345\256\277\344\270\273\345\215\253\345\267\242\347\231\276\345\244\253\351\225\277.png" diff --git "a/src/resources/assets/images/\350\220\250\345\215\241\345\205\271\346\236\257\346\234\275\345\220\236\345\231\254\350\200\205.png" "b/images/\350\220\250\345\215\241\345\205\271\346\236\257\346\234\275\345\220\236\345\231\254\350\200\205.png" similarity index 100% rename from "src/resources/assets/images/\350\220\250\345\215\241\345\205\271\346\236\257\346\234\275\345\220\236\345\231\254\350\200\205.png" rename to "images/\350\220\250\345\215\241\345\205\271\346\236\257\346\234\275\345\220\236\345\231\254\350\200\205.png" diff --git "a/src/resources/assets/images/\350\220\250\345\215\241\345\205\271\346\236\257\346\234\275\345\256\277\345\215\253.png" "b/images/\350\220\250\345\215\241\345\205\271\346\236\257\346\234\275\345\256\277\345\215\253.png" similarity index 100% rename from "src/resources/assets/images/\350\220\250\345\215\241\345\205\271\346\236\257\346\234\275\345\256\277\345\215\253.png" rename to "images/\350\220\250\345\215\241\345\205\271\346\236\257\346\234\275\345\256\277\345\215\253.png" diff --git "a/src/resources/assets/images/\350\220\250\345\215\241\345\205\271\346\236\257\346\234\275\346\210\230\350\275\246.png" "b/images/\350\220\250\345\215\241\345\205\271\346\236\257\346\234\275\346\210\230\350\275\246.png" similarity index 100% rename from "src/resources/assets/images/\350\220\250\345\215\241\345\205\271\346\236\257\346\234\275\346\210\230\350\275\246.png" rename to "images/\350\220\250\345\215\241\345\205\271\346\236\257\346\234\275\346\210\230\350\275\246.png" diff --git "a/src/resources/assets/images/\350\257\241\346\240\270\351\233\206\345\205\273\350\200\205.png" "b/images/\350\257\241\346\240\270\351\233\206\345\205\273\350\200\205.png" similarity index 100% rename from "src/resources/assets/images/\350\257\241\346\240\270\351\233\206\345\205\273\350\200\205.png" rename to "images/\350\257\241\346\240\270\351\233\206\345\205\273\350\200\205.png" diff --git "a/src/resources/assets/images/\350\265\217\351\207\221\347\214\216\344\272\272\345\274\251\346\211\213.png" "b/images/\350\265\217\351\207\221\347\214\216\344\272\272\345\274\251\346\211\213.png" similarity index 100% rename from "src/resources/assets/images/\350\265\217\351\207\221\347\214\216\344\272\272\345\274\251\346\211\213.png" rename to "images/\350\265\217\351\207\221\347\214\216\344\272\272\345\274\251\346\211\213.png" diff --git "a/src/resources/assets/images/\350\265\217\351\207\221\347\214\216\344\272\272\346\211\260\344\271\261\350\200\205.png" "b/images/\350\265\217\351\207\221\347\214\216\344\272\272\346\211\260\344\271\261\350\200\205.png" similarity index 100% rename from "src/resources/assets/images/\350\265\217\351\207\221\347\214\216\344\272\272\346\211\260\344\271\261\350\200\205.png" rename to "images/\350\265\217\351\207\221\347\214\216\344\272\272\346\211\260\344\271\261\350\200\205.png" diff --git "a/src/resources/assets/images/\350\277\267\350\267\257\347\232\204\345\267\250\345\203\217.png" "b/images/\350\277\267\350\267\257\347\232\204\345\267\250\345\203\217.png" similarity index 100% rename from "src/resources/assets/images/\350\277\267\350\267\257\347\232\204\345\267\250\345\203\217.png" rename to "images/\350\277\267\350\267\257\347\232\204\345\267\250\345\203\217.png" diff --git "a/src/resources/assets/images/\351\205\270\346\266\262\346\272\220\347\237\263\350\231\253\302\267\316\261.png" "b/images/\351\205\270\346\266\262\346\272\220\347\237\263\350\231\253\302\267\316\261.png" similarity index 100% rename from "src/resources/assets/images/\351\205\270\346\266\262\346\272\220\347\237\263\350\231\253\302\267\316\261.png" rename to "images/\351\205\270\346\266\262\346\272\220\347\237\263\350\231\253\302\267\316\261.png" diff --git "a/src/resources/assets/images/\351\207\215\350\243\205\351\230\262\345\276\241\350\200\205.png" "b/images/\351\207\215\350\243\205\351\230\262\345\276\241\350\200\205.png" similarity index 100% rename from "src/resources/assets/images/\351\207\215\350\243\205\351\230\262\345\276\241\350\200\205.png" rename to "images/\351\207\215\350\243\205\351\230\262\345\276\241\350\200\205.png" diff --git "a/src/resources/assets/images/\351\230\265\345\234\260\345\207\273\344\272\272\346\211\213.png" "b/images/\351\230\265\345\234\260\345\207\273\344\272\272\346\211\213.png" similarity index 100% rename from "src/resources/assets/images/\351\230\265\345\234\260\345\207\273\344\272\272\346\211\213.png" rename to "images/\351\230\265\345\234\260\345\207\273\344\272\272\346\211\213.png" diff --git "a/src/resources/assets/images/\351\243\216\346\203\205\350\241\227\342\200\234\346\230\237\346\234\257\345\270\210\342\200\235.png" "b/images/\351\243\216\346\203\205\350\241\227\342\200\234\346\230\237\346\234\257\345\270\210\342\200\235.png" similarity index 100% rename from "src/resources/assets/images/\351\243\216\346\203\205\350\241\227\342\200\234\346\230\237\346\234\257\345\270\210\342\200\235.png" rename to "images/\351\243\216\346\203\205\350\241\227\342\200\234\346\230\237\346\234\257\345\270\210\342\200\235.png" diff --git "a/src/resources/assets/images/\351\253\230\345\241\224\346\234\257\345\270\210.png" "b/images/\351\253\230\345\241\224\346\234\257\345\270\210.png" similarity index 100% rename from "src/resources/assets/images/\351\253\230\345\241\224\346\234\257\345\270\210.png" rename to "images/\351\253\230\345\241\224\346\234\257\345\270\210.png" diff --git "a/src/resources/assets/images/\351\253\230\346\231\256\345\260\274\345\205\213.png" "b/images/\351\253\230\346\231\256\345\260\274\345\205\213.png" similarity index 100% rename from "src/resources/assets/images/\351\253\230\346\231\256\345\260\274\345\205\213.png" rename to "images/\351\253\230\346\231\256\345\260\274\345\205\213.png" diff --git "a/src/resources/assets/images/\351\253\230\347\272\247\346\255\246\350\243\205\344\272\272\345\221\230.png" "b/images/\351\253\230\347\272\247\346\255\246\350\243\205\344\272\272\345\221\230.png" similarity index 100% rename from "src/resources/assets/images/\351\253\230\347\272\247\346\255\246\350\243\205\344\272\272\345\221\230.png" rename to "images/\351\253\230\347\272\247\346\255\246\350\243\205\344\272\272\345\221\230.png" diff --git "a/src/resources/assets/images/\351\253\230\350\203\275\346\272\220\347\237\263\350\231\253.png" "b/images/\351\253\230\350\203\275\346\272\220\347\237\263\350\231\253.png" similarity index 100% rename from "src/resources/assets/images/\351\253\230\350\203\275\346\272\220\347\237\263\350\231\253.png" rename to "images/\351\253\230\350\203\275\346\272\220\347\237\263\350\231\253.png" diff --git "a/src/resources/assets/images/\351\273\221\346\260\264\346\272\220\347\237\263\350\231\253.png" "b/images/\351\273\221\346\260\264\346\272\220\347\237\263\350\231\253.png" similarity index 100% rename from "src/resources/assets/images/\351\273\221\346\260\264\346\272\220\347\237\263\350\231\253.png" rename to "images/\351\273\221\346\260\264\346\272\220\347\237\263\350\231\253.png" diff --git a/src/ui/input_panel_ui.py b/input_panel_ui.py similarity index 80% rename from src/ui/input_panel_ui.py rename to input_panel_ui.py index 4a41ede..602ae10 100644 --- a/src/ui/input_panel_ui.py +++ b/input_panel_ui.py @@ -1,28 +1,14 @@ import json import re from collections import defaultdict -from PyQt6.QtWidgets import ( - QWidget, - QVBoxLayout, - QHBoxLayout, - QLabel, - QPushButton, - QFrame, -) -from PyQt6.QtWidgets import ( - QLineEdit, - QScrollArea, - QGridLayout, - QSizePolicy, - QGraphicsDropShadowEffect, -) -from PyQt6.QtCore import Qt, pyqtSignal -from PyQt6.QtGui import QPixmap, QColor +from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QFrame +from PyQt6.QtWidgets import QLineEdit, QScrollArea, QGridLayout, QSizePolicy, QGraphicsDropShadowEffect +from PyQt6.QtCore import Qt, QTimer, pyqtSignal, QObject, QThread +from PyQt6.QtGui import QPixmap, QImage, QFont, QIcon, QPainter, QColor import numpy as np import logging -from src.core.config import MONSTER_COUNT, MONSTER_DATA, FIELD_FEATURE_COUNT -from src.core.paths import image_path, resource_path +from config import MONSTER_COUNT, MONSTER_DATA, FIELD_FEATURE_COUNT logger = logging.getLogger(__name__) @@ -31,10 +17,8 @@ class InputPanelUI(QFrame): # Signals to communicate with the main application predict_requested = pyqtSignal() reset_requested = pyqtSignal() - input_changed = ( - pyqtSignal() - ) # Signal emitted when any monster input changes - terrain_changed = pyqtSignal(list) # New signal for terrain changes + input_changed = pyqtSignal() # Signal emitted when any monster input changes + terrain_changed = pyqtSignal(list) # New signal for terrain changes # Terrain display mapping terrain_display_mapping = { @@ -49,7 +33,7 @@ class InputPanelUI(QFrame): "crossbow_top_crossbow": "顶部弩炮", "fire_side_crossbow": "侧边弩炮", "fire_side_fire": "侧边火炮", - "fire_top_fire": "顶部火炮", + "fire_top_fire": "顶部火炮" } @staticmethod @@ -59,19 +43,17 @@ def get_terrain_feature_columns(): """ try: # 加载类别映射 - class_map_path = resource_path( - "tools", "battlefield_recognize", "class_to_idx.json" - ) - with open(class_map_path, "r", encoding="utf-8") as f: + class_map_path = "tools/battlefield_recognize/class_to_idx.json" + with open(class_map_path, 'r', encoding='utf-8') as f: class_to_idx = json.load(f) # 使用与data_cleaning_with_field_recognize_gpu.py相同的逻辑 grouped_elements = defaultdict(list) for class_name in class_to_idx.keys(): - if class_name.endswith("_none"): + if class_name.endswith('_none'): continue - condensed_name = re.sub(r"_left_", "_", class_name) - condensed_name = re.sub(r"_right_", "_", condensed_name) + condensed_name = re.sub(r'_left_', '_', class_name) + condensed_name = re.sub(r'_right_', '_', condensed_name) grouped_elements[condensed_name].append(class_name) # 返回排序后的特征列名 @@ -85,21 +67,14 @@ def __init__(self): super().__init__() self.left_monsters: dict[str, str] = {} self.right_monsters: dict[str, str] = {} - self.terrain_buttons = {} # Initialize terrain buttons + self.terrain_buttons = {} # Initialize terrain buttons self.terrain_feature_columns = self.get_terrain_feature_columns() if not self.terrain_feature_columns: # If fetching fails, use default terrain features self.terrain_feature_columns = [ - "altar_vertical", - "block_parallel", - "block_vertical_altar", - "block_vertical_block", - "coil_narrow", - "coil_wide", - "crossbow_top", - "fire_side_left", - "fire_side_right", - "fire_top", + "altar_vertical", "block_parallel", "block_vertical_altar", + "block_vertical_block", "coil_narrow", "coil_wide", + "crossbow_top", "fire_side_left", "fire_side_right", "fire_top" ] self.init_ui() @@ -107,16 +82,16 @@ def __init__(self): def init_ui(self): self.setObjectName("input_panel_id") - self.setStyleSheet(""" + self.setStyleSheet( + """ QWidget#input_panel_id { background-color: rgba(0, 0, 0, 40); border-radius: 15px; border: 5px solid #F5EA2D; } - """) - self.setSizePolicy( - QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding + """ ) + self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) self.main_layout = QVBoxLayout(self) self.main_layout.setContentsMargins(0, 0, 0, 0) @@ -127,7 +102,8 @@ def init_ui(self): # 创建滚动区域 scroll = QScrollArea() scroll.setWidgetResizable(True) - scroll.setStyleSheet(""" + scroll.setStyleSheet( + """ QScrollBar:horizontal { background: rgba(0, 0, 0, 0); width: 12px; /* 宽度 */ @@ -171,7 +147,8 @@ def init_ui(self): min-height: 20px; border-radius: 6px; } - """) + """ + ) scroll_content = QWidget() self.scroll_grid = QGridLayout(scroll_content) @@ -228,7 +205,7 @@ def init_ui(self): # 分两行显示按钮,每行6个,更好地利用空间 terrain_rows = [] - for row_idx in range(2): # Changed from 3 to 2 rows + for row_idx in range(2): # Changed from 3 to 2 rows row_terrain = QWidget() row_layout = QHBoxLayout(row_terrain) row_layout.setSpacing(3) @@ -236,14 +213,13 @@ def init_ui(self): terrain_rows.append((row_terrain, row_layout)) for i, terrain_key in enumerate(self.terrain_feature_columns): - display_name = self.terrain_display_mapping.get( - terrain_key, terrain_key - ) + display_name = self.terrain_display_mapping.get(terrain_key, terrain_key) btn = QPushButton(display_name) btn.setCheckable(True) btn.setFixedHeight(26) - btn.setStyleSheet(""" + btn.setStyleSheet( + """ QPushButton { background-color: #7B7B7B; color: #FAFAFA; @@ -266,16 +242,13 @@ def init_ui(self): color: #313131; padding: 0px; } - """) - btn.clicked.connect( - lambda checked, k=terrain_key: self.on_terrain_multi_selected( - k - ) + """ ) + btn.clicked.connect(lambda checked, k=terrain_key: self.on_terrain_multi_selected(k)) self.terrain_buttons[terrain_key] = btn # 分两行显示,每行6个按钮 - row_index = i // 6 # Changed from 4 to 6 buttons per row + row_index = i // 6 # Changed from 4 to 6 buttons per row if row_index < len(terrain_rows): terrain_rows[row_index][1].addWidget(btn) else: @@ -298,7 +271,8 @@ def init_ui(self): # 预测按钮 - 带样式 self.predict_button = QPushButton("开始预测") self.predict_button.clicked.connect(self.predict_requested.emit) - self.predict_button.setStyleSheet(""" + self.predict_button.setStyleSheet( + """ QPushButton { background-color: #313131; color: #F3F31F; @@ -313,14 +287,14 @@ def init_ui(self): QPushButton:pressed { background-color: #212121; } - """) - self.predict_button.setSizePolicy( - QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed + """ ) + self.predict_button.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed) self.reset_button = QPushButton("重置") self.reset_button.clicked.connect(self.reset_entries) - self.reset_button.setStyleSheet(""" + self.reset_button.setStyleSheet( + """ QPushButton { background-color: #313131; color: #F3F31F; @@ -335,7 +309,8 @@ def init_ui(self): QPushButton:pressed { background-color: #212121; } - """) + """ + ) result_button_layout.addWidget(self.predict_button) result_button_layout.addWidget(self.reset_button) @@ -371,9 +346,7 @@ def load_images(self): img_label.setAlignment(Qt.AlignmentFlag.AlignCenter) try: - pixmap = QPixmap( - str(image_path(MONSTER_DATA['原始名称'][i])) - ) + pixmap = QPixmap(f"images/{MONSTER_DATA['原始名称'][i]}.png") if not pixmap.isNull(): pixmap = pixmap.scaled( 60, @@ -398,9 +371,7 @@ def load_images(self): left_entry.setFixedWidth(60) left_entry.setPlaceholderText("左") left_entry.setAlignment(Qt.AlignmentFlag.AlignCenter) - left_entry.textChanged.connect( - self.input_changed.emit - ) # Connect to signal + left_entry.textChanged.connect(self.input_changed.emit) # Connect to signal self.left_monsters[str(i)] = left_entry # 右输入框 (放在左输入框下方) @@ -408,26 +379,16 @@ def load_images(self): right_entry.setFixedWidth(60) right_entry.setPlaceholderText("右") right_entry.setAlignment(Qt.AlignmentFlag.AlignCenter) - right_entry.textChanged.connect( - self.input_changed.emit - ) # Connect to signal + right_entry.textChanged.connect(self.input_changed.emit) # Connect to signal self.right_monsters[str(i)] = right_entry # 添加到容器 - container_layout.addWidget( - img_label, 0, Qt.AlignmentFlag.AlignCenter - ) - container_layout.addWidget( - left_entry, 0, Qt.AlignmentFlag.AlignCenter - ) - container_layout.addWidget( - right_entry, 0, Qt.AlignmentFlag.AlignCenter - ) + container_layout.addWidget(img_label, 0, Qt.AlignmentFlag.AlignCenter) + container_layout.addWidget(left_entry, 0, Qt.AlignmentFlag.AlignCenter) + container_layout.addWidget(right_entry, 0, Qt.AlignmentFlag.AlignCenter) # 添加到网格布局 - self.scroll_grid.addWidget( - monster_container, row, col, Qt.AlignmentFlag.AlignCenter - ) + self.scroll_grid.addWidget(monster_container, row, col, Qt.AlignmentFlag.AlignCenter) # 更新行列位置 col += 1 @@ -462,18 +423,14 @@ def set_monster_counts(self, left_counts: dict, right_counts: dict): if monster_id in self.left_monsters: self.left_monsters[monster_id].setText(str(count)) if count > 0: - self.left_monsters[monster_id].setStyleSheet( - "background-color: yellow;" - ) + self.left_monsters[monster_id].setStyleSheet("background-color: yellow;") else: self.left_monsters[monster_id].setStyleSheet("") for monster_id, count in right_counts.items(): if monster_id in self.right_monsters: self.right_monsters[monster_id].setText(str(count)) if count > 0: - self.right_monsters[monster_id].setStyleSheet( - "background-color: yellow;" - ) + self.right_monsters[monster_id].setStyleSheet("background-color: yellow;") else: self.right_monsters[monster_id].setStyleSheet("") self.input_changed.emit() @@ -501,9 +458,7 @@ def get_selected_terrains(self): def build_terrain_features(self, left_counts, right_counts): """构建包含地形的完整特征向量(支持多选地形)""" # Use the actual number of terrain feature columns - num_field_features = ( - len(self.terrain_feature_columns) if FIELD_FEATURE_COUNT else 0 - ) + num_field_features = len(self.terrain_feature_columns) if FIELD_FEATURE_COUNT else 0 # Build terrain feature vector terrain_features = np.zeros(num_field_features) @@ -517,9 +472,7 @@ def build_terrain_features(self, left_counts, right_counts): if terrain_idx < num_field_features: terrain_features[terrain_idx] = 1 else: - logger.warning( - f"Terrain {terrain} not in feature columns: {self.terrain_feature_columns}" - ) + logger.warning(f"Terrain {terrain} not in feature columns: {self.terrain_feature_columns}") logger.debug(f"Selected terrains: {selected_terrains}") logger.debug(f"Terrain feature vector: {terrain_features}") @@ -530,13 +483,11 @@ def build_terrain_features(self, left_counts, right_counts): # 1R-61R (Right monster features) # 62R-73R (Field features R, copied) - full_features = np.concatenate( - [ - left_counts, # 1L-61L (Left monster features) - terrain_features, # 62L-73L (Field features L) - right_counts, # 1R-61R (Right monster features) - terrain_features, # 62R-73R (Field features R, copied) - ] - ) + full_features = np.concatenate([ + left_counts, # 1L-61L (Left monster features) + terrain_features, # 62L-73L (Field features L) + right_counts, # 1R-61R (Right monster features) + terrain_features # 62R-73R (Field features R, copied) + ]) return full_features diff --git a/src/data/load_data.py b/loadData.py similarity index 76% rename from src/data/load_data.py rename to loadData.py index 4c6f6d6..5481459 100644 --- a/src/data/load_data.py +++ b/loadData.py @@ -5,18 +5,21 @@ import logging import gzip import win32gui +import win32api import win32con +import sys import os from pathlib import Path -from src.game.winrt_capture import WinRTScreenCapture +from winrt_capture import WinRTScreenCapture logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) + class AdbConnector: def __init__(self, adb_serial=None): - self.adb_path = r".\vendor\bin\platform-tools\adb.exe" + self.adb_path = r".\platform-tools\adb.exe" self.screen_width = 0 self.screen_height = 0 self.device_serial = adb_serial if adb_serial else "" @@ -26,9 +29,7 @@ def connect(self): # 初始化设备序列号 try: # 如果已经有序列号,则尝试更新该序列号;否则使用默认值 - target_serial = ( - self.device_serial if self.device_serial else "127.0.0.1:5555" - ) + target_serial = self.device_serial if self.device_serial else "127.0.0.1:5555" self.update_device_serial(target_serial) logger.info(f"最终使用设备: {self.device_serial}") except RuntimeError as e: @@ -62,11 +63,7 @@ def get_window_size(self): # 执行ADB命令获取分辨率 size_cmd = f"{self.adb_path} -s {self.device_serial} shell wm size" result = subprocess.run( - size_cmd, - shell=True, - capture_output=True, - text=True, - check=True, + size_cmd, shell=True, capture_output=True, text=True, check=True ) output = result.stdout.strip() @@ -87,13 +84,9 @@ def get_window_size(self): else: screen_width = height screen_height = width - logger.info( - f"成功获取模拟器分辨率: {screen_width}x{screen_height}" - ) + logger.info(f"成功获取模拟器分辨率: {screen_width}x{screen_height}") except Exception as e: # 否则使用默认分辨率 - logger.exception( - f"获取分辨率失败,使用默认分辨率1920x1080。错误: {e}" - ) + logger.exception(f"获取分辨率失败,使用默认分辨率1920x1080。错误: {e}") screen_width = 1920 screen_height = 1080 return screen_width, screen_height @@ -102,11 +95,7 @@ def get_device_list(self): try: device_cmd = f"{self.adb_path} devices" result = subprocess.run( - device_cmd, - shell=True, - capture_output=True, - text=True, - timeout=5, + device_cmd, shell=True, capture_output=True, text=True, timeout=5 ) devices: list[str] = [] for line in result.stdout.split("\n"): @@ -129,11 +118,7 @@ def update_device_serial(self, serial): # 检查手动设备是否在线 device_cmd = f"{self.adb_path} devices" result = subprocess.run( - device_cmd, - shell=True, - capture_output=True, - text=True, - timeout=5, + device_cmd, shell=True, capture_output=True, text=True, timeout=5 ) # 只在调试模式下输出完整设备列表 logger.debug(f"ADB devices输出:\n{result.stdout}") @@ -149,9 +134,7 @@ def update_device_serial(self, serial): return dev # 只使用指定的设备,不要自动选择其他设备 - logger.error( - f"未找到指定的设备: {serial},当前在线设备: {devices}" - ) + logger.error(f"未找到指定的设备: {serial},当前在线设备: {devices}") self.device_serial = "" return "" @@ -205,14 +188,10 @@ def decode_raw(self, data: bytes): # 确保数据长度正确(实际屏幕分辨率,4通道) expected_length = self.screen_width * self.screen_height * 4 if len(argb_array) != expected_length: - raise ValueError( - f"Invalid data length for {self.screen_width}x{self.screen_height} ARGB image" - ) + raise ValueError(f"Invalid data length for {self.screen_width}x{self.screen_height} ARGB image") # 转换为正确的形状 (高度, 宽度, 通道) - argb_array = argb_array.reshape( - (self.screen_height, self.screen_width, 4) - ) + argb_array = argb_array.reshape((self.screen_height, self.screen_width, 4)) # 分离Alpha通道(如果需要保留Alpha,可以去掉这步) # 这里将ARGB转换为BGR(OpenCV默认格式) @@ -229,19 +208,17 @@ def decode_raw_with_gzip(self, data: bytes): image = self.decode_raw(decompressed_data) return image except Exception as e: - logger.exception( - "Gzip decompression or image decoding failed: %s", e - ) + logger.exception("Gzip decompression or image decoding failed: %s", e) return None def capture_screenshot_raw_gzip(self): - get_raw_gzip_cmd = rf'{self.adb_path} -s {self.device_serial} exec-out "screencap | gzip -1"' + get_raw_gzip_cmd = ( + rf'{self.adb_path} -s {self.device_serial} exec-out "screencap | gzip -1"' + ) ta = time.time() try: # 获取经过gzip压缩的二进制图像数据 - screenshot_raw_gzip = subprocess.check_output( - get_raw_gzip_cmd, shell=True - ) + screenshot_raw_gzip = subprocess.check_output(get_raw_gzip_cmd, shell=True) image = self.decode_raw_with_gzip(screenshot_raw_gzip) if image is None: raise RuntimeError("OpenCV failed to decode image") @@ -283,51 +260,39 @@ def connect(self): rect = win32gui.GetClientRect(self.hwnd) self.screen_width = rect[2] - rect[0] self.screen_height = rect[3] - rect[1] - + try: - from ..game.maa_adb_connector import resolve_maafw_path - + from maa_adb_connector import resolve_maafw_path binary_path = resolve_maafw_path() if binary_path: os.environ["MAAFW_BINARY_PATH"] = binary_path - + from maa.toolkit import Toolkit - from maa.controller import ( - Win32Controller, - MaaWin32ScreencapMethodEnum, - MaaWin32InputMethodEnum, - ) - + from maa.controller import Win32Controller, MaaWin32ScreencapMethodEnum, MaaWin32InputMethodEnum Toolkit.init_option(str(Path.cwd())) - + # 既然纯 SendMessage 被引擎无视,我们退一步使用 SendMessageWithCursorPos # 它会在瞬间把鼠标光标移动到目标位置发送消息,再瞬间移回原位。这种方式可能不会强制将游戏窗口调回前台。 self.maa_ctrl = Win32Controller( self.hwnd, screencap_method=MaaWin32ScreencapMethodEnum.FramePool, mouse_method=MaaWin32InputMethodEnum.SendMessageWithCursorPos, - keyboard_method=MaaWin32InputMethodEnum.SendMessageWithCursorPos, + keyboard_method=MaaWin32InputMethodEnum.SendMessageWithCursorPos ) self.maa_ctrl.post_connection().wait() - + # 设置截图使用原始大小,防止因为MAA默认缩放导致外部坐标及图像切割计算出错 self.maa_ctrl.set_screenshot_use_raw_size(True) - - logger.info( - f"已成功通过 MaaFramework 接管 PC 窗口 (支持后台操作)" - ) + + logger.info(f"已成功通过 MaaFramework 接管 PC 窗口 (支持后台操作)") except Exception as e: - logger.warning( - f"MaaFramework 初始化失败,退回原有前台实现: {e}" - ) + logger.warning(f"MaaFramework 初始化失败,退回原有前台实现: {e}") self.maa_ctrl = None self.capture = WinRTScreenCapture(window_name=self.window_name) self.capture.start() self.is_connected = True - logger.info( - f"成功连接到PC端窗口: {self.window_name}, 分辨率: {self.screen_width}x{self.screen_height}" - ) + logger.info(f"成功连接到PC端窗口: {self.window_name}, 分辨率: {self.screen_width}x{self.screen_height}") else: logger.warning(f"未找到PC端窗口: {self.window_name}") self.is_connected = False @@ -335,7 +300,7 @@ def connect(self): def capture_screenshot(self): if not self.is_connected: return None - + if self.maa_ctrl: try: self.maa_ctrl.post_screencap().wait() @@ -352,7 +317,7 @@ def capture_screenshot(self): def click(self, point): if not self.hwnd: return - + try: # PC端点击需要重新获取一次ClientRect以防窗口大小改变 rect = win32gui.GetClientRect(self.hwnd) @@ -362,21 +327,17 @@ def click(self, point): x, y = point x_coord = int(x * self.screen_width) y_coord = int(y * self.screen_height) - + if self.maa_ctrl: logger.info(f"MAA后台点击坐标: ({x_coord}, {y_coord})") self.maa_ctrl.post_click(x_coord, y_coord).wait() return - client_left, client_top = win32gui.ClientToScreen( - self.hwnd, (0, 0) - ) + client_left, client_top = win32gui.ClientToScreen(self.hwnd, (0, 0)) screen_x = client_left + x_coord screen_y = client_top + y_coord - - logger.info( - f"PC端点击坐标: 窗口内({x_coord}, {y_coord}) -> 屏幕({screen_x}, {screen_y})" - ) + + logger.info(f"PC端点击坐标: 窗口内({x_coord}, {y_coord}) -> 屏幕({screen_x}, {screen_y})") # 尝试将窗口置于前台,忽略可能的错误 try: @@ -390,42 +351,16 @@ def click(self, point): # 使用底层 SendInput 模拟鼠标事件,支持多显示器 (VIRTUALDESK) 并且不会在权限不足时抛出异常 import ctypes - + PUL = ctypes.POINTER(ctypes.c_ulong) - class KeyBdInput(ctypes.Structure): - _fields_ = [ - ("wVk", ctypes.c_ushort), - ("wScan", ctypes.c_ushort), - ("dwFlags", ctypes.c_ulong), - ("time", ctypes.c_ulong), - ("dwExtraInfo", PUL), - ] - + _fields_ = [("wVk", ctypes.c_ushort), ("wScan", ctypes.c_ushort), ("dwFlags", ctypes.c_ulong), ("time", ctypes.c_ulong), ("dwExtraInfo", PUL)] class HardwareInput(ctypes.Structure): - _fields_ = [ - ("uMsg", ctypes.c_ulong), - ("wParamL", ctypes.c_short), - ("wParamH", ctypes.c_ushort), - ] - + _fields_ = [("uMsg", ctypes.c_ulong), ("wParamL", ctypes.c_short), ("wParamH", ctypes.c_ushort)] class MouseInput(ctypes.Structure): - _fields_ = [ - ("dx", ctypes.c_long), - ("dy", ctypes.c_long), - ("mouseData", ctypes.c_ulong), - ("dwFlags", ctypes.c_ulong), - ("time", ctypes.c_ulong), - ("dwExtraInfo", PUL), - ] - + _fields_ = [("dx", ctypes.c_long), ("dy", ctypes.c_long), ("mouseData", ctypes.c_ulong), ("dwFlags", ctypes.c_ulong), ("time", ctypes.c_ulong), ("dwExtraInfo", PUL)] class Input_I(ctypes.Union): - _fields_ = [ - ("ki", KeyBdInput), - ("mi", MouseInput), - ("hi", HardwareInput), - ] - + _fields_ = [("ki", KeyBdInput), ("mi", MouseInput), ("hi", HardwareInput)] class Input(ctypes.Structure): _fields_ = [("type", ctypes.c_ulong), ("ii", Input_I)] @@ -433,19 +368,11 @@ class Input(ctypes.Structure): SM_YVIRTUALSCREEN = 77 SM_CXVIRTUALSCREEN = 78 SM_CYVIRTUALSCREEN = 79 - - vscreen_x = ctypes.windll.user32.GetSystemMetrics( - SM_XVIRTUALSCREEN - ) - vscreen_y = ctypes.windll.user32.GetSystemMetrics( - SM_YVIRTUALSCREEN - ) - vscreen_w = ctypes.windll.user32.GetSystemMetrics( - SM_CXVIRTUALSCREEN - ) - vscreen_h = ctypes.windll.user32.GetSystemMetrics( - SM_CYVIRTUALSCREEN - ) + + vscreen_x = ctypes.windll.user32.GetSystemMetrics(SM_XVIRTUALSCREEN) + vscreen_y = ctypes.windll.user32.GetSystemMetrics(SM_YVIRTUALSCREEN) + vscreen_w = ctypes.windll.user32.GetSystemMetrics(SM_CXVIRTUALSCREEN) + vscreen_h = ctypes.windll.user32.GetSystemMetrics(SM_CYVIRTUALSCREEN) if vscreen_w == 0 or vscreen_h == 0: vscreen_w = 1920 @@ -463,58 +390,25 @@ class Input(ctypes.Structure): extra = ctypes.c_ulong(0) ii_ = Input_I() - + # 移动鼠标 - ii_.mi = MouseInput( - dx, - dy, - 0, - MOUSEEVENTF_MOVE - | MOUSEEVENTF_ABSOLUTE - | MOUSEEVENTF_VIRTUALDESK, - 0, - ctypes.pointer(extra), - ) + ii_.mi = MouseInput(dx, dy, 0, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK, 0, ctypes.pointer(extra)) cmd = Input(ctypes.c_ulong(0), ii_) - ctypes.windll.user32.SendInput( - 1, ctypes.pointer(cmd), ctypes.sizeof(cmd) - ) - + ctypes.windll.user32.SendInput(1, ctypes.pointer(cmd), ctypes.sizeof(cmd)) + time.sleep(0.05) - + # 按下左键 - ii_.mi = MouseInput( - dx, - dy, - 0, - MOUSEEVENTF_LEFTDOWN - | MOUSEEVENTF_ABSOLUTE - | MOUSEEVENTF_VIRTUALDESK, - 0, - ctypes.pointer(extra), - ) + ii_.mi = MouseInput(dx, dy, 0, MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK, 0, ctypes.pointer(extra)) cmd = Input(ctypes.c_ulong(0), ii_) - ctypes.windll.user32.SendInput( - 1, ctypes.pointer(cmd), ctypes.sizeof(cmd) - ) - + ctypes.windll.user32.SendInput(1, ctypes.pointer(cmd), ctypes.sizeof(cmd)) + time.sleep(0.05) - + # 抬起左键 - ii_.mi = MouseInput( - dx, - dy, - 0, - MOUSEEVENTF_LEFTUP - | MOUSEEVENTF_ABSOLUTE - | MOUSEEVENTF_VIRTUALDESK, - 0, - ctypes.pointer(extra), - ) + ii_.mi = MouseInput(dx, dy, 0, MOUSEEVENTF_LEFTUP | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK, 0, ctypes.pointer(extra)) cmd = Input(ctypes.c_ulong(0), ii_) - ctypes.windll.user32.SendInput( - 1, ctypes.pointer(cmd), ctypes.sizeof(cmd) - ) + ctypes.windll.user32.SendInput(1, ctypes.pointer(cmd), ctypes.sizeof(cmd)) except Exception as e: logger.exception(f"PC端点击出错: {e}") diff --git a/src/game/login.py b/login.py similarity index 72% rename from src/game/login.py rename to login.py index 6128b8d..fea67ae 100644 --- a/src/game/login.py +++ b/login.py @@ -1,7 +1,6 @@ import os - # 设置 OpenCV 日志级别为 ERROR,减少 libpng 警告 -os.environ["OPENCV_LOG_LEVEL"] = "ERROR" +os.environ['OPENCV_LOG_LEVEL'] = 'ERROR' import logging import time @@ -10,18 +9,15 @@ import cv2 import numpy as np -from src.core.paths import PROCESS_IMAGES_DIR, process_image_path - logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) - class LoginManager: """登录管理器,处理游戏登录和页面跳转""" - + def __init__(self, connector, max_restart_count=3): self.connector = connector - self.template_dir = PROCESS_IMAGES_DIR / "login" + self.template_dir = Path("images") / "login" self.template_dir.mkdir(parents=True, exist_ok=True) self.restart_count = 0 self.max_restart_count = max_restart_count @@ -30,7 +26,7 @@ def __init__(self, connector, max_restart_count=3): except Exception as e: logger.error(f"模板加载失败: {e}") self.templates = {} - + def _log(self, level, message): """生成带有设备序列号的日志消息""" serial = getattr(self.connector, "device_serial", None) @@ -38,16 +34,16 @@ def _log(self, level, message): logger.log(level, f"[{serial}] {message}") else: logger.log(level, message) - + def reset_restart_count(self): """重置重启计数器""" self.restart_count = 0 self._log(logging.INFO, "重启计数器已重置") - + def can_restart(self): """检查是否可以重启""" return self.restart_count < self.max_restart_count - + def _load_templates(self): """加载模板图片""" self.templates = {} @@ -58,51 +54,38 @@ def _load_templates(self): if template is not None: self.templates[template_name] = template logger.info(f"加载模板: {template_name}") - + def match_template(self, screenshot, template_name, threshold=0.9): """匹配模板""" if template_name not in self.templates: logger.error(f"模板不存在: {template_name}") return False, (0, 0) - + template = self.templates[template_name] - + # 转换为灰度图像 screenshot_gray = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY) template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY) - + # 多尺度模板匹配 found = None for scale in np.linspace(0.5, 1.5, 10): # 调整模板大小 - resized = cv2.resize( - template_gray, - ( - int(template_gray.shape[1] * scale), - int(template_gray.shape[0] * scale), - ), - ) - if ( - resized.shape[0] > screenshot_gray.shape[0] - or resized.shape[1] > screenshot_gray.shape[1] - ): + resized = cv2.resize(template_gray, (int(template_gray.shape[1] * scale), int(template_gray.shape[0] * scale))) + if resized.shape[0] > screenshot_gray.shape[0] or resized.shape[1] > screenshot_gray.shape[1]: break - + # 匹配 - result = cv2.matchTemplate( - screenshot_gray, resized, cv2.TM_CCOEFF_NORMED - ) + result = cv2.matchTemplate(screenshot_gray, resized, cv2.TM_CCOEFF_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) - + # 更新最佳匹配 if found is None or max_val > found[0]: found = (max_val, max_loc, scale) - + if found: max_val, max_loc, scale = found - h, w = int(template.shape[0] * scale), int( - template.shape[1] * scale - ) + h, w = int(template.shape[0] * scale), int(template.shape[1] * scale) if max_val >= threshold: logger.info(f"匹配到模板 {template_name},置信度: {max_val}") # 返回模板中心点坐标 @@ -110,29 +93,26 @@ def match_template(self, screenshot, template_name, threshold=0.9): center_y = max_loc[1] + h // 2 return True, (center_x, center_y) else: - logger.debug( - f"未匹配到模板 {template_name},最高置信度: {max_val}" - ) + logger.debug(f"未匹配到模板 {template_name},最高置信度: {max_val}") return False, (0, 0) else: logger.debug(f"未匹配到模板 {template_name}") return False, (0, 0) + + def restart_game(self): """重启游戏""" self._log(logging.INFO, "开始重启游戏") - + # 确定连接类型 - is_pc = hasattr(self.connector, "hwnd") and self.connector.hwnd - is_adb = ( - hasattr(self.connector, "device_serial") - and self.connector.device_serial - ) - + is_pc = hasattr(self.connector, 'hwnd') and self.connector.hwnd + is_adb = hasattr(self.connector, 'device_serial') and self.connector.device_serial + if not is_pc and not is_adb: self._log(logging.ERROR, "无法确定连接类型,无法重启游戏") return False - + # 关闭游戏进程 try: if is_pc: @@ -140,101 +120,71 @@ def restart_game(self): import win32gui import win32process import win32api - - _, process_id = win32process.GetWindowThreadProcessId( - self.connector.hwnd - ) + _, process_id = win32process.GetWindowThreadProcessId(self.connector.hwnd) process = win32api.OpenProcess(1, False, process_id) win32api.TerminateProcess(process, 0) win32api.CloseHandle(process) self._log(logging.INFO, "关闭游戏进程成功") else: # 对于ADB端,关闭游戏进程 - adb_path = getattr(self.connector, "adb_path", "adb") - subprocess.run( - f"{adb_path} -s {self.connector.device_serial} shell am force-stop com.hypergryph.arknights", - shell=True, - ) + adb_path = getattr(self.connector, 'adb_path', 'adb') + subprocess.run(f"{adb_path} -s {self.connector.device_serial} shell am force-stop com.hypergryph.arknights", shell=True) self._log(logging.INFO, "关闭游戏进程成功") except Exception as e: self._log(logging.ERROR, f"关闭游戏进程失败: {e}") return False - + # 等待一段时间后重新启动游戏 time.sleep(3) - + try: if is_pc: # 对于PC端,重新启动游戏 # 尝试从注册表获取游戏路径 try: import winreg - - key = winreg.OpenKey( - winreg.HKEY_LOCAL_MACHINE, - r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", - ) + key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall") for i in range(winreg.QueryInfoKey(key)[0]): subkey_name = winreg.EnumKey(key, i) subkey = winreg.OpenKey(key, subkey_name) try: - display_name = winreg.QueryValueEx( - subkey, "DisplayName" - )[0] + display_name = winreg.QueryValueEx(subkey, "DisplayName")[0] if "Arknights" in display_name: - install_location = winreg.QueryValueEx( - subkey, "InstallLocation" - )[0] - game_path = ( - Path(install_location) / "Arknights.exe" - ) + install_location = winreg.QueryValueEx(subkey, "InstallLocation")[0] + game_path = Path(install_location) / "Arknights.exe" if game_path.exists(): subprocess.Popen(str(game_path)) - self._log( - logging.INFO, - f"从注册表获取游戏路径并启动: {game_path}", - ) + self._log(logging.INFO, f"从注册表获取游戏路径并启动: {game_path}") break except: pass else: # 如果从注册表获取失败,使用默认路径 - game_path = Path( - "C:\\Program Files\\Arknights\\Arknights.exe" - ) + game_path = Path("C:\\Program Files\\Arknights\\Arknights.exe") if game_path.exists(): subprocess.Popen(str(game_path)) - self._log( - logging.INFO, - f"使用默认路径启动游戏: {game_path}", - ) + self._log(logging.INFO, f"使用默认路径启动游戏: {game_path}") else: self._log(logging.ERROR, "无法找到游戏可执行文件") return False except: # 如果注册表操作失败,使用默认路径 - game_path = Path( - "C:\\Program Files\\Arknights\\Arknights.exe" - ) + game_path = Path("C:\\Program Files\\Arknights\\Arknights.exe") if game_path.exists(): subprocess.Popen(str(game_path)) - self._log( - logging.INFO, f"使用默认路径启动游戏: {game_path}" - ) + self._log(logging.INFO, f"使用默认路径启动游戏: {game_path}") else: self._log(logging.ERROR, "无法找到游戏可执行文件") return False else: # 对于ADB端,重新启动游戏 - adb_path = getattr(self.connector, "adb_path", "adb") - subprocess.run( - f"{adb_path} -s {self.connector.device_serial} shell am start -n com.hypergryph.arknights/com.u8.sdk.U8UnityContext" - ) + adb_path = getattr(self.connector, 'adb_path', 'adb') + subprocess.run(f"{adb_path} -s {self.connector.device_serial} shell am start -n com.hypergryph.arknights/com.u8.sdk.U8UnityContext") self._log(logging.INFO, "重新启动游戏成功") except Exception as e: self._log(logging.ERROR, f"重新启动游戏失败: {e}") return False - + # 重新连接 try: self.connector.connect() @@ -244,19 +194,19 @@ def restart_game(self): self._log(logging.WARNING, "游戏重启后重新连接失败") except Exception as e: self._log(logging.ERROR, f"重新连接失败: {e}") - + return True def auto_login(self, first_start=False, stop_callback=None): """自动登录功能,处理服务器维护或掉线后的重新登录""" self._log(logging.INFO, "开始自动登录流程") - + def check_stop(): if stop_callback and not stop_callback(): self._log(logging.INFO, "检测到停止信号,中断登录流程") return False return True - + def sleep_with_check(seconds): """可中断的等待函数""" start_time = time.time() @@ -265,12 +215,9 @@ def sleep_with_check(seconds): return False time.sleep(0.1) return True - + # 确保连接器已连接 - if ( - not hasattr(self.connector, "is_connected") - or not self.connector.is_connected - ): + if not hasattr(self.connector, 'is_connected') or not self.connector.is_connected: logger.info("连接器未连接,尝试重新连接") try: self.connector.connect() @@ -280,29 +227,27 @@ def sleep_with_check(seconds): except Exception as e: logger.error(f"重新连接失败: {e}") return False - + # 首次启动时,先检测是否已经在游戏流程中 if first_start: logger.info("首次启动,检测是否已在游戏流程中") - + # 检查是否需要停止 if not check_stop(): return False - + screenshot = self.connector.capture_screenshot() if screenshot is not None: # 检查是否匹配到争锋频道入口 - matched, _ = self.match_template( - screenshot, "competition_page", threshold=0.7 - ) + matched, _ = self.match_template(screenshot, "competition_page", threshold=0.7) if matched: logger.info("已在争锋频道入口,无需登录") return True - + # 检查是否需要停止 if not check_stop(): return False - + # 检查是否匹配到0.png或1.png(加入赛事或开始游戏) try: # 尝试简单匹配 @@ -310,75 +255,53 @@ def sleep_with_check(seconds): # 检查是否需要停止 if not check_stop(): return False - - template_path = process_image_path(template_name) + + template_path = Path(f"images/process/{template_name}.png") if template_path.exists(): template = cv2.imread(str(template_path)) if template is not None: - screenshot_gray = cv2.cvtColor( - screenshot, cv2.COLOR_BGR2GRAY - ) - template_gray = cv2.cvtColor( - template, cv2.COLOR_BGR2GRAY - ) - res = cv2.matchTemplate( - screenshot_gray, - template_gray, - cv2.TM_CCOEFF_NORMED, - ) + screenshot_gray = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY) + template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY) + res = cv2.matchTemplate(screenshot_gray, template_gray, cv2.TM_CCOEFF_NORMED) _, max_val, _, _ = cv2.minMaxLoc(res) if max_val > 0.7: - logger.info( - f"已在争锋频道页面,找到模板 {template_name}.png" - ) + logger.info(f"已在争锋频道页面,找到模板 {template_name}.png") return True except Exception as e: logger.debug(f"检测争锋频道页面模板失败: {e}") - + # 检查是否需要停止 if not check_stop(): return False - + # 检查是否在战斗前准备阶段(PRE_BATTLE) # 匹配战斗前准备相关的模板(模板索引3,4,5,15) for template_name in ["3", "4", "5", "15"]: # 检查是否需要停止 if not check_stop(): return False - - template_path = process_image_path(template_name) + + template_path = Path(f"images/process/{template_name}.png") if template_path.exists(): try: template = cv2.imread(str(template_path)) if template is not None: - screenshot_gray = cv2.cvtColor( - screenshot, cv2.COLOR_BGR2GRAY - ) - template_gray = cv2.cvtColor( - template, cv2.COLOR_BGR2GRAY - ) - res = cv2.matchTemplate( - screenshot_gray, - template_gray, - cv2.TM_CCOEFF_NORMED, - ) + screenshot_gray = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY) + template_gray = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY) + res = cv2.matchTemplate(screenshot_gray, template_gray, cv2.TM_CCOEFF_NORMED) _, max_val, _, _ = cv2.minMaxLoc(res) if max_val > 0.7: - logger.info( - f"已在战斗前准备阶段,找到模板 {template_name}.png,无需登录" - ) + logger.info(f"已在战斗前准备阶段,找到模板 {template_name}.png,无需登录") return True except Exception as e: - logger.debug( - f"检测战斗前准备模板 {template_name}.png 失败: {e}" - ) - + logger.debug(f"检测战斗前准备模板 {template_name}.png 失败: {e}") + # 非首次启动时,等待游戏启动 if not first_start: self._log(logging.INFO, "重启游戏,等待游戏启动...") if not sleep_with_check(40): return False - + # 点击屏幕中心跳过中转页面(点击3次,每次间隔2秒) self._log(logging.INFO, "点击屏幕中心跳过中转页面") for i in range(3): @@ -387,7 +310,7 @@ def sleep_with_check(seconds): if i < 2: if not sleep_with_check(2): return False - + # 寻找并点击登录按钮 self._log(logging.INFO, "寻找登录按钮") login_button_found = False @@ -401,31 +324,26 @@ def sleep_with_check(seconds): if not sleep_with_check(1): return False continue - + h, w = screenshot.shape[:2] self._log(logging.DEBUG, f"截图尺寸: {w}x{h}") - - matched, pos = self.match_template( - screenshot, "login_button", threshold=0.9 - ) + + matched, pos = self.match_template(screenshot, "login_button", threshold=0.9) if matched: rel_x = pos[0] / w rel_y = pos[1] / h - self._log( - logging.INFO, - f"登录按钮位置: ({pos[0]}, {pos[1]}), 相对坐标: ({rel_x:.2f}, {rel_y:.2f})", - ) + self._log(logging.INFO, f"登录按钮位置: ({pos[0]}, {pos[1]}), 相对坐标: ({rel_x:.2f}, {rel_y:.2f})") self.connector.click((rel_x, rel_y)) self._log(logging.INFO, "点击登录按钮") login_button_found = True break if not sleep_with_check(1): return False - + if not login_button_found: self._log(logging.ERROR, "未找到登录按钮,登录流程中断") return False - + # 等待登录完成,最多等待70秒 self._log(logging.INFO, "等待登录完成 (最长70秒,动态检测)...") start_time = time.time() @@ -455,15 +373,13 @@ def sleep_with_check(seconds): # 寻找争锋频道入口,最多等待30秒 self._log(logging.INFO, "寻找争锋频道入口") start_time = time.time() - + # 尝试识别争锋频道 screenshot = self.connector.capture_screenshot() if screenshot is not None: - if self._check_and_click_competition_page( - screenshot, sleep_with_check, check_stop - ): + if self._check_and_click_competition_page(screenshot, sleep_with_check, check_stop): return True - + # 识别失败时点击右上角两次 self._log(logging.INFO, "未检测到争锋频道入口,点击屏幕右上角") for _ in range(2): @@ -474,9 +390,7 @@ def sleep_with_check(seconds): # 点击右上角后,立即再次检查争锋频道入口 screenshot = self.connector.capture_screenshot() if screenshot is not None: - if self._check_and_click_competition_page( - screenshot, sleep_with_check, check_stop - ): + if self._check_and_click_competition_page(screenshot, sleep_with_check, check_stop): return True # 同时检测两种关闭按钮五次(每次间隔2秒) @@ -509,9 +423,7 @@ def sleep_with_check(seconds): screenshot = self.connector.capture_screenshot() if screenshot is not None: - if self._check_and_click_competition_page( - screenshot, sleep_with_check, check_stop - ): + if self._check_and_click_competition_page(screenshot, sleep_with_check, check_stop): return True # 每次轮询间隔2秒,避免频繁截图造成性能浪费 @@ -521,22 +433,15 @@ def sleep_with_check(seconds): # 还是失败的话就重启 self._log(logging.ERROR, "未找到争锋频道入口,登录流程失败") return False - - def _check_and_click_competition_page( - self, screenshot, sleep_with_check, check_stop - ): + + def _check_and_click_competition_page(self, screenshot, sleep_with_check, check_stop): """争锋频道入口检测和点击方法""" - matched, pos = self.match_template( - screenshot, "competition_page", threshold=0.7 - ) + matched, pos = self.match_template(screenshot, "competition_page", threshold=0.7) if matched: h, w = screenshot.shape[:2] rel_x = pos[0] / w rel_y = pos[1] / h - self._log( - logging.INFO, - f"争锋频道入口位置: ({pos[0]}, {pos[1]}), 相对坐标: ({rel_x:.2f}, {rel_y:.2f})", - ) + self._log(logging.INFO, f"争锋频道入口位置: ({pos[0]}, {pos[1]}), 相对坐标: ({rel_x:.2f}, {rel_y:.2f})") self.connector.click((rel_x, rel_y)) self._log(logging.INFO, "点击进入争锋频道页面") if not sleep_with_check(2): @@ -544,7 +449,7 @@ def _check_and_click_competition_page( self._log(logging.INFO, "自动登录流程完成") return True return False - + def try_login_with_retry(self, max_wait_seconds=6, stop_callback=None): """尝试登录,如果未找到登录按钮则等待重试""" for i in range(max_wait_seconds): @@ -552,13 +457,11 @@ def try_login_with_retry(self, max_wait_seconds=6, stop_callback=None): if stop_callback and not stop_callback(): logger.info("检测到停止信号,取消登录尝试") return False - + screenshot = self.connector.capture_screenshot() if screenshot is not None: logger.info("获取截图成功,检查是否存在登录按钮") - matched, _ = self.match_template( - screenshot, "login_button", threshold=0.9 - ) + matched, _ = self.match_template(screenshot, "login_button", threshold=0.9) if matched: logger.info("找到登录按钮,执行登录流程") # 传递 stop_callback 给 auto_login @@ -569,7 +472,7 @@ def try_login_with_retry(self, max_wait_seconds=6, stop_callback=None): return False else: logger.info(f"第 {i+1} 次检查:未找到登录按钮,继续等待") - + # 可中断的等待 start_time = time.time() while time.time() - start_time < 6: @@ -578,32 +481,27 @@ def try_login_with_retry(self, max_wait_seconds=6, stop_callback=None): return False time.sleep(0.1) return False - + def restart_and_login(self, first_start=False, stop_callback=None): """重启游戏并尝试登录""" # 检查是否需要停止 if stop_callback and not stop_callback(): self._log(logging.INFO, "检测到停止信号,取消重启") return False - - self._log( - logging.INFO, - f"尝试重启游戏 (第 {self.restart_count + 1}/{self.max_restart_count} 次)", - ) + + self._log(logging.INFO, f"尝试重启游戏 (第 {self.restart_count + 1}/{self.max_restart_count} 次)") self.restart_count += 1 - + if self.restart_game(): self._log(logging.INFO, "游戏重启成功,尝试重新登录") - + # 检查是否需要停止 if stop_callback and not stop_callback(): self._log(logging.INFO, "检测到停止信号,取消登录") return False - + # 传递 stop_callback 给 auto_login - if self.auto_login( - first_start=first_start, stop_callback=stop_callback - ): + if self.auto_login(first_start=first_start, stop_callback=stop_callback): return True else: self._log(logging.ERROR, "重启后自动登录失败") @@ -611,26 +509,20 @@ def restart_and_login(self, first_start=False, stop_callback=None): else: self._log(logging.ERROR, "重启游戏失败") return False - + def auto_login_with_restart(self, first_start=False, stop_callback=None): """自动登录,失败时自动重启重试""" # 首先尝试直接登录(首次启动) - if self.auto_login( - first_start=first_start, stop_callback=stop_callback - ): + if self.auto_login(first_start=first_start, stop_callback=stop_callback): self.reset_restart_count() return True - + # 登录失败,尝试重启登录 for _ in range(self.max_restart_count - 1): - if not self.restart_and_login( - first_start=False, stop_callback=stop_callback - ): + if not self.restart_and_login(first_start=False, stop_callback=stop_callback): self._log(logging.WARNING, "重启登录失败,继续尝试") continue return True - - self._log( - logging.ERROR, f"已尝试 {self.max_restart_count} 次,登录失败" - ) - return False + + self._log(logging.ERROR, f"已尝试 {self.max_restart_count} 次,登录失败") + return False \ No newline at end of file diff --git a/src/game/maa_adb_connector.py b/maa_adb_connector.py similarity index 82% rename from src/game/maa_adb_connector.py rename to maa_adb_connector.py index 8c11a1c..b47bc9c 100644 --- a/src/game/maa_adb_connector.py +++ b/maa_adb_connector.py @@ -15,12 +15,9 @@ def resolve_maafw_path() -> str: if os.environ.get("MAAFW_BINARY_PATH"): return os.environ["MAAFW_BINARY_PATH"] candidates = [ - Path(sys.executable).parent / "vendor" / "bin" / "maafw", - Path.cwd() / "vendor" / "bin" / "maafw", - Path(__file__).resolve().parent.parent.parent - / "vendor" - / "bin" - / "maafw", + Path(sys.executable).parent / "maafw", + Path.cwd() / "maafw", + Path(__file__).resolve().parent / "maafw", ] for p in candidates: if p.is_dir() and any(p.glob("MaaFramework.dll")): @@ -58,7 +55,7 @@ class InputMethodOption: @dataclass(frozen=True) class MaaConnectionConfig: maa_binary_path: str = "" - adb_path: str = r".\vendor\bin\platform-tools\adb.exe" + adb_path: str = r".\platform-tools\adb.exe" device_serial: str = "" screencap_method: int = 1 input_method: int = 4 @@ -142,30 +139,12 @@ def reset(cls): class ConnectionTypeRegistry: _types: list[ConnectionType] = [ - ConnectionType( - "adb", "ADB连接", "", "通用ADB连接,需手动指定设备地址" - ), - ConnectionType( - "ldplayer", "雷电模拟器", "emulator-5554", "雷电模拟器默认ADB地址" - ), - ConnectionType( - "mumu", "MuMu模拟器", "127.0.0.1:7555", "MuMu模拟器默认ADB地址" - ), - ConnectionType( - "mumu12", - "MuMu12模拟器", - "127.0.0.1:16384", - "MuMu12模拟器默认ADB地址", - ), - ConnectionType( - "bluestacks", - "蓝叠模拟器", - "127.0.0.1:5555", - "蓝叠模拟器默认ADB地址", - ), - ConnectionType( - "nox", "夜神模拟器", "127.0.0.1:62001", "夜神模拟器默认ADB地址" - ), + ConnectionType("adb", "ADB连接", "", "通用ADB连接,需手动指定设备地址"), + ConnectionType("ldplayer", "雷电模拟器", "emulator-5554", "雷电模拟器默认ADB地址"), + ConnectionType("mumu", "MuMu模拟器", "127.0.0.1:7555", "MuMu模拟器默认ADB地址"), + ConnectionType("mumu12", "MuMu12模拟器", "127.0.0.1:16384", "MuMu12模拟器默认ADB地址"), + ConnectionType("bluestacks", "蓝叠模拟器", "127.0.0.1:5555", "蓝叠模拟器默认ADB地址"), + ConnectionType("nox", "夜神模拟器", "127.0.0.1:62001", "夜神模拟器默认ADB地址"), ] @classmethod @@ -189,24 +168,10 @@ def get_type_by_id(cls, type_id: str) -> ConnectionType | None: class InputMethodRegistry: _methods: list[InputMethodOption] = [ - InputMethodOption( - "adb_shell", 1, "AdbShell", "ADB shell input命令,兼容性最高" - ), - InputMethodOption( - "minitouch_adb_key", - 2, - "MinitouchAndAdbKey", - "minitouch注入+ADB按键,低延迟需root", - ), - InputMethodOption( - "maatouch", 4, "Maatouch", "Maatouch注入,低延迟MAA自带" - ), - InputMethodOption( - "emulator_extras", - 8, - "EmulatorExtras", - "模拟器扩展接口,仅特定模拟器支持", - ), + InputMethodOption("adb_shell", 1, "AdbShell", "ADB shell input命令,兼容性最高"), + InputMethodOption("minitouch_adb_key", 2, "MinitouchAndAdbKey", "minitouch注入+ADB按键,低延迟需root"), + InputMethodOption("maatouch", 4, "Maatouch", "Maatouch注入,低延迟MAA自带"), + InputMethodOption("emulator_extras", 8, "EmulatorExtras", "模拟器扩展接口,仅特定模拟器支持"), ] @classmethod @@ -258,9 +223,7 @@ def connect(self): Toolkit.init_option(str(Path.cwd())) - target_serial = ( - self.device_serial if self.device_serial else "127.0.0.1:5555" - ) + target_serial = self.device_serial if self.device_serial else "127.0.0.1:5555" self.device_serial = target_serial adb_path = str(Path(self._config.adb_path).resolve()) @@ -273,24 +236,18 @@ def connect(self): ) self._ctrl.post_connection().wait() - self._ctrl.set_screenshot_use_raw_size( - self._config.screenshot_use_raw_size - ) + self._ctrl.set_screenshot_use_raw_size(self._config.screenshot_use_raw_size) self._ctrl.post_screencap().wait() image = self._ctrl.cached_image if image is not None: self.screen_height, self.screen_width = image.shape[:2] else: - self.screen_width, self.screen_height = ( - self._get_window_size_fallback() - ) + self.screen_width, self.screen_height = self._get_window_size_fallback() self.is_maa_available = True self.is_connected = True - logger.info( - f"MAA Framework ADB连接成功: {target_serial}, 分辨率: {self.screen_width}x{self.screen_height}" - ) + logger.info(f"MAA Framework ADB连接成功: {target_serial}, 分辨率: {self.screen_width}x{self.screen_height}") except Exception as e: self.is_maa_available = False @@ -300,14 +257,7 @@ def connect(self): def _get_window_size_fallback(self) -> tuple[int, int]: try: size_cmd = f"{self._config.adb_path} -s {self.device_serial} shell wm size" - result = subprocess.run( - size_cmd, - shell=True, - capture_output=True, - text=True, - check=True, - timeout=5, - ) + result = subprocess.run(size_cmd, shell=True, capture_output=True, text=True, check=True, timeout=5) output = result.stdout.strip() if "Physical size:" in output: res_str = output.split("Physical size: ")[1] @@ -346,12 +296,7 @@ def click(self, point: tuple[float, float]): except Exception as e: logger.error(f"MAA点击失败: {e}") - def swipe( - self, - start: tuple[float, float], - end: tuple[float, float], - duration: int = 500, - ): + def swipe(self, start: tuple[float, float], end: tuple[float, float], duration: int = 500): if not self.is_connected or self._ctrl is None: return try: @@ -361,19 +306,14 @@ def swipe( y1_coord = int(y1 * self.screen_height) x2_coord = int(x2 * self.screen_width) y2_coord = int(y2 * self.screen_height) - logger.info( - f"MAA滑动: ({x1_coord},{y1_coord}) -> ({x2_coord},{y2_coord})" - ) - self._ctrl.post_swipe( - x1_coord, y1_coord, x2_coord, y2_coord, duration - ).wait() + logger.info(f"MAA滑动: ({x1_coord},{y1_coord}) -> ({x2_coord},{y2_coord})") + self._ctrl.post_swipe(x1_coord, y1_coord, x2_coord, y2_coord, duration).wait() except Exception as e: logger.error(f"MAA滑动失败: {e}") def get_device_list(self) -> list[str]: try: from maa.toolkit import AdbDevice - devices = AdbDevice.find() if devices: return [d.name for d in devices] @@ -381,13 +321,7 @@ def get_device_list(self) -> list[str]: logger.debug("MAA AdbDevice.find()失败,降级到subprocess") try: device_cmd = f"{self._config.adb_path} devices" - result = subprocess.run( - device_cmd, - shell=True, - capture_output=True, - text=True, - timeout=5, - ) + result = subprocess.run(device_cmd, shell=True, capture_output=True, text=True, timeout=5) devices = [] for line in result.stdout.split("\n"): if "\tdevice" in line: @@ -417,10 +351,9 @@ def set_config(self, config: MaaConnectionConfig): class AdbConnectorAdapter: - def __init__(self, adb_path: str = r".\vendor\bin\platform-tools\adb.exe"): - from src.data import load_data - - self._legacy_connector = load_data.AdbConnector() + def __init__(self, adb_path: str = r".\platform-tools\adb.exe"): + import loadData + self._legacy_connector = loadData.AdbConnector() self._maa_connector: MaaAdbConnector | None = None self._use_maa: bool = False self._maa_config = MaaConnectionConfig(adb_path=adb_path) @@ -523,10 +456,7 @@ def connect(self): if MaaFrameworkDetector.is_available(): try: maa_connector = MaaAdbConnector(self._maa_config) - maa_connector.device_serial = ( - self._legacy_connector.device_serial - or self._maa_config.device_serial - ) + maa_connector.device_serial = self._legacy_connector.device_serial or self._maa_config.device_serial maa_connector.connect() if maa_connector.is_connected: self._maa_connector = maa_connector @@ -557,12 +487,7 @@ def click(self, point: tuple[float, float]): else: self._legacy_connector.click(point) - def swipe( - self, - start: tuple[float, float], - end: tuple[float, float], - duration: int = 500, - ): + def swipe(self, start: tuple[float, float], end: tuple[float, float], duration: int = 500): if self._use_maa and self._maa_connector: self._maa_connector.swipe(start, end, duration) else: diff --git a/vendor/bin/maafw/DirectML.dll b/maafw/DirectML.dll similarity index 100% rename from vendor/bin/maafw/DirectML.dll rename to maafw/DirectML.dll diff --git a/vendor/bin/maafw/MaaAdbControlUnit.dll b/maafw/MaaAdbControlUnit.dll similarity index 100% rename from vendor/bin/maafw/MaaAdbControlUnit.dll rename to maafw/MaaAdbControlUnit.dll diff --git a/vendor/bin/maafw/MaaAgentClient.dll b/maafw/MaaAgentClient.dll similarity index 100% rename from vendor/bin/maafw/MaaAgentClient.dll rename to maafw/MaaAgentClient.dll diff --git a/vendor/bin/maafw/MaaAgentServer.dll b/maafw/MaaAgentServer.dll similarity index 100% rename from vendor/bin/maafw/MaaAgentServer.dll rename to maafw/MaaAgentServer.dll diff --git a/vendor/bin/maafw/MaaCustomControlUnit.dll b/maafw/MaaCustomControlUnit.dll similarity index 100% rename from vendor/bin/maafw/MaaCustomControlUnit.dll rename to maafw/MaaCustomControlUnit.dll diff --git a/vendor/bin/maafw/MaaFramework.dll b/maafw/MaaFramework.dll similarity index 100% rename from vendor/bin/maafw/MaaFramework.dll rename to maafw/MaaFramework.dll diff --git a/vendor/bin/maafw/MaaGamepadControlUnit.dll b/maafw/MaaGamepadControlUnit.dll similarity index 100% rename from vendor/bin/maafw/MaaGamepadControlUnit.dll rename to maafw/MaaGamepadControlUnit.dll diff --git a/vendor/bin/maafw/MaaNode.node b/maafw/MaaNode.node similarity index 100% rename from vendor/bin/maafw/MaaNode.node rename to maafw/MaaNode.node diff --git a/vendor/bin/maafw/MaaNodeServer.node b/maafw/MaaNodeServer.node similarity index 100% rename from vendor/bin/maafw/MaaNodeServer.node rename to maafw/MaaNodeServer.node diff --git a/vendor/bin/maafw/MaaPiCli.exe b/maafw/MaaPiCli.exe similarity index 100% rename from vendor/bin/maafw/MaaPiCli.exe rename to maafw/MaaPiCli.exe diff --git a/vendor/bin/maafw/MaaRecordControlUnit.dll b/maafw/MaaRecordControlUnit.dll similarity index 100% rename from vendor/bin/maafw/MaaRecordControlUnit.dll rename to maafw/MaaRecordControlUnit.dll diff --git a/vendor/bin/maafw/MaaReplayControlUnit.dll b/maafw/MaaReplayControlUnit.dll similarity index 100% rename from vendor/bin/maafw/MaaReplayControlUnit.dll rename to maafw/MaaReplayControlUnit.dll diff --git a/vendor/bin/maafw/MaaToolkit.dll b/maafw/MaaToolkit.dll similarity index 100% rename from vendor/bin/maafw/MaaToolkit.dll rename to maafw/MaaToolkit.dll diff --git a/vendor/bin/maafw/MaaUtils.dll b/maafw/MaaUtils.dll similarity index 100% rename from vendor/bin/maafw/MaaUtils.dll rename to maafw/MaaUtils.dll diff --git a/vendor/bin/maafw/MaaWin32ControlUnit.dll b/maafw/MaaWin32ControlUnit.dll similarity index 100% rename from vendor/bin/maafw/MaaWin32ControlUnit.dll rename to maafw/MaaWin32ControlUnit.dll diff --git a/vendor/bin/maafw/ViGEmClient.dll b/maafw/ViGEmClient.dll similarity index 100% rename from vendor/bin/maafw/ViGEmClient.dll rename to maafw/ViGEmClient.dll diff --git a/vendor/bin/maafw/fastdeploy_ppocr_maa.dll b/maafw/fastdeploy_ppocr_maa.dll similarity index 100% rename from vendor/bin/maafw/fastdeploy_ppocr_maa.dll rename to maafw/fastdeploy_ppocr_maa.dll diff --git a/vendor/bin/maafw/onnxruntime_maa.dll b/maafw/onnxruntime_maa.dll similarity index 100% rename from vendor/bin/maafw/onnxruntime_maa.dll rename to maafw/onnxruntime_maa.dll diff --git a/vendor/bin/maafw/opencv_world4_maa.dll b/maafw/opencv_world4_maa.dll similarity index 100% rename from vendor/bin/maafw/opencv_world4_maa.dll rename to maafw/opencv_world4_maa.dll diff --git a/vendor/bin/maafw/plugins/MaaPluginDemo.dll b/maafw/plugins/MaaPluginDemo.dll similarity index 100% rename from vendor/bin/maafw/plugins/MaaPluginDemo.dll rename to maafw/plugins/MaaPluginDemo.dll diff --git a/main.py b/main.py index af13f4c..85a35e4 100644 --- a/main.py +++ b/main.py @@ -8,54 +8,27 @@ import numpy as np from pathlib import Path import onnxruntime # workaround: Pre-import to avoid ImportError: DLL load failed while importing onnxruntime_pybind11_state: 动态链接库(DLL)初始化例程失败。 -from PyQt6.QtWidgets import ( - QApplication, - QMainWindow, - QWidget, - QVBoxLayout, - QHBoxLayout, -) -from PyQt6.QtWidgets import ( - QLabel, - QPushButton, - QLineEdit, - QCheckBox, - QComboBox, - QButtonGroup, -) -from PyQt6.QtWidgets import ( - QGroupBox, - QMessageBox, - QGraphicsDropShadowEffect, - QFrame, -) -from PyQt6.QtCore import ( - Qt, - pyqtSignal, - QThread, - QPropertyAnimation, - QEasingCurve, -) +from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout +from PyQt6.QtWidgets import QLabel, QPushButton, QLineEdit, QCheckBox, QComboBox, QButtonGroup +from PyQt6.QtWidgets import QGroupBox, QMessageBox, QGraphicsDropShadowEffect, QFrame +from PyQt6.QtCore import Qt, pyqtSignal, QThread, QPropertyAnimation, QEasingCurve from PyQt6.QtGui import QPixmap, QFont, QIcon, QPainter, QColor import PyQt6.QtCore as QtCore -from src.data import load_data -from src.game import auto_fetch -from src.game.maa_adb_connector import ( - AdbConnectorAdapter, - ConnectionTypeRegistry, - InputMethodRegistry, -) -from src.ui.dark_mode_style_fix import DarkModeStyleFix -from src.analysis import similar_history_match -from src.recognition import recognize -from src.recognition.recognize import MONSTER_COUNT -from src.recognition.specialmonster import SpecialMonsterHandler -from src.data import data_package -from src.game import winrt_capture -from src.core.config import MONSTER_DATA -from src.ui.similar_history_match_ui import HistoryMatchUI -from src.ui.input_panel_ui import InputPanelUI +import loadData +import auto_fetch +import maa_adb_connector +from maa_adb_connector import AdbConnectorAdapter, ConnectionTypeRegistry, InputMethodRegistry, MaaFrameworkDetector +from dark_mode_style_fix import DarkModeStyleFix +import similar_history_match +import recognize +from recognize import MONSTER_COUNT +from specialmonster import SpecialMonsterHandler +import data_package +import winrt_capture +from config import FIELD_FEATURE_COUNT, MONSTER_DATA +from simular_history_match_ui import HistoryMatchUI +from input_panel_ui import InputPanelUI logging.getLogger().setLevel(logging.DEBUG) logging.getLogger("PIL").setLevel(logging.INFO) @@ -70,18 +43,19 @@ try: - from src.models.predict import CannotModel + from predict import CannotModel + from train import UnitAwareTransformer logger.info("Using PyTorch model for predictions.") except: - from src.models.predict_onnx import CannotModel + from predict_onnx import CannotModel logger.info("Using ONNX model for predictions.") class ADBConnectorThread(QThread): """ - Worker thread to run load_data.AdbConnector.connect() without blocking the UI. + Worker thread to run loadData.AdbConnector.connect() without blocking the UI. """ connect_finished = pyqtSignal() @@ -94,7 +68,6 @@ def run(self): self.app.adb_connector.connect() self.connect_finished.emit() - class ArknightsApp(QMainWindow): # 添加自定义信号 update_button_signal = pyqtSignal(str) # 用于更新按钮文本 @@ -125,11 +98,9 @@ def __init__(self): # 尝试连接模拟器 self.adb_connector = AdbConnectorAdapter() - self.pc_connector = load_data.PcConnector() + self.pc_connector = loadData.PcConnector() self.adb_connector_thread = ADBConnectorThread(self) - self.adb_connector_thread.connect_finished.connect( - self.on_adb_connected - ) + self.adb_connector_thread.connect_finished.connect(self.on_adb_connected) self.adb_connector_thread.start() self.auto_fetch_running = False @@ -148,16 +119,10 @@ def __init__(self): self.history_match = similar_history_match.HistoryMatch() # Ensure feat_past and N_history are initialized try: - self.history_match.feat_past = np.hstack( - [self.history_match.past_left, self.history_match.past_right] - ) + self.history_match.feat_past = np.hstack([self.history_match.past_left, self.history_match.past_right]) except Exception: self.history_match.feat_past = None - self.history_match.N_history = ( - 0 - if self.history_match.labels is None - else len(self.history_match.labels) - ) + self.history_match.N_history = 0 if self.history_match.labels is None else len(self.history_match.labels) logger.info("错题本加载成功") # 初始化特殊怪物语言触发处理程序 @@ -170,9 +135,7 @@ def __init__(self): self.recognize_button.setEnabled(False) self.recognize_button.setToolTip("模型未加载,无法使用此功能") self.input_panel.predict_button.setEnabled(False) - self.input_panel.predict_button.setToolTip( - "模型未加载,无法使用此功能" - ) + self.input_panel.predict_button.setToolTip("模型未加载,无法使用此功能") def init_ui(self): try: @@ -181,19 +144,13 @@ def init_ui(self): version = pyproject_data["project"]["version"] except (FileNotFoundError, KeyError): version = "unknown" - model_name = ( - Path(self.cannot_model.model_path).name - if self.cannot_model.model_path - else "未加载" - ) - self.setWindowTitle( - f"铁鲨鱼_Arknights Neural Network - v{version} - model: {model_name}" - ) - self.setWindowIcon(QIcon("src/resources/assets/icons/icon.ico")) + model_name = Path(self.cannot_model.model_path).name if self.cannot_model.model_path else "未加载" + self.setWindowTitle(f"铁鲨鱼_Arknights Neural Network - v{version} - model: {model_name}") + self.setWindowIcon(QIcon("ico/icon.ico")) self.setGeometry(100, 100, 500, 580) self.setMinimumWidth(580) self.setMaximumWidth(580) - self.background = QPixmap("src/resources/assets/icons/background.png") + self.background = QPixmap("ico/background.png") # 初始化动画对象 self.size_animation = QPropertyAnimation(self, b"size") @@ -220,7 +177,8 @@ def init_ui(self): # 顶部区域 - 输入显示 input_display = QGroupBox() - input_display.setStyleSheet(""" + input_display.setStyleSheet( + """ QGroupBox { background-color: rgba(0, 0, 0, 120); border-radius: 15px; @@ -234,7 +192,8 @@ def init_ui(self): left: 15px; padding: 0 5px; } - """) + """ + ) input_layout = QHBoxLayout(input_display) # 左侧人物显示 @@ -261,13 +220,15 @@ def init_ui(self): # 中部区域 - 预测结果 result_group = QGroupBox() - result_group.setStyleSheet(""" + result_group.setStyleSheet( + """ QGroupBox { background-color: rgba(120, 120, 120, 10); border-radius: 15px; border: 1px solid #747474; } - """) + """ + ) result_layout = QVBoxLayout(result_group) result_layout.setSpacing(10) result_layout.setContentsMargins(10, 10, 10, 10) @@ -279,16 +240,10 @@ def init_ui(self): result_layout.addWidget(self.result_label) # 添加模型名称显示 - model_name = ( - Path(self.cannot_model.model_path).name - if self.cannot_model.model_path - else "未加载" - ) + model_name = Path(self.cannot_model.model_path).name if self.cannot_model.model_path else "未加载" self.model_name_label = QLabel(f"model: {model_name}") self.model_name_label.setFont(QFont("Microsoft YaHei", 8)) - self.model_name_label.setAlignment( - Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignBottom - ) + self.model_name_label.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignBottom) self.model_name_label.setStyleSheet("color: #666666;") result_layout.addWidget(self.model_name_label) @@ -430,9 +385,7 @@ def init_ui(self): self.connection_type_combo = QComboBox() for ct in ConnectionTypeRegistry.get_all_types(): self.connection_type_combo.addItem(ct.display_name, ct.type_id) - self.connection_type_combo.currentIndexChanged.connect( - self.on_connection_type_changed - ) + self.connection_type_combo.currentIndexChanged.connect(self.on_connection_type_changed) self.input_method_label = QLabel("输入方式:") self.input_method_combo = QComboBox() @@ -442,9 +395,7 @@ def init_ui(self): idx = self.input_method_combo.findData(default_method.method_id) if idx >= 0: self.input_method_combo.setCurrentIndex(idx) - self.input_method_combo.currentIndexChanged.connect( - self.on_input_method_changed - ) + self.input_method_combo.currentIndexChanged.connect(self.on_input_method_changed) maa_row_layout.addWidget(self.connection_type_label) maa_row_layout.addWidget(self.connection_type_combo) @@ -580,9 +531,7 @@ def animate_size_change(self, target_width, target_height=None): self.setMaximumWidth(max(self.width(), target_width)) self.size_animation.setStartValue(self.size()) - self.size_animation.setEndValue( - QtCore.QSize(target_width, target_height) - ) + self.size_animation.setEndValue(QtCore.QSize(target_width, target_height)) self.size_animation.start() def set_fixed_after_animation(): @@ -601,14 +550,14 @@ def on_mode_changed(self, mode): self.current_capture_mode = mode logger.info(f"切换捕获模式为: {mode}") - is_win_mode = mode == "WIN" - is_adb_mode = mode == "ADB" - is_pc_mode = mode == "PC" + is_win_mode = (mode == "WIN") + is_adb_mode = (mode == "ADB") + is_pc_mode = (mode == "PC") # 切换窗口捕获相关控件 self.choose_window_button.setEnabled(is_win_mode) self.reselect_button.setEnabled(is_win_mode) - + # 切换 ADB 相关控件 self.serial_label.setEnabled(is_adb_mode) self.serial_entry.setEnabled(is_adb_mode) @@ -629,30 +578,20 @@ def on_mode_changed(self, mode): if self.recognizer._winrt is None: self.choose_capture_window() elif mode == "PC": - self.recognizer = recognize.RecognizeMonster( - method="ADB" - ) # reuse ADB reading methodology but on PC Connector + self.recognizer = recognize.RecognizeMonster(method="ADB") # reuse ADB reading methodology but on PC Connector if not self.pc_connector.is_connected: self.pc_connector.connect() if not self.pc_connector.is_connected: - QMessageBox.warning( - self, "警告", "未能连接到PC端窗口(明日方舟)。" - ) + QMessageBox.warning(self, "警告", "未能连接到PC端窗口(明日方舟)。") def on_adb_connected(self): logger.info("模拟器初始化完成") if self.adb_connector.is_maa_available: self.maa_status_label.setText("MAA Framework已连接") - self.maa_status_label.setStyleSheet( - "color: #00aa00; font-size: 10px;" - ) + self.maa_status_label.setStyleSheet("color: #00aa00; font-size: 10px;") else: - self.maa_status_label.setText( - "使用自有ADB实现(MAA Framework不可用)" - ) - self.maa_status_label.setStyleSheet( - "color: #996600; font-size: 10px;" - ) + self.maa_status_label.setText("使用自有ADB实现(MAA Framework不可用)") + self.maa_status_label.setStyleSheet("color: #996600; font-size: 10px;") def on_connection_type_changed(self, index): type_id = self.connection_type_combo.currentData() @@ -666,9 +605,7 @@ def on_connection_type_changed(self, index): if self.adb_connector.is_connected: self.adb_connector.disconnect() self.maa_status_label.setText("已断开,请重新连接") - self.maa_status_label.setStyleSheet( - "color: #aa0000; font-size: 10px;" - ) + self.maa_status_label.setStyleSheet("color: #aa0000; font-size: 10px;") def on_input_method_changed(self, index): method_id = self.input_method_combo.currentData() @@ -676,9 +613,7 @@ def on_input_method_changed(self, index): return self.adb_connector.set_input_method(method_id) if self.adb_connector.is_connected: - QMessageBox.information( - self, "提示", "输入方式已更改,请重新连接以生效" - ) + QMessageBox.information(self, "提示", "输入方式已更改,请重新连接以生效") def choose_capture_window(self): """弹出窗口选择器,切换 WinRT 截屏源(窗口标题或整屏)。""" @@ -702,32 +637,20 @@ def choose_capture_window(self): return hint = "" if "window_name" in sel: - self.recognizer = recognize.RecognizeMonster( - method="WIN", - window_name=sel["window_name"], - monitor_index=None, - ) + self.recognizer = recognize.RecognizeMonster(method="WIN", window_name=sel["window_name"], monitor_index=None) hint = f"已切换至窗口:{sel['window_name']}" else: idx = max(1, sel["monitor_index"]) - self.recognizer = recognize.RecognizeMonster( - method="WIN", window_name=None, monitor_index=idx - ) + self.recognizer = recognize.RecognizeMonster(method="WIN", window_name=None, monitor_index=idx) hint = f"已切换至整屏:显示器 {sel['monitor_index']}" self.no_region = True - QMessageBox.information( - self, "成功", hint + "\n建议重新选择范围。" - ) + QMessageBox.information(self, "成功", hint + "\n建议重新选择范围。") except Exception as e: - QMessageBox.critical( - self, "异常", f"{e}\n\n{traceback.format_exc()}" - ) + QMessageBox.critical(self, "异常", f"{e}\n\n{traceback.format_exc()}") finally: self._switching_source = False - self.choose_window_button.setEnabled( - self.current_capture_mode == "WIN" - ) + self.choose_window_button.setEnabled(self.current_capture_mode == "WIN") def paintEvent(self, event): painter = QPainter(self) @@ -745,9 +668,7 @@ def paintEvent(self, event): ) def update_input_display(self): - left_monsters_dict, right_monsters_dict = ( - self.input_panel.get_monster_counts() - ) + left_monsters_dict, right_monsters_dict = self.input_panel.get_monster_counts() def update_input_display_half(input_layout, monsters_dict): # 清除现有显示 @@ -760,9 +681,7 @@ def update_input_display_half(input_layout, monsters_dict): value = monsters_dict[str(i)].text() if value.isdigit() and int(value) > 0: has_input = True - monster_widget = self.create_monster_display_widget( - i, value - ) + monster_widget = self.create_monster_display_widget(i, value) input_layout.addWidget(monster_widget) # 如果没有输入,显示提示 if not has_input: @@ -781,11 +700,13 @@ def create_monster_display_widget(self, monster_id, count): shadow.setOffset(2) # 偏移量(0表示均匀四周发光) widget.setGraphicsEffect(shadow) - widget.setStyleSheet(""" + widget.setStyleSheet( + """ QWidget { border-radius: 0px; } - """) + """ + ) layout = QVBoxLayout(widget) layout.setSpacing(2) @@ -798,15 +719,10 @@ def create_monster_display_widget(self, monster_id, count): img_label.setAlignment(Qt.AlignmentFlag.AlignCenter) try: - pixmap = QPixmap( - f"src/resources/assets/images/{MONSTER_DATA['原始名称'][monster_id]}.png" - ) + pixmap = QPixmap(f"images/{MONSTER_DATA['原始名称'][monster_id]}.png") if not pixmap.isNull(): pixmap = pixmap.scaled( - 70, - 70, - Qt.AspectRatioMode.KeepAspectRatio, - Qt.TransformationMode.SmoothTransformation, + 70, 70, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation ) img_label.setPixmap(pixmap) except Exception as e: @@ -824,13 +740,15 @@ def create_monster_display_widget(self, monster_id, count): # 数量标签 count_label = QLabel(count) count_label.setAlignment(Qt.AlignmentFlag.AlignCenter) - count_label.setStyleSheet(""" + count_label.setStyleSheet( + """ color: #EDEDED; font: bold 20px SimHei; border-radius: 5px; padding: 2px 5px; min-width: 20px; - """) + """ + ) layout.addWidget(img_label) layout.addWidget(count_label) @@ -844,40 +762,28 @@ def reset_entries(self): def get_prediction(self): try: - left_monsters_dict, right_monsters_dict = ( - self.input_panel.get_monster_counts() - ) + left_monsters_dict, right_monsters_dict = self.input_panel.get_monster_counts() left_counts = np.zeros(MONSTER_COUNT, dtype=np.int16) right_counts = np.zeros(MONSTER_COUNT, dtype=np.int16) for name, entry in left_monsters_dict.items(): value = entry.text() - left_counts[int(name) - 1] = ( - int(value) if value.isdigit() else 0 - ) + left_counts[int(name) - 1] = int(value) if value.isdigit() else 0 for name, entry in right_monsters_dict.items(): value = entry.text() - right_counts[int(name) - 1] = ( - int(value) if value.isdigit() else 0 - ) + right_counts[int(name) - 1] = int(value) if value.isdigit() else 0 # 构建包含地形的完整特征向量 - full_features = self.input_panel.build_terrain_features( - left_counts, right_counts - ) + full_features = self.input_panel.build_terrain_features(left_counts, right_counts) - prediction = self.cannot_model.get_prediction_with_terrain( - full_features - ) + prediction = self.cannot_model.get_prediction_with_terrain(full_features) return prediction except FileNotFoundError: QMessageBox.critical(self, "错误", "未找到模型文件,请先训练") except RuntimeError as e: if "size mismatch" in str(e): - QMessageBox.critical( - self, "错误", "模型结构不匹配!请删除旧模型并重新训练" - ) + QMessageBox.critical(self, "错误", "模型结构不匹配!请删除旧模型并重新训练") else: QMessageBox.critical(self, "错误", f"模型加载失败: {str(e)}") except ValueError: @@ -904,20 +810,13 @@ def update_prediction(self, prediction): else: self.result_label.setStyleSheet("color: #25ace2; font: bold,14px;") - left_monsters_dict, right_monsters_dict = ( - self.input_panel.get_monster_counts() - ) + left_monsters_dict, right_monsters_dict = self.input_panel.get_monster_counts() # 生成结果文本 if winner != "难说": - result_text = ( - f"预测胜方: {winner}\n" - f"左 {left_win_prob:.2%} | 右 {right_win_prob:.2%}\n" - ) + result_text = f"预测胜方: {winner}\n" f"左 {left_win_prob:.2%} | 右 {right_win_prob:.2%}\n" else: result_text = ( - f"这一把{winner}\n" - f"左 {left_win_prob:.2%} | 右 {right_win_prob:.2%}\n" - f"难道说?难道说?难道说?\n" + f"这一把{winner}\n" f"左 {left_win_prob:.2%} | 右 {right_win_prob:.2%}\n" f"难道说?难道说?难道说?\n" ) self.result_label.setStyleSheet("color: black; font: bold,24px;") @@ -936,12 +835,8 @@ def predict(self): self.update_input_display() if self.history_match_ui.isVisible(): - left_monsters_dict, right_monsters_dict = ( - self.input_panel.get_monster_counts() - ) - self.history_match_ui.render_similar_matches( - left_monsters_dict, right_monsters_dict - ) + left_monsters_dict, right_monsters_dict = self.input_panel.get_monster_counts() + self.history_match_ui.render_similar_matches(left_monsters_dict, right_monsters_dict) def get_recognize(self): """ @@ -956,7 +851,7 @@ def get_recognize(self): screenshot = self.active_connector.capture_screenshot() if screenshot is None: logger.error(f"{self.current_capture_mode} 截图失败") - + results = self.recognizer.process_regions(screenshot) else: # WIN 模式,recognizer 内部处理 WinRT 或 PIL @@ -993,32 +888,22 @@ def recognize_and_predict(self): self.update_prediction(prediction) # 历史对局 if self.history_match_ui.isVisible(): - left_monsters_dict, right_monsters_dict = ( - self.input_panel.get_monster_counts() - ) - self.history_match_ui.render_similar_matches( - left_monsters_dict, right_monsters_dict - ) + left_monsters_dict, right_monsters_dict = self.input_panel.get_monster_counts() + self.history_match_ui.render_similar_matches(left_monsters_dict, right_monsters_dict) def toggle_history_panel(self): """切换历史对局面板的显示""" target_width = self.width() if self.history_match is None: - QMessageBox.warning( - self, "警告", "历史数据加载失败,无法显示历史对局" - ) + QMessageBox.warning(self, "警告", "历史数据加载失败,无法显示历史对局") return is_visible = self.history_match_ui.isVisible() self.history_match_ui.setVisible(not is_visible) if not is_visible: self.history_button.setText("隐藏历史对局") - left_monsters_dict, right_monsters_dict = ( - self.input_panel.get_monster_counts() - ) - self.history_match_ui.render_similar_matches( - left_monsters_dict, right_monsters_dict - ) + left_monsters_dict, right_monsters_dict = self.input_panel.get_monster_counts() + self.history_match_ui.render_similar_matches(left_monsters_dict, right_monsters_dict) target_width += 540 else: self.history_button.setText("显示历史对局") @@ -1029,9 +914,7 @@ def reselect_roi(self): self.recognizer.select_roi() def toggle_auto_fetch(self): - if not ( - hasattr(self, "auto_fetch") and self.auto_fetch.auto_fetch_running - ): + if not (hasattr(self, "auto_fetch") and self.auto_fetch.auto_fetch_running): self.auto_fetch = auto_fetch.AutoFetch( self.active_connector, self.game_mode, @@ -1041,8 +924,7 @@ def toggle_auto_fetch(self): updater=self.update_statistics_callback, start_callback=self.start_callback, stop_callback=self.stop_callback, - training_duration=float(self.duration_entry.text()) - * 3600, # 获取训练时长 + training_duration=float(self.duration_entry.text()) * 3600, # 获取训练时长 recognizer=self.recognizer, cannot_model=self.cannot_model, ) @@ -1051,11 +933,7 @@ def toggle_auto_fetch(self): self.auto_fetch.stop_auto_fetch() def update_statistics(self): - elapsed_time = ( - time.time() - self.auto_fetch.start_time - if self.auto_fetch.start_time - else 0 - ) + elapsed_time = time.time() - self.auto_fetch.start_time if self.auto_fetch.start_time else 0 hours, remainder = divmod(elapsed_time, 3600) minutes, _ = divmod(remainder, 60) stats_text = ( @@ -1078,18 +956,14 @@ def refresh_device_list(self): self.serial_entry.setCurrentIndex(0) else: self.serial_entry.addItem("127.0.0.1:5555") - self.serial_entry.setCurrentText( - current_text if current_text else "127.0.0.1:5555" - ) + self.serial_entry.setCurrentText(current_text if current_text else "127.0.0.1:5555") def update_device_serial(self): new_serial = self.serial_entry.currentText() device_serial = self.adb_connector.update_device_serial(new_serial) self.adb_connector.connect() # 尝试连接新设备 self.serial_entry.setCurrentText(device_serial) - QMessageBox.information( - self, "提示", f"已更新模拟器序列号为: {device_serial}" - ) + QMessageBox.information(self, "提示", f"已更新模拟器序列号为: {device_serial}") def start_callback(self): self.update_button_signal.emit("停止自动获取数据") @@ -1113,9 +987,7 @@ def run_simulation(self): left_monsters_data = {} right_monsters_data = {} - left_monsters_dict, right_monsters_dict = ( - self.input_panel.get_monster_counts() - ) + left_monsters_dict, right_monsters_dict = self.input_panel.get_monster_counts() # 获取左侧怪物信息 for monster_id, entry in left_monsters_dict.items(): @@ -1131,9 +1003,7 @@ def run_simulation(self): except ValueError: logger.error(f"Invalid monster ID: {monster_id}") except Exception as e: - logger.error( - f"Error getting monster name for ID {monster_id}: {e}" - ) + logger.error(f"Error getting monster name for ID {monster_id}: {e}") # 获取右侧怪物信息 for monster_id, entry in right_monsters_dict.items(): @@ -1145,20 +1015,13 @@ def run_simulation(self): if monster_name: right_monsters_data[monster_name] = int(count) else: - logger.error( - f"Monster name not found for ID {monster_id}" - ) + logger.error(f"Monster name not found for ID {monster_id}") except ValueError: logger.error(f"Invalid monster ID: {monster_id}") except Exception as e: - logger.error( - f"Error getting monster name for ID {monster_id}: {e}" - ) + logger.error(f"Error getting monster name for ID {monster_id}: {e}") - simulation_data = { - "left": left_monsters_data, - "right": right_monsters_data, - } + simulation_data = {"left": left_monsters_data, "right": right_monsters_data} json_data = json.dumps(simulation_data, ensure_ascii=False) logger.info(f"Simulation data JSON: {json_data}") @@ -1167,40 +1030,29 @@ def run_simulation(self): # 启动main_sim.py子进程 (非阻塞) # Use sys.executable to ensure the same Python interpreter is used process = subprocess.Popen( - [sys.executable, "main_sim.py"], - stdin=subprocess.PIPE, - text=True, - encoding="utf-8", + [sys.executable, "main_sim.py"], stdin=subprocess.PIPE, text=True, encoding="utf-8" ) # 通过stdin传递JSON数据并关闭stdin process.stdin.write(json_data) process.stdin.close() except FileNotFoundError: - QMessageBox.critical( - self, "错误", "未找到 main_sim.py 文件,请检查路径。" - ) + QMessageBox.critical(self, "错误", "未找到 main_sim.py 文件,请检查路径。") except Exception as e: - QMessageBox.critical( - self, "错误", f"启动模拟器时发生错误: {str(e)}" - ) + QMessageBox.critical(self, "错误", f"启动模拟器时发生错误: {str(e)}") def get_monster_name_by_id(self, monster_id: int): """根据怪物ID获取怪物名称""" - # Need to import MONSTER_MAPPING from src.simulation.utils + # Need to import MONSTER_MAPPING from simulator.utils try: - from src.simulation.utils import MONSTER_MAPPING + from simulator.utils import MONSTER_MAPPING # Adjust for 1-based UI IDs vs 0-based mapping keys monster_name = MONSTER_MAPPING.get(monster_id - 1) if not monster_name: - logger.error( - f"Monster ID {monster_id} not found in MONSTER_MAPPING." - ) + logger.error(f"Monster ID {monster_id} not found in MONSTER_MAPPING.") return monster_name except ImportError: - logger.error( - "Error importing MONSTER_MAPPING from src.simulation.utils" - ) + logger.error("Error importing MONSTER_MAPPING from simulator.utils") return None def update_game_mode(self, mode): @@ -1219,9 +1071,7 @@ def update_stats(self, total, incorrect, duration): def update_image_display(self, qimage): self.image_display.setPixmap( QPixmap.fromImage(qimage).scaled( - self.image_display.width(), - self.image_display.height(), - Qt.AspectRatioMode.KeepAspectRatio, + self.image_display.width(), self.image_display.height(), Qt.AspectRatioMode.KeepAspectRatio ) ) @@ -1231,28 +1081,21 @@ def package_data_and_show(self): if zip_filename: # 在文件浏览器中高亮显示文件 subprocess.run(f'explorer /select,"{zip_filename}"') - QMessageBox.information( - self, "成功", f"数据已打包到 {zip_filename}" - ) + QMessageBox.information(self, "成功", f"数据已打包到 {zip_filename}") else: - QMessageBox.warning( - self, "警告", "没有找到可以打包的数据目录。" - ) + QMessageBox.warning(self, "警告", "没有找到可以打包的数据目录。") except Exception as e: QMessageBox.critical(self, "错误", f"打包数据时发生错误: {str(e)}") + def toggle_always_on_top(self): if self.windowFlags() & Qt.WindowType.WindowStaysOnTopHint: - self.setWindowFlags( - self.windowFlags() & ~Qt.WindowType.WindowStaysOnTopHint - ) + self.setWindowFlags(self.windowFlags() & ~Qt.WindowType.WindowStaysOnTopHint) self.always_on_top_button.setText("窗口置顶") else: - self.setWindowFlags( - self.windowFlags() | Qt.WindowType.WindowStaysOnTopHint - ) + self.setWindowFlags(self.windowFlags() | Qt.WindowType.WindowStaysOnTopHint) self.always_on_top_button.setText("取消置顶") - self.show() # Reapply window flags + self.show() # Reapply window flags def closeEvent(self, event): """窗口关闭时的处理""" diff --git a/main.spec b/main.spec index 924881c..05b2505 100644 --- a/main.spec +++ b/main.spec @@ -11,8 +11,6 @@ a_main = Analysis( pathex=[project_root], binaries=[], datas=[ - ('src', 'src'), - ('vendor', 'vendor'), ('.venv/Lib/site-packages/rapidocr/default_models.yaml', 'rapidocr'), ('.venv/Lib/site-packages/rapidocr/config.yaml', 'rapidocr'), ('.venv/Lib/site-packages/rapidocr/models', 'rapidocr/models') @@ -21,7 +19,7 @@ a_main = Analysis( hookspath=[], hooksconfig={}, runtime_hooks=[], - excludes=['torch', 'torchvision', 'matplotlib', 'sklearn', 'scikit-learn', 'scipy', 'PyQt6.QtPdf', 'PyQt6.QtNetwork', 'predict', 'onnxscript'], + excludes=['train', 'torch', 'torchvision', 'matplotlib', 'sklearn', 'scikit-learn', 'scipy', 'PyQt6.QtPdf', 'PyQt6.QtNetwork', 'predict', 'onnxscript'], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, @@ -42,7 +40,7 @@ exe_main = EXE( a_main.scripts, [], exclude_binaries=True, - name='CannotMax', + name='main', debug=False, bootloader_ignore_signals=False, strip=False, @@ -53,7 +51,7 @@ exe_main = EXE( target_arch=None, codesign_identity=None, entitlements_file=None, - icon=['src\\resources\\assets\\icons\\icon_64x64.ico'], + icon=['ico\\icon_64x64.ico'], ) # 多开管理器分析 @@ -62,8 +60,6 @@ a_multi = Analysis( pathex=[project_root], binaries=[], datas=[ - ('src', 'src'), - ('vendor', 'vendor'), ('.venv/Lib/site-packages/rapidocr/default_models.yaml', 'rapidocr'), ('.venv/Lib/site-packages/rapidocr/config.yaml', 'rapidocr'), ('.venv/Lib/site-packages/rapidocr/models', 'rapidocr/models') @@ -72,7 +68,7 @@ a_multi = Analysis( hookspath=[], hooksconfig={}, runtime_hooks=[], - excludes=['torch', 'torchvision', 'matplotlib', 'sklearn', 'scikit-learn', 'scipy', 'PyQt6.QtPdf', 'PyQt6.QtNetwork', 'predict', 'onnxscript'], + excludes=['train', 'torch', 'torchvision', 'matplotlib', 'sklearn', 'scikit-learn', 'scipy', 'PyQt6.QtPdf', 'PyQt6.QtNetwork', 'predict', 'onnxscript'], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, @@ -100,7 +96,7 @@ exe_multi = EXE( target_arch=None, codesign_identity=None, entitlements_file=None, - icon=['src\\resources\\assets\\icons\\icon_64x64.ico'], + icon=['ico\\icon_64x64.ico'], ) coll = COLLECT( diff --git a/main_old.py b/main_old.py new file mode 100644 index 0000000..89d18ed --- /dev/null +++ b/main_old.py @@ -0,0 +1,650 @@ +import logging +import subprocess +import threading +import time +import tkinter as tk +from tkinter import messagebox +import numpy as np +import math +from PIL import Image, ImageTk +from predict import CannotModel +import loadData +import recognize +from train import UnitAwareTransformer +from recognize import MONSTER_COUNT +from similar_history_match import HistoryMatch +from auto_fetch import AutoFetch + +logging.getLogger().setLevel(logging.DEBUG) +logging.getLogger("PIL").setLevel(logging.INFO) +stream_handler = logging.StreamHandler() +formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s",) +stream_handler.setFormatter(formatter) +logging.getLogger().addHandler(stream_handler) +logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) + + +class ArknightsApp: + def __init__(self, root): + self.root = root + self.root.title("Arknights Neural Network") + self.history_match = HistoryMatch() + + self.main_panel = tk.Frame(self.root) + self.main_panel.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + + # 鼠标滚轮滚动历史面板 + self.root.bind_all("", self._on_mousewheel) + self.root.bind_all("", self._on_shift_mousewheel) + # 运行 + self.no_region = True + self.first_recognize = True + + # 尝试连接模拟器 + self.adb_connector = loadData.AdbConnector() + self.adb_connector.connect() + + # 用户选项 + self.is_invest = tk.BooleanVar(value=False) # 添加投资状态变量 + self.game_mode = tk.StringVar(value="单人") # 添加游戏模式变量,默认单人模式 + self.device_serial = tk.StringVar(value="127.0.0.1:5555") # 添加设备序列号变量 + + # 数据缓存 + self.left_monsters = {} + self.right_monsters = {} + self.images = {} + self.progress_var = tk.StringVar() + + self.load_images() + self.create_widgets() + + # 怪物识别模块 + self.recognizer = recognize.RecognizeMonster() + + # 历史对局面板 + self.history_visible = False + self.history_container = tk.Frame(self.root, bd=1, relief="sunken") + + # Canvas & Scrollbars + self.history_canvas = tk.Canvas(self.history_container, bg="white") + self.history_vscroll = tk.Scrollbar( + self.history_container, orient="vertical", command=self.history_canvas.yview + ) + self.history_hscroll = tk.Scrollbar( + self.history_container, orient="horizontal", command=self.history_canvas.xview + ) + + self.history_canvas.configure( + yscrollcommand=self.history_vscroll.set, xscrollcommand=self.history_hscroll.set + ) + + # 真正放内容的 Frame + self.history_frame = tk.Frame(self.history_canvas) + self.history_canvas.create_window((0, 0), window=self.history_frame, anchor="nw") + + # 更新 scroll region + self.history_frame.bind( + "", + lambda e: self.history_canvas.configure(scrollregion=self.history_canvas.bbox("all")), + ) + + # Canvas + 两条滚动条在 history_container 里排版 + self.history_canvas.grid(row=0, column=0, sticky="nsew") + self.history_vscroll.grid(row=0, column=1, sticky="ns") + self.history_hscroll.grid(row=1, column=0, sticky="ew") + + # 让 Canvas 单元格可伸缩 + self.history_container.grid_rowconfigure(0, weight=1) + self.history_container.grid_columnconfigure(0, weight=1) + + # 模型相关属性 + self.cannot_model = CannotModel() + + + def _on_mousewheel(self, event): + """滑动鼠标滚轮 → 垂直滚动错题本面板""" + self.history_canvas.yview_scroll(int(-1 * (event.delta / 120)), "units") + + def _on_shift_mousewheel(self, event): + """按住 Shift + 滚轮 → 水平滚动错题本面板""" + self.history_canvas.xview_scroll(int(-1 * (event.delta / 120)), "units") + + def load_images(self): + # 获取系统缩放因子 + scaling_factor = self.root.tk.call("tk", "scaling") + base_size = 30 + icon_size = int(base_size * scaling_factor) # 动态计算图标大小 + + for i in range(1, MONSTER_COUNT + 1): + # 使用PIL打开图像并缩放 + img = Image.open(f"images/{i}.png") + width, height = img.size + + # 计算缩放比例,保持宽高比且不超过目标尺寸 + ratio = min(icon_size / width, icon_size / height) + new_size = (int(width * ratio), int(height * ratio)) + + # 高质量缩放 + img_resized = img.resize(new_size, Image.Resampling.LANCZOS) + + # 转换为Tkinter兼容格式 + photo_img = ImageTk.PhotoImage(img_resized) + self.images[str(i)] = photo_img + + def create_widgets(self): + # 创建顶层容器 + self.top_container = tk.Frame(self.main_panel) + self.bottom_container = tk.Frame(self.main_panel) + + # 顶部容器布局(填充整个水平空间) + self.top_container.pack(side=tk.TOP, fill=tk.X, pady=10) + self.bottom_container.pack(side=tk.TOP, fill=tk.BOTH, expand=True, pady=10) + + # 创建居中容器用于放置左右怪物框 + self.monster_center = tk.Frame(self.top_container) + self.monster_center.pack(side=tk.TOP, anchor="center") + + # 创建左右怪物容器(添加边框和背景色) + self.left_frame = tk.Frame( + self.monster_center, borderwidth=2, relief="groove", padx=5, pady=5 + ) + self.right_frame = tk.Frame( + self.monster_center, borderwidth=2, relief="groove", padx=5, pady=5 + ) + + # 添加左右标题 + tk.Label(self.left_frame, text="左侧怪物", font=("Helvetica", 10, "bold")).grid( + row=0, columnspan=10 + ) + tk.Label(self.right_frame, text="右侧怪物", font=("Helvetica", 10, "bold")).grid( + row=0, columnspan=10 + ) + + # 左右布局(添加显式间距并居中) + self.left_frame.pack(side=tk.LEFT, padx=10, anchor="n", pady=5) + self.right_frame.pack(side=tk.RIGHT, padx=10, anchor="n", pady=5) + + for side, frame, monsters in [ + ("left", self.left_frame, self.left_monsters), + ("right", self.right_frame, self.right_monsters), + ]: + row_n = 6 + monsters_per_row = math.ceil(MONSTER_COUNT / row_n) + for row in range(row_n): + start = row * monsters_per_row + 1 + end = min((row + 1) * monsters_per_row + 1, MONSTER_COUNT + 1) + for i in range(start, end): + # 图片标签(缩小尺寸) + tk.Label(frame, image=self.images[str(i)], padx=1, pady=1).grid( + row=row * 2, column=i - start, sticky="ew" + ) + # 输入框(保持宽度5) + monsters[str(i)] = tk.Entry(frame, width=5) + monsters[str(i)].grid( + row=row * 2 + 1, column=i - start, pady=(0, 1) # 减小底部间距 + ) + + # 调整列权重使布局更紧凑 + for col in range(monsters_per_row): + frame.grid_columnconfigure(col, weight=1, minsize=25) # 适当调整最小列宽 + + # 结果显示区域(增加边框) + self.result_frame = tk.Frame(self.bottom_container, relief="ridge", borderwidth=1) + self.result_frame.pack(fill=tk.X, pady=5) + + # 使用更醒目的字体 + self.result_label = tk.Label( + self.result_frame, text="Prediction: ", font=("Helvetica", 16, "bold"), fg="blue" + ) + self.result_label.pack(pady=3) + self.stats_label = tk.Label(self.result_frame, text="", font=("Helvetica", 12), fg="green") + self.stats_label.pack(pady=3) + + # 按钮区域容器(增加边框和背景) + self.button_frame = tk.Frame( + self.bottom_container, relief="groove", borderwidth=2, padx=10, pady=10 + ) + self.button_frame.pack(fill=tk.BOTH, expand=True) + + # 按钮布局(分左右两列布局) + left_buttons = tk.Frame(self.button_frame) + center_buttons = tk.Frame(self.button_frame) # 新增中间按钮容器 + right_buttons = tk.Frame(self.button_frame) + + # 使用grid布局实现均匀分布 + left_buttons.grid(row=0, column=0, sticky="ew") + center_buttons.grid(row=0, column=1, sticky="ew") # 中间列 + right_buttons.grid(row=0, column=2, sticky="ew") + self.button_frame.grid_columnconfigure((0, 1, 2), weight=1) # 均匀分布三列 + + # 左侧按钮列(控制选项) + control_col = tk.Frame(left_buttons) + control_col.pack(anchor="center", expand=True) + + # 时长输入组 + duration_frame = tk.Frame(control_col) + duration_frame.pack(pady=2) + tk.Label(duration_frame, text="训练时长:").pack(side=tk.LEFT) + self.duration_entry = tk.Entry(duration_frame, width=6) + self.duration_entry.insert(0, "-1") + self.duration_entry.pack(side=tk.LEFT, padx=5) + + # 模式选择组 + mode_frame = tk.Frame(control_col) + mode_frame.pack(pady=2) + self.mode_menu = tk.OptionMenu(mode_frame, self.game_mode, "单人", "30人") + self.mode_menu.pack(side=tk.LEFT) + self.invest_checkbox = tk.Checkbutton(mode_frame, text="投资", variable=self.is_invest) + self.invest_checkbox.pack(side=tk.LEFT, padx=5) + + # 中间按钮列(核心操作) + action_col = tk.Frame(center_buttons) + action_col.pack(anchor="center", expand=True) + + # 核心操作按钮 + action_buttons = [("自动获取数据", self.toggle_auto_fetch)] + # 单独处理自动获取数据按钮 + for text, cmd in action_buttons: + btn = tk.Button(action_col, text=text, command=cmd, width=14) # 加宽按钮 + btn.pack(pady=5, ipadx=5) + if text == "自动获取数据": + self.auto_fetch_button = btn + btn.pack(pady=5, ipadx=5) + + # 右侧按钮列(功能按钮) + func_col = tk.Frame(right_buttons) + func_col.pack(anchor="center", expand=True) + + # 预测功能组 + predict_frame = tk.Frame(func_col) + predict_frame.pack(pady=2) + self.predict_button = tk.Button( + predict_frame, text="预测", command=self.predict, width=8, bg="#FFE4B5" + ) + self.predict_button.pack(side=tk.LEFT, padx=2) + + self.recognize_button = tk.Button( + predict_frame, text="识别并预测", command=self.recognize_and_predict, width=10, bg="#98FB98" + ) + self.recognize_button.pack(side=tk.LEFT, padx=2) + + self.reset_button = tk.Button( + predict_frame, text="归零", command=self.reset_entries, width=6 + ) + self.reset_button.pack(side=tk.LEFT, padx=2) + + # 设备序列号组(独立行) + serial_frame = tk.Frame(func_col) + serial_frame.pack(pady=5) + + self.reselect_button = tk.Button( + serial_frame, text="选择范围", command=self.reselect_roi, width=10 + ) + self.reselect_button.pack(side=tk.LEFT) + + tk.Label(serial_frame, text="设备号:").pack(side=tk.LEFT) + self.serial_entry = tk.Entry(serial_frame, textvariable=self.device_serial, width=15) + self.serial_entry.pack(side=tk.LEFT, padx=3) + + self.serial_button = tk.Button( + serial_frame, text="更新", command=self.update_device_serial, width=6 + ) + self.serial_button.pack(side=tk.LEFT) + + # 错题本开关 + self.history_button = tk.Button( + func_col, text="显示错题本", command=self.toggle_history_panel, width=10 + ) + self.history_button.pack(pady=4) # 可以 side=tk.TOP / BOTTOM 都行 + + def toggle_history_panel(self): + if not self.history_visible: + self.history_container.pack(side="right", fill="both", padx=5, pady=5) + self.history_button.config(text="隐藏错题本") + for w in self.history_frame.winfo_children(): + w.destroy() + self.render_history(self.history_frame) + self.history_canvas.configure(scrollregion=self.history_canvas.bbox("all")) + else: + self.history_container.pack_forget() + self.history_button.config(text="显示错题本") + self.history_visible = not self.history_visible + + def render_history(self, parent): + # 准备输入数据(完全匹配ArknightsDataset的处理方式) + left_counts = np.zeros(MONSTER_COUNT, dtype=np.int16) + right_counts = np.zeros(MONSTER_COUNT, dtype=np.int16) + # 从界面获取数据(空值处理为0) + for name, entry in self.left_monsters.items(): + value = entry.get() + left_counts[int(name) - 1] = int(value) if value.isdigit() else 0 + for name, entry in self.right_monsters.items(): + value = entry.get() + right_counts[int(name) - 1] = int(value) if value.isdigit() else 0 + + self.history_match.render_similar_matches(left_counts, right_counts) + try: + left_rate = self.history_match.left_rate + right_rate = self.history_match.right_rate + cur_left = self.history_match.cur_left + cur_right = self.history_match.cur_right + sims = self.history_match.sims + swap = self.history_match.swap + top20_idx = self.history_match.top20_idx + # 清空旧内容 + for w in parent.winfo_children(): + w.destroy() + + # 标题 + head = tk.Frame(parent) + head.pack(fill="x", pady=4) + fgL, fgR = ("#E23F25", "#666") if left_rate > right_rate else ("#666", "#25ace2") + tk.Label(head, text="近5条左右胜率:", font=("Helvetica", 12, "bold")).pack(side="left") + tk.Label( + head, text=f"左边 {left_rate:.2%} ", fg=fgL, font=("Helvetica", 12, "bold") + ).pack(side="left") + tk.Label( + head, text=f"右边 {right_rate:.2%}", fg=fgR, font=("Helvetica", 12, "bold") + ).pack(side="left") + + # 错题本主体渲染 + self._history_parent = parent + self._top20 = top20_idx.tolist() + self._sims = sims + self._swap = swap + self._batch_idx = 0 + + # 调整Canvas宽度 + self.history_canvas.config(width=700) # 增加Canvas宽度 + self.history_frame.config(width=700) # 增加Frame宽度 + + parent.after(0, lambda: self._render_batch(batch_size=5)) + + except Exception as e: + print("[渲染错题本失败]", e) + + def _render_batch(self, batch_size=5): + start = self._batch_idx * batch_size + end = start + batch_size + history_match = self.history_match + parent = self._history_parent + top20 = self._top20 + sims = self._sims + swap = self._swap + + for rank, idx in enumerate(top20[start:end], start + 1): + sims_val = sims[idx] + swapped = swap[idx] + Lh, Rh = (history_match.past_left if not swapped else history_match.past_right)[idx], ( + history_match.past_right if not swapped else history_match.past_left + )[idx] + lab = history_match.labels[idx] + if swapped: + lab = "L" if lab == "R" else "R" + winL, winR = (lab == "L"), (lab == "R") + + # csv中的行数=局数 + real_no = idx + 2 + + row = tk.Frame(parent, pady=6) + row.pack(fill="x") + + # 左侧信息区域 + info_frame = tk.Frame(row) + info_frame.pack(side="left", fill="y", padx=5) + + # 局数 + tk.Label( + info_frame, + text=f"第 {real_no} 局", + font=("Helvetica", 10), + ).pack(anchor="w") + + # 相似度 + tk.Label( + info_frame, text=f"{rank}. 相似度 {sims_val:.2f}", font=("Helvetica", 10, "bold") + ).pack(anchor="w") + + # 右侧阵容区域 + roster_frame = tk.Frame(row) + roster_frame.pack(side="right", fill="both", expand=True) + + # 左右阵容渲染(修改为水平排列) + for side_name, is_left, win, bg_color, fg_color in [ + ("左", True, winL, "#ffe5e5", "#E23F25"), + ("右", False, winR, "#e5e5ff", "#25ace2"), + ]: + pane = tk.Frame( + roster_frame, + bd=2, + relief="solid", + bg=bg_color, + highlightbackground="red" if winL and is_left or winR and not is_left else "#aaa", + highlightthickness=2, + ) + pane.pack(side="left" if is_left else "right", fill="both", expand=True, padx=5) + + # 侧边阵容 + tk.Label( + pane, + text=f"{side_name}边", + fg=fg_color if win else "#666", + bg=bg_color if win else "#f0f0f0", + font=("Helvetica", 9, "bold"), + ).pack(anchor="w", padx=4) + inner = tk.Frame(pane, bg=bg_color if win else "#f0f0f0") + inner.pack(fill="x", padx=4, pady=2) + data = Lh if is_left else Rh + for i, count in enumerate(data): + if count > 0: + img = self.images[str(i + 1)] + tk.Label(inner, image=img, bg=bg_color if win else "#f0f0f0").pack( + side="left", padx=2 + ) + tk.Label( + inner, text=f"×{int(count)}", bg=bg_color if win else "#f0f0f0" + ).pack(side="left", padx=(0, 6)) + self._batch_idx += 1 + # 更新滚动区域 + self.history_canvas.configure(scrollregion=self.history_canvas.bbox("all")) + if end < len(top20): + parent.after(50, lambda: self._render_batch(batch_size)) + + def reset_entries(self): + for entry in self.left_monsters.values(): + entry.delete(0, tk.END) + entry.config(bg="white") # Reset color + for entry in self.right_monsters.values(): + entry.delete(0, tk.END) + entry.config(bg="white") # Reset color + self.result_label.config(text="Prediction: ") + + def get_prediction(self): + # 准备输入数据(完全匹配ArknightsDataset的处理方式) + left_counts = np.zeros(MONSTER_COUNT, dtype=np.int16) + right_counts = np.zeros(MONSTER_COUNT, dtype=np.int16) + # 从界面获取数据(空值处理为0) + for name, entry in self.left_monsters.items(): + value = entry.get() + left_counts[int(name) - 1] = int(value) if value.isdigit() else 0 + for name, entry in self.right_monsters.items(): + value = entry.get() + right_counts[int(name) - 1] = int(value) if value.isdigit() else 0 + + try: + prediction = self.cannot_model.get_prediction(left_counts, right_counts) + return prediction + except FileNotFoundError: + messagebox.showerror("错误", "未找到模型文件,请先点击「训练」按钮") + return 0.5 + except RuntimeError as e: + if "size mismatch" in str(e): + messagebox.showerror("错误", "模型结构不匹配!请删除旧模型并重新训练") + else: + messagebox.showerror("错误", f"模型加载失败: {str(e)}") + return 0.5 + except ValueError: + messagebox.showerror("错误", "请输入有效的数字(0或正整数)") + return 0.5 + except Exception as e: + messagebox.showerror("错误", f"预测时发生错误: {str(e)}") + return 0.5 + + def update_prediction(self, prediction): + # 结果解释(注意:prediction直接对应标签'R'的概率) + right_win_prob = prediction # 模型输出的是右方胜率 + left_win_prob = 1 - right_win_prob + + # 格式化输出 + result_text = ( + f"预测结果:\n\n左方胜率: {left_win_prob:.2%}\t\t" f"右方胜率: {right_win_prob:.2%}" + ) + + # 根据胜率设置颜色(保持与之前一致) + self.result_label.config(text=result_text) + if left_win_prob > 0.7: + self.result_label.config(fg="#E23F25", font=("Helvetica", 12, "bold")) # red + elif left_win_prob > 0.6: + self.result_label.config(fg="#E23F25", font=("Helvetica", 12, "bold")) + elif right_win_prob > 0.7: + self.result_label.config(fg="#25ace2", font=("Helvetica", 12, "bold")) # blue + elif right_win_prob > 0.6: + self.result_label.config(fg="#25ace2", font=("Helvetica", 12, "bold")) + else: + self.result_label.config(fg="black", font=("Helvetica", 12, "bold")) + + def predict(self): + # 保存当前预测结果用于后续数据收集 + self.current_prediction = self.get_prediction() + self.update_prediction(self.current_prediction) + + if self.history_visible: + for w in self.history_frame.winfo_children(): + w.destroy() + self.render_history(self.history_frame) + self.history_canvas.configure(scrollregion=self.history_canvas.bbox("all")) + + def recognize(self): + # 如果正在进行自动获取数据,从adb加载截图 + if hasattr(self, "auto_fetch") and self.auto_fetch.auto_fetch_running: + screenshot = self.adb_connector.capture_screenshot() + else: + screenshot = None + + if self.no_region: # 如果尚未选择区域,从adb获取截图 + if self.first_recognize: # 首次识别时,尝试连接adb + self.adb_connector.connect() + self.first_recognize = False + screenshot = self.adb_connector.capture_screenshot() + + results = self.recognizer.process_regions(screenshot) + self.reset_entries() + return results, screenshot + + def update_monster(self, results): + # 处理结果 + for res in results: + region_id = res["region_id"] + if "error" not in res: + matched_id = res["matched_id"] + number = res["number"] + if matched_id != 0: + if region_id < 3: + entry = self.left_monsters[str(matched_id)] + else: + entry = self.right_monsters[str(matched_id)] + entry.delete(0, tk.END) + entry.insert(0, number) + # Highlight the image if the entry already has data + if entry.get(): + entry.config(bg="yellow") + else: + if "matched_id" in res: + matched_id = res["matched_id"] + if region_id < 3: + entry = self.left_monsters[str(matched_id)] + else: + entry = self.right_monsters[str(matched_id)] + entry.delete(0, tk.END) + entry.config(bg="red") + entry.insert(0, "Error") + + def recognize_and_predict(self): + results, screenshot = self.recognize() + self.update_monster(results) + prediction = self.get_prediction() + self.update_prediction(prediction) + + # 历史对局 + if self.history_visible: + for w in self.history_frame.winfo_children(): + w.destroy() + self.render_history(self.history_frame) + self.history_canvas.configure(scrollregion=self.history_canvas.bbox("all")) + return prediction, results, screenshot + + def reselect_roi(self): + self.recognizer.select_roi() + self.no_region = False + + def start_training(self): + threading.Thread(target=self.train_model).start() + + def train_model(self): + # Update progress + self.root.update_idletasks() + + # Simulate training process + subprocess.run(["python", "train.py"]) + self.root.update_idletasks() + + messagebox.showinfo("Info", "Model trained successfully") + + def start_callback(self): + self.auto_fetch_button.config(text="停止自动获取数据") + pass + + def stop_callback(self): + self.auto_fetch_button.config(text="自动获取数据") + pass + + def update_statistics(self): + elapsed_time = time.time() - self.auto_fetch.start_time if self.auto_fetch.start_time else 0 + hours, remainder = divmod(elapsed_time, 3600) + minutes, _ = divmod(remainder, 60) + stats_text = ( + f"总共填写次数: {self.auto_fetch.total_fill_count} , " + f"填写×次数: {self.auto_fetch.incorrect_fill_count}, " + f"当次运行时长: {int(hours)}小时{int(minutes)}分钟" + ) + self.stats_label.config(text=stats_text) + + def toggle_auto_fetch(self): + if not (hasattr(self, "auto_fetch") and self.auto_fetch.auto_fetch_running): + self.auto_fetch = AutoFetch( + self.adb_connector, + self.game_mode, + self.is_invest, + update_monster_callback=self.update_monster, + update_prediction_callback=self.update_prediction, + updater=self.update_statistics, + start_callback=self.start_callback, + stop_callback=self.stop_callback, + training_duration=float(self.duration_entry.get()) * 3600, # 获取训练时长 + ) + self.auto_fetch.start_auto_fetch() + else: + self.auto_fetch.stop_auto_fetch() + + def update_device_serial(self): + """更新设备序列号""" + new_serial = self.device_serial.get() + self.adb_connector.update_device_serial(new_serial) # 重新初始化设备连接 + messagebox.showinfo("提示", f"已更新模拟器序列号为: {new_serial}") + + +if __name__ == "__main__": + root = tk.Tk() + app = ArknightsApp(root) + root.mainloop() diff --git a/main_sim.py b/main_sim.py index 8395dde..9ff686b 100644 --- a/main_sim.py +++ b/main_sim.py @@ -3,21 +3,22 @@ import tkinter as tk from tkinter import messagebox from PIL import Image, ImageTk -from src.utils.unit import Unit -import json -import sys +import math +from unit import Unit # 确保 Unit 已导入 +import json # REMOVED_TEAM_INTERFACE: Added missing import for the main block +import random # REMOVED_TEAM_INTERFACE: Added missing import for the main block +import sys # Import sys for stdin import logging -from src.simulation.battle_field import Battlefield -from src.simulation.utils import Faction -from src.simulation.vector2d import FastVector -from src.simulation.monsters import AttackState, Monster -from src.core.config import MONSTER_DATA, MONSTER_IMAGES -from src.recognition.recognize import MONSTER_COUNT +from simulator.battle_field import Battlefield # 确保 Battlefield 已导入 +from simulator.monsters import MonsterFactory # 确保 MonsterFactory 已导入 +from simulator.utils import MONSTER_MAPPING, REVERSE_MONSTER_MAPPING, Faction # 根据你的实际路径调整 +from simulator.vector2d import FastVector # 确保 FastVector 已导入 +from simulator.monsters import AttackState, Monster, MonsterFactory +from recognize import MONSTER_COUNT logger = logging.getLogger(__name__) - class AppState(Enum): INITIAL = auto() # 初始状态 SETUP = auto() # 部署阶段 @@ -34,81 +35,63 @@ def __init__(self, ui_update_callback): def transition_to(self, new_state): """状态转换并触发UI更新""" allowed_transitions = { - AppState.INITIAL: [ - AppState.INITIAL, - AppState.SETUP, - AppState.ENDED, - ], - AppState.SETUP: [ - AppState.INITIAL, - AppState.SETUP, - AppState.SIMULATING, - ], + AppState.INITIAL: [AppState.INITIAL, AppState.SETUP, AppState.ENDED], + AppState.SETUP: [AppState.INITIAL, AppState.SETUP, AppState.SIMULATING], AppState.SIMULATING: [AppState.PAUSED, AppState.ENDED], AppState.PAUSED: [AppState.SIMULATING, AppState.SETUP], - AppState.ENDED: [AppState.INITIAL, AppState.SETUP], + AppState.ENDED: [AppState.INITIAL, AppState.SETUP] } if new_state in allowed_transitions[self.state]: self.state = new_state self.ui_update() else: - logger.error( - f"Illegal state transition from {self.state} to {new_state}" - ) + logger.error(f"Illegal state transition from {self.state} to {new_state}") def get_control_states(self): """返回各控件的状态字典""" states = { - "deploy": {"state": tk.NORMAL, "text": "部署怪物"}, - "confirm_start": {"state": tk.DISABLED}, - "pause": {"state": tk.DISABLED, "text": "暂停"}, - "restore": {"state": tk.DISABLED}, - "speed_entry": {"state": tk.NORMAL}, - "clear": {"state": tk.NORMAL}, - "timer": {"text": ""}, + 'deploy': {'state': tk.NORMAL, 'text': '部署怪物'}, + 'confirm_start': {'state': tk.DISABLED}, + 'pause': {'state': tk.DISABLED, 'text': '暂停'}, + 'restore': {'state': tk.DISABLED}, + 'speed_entry': {'state': tk.NORMAL}, + 'clear': {'state': tk.NORMAL}, + 'timer': {'text': ''} } if self.state == AppState.INITIAL: pass elif self.state == AppState.SETUP: - states.update( - { - "deploy": {"state": tk.NORMAL, "text": "重新部署"}, - "confirm_start": {"state": tk.NORMAL}, - "timer": {"text": "未开始"}, - } - ) + states.update({ + 'deploy': {'state': tk.NORMAL, 'text': '重新部署'}, + 'confirm_start': {'state': tk.NORMAL}, + 'timer': {'text': '未开始'} + }) elif self.state == AppState.SIMULATING: - states.update( - { - "deploy": {"state": tk.DISABLED, "text": "重新部署"}, - "confirm_start": {"state": tk.DISABLED}, - "pause": {"state": tk.NORMAL, "text": "暂停"}, - "clear": {"state": tk.DISABLED}, - } - ) + states.update({ + 'deploy': {'state': tk.DISABLED, 'text': '重新部署'}, + 'confirm_start': {'state': tk.DISABLED}, + 'pause': {'state': tk.NORMAL, 'text': '暂停'}, + 'clear': {'state': tk.DISABLED}, + }) elif self.state == AppState.PAUSED: - states.update( - { - "restore": {"state": tk.NORMAL}, - "pause": {"state": tk.NORMAL, "text": "继续"}, - "deploy": {"state": tk.NORMAL, "text": "重新部署"}, - } - ) + states.update({ + 'restore': {'state': tk.NORMAL}, + 'pause': {'state': tk.NORMAL, 'text': '继续'}, + 'deploy': {'state': tk.NORMAL, 'text': '重新部署'} + }) elif self.state == AppState.ENDED: - states.update( - { - "deploy": {"state": tk.DISABLED, "text": "重新部署"}, - "restore": {"state": tk.NORMAL}, - "pause": {"state": tk.DISABLED, "text": "暂停"}, - "timer": {"text": "战斗结束"}, - } - ) + states.update({ + 'deploy': {'state': tk.DISABLED, 'text': '重新部署'}, + 'restore': {'state': tk.NORMAL}, + 'pause': {'state': tk.DISABLED, 'text': '暂停'}, + 'timer': {'text': '战斗结束'} + }) return states @@ -142,9 +125,7 @@ def __init__(self, master: tk.Tk, battle_data): self.initial_battlefield = None # 新增状态 self.setup_phase_active = False # 怪物部署和调整阶段是否激活 - self.selected_monster_for_drag = ( - None # 当前拖动的怪物对象 (Monster 类型) - ) + self.selected_monster_for_drag = None # 当前拖动的怪物对象 (Monster 类型) self.message_label = None # 用于显示提示信息的标签 self.message_timer_id = None # 用于定时清除提示信息的ID @@ -155,35 +136,25 @@ def __init__(self, master: tk.Tk, battle_data): self.state_machine.transition_to(AppState.INITIAL) self.enter_setup_phase() - def _resolve_monster_icon_key(self, monster_name: str) -> str: - """根据怪物名称解析对应的图标文件名。""" - if monster_name in self.monster_icon_key_map: - return self.monster_icon_key_map[monster_name] - - if monster_name in MONSTER_IMAGES: - return monster_name - - return self.default_icon_key - def update_ui_state(self): """根据当前状态更新所有控件状态""" states = self.state_machine.get_control_states() self.deploy_button.config( - state=states["deploy"]["state"], text=states["deploy"]["text"] - ) - self.confirm_start_button.config( - state=states["confirm_start"]["state"] + state=states['deploy']['state'], + text=states['deploy']['text'] ) + self.confirm_start_button.config(state=states['confirm_start']['state']) self.pause_button.config( - state=states["pause"]["state"], text=states["pause"]["text"] + state=states['pause']['state'], + text=states['pause']['text'] ) - self.restore_button.config(state=states["restore"]["state"]) - self.speed_entry.config(state=states["speed_entry"]["state"]) - self.clear_button.config(state=states["clear"]["state"]) + self.restore_button.config(state=states['restore']['state']) + self.speed_entry.config(state=states['speed_entry']['state']) + self.clear_button.config(state=states['clear']['state']) - if states["timer"]["text"] != "": - self.timer_label.config(text=states["timer"]["text"]) + if states['timer']['text'] != '': + self.timer_label.config(text=states['timer']['text']) def hide_window(self): if self.state_machine.state == AppState.SIMULATING: @@ -193,10 +164,8 @@ def hide_window(self): def load_assets(self): self.icons = {} - self.monster_icon_key_map = {} - self.default_icon_key = "empty" if "empty" in MONSTER_IMAGES else "" try: - with open("src/simulation/monsters.json", encoding="utf-8") as f: + with open("simulator/monsters.json", encoding='utf-8') as f: self.monster_data = json.load(f)["monsters"] except FileNotFoundError: logger.error("错误: monsters.json 未找到,请检查路径!") @@ -204,47 +173,21 @@ def load_assets(self): return - # 构建“名称/原始名称 -> 图标文件名”的映射,优先使用原始名称对应的图片。 - for _, row in MONSTER_DATA.iterrows(): - monster_name = str(row["名称"]) - original_name = str(row["原始名称"]) - - icon_key = None - if original_name in MONSTER_IMAGES: - icon_key = original_name - elif monster_name in MONSTER_IMAGES: - icon_key = monster_name - - if icon_key is None: - icon_key = self.default_icon_key - - self.monster_icon_key_map[monster_name] = icon_key - self.monster_icon_key_map[original_name] = icon_key - - # 为实际存在的图片创建 Tk 图像,未命中的统一回退到灰色或 empty。 - for image_key, image_array in MONSTER_IMAGES.items(): + for i in range(self.num_monsters): + image_file_id = i + 1 try: - if image_array is None: - raise ValueError("图像数据为空") - - image = Image.fromarray(image_array[:, :, ::-1]) - image_40 = image.resize((40, 40)) - self.icons[image_key] = { - "red": ImageTk.PhotoImage(image_40, master=self.master), - "blue": ImageTk.PhotoImage( - image_40.transpose(Image.FLIP_LEFT_RIGHT), - master=self.master, - ), + image = Image.open(f'images/{image_file_id}.png') + self.icons[i] = { + "red": ImageTk.PhotoImage(image.resize((40, 40))), + "blue": ImageTk.PhotoImage(image.resize((40, 40)).transpose(Image.FLIP_LEFT_RIGHT)) } except Exception as e: - logger.error(f"加载图标错误 (图标键: {image_key}): {str(e)}") - - if self.default_icon_key and self.default_icon_key not in self.icons: - fallback = Image.new("RGB", (40, 40), "gray") - self.icons[self.default_icon_key] = { - "red": ImageTk.PhotoImage(fallback, master=self.master), - "blue": ImageTk.PhotoImage(fallback, master=self.master), - } + # 同样,show_message_below_button 可能还不可用 + logger.error(f"加载图标错误 (图标键: {i}, 文件名ID: {image_file_id}): {str(e)}") + self.icons[i] = { + "red": ImageTk.PhotoImage(Image.new("RGB", (40, 40), "gray")), + "blue": ImageTk.PhotoImage(Image.new("RGB", (40, 40), "gray")) + } def init_battlefield_for_setup(self): self.state_machine.transition_to(AppState.SETUP) @@ -254,9 +197,7 @@ def init_battlefield_for_setup(self): left_army_config = self.battle_data.get("left", {}) right_army_config = self.battle_data.get("right", {}) - self.battle_field.setup_battle( - left_army_config, right_army_config, self.monster_data - ) + self.battle_field.setup_battle(left_army_config, right_army_config, self.monster_data) while self.battle_field.gameTime < 6.0: result = self.battle_field.run_one_frame() if result: @@ -264,10 +205,7 @@ def init_battlefield_for_setup(self): self.refresh_canvas_display() def on_mouse_drag(self, event): - if self.selected_monster_for_drag and self.state_machine.state in [ - AppState.PAUSED, - AppState.SETUP, - ]: + if self.selected_monster_for_drag and self.state_machine.state in [AppState.PAUSED, AppState.SETUP]: new_grid_x = event.x / self.cell_size new_grid_y = event.y / self.cell_size new_grid_x = max(0.25, min(new_grid_x, self.grid_width - 0.25)) @@ -275,9 +213,7 @@ def on_mouse_drag(self, event): self.selected_monster_for_drag.position.x = new_grid_x self.selected_monster_for_drag.position.y = new_grid_y - self.selected_monster_for_drag.target_deployment_position = ( - FastVector(new_grid_x, new_grid_y) - ) + self.selected_monster_for_drag.target_deployment_position = FastVector(new_grid_x, new_grid_y) self.refresh_canvas_display() @@ -294,44 +230,25 @@ def create_widgets(self): self.speed_entry = tk.Entry(speed_frame, width=5) self.speed_entry.pack(side=tk.LEFT) self.speed_entry.insert(0, f"{int(self.speed_multiplier)}") - tk.Button(speed_frame, text="应用", command=self.apply_speed).pack( - side=tk.LEFT - ) + tk.Button(speed_frame, text="应用", command=self.apply_speed).pack(side=tk.LEFT) - self.deploy_button = tk.Button( - top_control_frame, text="部署怪物", command=self.enter_setup_phase - ) + self.deploy_button = tk.Button(top_control_frame, text="部署怪物", command=self.enter_setup_phase) self.deploy_button.pack(side=tk.LEFT, padx=5) - self.confirm_start_button = tk.Button( - top_control_frame, - text="开始战斗", - command=self.start_actual_simulation, - state=tk.DISABLED, - ) + self.confirm_start_button = tk.Button(top_control_frame, text="开始战斗", command=self.start_actual_simulation, + state=tk.DISABLED) self.confirm_start_button.pack(side=tk.LEFT, padx=5) - self.clear_button = tk.Button( - top_control_frame, text="清空战场", command=self.clear_sandbox - ) + self.clear_button = tk.Button(top_control_frame, text="清空战场", command=self.clear_sandbox) self.clear_button.pack(side=tk.LEFT, padx=5) self.timer_label = tk.Label(top_control_frame, text="0.00秒") self.timer_label.pack(side=tk.LEFT, padx=100) - self.pause_button = tk.Button( - top_control_frame, - text="暂停", - command=self.toggle_pause, - state=tk.DISABLED, - ) + self.pause_button = tk.Button(top_control_frame, text="暂停", command=self.toggle_pause, state=tk.DISABLED) self.pause_button.pack(side=tk.LEFT, padx=5) - self.restore_button = tk.Button( - top_control_frame, - text="恢复站位", - command=self.restore_initial_positions, - state=tk.DISABLED, - ) + self.restore_button = tk.Button(top_control_frame, text="恢复站位", command=self.restore_initial_positions, + state=tk.DISABLED) self.restore_button.pack(side=tk.LEFT, padx=5) self.game_over_label = tk.Label(top_control_frame, text="", fg="red") @@ -341,12 +258,7 @@ def create_widgets(self): self.message_label = tk.Label(control_frame, text="", fg="black") self.message_label.pack(pady=2) - self.canvas = tk.Canvas( - self.master, - width=self.canvas_width, - height=self.canvas_height, - bg="white", - ) + self.canvas = tk.Canvas(self.master, width=self.canvas_width, height=self.canvas_height, bg='white') self.canvas.pack(pady=10) self.draw_grid() @@ -354,19 +266,13 @@ def create_widgets(self): self.canvas.bind("", self.on_mouse_drag) self.canvas.bind("", self.on_mouse_up) - def show_message_below_button( - self, message, is_error=False, duration=5000 - ): + def show_message_below_button(self, message, is_error=False, duration=5000): """在按钮下方显示文字提示,并在指定时间后消失""" if self.message_label: - self.message_label.config( - text=message, fg="red" if is_error else "black" - ) + self.message_label.config(text=message, fg="red" if is_error else "black") if self.message_timer_id: self.master.after_cancel(self.message_timer_id) - self.message_timer_id = self.master.after( - duration, self.clear_message_below_button - ) + self.message_timer_id = self.master.after(duration, self.clear_message_below_button) def clear_message_below_button(self): """清除提示信息""" @@ -395,82 +301,37 @@ def apply_speed(self): def draw_grid(self): danger_zone = 0 if self.battle_field and self.battle_field.danger_zone_size() > 0: - danger_zone = min( - self.battle_field.danger_zone_size(), self.grid_height / 2 + 1 - ) - self.canvas.create_rectangle( - 0, - 0, - self.canvas_width, - danger_zone * self.cell_size, - fill="#cccc00", - outline="", - ) - self.canvas.create_rectangle( - 0, - 0, - (danger_zone + 1) * self.cell_size, - self.canvas_height, - fill="#cccc00", - outline="", - ) - self.canvas.create_rectangle( - self.canvas_width, - 0, - self.canvas_width - (danger_zone + 1) * self.cell_size, - self.canvas_height, - fill="#cccc00", - outline="", - ) - self.canvas.create_rectangle( - self.canvas_width, - self.canvas_height, - 0, - self.canvas_height - danger_zone * self.cell_size, - fill="#cccc00", - outline="", - ) + danger_zone = min(self.battle_field.danger_zone_size(), self.grid_height / 2 + 1) + self.canvas.create_rectangle(0, 0, self.canvas_width, danger_zone * self.cell_size, fill='#cccc00', + outline="") + self.canvas.create_rectangle(0, 0, (danger_zone+1) * self.cell_size , self.canvas_height, fill='#cccc00', + outline="") + self.canvas.create_rectangle(self.canvas_width, 0, self.canvas_width - (danger_zone+1) * self.cell_size, + self.canvas_height, fill='#cccc00', outline="") + self.canvas.create_rectangle(self.canvas_width, self.canvas_height, 0, + self.canvas_height - danger_zone * self.cell_size, fill='#cccc00', outline="") # 绘制最左侧的柔和红色列 - soft_red_fill = "#F08080" # 亮珊瑚色 - soft_red_line = "#D87070" # 稍暗的亮珊瑚色 - self.canvas.create_rectangle( - 0, - 0, - self.cell_size, - self.canvas_height, - fill=soft_red_fill, - outline="", - ) + soft_red_fill = '#F08080' # 亮珊瑚色 + soft_red_line = '#D87070' # 稍暗的亮珊瑚色 + self.canvas.create_rectangle(0, 0, self.cell_size, self.canvas_height, fill=soft_red_fill, outline="") # 绘制最右侧的柔和蓝色列 - soft_blue_fill = "#ADD8E6" # 浅蓝色 - soft_blue_line = "#9CC2D0" # 稍暗的浅蓝色 - self.canvas.create_rectangle( - self.canvas_width - self.cell_size, - 0, - self.canvas_width, - self.canvas_height, - fill=soft_blue_fill, - outline="", - ) + soft_blue_fill = '#ADD8E6' # 浅蓝色 + soft_blue_line = '#9CC2D0' # 稍暗的浅蓝色 + self.canvas.create_rectangle(self.canvas_width - self.cell_size, 0, self.canvas_width, self.canvas_height, + fill=soft_blue_fill, outline="") for i in range(self.grid_width + 1): x = i * self.cell_size if i == 0 or i == self.grid_width: continue if i == 1: # 红色列的右边缘线 - self.canvas.create_line( - x, 0, x, self.canvas_height, fill=soft_red_line - ) + self.canvas.create_line(x, 0, x, self.canvas_height, fill=soft_red_line) elif i == self.grid_width - 1: # 蓝色列的左边缘线 - self.canvas.create_line( - x, 0, x, self.canvas_height, fill=soft_blue_line - ) + self.canvas.create_line(x, 0, x, self.canvas_height, fill=soft_blue_line) else: - self.canvas.create_line( - x, 0, x, self.canvas_height, fill="lightgray" - ) # 垂直网格线 + self.canvas.create_line(x, 0, x, self.canvas_height, fill='lightgray') # 垂直网格线 # 绘制水平网格线 for i in range(self.grid_height + 1): @@ -478,43 +339,27 @@ def draw_grid(self): # 左边红色区域的水平线可以特殊处理,使其在红色背景上更明显,或者保持lightgray if self.cell_size > 0: # 确保 cell_size > 0 避免问题 # 在红色区域内绘制颜色稍浅的水平线,或者使用对比色 - self.canvas.create_line( - 0, y, self.cell_size, y, fill="#E07070" - ) # 示例:红色区域内的水平线 + self.canvas.create_line(0, y, self.cell_size, y, fill='#E07070') # 示例:红色区域内的水平线 # 在蓝色区域内绘制颜色稍浅的水平线 - self.canvas.create_line( - self.canvas_width - self.cell_size, - y, - self.canvas_width, - y, - fill="#9CBED0", - ) # 示例:蓝色区域内的水平线 + self.canvas.create_line(self.canvas_width - self.cell_size, y, self.canvas_width, y, + fill='#9CBED0') # 示例:蓝色区域内的水平线 # 中间区域的水平线 - self.canvas.create_line( - self.cell_size, - y, - self.canvas_width - self.cell_size, - y, - fill="lightgray", - ) + self.canvas.create_line(self.cell_size, y, self.canvas_width - self.cell_size, y, fill='lightgray') else: # 如果 cell_size 为0或负,则绘制完整线条 - self.canvas.create_line( - 0, y, self.canvas_width, y, fill="lightgray" - ) + self.canvas.create_line(0, y, self.canvas_width, y, fill='lightgray') def refresh_canvas_display(self): - if not self.canvas: - return + if not self.canvas: return self.canvas.delete("all") self.draw_grid() self.canvas.delete("victory_text") # 清除可能存在的胜利信息 if len(self.battle_field.monsters) > len(self.units): for i in range(len(self.units), len(self.battle_field.monsters)): - new_unit = Unit("red", 0, 0, 0) + new_unit = Unit('red', 0, 0, 0) self.units.append(new_unit) elif len(self.battle_field.monsters) < len(self.units): - self.units = self.units[: len(self.battle_field.monsters)] + self.units = self.units[:len(self.battle_field.monsters)] index = 0 for monster in self.battle_field.monsters: @@ -523,11 +368,14 @@ def refresh_canvas_display(self): if monster and monster.is_alive: ui_unit.x = monster.position.x ui_unit.y = monster.position.y - ui_unit.team = ( - "red" if monster.faction == Faction.LEFT else "blue" - ) - ui_unit.unit_id = self._resolve_monster_icon_key(monster.name) - ui_unit.monster_name = monster.name + ui_unit.team = 'red' if monster.faction == Faction.LEFT else 'blue' + display_id_for_icon = REVERSE_MONSTER_MAPPING.get(monster.name) + if display_id_for_icon is None: + logger.error(f"怪物名 {monster.name} 在 REVERSE_MONSTER_MAPPING 中未找到!") + self.show_message_below_button(f"怪物名 {monster.name} 在 REVERSE_MONSTER_MAPPING 中未找到!", + is_error=True) + display_id_for_icon = 0 + ui_unit.unit_id = display_id_for_icon ui_unit.health = monster.health ui_unit.max_health = monster.max_health ui_unit.skill = monster.get_skill_bar() @@ -539,84 +387,42 @@ def refresh_canvas_display(self): for monster_obj in self.battle_field.monsters: if monster_obj.is_alive and monster_obj.target is not None: self.canvas.create_line( - monster_obj.position.x * self.cell_size, - monster_obj.position.y * self.cell_size, - monster_obj.target.position.x * self.cell_size, - monster_obj.target.position.y * self.cell_size, - fill=( - "#FF3030" - if monster_obj.faction == Faction.LEFT - else "#3030FF" - ), - width=1, - arrow="last", - ) + monster_obj.position.x * self.cell_size, monster_obj.position.y * self.cell_size, + monster_obj.target.position.x * self.cell_size, monster_obj.target.position.y * self.cell_size, + fill="#FF3030" if monster_obj.faction == Faction.LEFT else "#3030FF", width=1, arrow='last') self.timer_label.config(text=f"{self.battle_field.gameTime:.2f}秒") - def draw_unit(self, unit, monster: "Monster"): + def draw_unit(self, unit, monster: 'Monster'): x_pixel = unit.x * self.cell_size y_pixel = unit.y * self.cell_size icon_to_draw = None - icon_key = getattr(unit, "unit_id", self.default_icon_key) - if icon_key not in self.icons: - icon_key = self.default_icon_key - - if icon_key in self.icons and unit.team in self.icons[icon_key]: - icon_to_draw = self.icons[icon_key][unit.team] + if unit.unit_id in self.icons and unit.team in self.icons[unit.unit_id]: + icon_to_draw = self.icons[unit.unit_id][unit.team] else: - self.canvas.create_rectangle( - x_pixel - 20, - y_pixel - 20, - x_pixel + 20, - y_pixel + 20, - fill="gray", - tags=("unit",), - ) + self.canvas.create_rectangle(x_pixel - 20, y_pixel - 20, x_pixel + 20, y_pixel + 20, fill="gray", + tags=("unit",)) return - self.canvas.create_image( - x_pixel, y_pixel, image=icon_to_draw, tags=("unit",) - ) + self.canvas.create_image(x_pixel, y_pixel, image=icon_to_draw, tags=("unit",)) bar_width = 40 bar_height = 5 health_bar_y = y_pixel + 25 - health_ratio = ( - min(1, unit.health / unit.max_health) if unit.max_health > 0 else 0 - ) + health_ratio = min(1, unit.health / unit.max_health) if unit.max_health > 0 else 0 current_health_width = max(0, bar_width * health_ratio) - self.canvas.create_rectangle( - x_pixel - bar_width / 2, - health_bar_y - bar_height / 2, - x_pixel + bar_width / 2, - health_bar_y + bar_height / 2, - fill="#400000", - outline="", - ) + self.canvas.create_rectangle(x_pixel - bar_width / 2, health_bar_y - bar_height / 2, x_pixel + bar_width / 2, + health_bar_y + bar_height / 2, fill="#400000", outline="") if current_health_width > 0: - self.canvas.create_rectangle( - x_pixel - bar_width / 2, - health_bar_y - bar_height / 2, - x_pixel - bar_width / 2 + current_health_width, - health_bar_y + bar_height / 2, - fill="#FF3030", - outline="", - ) + self.canvas.create_rectangle(x_pixel - bar_width / 2, health_bar_y - bar_height / 2, + x_pixel - bar_width / 2 + current_health_width, health_bar_y + bar_height / 2, + fill="#FF3030", outline="") skill_bar_y = health_bar_y + 7 - skill_ratio = ( - min(1, unit.skill / unit.max_skill) if unit.max_skill > 0 else 0 - ) + skill_ratio = min(1, unit.skill / unit.max_skill) if unit.max_skill > 0 else 0 current_skill_width = bar_width * skill_ratio - self.canvas.create_rectangle( - x_pixel - bar_width / 2, - skill_bar_y - bar_height / 2, - x_pixel + bar_width / 2, - skill_bar_y + bar_height / 2, - fill="black", - outline="", - ) + self.canvas.create_rectangle(x_pixel - bar_width / 2, skill_bar_y - bar_height / 2, x_pixel + bar_width / 2, + skill_bar_y + bar_height / 2, fill="black", outline="") attack_state_color = "#ffcccc" if monster.attack_state == AttackState.后摇: @@ -625,14 +431,9 @@ def draw_unit(self, unit, monster: "Monster"): attack_state_color = "yellow" if current_skill_width > 0: - self.canvas.create_rectangle( - x_pixel - bar_width / 2, - skill_bar_y - bar_height / 2, - x_pixel - bar_width / 2 + current_skill_width, - skill_bar_y + bar_height / 2, - fill=attack_state_color, - outline="", - ) + self.canvas.create_rectangle(x_pixel - bar_width / 2, skill_bar_y - bar_height / 2, + x_pixel - bar_width / 2 + current_skill_width, skill_bar_y + bar_height / 2, + fill=attack_state_color, outline="") def on_mouse_down(self, event): grid_x = event.x / self.cell_size @@ -641,18 +442,13 @@ def on_mouse_down(self, event): if self.state_machine.state in [AppState.PAUSED, AppState.SETUP]: clicked_monster_obj = None for unit_in_list in reversed(self.units): - monster = self.battle_field.get_monster_with_id( - unit_in_list.monster_global_id - ) - if not monster: - continue + monster = self.battle_field.get_monster_with_id(unit_in_list.monster_global_id) + if not monster: continue monster_center_x_px = monster.position.x * self.cell_size monster_center_y_px = monster.position.y * self.cell_size icon_half_size_px = 20 - if ( - abs(event.x - monster_center_x_px) < icon_half_size_px - and abs(event.y - monster_center_y_px) < icon_half_size_px - ): + if (abs(event.x - monster_center_x_px) < icon_half_size_px and + abs(event.y - monster_center_y_px) < icon_half_size_px): clicked_monster_obj = monster break if clicked_monster_obj: @@ -660,19 +456,14 @@ def on_mouse_down(self, event): return def on_mouse_drag(self, event): - if self.selected_monster_for_drag and self.state_machine.state in [ - AppState.PAUSED, - AppState.SETUP, - ]: + if self.selected_monster_for_drag and self.state_machine.state in [AppState.PAUSED, AppState.SETUP]: new_grid_x = event.x / self.cell_size new_grid_y = event.y / self.cell_size new_grid_x = max(0.25, min(new_grid_x, self.grid_width - 0.25)) new_grid_y = max(0.25, min(new_grid_y, self.grid_height - 0.25)) self.selected_monster_for_drag.position.x = new_grid_x self.selected_monster_for_drag.position.y = new_grid_y - self.selected_monster_for_drag.target = ( - self.selected_monster_for_drag.find_target() - ) + self.selected_monster_for_drag.target = self.selected_monster_for_drag.find_target() self.refresh_canvas_display() def on_mouse_up(self, event): @@ -734,20 +525,14 @@ def simulate(self): # 在画布中央放大显示信息 self.canvas.create_text( - self.canvas_width / 2, - self.canvas_height / 2, - text=game_over_message, - font=font_style, - fill=text_color, - tags="victory_text", + self.canvas_width / 2, self.canvas_height / 2, + text=game_over_message, font=font_style, fill=text_color, tags="victory_text" ) else: interval = max(1, 33) self.simulation_id = self.master.after(interval, self.simulate) - def show_result( - self, message - ): # 此方法现在主要被画布显示和按钮下方提示替代 + def show_result(self, message): # 此方法现在主要被画布显示和按钮下方提示替代 self.show_message_below_button(message) def clear_sandbox(self): @@ -771,9 +556,7 @@ def restore_initial_positions(self): self.show_message_below_button("没有可恢复的初始站位") return self.battle_field = copy.deepcopy(self.initial_battlefield) - self.battle_field.gameTime = ( - self.initial_battlefield.gameTime - ) # 保持时间连续性 + self.battle_field.gameTime = self.initial_battlefield.gameTime # 保持时间连续性 if self.state_machine.state in [AppState.PAUSED, AppState.ENDED]: self.state_machine.transition_to(AppState.SETUP) self.refresh_canvas_display() # 会清除 "victory_text" @@ -784,13 +567,10 @@ def main(): root = tk.Tk() # root.withdraw() # 如果不需要立即隐藏主窗口,可以注释掉 - initial_battle_setup = { - "left": {"Vvan": 4, "炮击组长": 3, "“庞贝”": 2}, - "right": {"大喷蛛": 6, "冰爆源石虫": 23}, - "result": "left", - } + initial_battle_setup = {"left": {"Vvan": 4, "炮击组长": 3, "“庞贝”": 2}, "right": {"大喷蛛": 6, "冰爆源石虫": 23}, + "result": "left"} - sys.stdin.reconfigure(encoding="utf-8") + sys.stdin.reconfigure(encoding='utf-8') try: if not sys.stdin.isatty(): json_data = sys.stdin.read() @@ -802,14 +582,10 @@ def main(): else: logger.info("stdin 是交互式终端,使用默认配置。") except json.JSONDecodeError: - logger.error( - "错误: 无法解析 stdin 中的 JSON 数据,请检查格式,将使用默认配置。" - ) + logger.error("错误: 无法解析 stdin 中的 JSON 数据,请检查格式,将使用默认配置。") except Exception as e: - logger.error( - f"从 stdin 读取或解析时发生未知错误: {e},将使用默认配置。" - ) + logger.error(f"从 stdin 读取或解析时发生未知错误: {e},将使用默认配置。") try: app = SandboxSimulator(root, initial_battle_setup) @@ -823,41 +599,26 @@ def main(): if not app.monster_data: # 检查 monsters.json 是否加载成功 error_messages.append("错误: monsters.json 未找到或为空,请检查文件!") - if ( - len(initial_battle_setup.get("left", {})) == 0 - or len(initial_battle_setup.get("right", {})) == 0 - ): + if len(initial_battle_setup.get("left", {})) == 0 or len(initial_battle_setup.get("right", {})) == 0: error_messages.append("错误:至少一方的怪物列表为空!") problematic_monsters_found = [] - problematic_monster_names = [ - "矿脉守卫", - "提亚卡乌好战者", - "凋零萨卡兹", - "狂暴宿主组长", - "高能源石虫", - ] + problematic_monster_names = ["矿脉守卫", "提亚卡乌好战者", "凋零萨卡兹", "狂暴宿主组长", "高能源石虫"] for team_key in ["left", "right"]: for monster_name in initial_battle_setup.get(team_key, {}): if monster_name in problematic_monster_names: problematic_monsters_found.append( - f"{('左方' if team_key == 'left' else '右方')}存在问题怪物: {monster_name}" - ) + f"{('左方' if team_key == 'left' else '右方')}存在问题怪物: {monster_name}") if problematic_monsters_found: - error_messages.append( - "警告: " + "; ".join(problematic_monsters_found) - ) + error_messages.append("警告: " + "; ".join(problematic_monsters_found)) if error_messages: - app.show_message_below_button( - " | ".join(error_messages), is_error=True, duration=10000 - ) + app.show_message_below_button(" | ".join(error_messages), is_error=True, duration=10000) if "monsters.json 未找到或为空" in " | ".join(error_messages): - logger.error( - "由于 monsters.json 缺失或错误,模拟器可能无法正常工作。" - ) + logger.error("由于 monsters.json 缺失或错误,模拟器可能无法正常工作。") + if not root.winfo_exists(): return @@ -869,10 +630,8 @@ def main(): logging.getLogger().setLevel(logging.DEBUG) logging.getLogger("PIL").setLevel(logging.INFO) stream_handler = logging.StreamHandler() - stream_handler.setFormatter( - logging.Formatter( - "%(asctime)s - %(name)s - %(levelname)s - %(message)s", - ) - ) + stream_handler.setFormatter(logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s", + )) logging.getLogger().addHandler(stream_handler) main() diff --git a/src/analysis/__init__.py b/models/__init__.py similarity index 100% rename from src/analysis/__init__.py rename to models/__init__.py diff --git a/src/models/model.py b/models/model.py similarity index 94% rename from src/models/model.py rename to models/model.py index 69ad1e4..c55a035 100644 --- a/src/models/model.py +++ b/models/model.py @@ -1,12 +1,9 @@ import torch import torch.nn as nn -from src.core.config import FIELD_FEATURE_COUNT, MONSTER_COUNT - +from config import FIELD_FEATURE_COUNT, MONSTER_COUNT class UnitAwareTransformer(nn.Module): - def __init__( - self, num_units, embed_dim=256, num_heads=4, num_layers=4, dropout=0.3 - ): + def __init__(self, num_units, embed_dim=256, num_heads=4, num_layers=4, dropout=0.3): super().__init__() # num_units,包括怪物种类和场地特征种类 # 怪物特征 + 场地特征 = 总特征数量 @@ -70,12 +67,13 @@ def __init__( nn.init.xavier_uniform_(self.friend_attentions[-1].in_proj_weight) self.norm.append(nn.LayerNorm(embed_dim)) + # 全连接输出层 self.fc = nn.Sequential( nn.Linear(embed_dim, embed_dim * 2), nn.ReLU(), nn.Dropout(dropout), - nn.Linear(embed_dim * 2, 1), + nn.Linear(embed_dim * 2, 1) ) def forward(self, left_signs, left_counts, right_signs, right_counts): @@ -96,7 +94,7 @@ def forward(self, left_signs, left_counts, right_signs, right_counts): left_feat = torch.cat( [ left_feat[..., : embed_dim // 2], # 前x维 - left_feat[..., embed_dim // 2 :] + left_feat[..., embed_dim // 2:] * left_values.unsqueeze(-1), # 后y维乘数量 ], dim=-1, @@ -104,7 +102,7 @@ def forward(self, left_signs, left_counts, right_signs, right_counts): right_feat = torch.cat( [ right_feat[..., : embed_dim // 2], - right_feat[..., embed_dim // 2 :] * right_values.unsqueeze(-1), + right_feat[..., embed_dim // 2:] * right_values.unsqueeze(-1), ], dim=-1, ) diff --git a/src/models/muon.py b/models/muon.py similarity index 75% rename from src/models/muon.py rename to models/muon.py index 1b59250..0e87c93 100644 --- a/src/models/muon.py +++ b/models/muon.py @@ -1,4 +1,5 @@ import torch +import torch.optim as optim class Lion(torch.optim.Optimizer): @@ -27,26 +28,26 @@ def step(self, closure=None): loss = closure() for group in self.param_groups: - for p in group["params"]: + for p in group['params']: if p.grad is None: continue # 首先执行 Weight Decay - p.data.mul_(1 - group["lr"] * group["weight_decay"]) + p.data.mul_(1 - group['lr'] * group['weight_decay']) grad = p.grad state = self.state[p] # 初始化动量状态 if len(state) == 0: - state["exp_avg"] = torch.zeros_like(p) + state['exp_avg'] = torch.zeros_like(p) - exp_avg = state["exp_avg"] - beta1, beta2 = group["betas"] + exp_avg = state['exp_avg'] + beta1, beta2 = group['betas'] # 计算 Lion 特有的更新:符号动量 update = exp_avg * beta1 + grad * (1 - beta1) - p.add_(torch.sign(update), alpha=-group["lr"]) + p.add_(torch.sign(update), alpha=-group['lr']) # 更新 EMA 动量 exp_avg.mul_(beta2).add_(grad, alpha=1 - beta2) @@ -59,15 +60,8 @@ class Muon(torch.optim.Optimizer): 根据《Muon is Scalable for LLM Training》技术报告实现的 Muon 优化器。 """ - def __init__( - self, params, lr=1e-3, momentum=0.95, weight_decay=0.1, ns_steps=5 - ): - defaults = dict( - lr=lr, - momentum=momentum, - weight_decay=weight_decay, - ns_steps=ns_steps, - ) + def __init__(self, params, lr=1e-3, momentum=0.95, weight_decay=0.1, ns_steps=5): + defaults = dict(lr=lr, momentum=momentum, weight_decay=weight_decay, ns_steps=ns_steps) super().__init__(params, defaults) @torch.no_grad() @@ -78,23 +72,23 @@ def step(self, closure=None): loss = closure() for group in self.param_groups: - lr = group["lr"] - momentum = group["momentum"] - weight_decay = group["weight_decay"] - ns_steps = group["ns_steps"] + lr = group['lr'] + momentum = group['momentum'] + weight_decay = group['weight_decay'] + ns_steps = group['ns_steps'] - for p in group["params"]: + for p in group['params']: if p.grad is None: continue grad = p.grad if grad.is_sparse: - raise RuntimeError("Muon 不支持稀疏梯度计算") + raise RuntimeError('Muon 不支持稀疏梯度计算') state = self.state[p] if len(state) == 0: - state["momentum_buffer"] = torch.zeros_like(grad) + state['momentum_buffer'] = torch.zeros_like(grad) - buf = state["momentum_buffer"] + buf = state['momentum_buffer'] # 应用基于 Nesterov 的动量: M_t = \mu * M_{t-1} + \nabla L_t buf.mul_(momentum).add_(grad) @@ -124,7 +118,7 @@ def step(self, closure=None): dim0, dim1 = X.size(0), X.size(1) if X.ndim > 1 else 1 max_dim = max(dim0, dim1) - scale = 0.2 * (max_dim**0.5) + scale = 0.2 * (max_dim ** 0.5) p.data.mul_(1 - lr * weight_decay) p.data.add_(X, alpha=-lr * scale) @@ -132,9 +126,7 @@ def step(self, closure=None): return loss -def get_muon_lion_optimizers( - model, muon_lr, lion_lr, weight_decay=0.1, muon_momentum=0.95 -): +def get_muon_lion_optimizers(model, muon_lr, lion_lr, weight_decay=0.1, muon_momentum=0.95): """ 提供 Muon + Lion 的组合优化器分发策略。 对模型的所有 >=2D 参数采用 Muon; @@ -148,17 +140,12 @@ def get_muon_lion_optimizers( if not p.requires_grad: continue - if p.ndim >= 2 and "embed" not in name.lower(): + if p.ndim >= 2 and 'embed' not in name.lower(): muon_params.append(p) else: lion_params.append(p) - muon_opt = Muon( - muon_params, - lr=muon_lr, - momentum=muon_momentum, - weight_decay=weight_decay, - ) + muon_opt = Muon(muon_params, lr=muon_lr, momentum=muon_momentum, weight_decay=weight_decay) # Lion 需要稍微大一点的 weight_decay 以防止过拟合,通常建议比 AdamW 大 3-10 倍 # 这里我们将其设置为常规 weight_decay 的 3 倍 diff --git a/models/update.md b/models/update.md new file mode 100644 index 0000000..fd552e3 --- /dev/null +++ b/models/update.md @@ -0,0 +1,7 @@ +# 这个文件用来放模型更新日志(如果有人想写的话) +---- +2025/5/6: + +- 数据库:dataset56f_64k +- 超参数:256/4/8/5e-4/30/1145 +- 准确率:93.23%/89.32% \ No newline at end of file diff --git a/src/resources/data/monster.csv b/monster.csv similarity index 100% rename from src/resources/data/monster.csv rename to monster.csv diff --git a/src/resources/data/monster_greenvine.csv b/monster_greenvine.csv similarity index 100% rename from src/resources/data/monster_greenvine.csv rename to monster_greenvine.csv diff --git a/multi_instance.py b/multi_instance.py index 4f74b93..b9307c2 100644 --- a/multi_instance.py +++ b/multi_instance.py @@ -5,61 +5,47 @@ import subprocess from pathlib import Path from PyQt6.QtWidgets import ( - QApplication, - QMainWindow, - QWidget, - QVBoxLayout, - QHBoxLayout, - QPushButton, - QLabel, - QPlainTextEdit, - QComboBox, - QCheckBox, - QMessageBox, - QSplitter, - QScrollArea, - QFrame, - QLineEdit, + QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, + QPushButton, QLabel, QPlainTextEdit, QSpinBox, QComboBox, QCheckBox, + QMessageBox, QSplitter, QScrollArea, QFrame, QLineEdit ) -from PyQt6.QtCore import Qt, QTimer, pyqtSignal +from PyQt6.QtCore import Qt, QTimer, pyqtSignal, QObject, pyqtSlot from PyQt6.QtGui import QFont -from src.data import load_data -from src.game import auto_fetch -from src.data import data_package -from src.game.login import LoginManager -from src.core.config import FIELD_FEATURE_COUNT +import loadData +import auto_fetch +import data_package +from recognize import MONSTER_COUNT +from login import LoginManager +from config import FIELD_FEATURE_COUNT class LogDisplay(QPlainTextEdit): log_signal = pyqtSignal(str) - + def __init__(self, parent=None): super().__init__(parent) self.setReadOnly(True) self._auto_scroll = True self.log_signal.connect(self._on_log) - + def is_at_bottom(self): scrollbar = self.verticalScrollBar() return scrollbar.value() >= scrollbar.maximum() - 10 - + def scrollContentsBy(self, dx, dy): super().scrollContentsBy(dx, dy) self._auto_scroll = self.is_at_bottom() - + def _on_log(self, text): was_at_bottom = self._auto_scroll self.appendPlainText(text) if was_at_bottom: - self.verticalScrollBar().setValue( - self.verticalScrollBar().maximum() - ) - + self.verticalScrollBar().setValue(self.verticalScrollBar().maximum()) + def append_log(self, text): self.log_signal.emit(text) - logging.getLogger().setLevel(logging.DEBUG) logging.getLogger("PIL").setLevel(logging.INFO) stream_handler = logging.StreamHandler() @@ -74,7 +60,6 @@ def append_log(self, text): class SmartPortsLineEdit(QLineEdit): """智能端口输入框:支持延迟格式化、失去焦点格式化和粘贴立即格式化""" - def __init__(self, parent=None): super().__init__(parent) self.format_timer = QTimer(self) @@ -99,26 +84,19 @@ def _format_text(self): if self._formatting: return self._formatting = True - + text = self.text() - parts = ( - text.replace("\n", ",") - .replace(",", ",") - .replace(";", ",") - .replace(" ", ",") - .split(",") - ) + parts = text.replace('\n', ',').replace(',', ',').replace(';', ',').replace(' ', ',').split(',') ports = [p.strip() for p in parts if p.strip().isdigit()] formatted = ", ".join(ports) - + if text != formatted and ports: cursor_pos = self.cursorPosition() self.setText(formatted) self.setCursorPosition(min(cursor_pos, len(formatted))) - + self._formatting = False - # 用于共享资源密集型对象,减少多开时的内存占用 _cannot_model = None _recognizer = None @@ -131,14 +109,12 @@ def get_cannot_model(): if _cannot_model is None: logger.info("首次初始化 CannotModel...") try: - from src.models.predict import CannotModel - + from predict import CannotModel logger.info("Using PyTorch model for predictions.") except Exception: - from src.models.predict_onnx import CannotModel - + from predict_onnx import CannotModel logger.info("Using ONNX model for predictions.") - + _cannot_model = CannotModel() logger.info("CannotModel 初始化完成") return _cannot_model @@ -149,8 +125,7 @@ def get_recognizer(): global _recognizer if _recognizer is None: logger.info("首次初始化 RecognizeMonster...") - from src.recognition.recognize import RecognizeMonster - + from recognize import RecognizeMonster _recognizer = RecognizeMonster(method="ADB") logger.info("RecognizeMonster 初始化完成") return _recognizer @@ -161,8 +136,7 @@ def get_field_recognizer(): global _field_recognizer if _field_recognizer is None: logger.info("首次初始化 FieldRecognizer...") - from src.recognition.field_recognition import FieldRecognizer - + from field_recognition import FieldRecognizer _field_recognizer = FieldRecognizer() logger.info("FieldRecognizer 初始化完成") return _field_recognizer @@ -181,14 +155,12 @@ class DeviceInstance: def __init__(self, port): self.port = port self.serial = f"127.0.0.1:{port}" - self.connector = load_data.AdbConnector(self.serial) + self.connector = loadData.AdbConnector(self.serial) self.auto_fetch = None self.login_manager = None self.status = "已停止" self.auto_fetch_thread = None # 保存线程引用 - self.stop_event = ( - threading.Event() - ) # 使用Event对象进行线程间通信,更可靠 + self.stop_event = threading.Event() # 使用Event对象进行线程间通信,更可靠 self.start_time = None # 实例启动时间戳 self.last_activity_time = time.time() # 最后活动时间戳(用于检测崩溃) self.thread_running = False # 线程是否正在运行的标志 @@ -200,56 +172,49 @@ def start(self, game_mode, is_invest): # 保存设置 self.game_mode = game_mode self.is_invest = is_invest - + # 重置停止事件和标志 self.stop_event.clear() self.thread_running = True self.last_activity_time = time.time() self.status = "连接中" - - logger.info( - f"[{self.serial}] 开始启动实例,游戏模式: {game_mode}, 自动投资: {is_invest}" - ) - + + logger.info(f"[{self.serial}] 开始启动实例,游戏模式: {game_mode}, 自动投资: {is_invest}") + # 记录实例启动时间戳 self.start_time = time.time() - + self.connector.connect() if not self.connector.is_connected: self.status = "连接失败" logger.error(f"[{self.serial}] 连接失败") self.thread_running = False return False - + self.login_manager = LoginManager(self.connector) logger.info(f"[{self.serial}] 尝试首次启动自动登录") self.status = "登录中" - login_success = self.login_manager.auto_login_with_restart( - first_start=True, - stop_callback=lambda: not self.stop_event.is_set(), - ) - + login_success = self.login_manager.auto_login_with_restart(first_start=True, stop_callback=lambda: not self.stop_event.is_set()) + # 检查是否在登录过程中用户点击了停止 if self.stop_event.is_set(): logger.info(f"[{self.serial}] 登录过程被用户停止") self.status = "已停止" self.thread_running = False return False - + if login_success: logger.info(f"[{self.serial}] 首次启动自动登录成功") else: - logger.warning( - f"[{self.serial}] 首次启动自动登录失败,继续启动" - ) - + logger.warning(f"[{self.serial}] 首次启动自动登录失败,继续启动") + # 再次检查停止标志(防止在登录成功后、创建auto_fetch前用户点击停止) if self.stop_event.is_set(): logger.info(f"[{self.serial}] 用户在登录成功后点击了停止") self.status = "已停止" self.thread_running = False return False - + self.auto_fetch = auto_fetch.AutoFetch( self.connector, game_mode, @@ -262,9 +227,7 @@ def start(self, game_mode, is_invest): training_duration=-1, recognizer=get_recognizer(), cannot_model=get_cannot_model(), - field_recognizer=( - get_field_recognizer() if FIELD_FEATURE_COUNT > 0 else None - ), + field_recognizer=get_field_recognizer() if FIELD_FEATURE_COUNT > 0 else None, start_timestamp=self.start_time, # 传递实例启动时间戳 ) logger.info(f"[{self.serial}] 初始化 AutoFetch 成功") @@ -277,11 +240,11 @@ def start(self, game_mode, is_invest): logger.error(f"[{self.serial}] 启动失败: {str(e)}") self.thread_running = False return False - + def _update_activity_time(self, *args, **kwargs): """更新活动时间""" self.last_activity_time = time.time() - + def _on_stop_callback(self): """当 auto_fetch 停止时的回调""" self.thread_running = False @@ -292,7 +255,7 @@ def stop(self): # 设置停止事件,用于中断登录流程 self.stop_event.set() self.thread_running = False - + if self.auto_fetch: # 强制设置停止标志,不等待线程退出 self.auto_fetch.auto_fetch_running = False @@ -300,7 +263,7 @@ def stop(self): else: # 如果 auto_fetch 还未创建,说明可能正在登录过程中 logger.info(f"[{self.serial}] auto_fetch 尚未创建,停止登录过程") - + # 状态改为已停止(stop_event 会在下次启动时自动清除) self.status = "已停止" logger.info(f"[{self.serial}] 强制停止成功,状态: {self.status}") @@ -308,74 +271,67 @@ def stop(self): def get_status_line(self): if not self.auto_fetch or not self.auto_fetch.auto_fetch_running: return f"[{self.serial:<15}] 状态: {self.status}" - + af = self.auto_fetch elapsed = time.time() - af.start_time if af.start_time else 0 hours, remainder = divmod(elapsed, 3600) minutes, _ = divmod(remainder, 60) - + state_name = "过场动画" - if hasattr(af, "last_state") and af.last_state: - state_name = ( - af.last_state.name - if hasattr(af.last_state, "name") - else str(af.last_state) - ) - - return ( - f"[{self.serial:<15}] " - f"状态: {state_name:<8} | " - f"填写: {af.total_fill_count:<3} | " - f"错误: {af.incorrect_fill_count:<3} | " - f"预测: {af.current_prediction:.2f} | " - f"时长: {int(hours)}h {int(minutes)}m" - ) - + if hasattr(af, 'last_state') and af.last_state: + state_name = af.last_state.name if hasattr(af.last_state, 'name') else str(af.last_state) + + return (f"[{self.serial:<15}] " + f"状态: {state_name:<8} | " + f"填写: {af.total_fill_count:<3} | " + f"错误: {af.incorrect_fill_count:<3} | " + f"预测: {af.current_prediction:.2f} | " + f"时长: {int(hours)}h {int(minutes)}m") class MultiInstanceManager(QMainWindow): instance = None # 类变量,用于在回调函数中引用当前实例 - + def __init__(self): super().__init__() MultiInstanceManager.instance = self # 保存当前实例的引用 self.setWindowTitle("铁鲨鱼多开自动化工具") self.setGeometry(100, 100, 530, 720) - + self.instances = {} self.starting_ports = set() # 正在启动中的端口集合,防止重复启动 self.init_ui() self.setup_logger() - + # 定时更新界面 self.timer = QTimer() self.timer.timeout.connect(self.update_display) self.timer.start(1000) - + # 崩溃检测定时器(每 5 秒检查一次) self.crash_detection_timer = QTimer() self.crash_detection_timer.timeout.connect(self.check_instances_crash) self.crash_detection_timer.start(5000) - + def init_ui(self): central_widget = QWidget() self.setCentralWidget(central_widget) layout = QVBoxLayout(central_widget) - + # 配置区域 settings_layout = QHBoxLayout() - + self.game_mode_combo = QComboBox() self.game_mode_combo.addItems(["单人", "30人"]) settings_layout.addWidget(QLabel("模式:")) settings_layout.addWidget(self.game_mode_combo) - + self.invest_check = QCheckBox("自动投资") self.invest_check.setChecked(False) settings_layout.addWidget(self.invest_check) settings_layout.addStretch() - + layout.addLayout(settings_layout) - + # 端口输入(横向,逗号分隔) ports_layout = QHBoxLayout() ports_layout.addWidget(QLabel("端口:")) @@ -390,7 +346,7 @@ def init_ui(self): pass ports_layout.addWidget(self.ports_input) layout.addLayout(ports_layout) - + # 按钮和端口选择器 btn_layout = QHBoxLayout() self.start_btn = QPushButton("全部启动") @@ -399,26 +355,26 @@ def init_ui(self): self.stop_btn.clicked.connect(self.stop_all) self.package_btn = QPushButton("打包数据") self.package_btn.clicked.connect(self.package_data) - + # 端口选择器,用于选择要查看哪个端口的日志 self.port_combo = QComboBox() self.port_combo.addItem("全部端口") self.port_combo.currentTextChanged.connect(self.update_log_filter) - + btn_layout.addWidget(self.start_btn) btn_layout.addWidget(self.stop_btn) btn_layout.addWidget(self.package_btn) btn_layout.addWidget(QLabel("日志过滤:")) btn_layout.addWidget(self.port_combo) layout.addLayout(btn_layout) - + font = QFont("Courier New", 10) if sys.platform == "win32": font = QFont("Consolas", 10) - + # 使用 QSplitter 让状态和日志区域可以自由拖动调整大小 splitter = QSplitter(Qt.Orientation.Vertical) - + # 状态显示区域(带单独控制按钮的滚动区域) self.status_scroll = QScrollArea() self.status_scroll.setWidgetResizable(True) @@ -431,29 +387,23 @@ def init_ui(self): self.status_scroll.setWidget(self.status_container) self.status_scroll.setMinimumHeight(80) splitter.addWidget(self.status_scroll) - + # 日志显示 self.log_display = LogDisplay() self.log_display.setFont(font) self.log_display.setMaximumBlockCount(2000) splitter.addWidget(self.log_display) - + splitter.setStretchFactor(0, 1) splitter.setStretchFactor(1, 3) splitter.setSizes([440, 330]) layout.addWidget(splitter) - + self.port_widgets = {} @staticmethod def _parse_ports(text): - parts = ( - text.replace("\n", ",") - .replace(",", ",") - .replace(";", ",") - .replace(" ", ",") - .split(",") - ) + parts = text.replace('\n', ',').replace(',', ',').replace(';', ',').replace(' ', ',').split(',') return [p.strip() for p in parts if p.strip().isdigit()] def start_all(self): @@ -462,15 +412,13 @@ def start_all(self): logger.info("保存端口配置到 multi_ports.txt") except Exception as e: logger.error(f"保存端口配置失败: {str(e)}") - + ports = self._parse_ports(self.ports_input.text()) game_mode = self.game_mode_combo.currentText() is_invest = self.invest_check.isChecked() - - logger.info( - f"开始启动多开实例,端口列表: {ports}, 游戏模式: {game_mode}, 自动投资: {is_invest}" - ) - + + logger.info(f"开始启动多开实例,端口列表: {ports}, 游戏模式: {game_mode}, 自动投资: {is_invest}") + def start_single_instance(port): # 检查是否已经在运行或正在启动中 is_running = False @@ -478,12 +426,12 @@ def start_single_instance(port): inst = self.instances[port] if inst.auto_fetch and inst.auto_fetch.auto_fetch_running: is_running = True - + # 使用启动锁防止重复启动 if port in self.starting_ports: logger.info(f"端口 {port} 的实例正在启动中,跳过重复启动") return - + if not is_running: # 添加到启动中集合 self.starting_ports.add(port) @@ -501,21 +449,19 @@ def start_single_instance(port): self.starting_ports.discard(port) else: logger.info(f"端口 {port} 的实例已经在运行,跳过启动") - + def start_all_instances(): threads = [] for port in ports: - t = threading.Thread( - target=start_single_instance, args=(port,), daemon=True - ) + t = threading.Thread(target=start_single_instance, args=(port,), daemon=True) t.start() threads.append(t) time.sleep(3) for t in threads: t.join() - + threading.Thread(target=start_all_instances, daemon=True).start() - + def stop_all(self): logger.info("开始停止所有实例") # 清空启动中集合,防止正在启动的实例继续运行 @@ -531,16 +477,10 @@ def package_data(self): zip_filename = data_package.package_data() if zip_filename and Path(zip_filename).exists(): # 在文件浏览器中高亮显示文件 - subprocess.run( - f'explorer /select,"{Path(zip_filename).absolute()}"' - ) - QMessageBox.information( - self, "成功", f"数据已打包到 {zip_filename}" - ) + subprocess.run(f'explorer /select,"{Path(zip_filename).absolute()}"') + QMessageBox.information(self, "成功", f"数据已打包到 {zip_filename}") else: - QMessageBox.warning( - self, "警告", "没有找到可以打包的数据目录或打包失败。" - ) + QMessageBox.warning(self, "警告", "没有找到可以打包的数据目录或打包失败。") except Exception as e: QMessageBox.critical(self, "错误", f"打包数据时发生错误: {str(e)}") @@ -549,57 +489,43 @@ class QTextEditLogger(logging.Handler): def __init__(self, text_edit): super().__init__() self.text_edit = text_edit - self.setFormatter( - logging.Formatter( - "%(asctime)s - %(levelname)s - %(message)s" - ) - ) + self.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')) self.target_port = None self.log_history = [] - + def set_target_port(self, port): self.target_port = port - + def emit(self, record): try: msg = self.format(record) except Exception: return - + self.log_history.append(msg) if len(self.log_history) > 2000: self.log_history.pop(0) - + if self.target_port: port_str = str(self.target_port) - if not ( - f"[127.0.0.1:{port_str}]" in msg - or f"[{port_str}]" in msg - or f"端口 {port_str}" in msg - ): + if not (f"[127.0.0.1:{port_str}]" in msg or f"[{port_str}]" in msg or f"端口 {port_str}" in msg): return - + if self.text_edit is not None: self.text_edit.append_log(msg) - + root_logger = logging.getLogger() self.text_edit_logger = QTextEditLogger(self.log_display) self.text_edit_logger.setLevel(logging.INFO) root_logger.addHandler(self.text_edit_logger) root_logger.setLevel(logging.INFO) - + # 确保子模块日志传播到 root logger - for name in [ - "login", - "auto_fetch", - "recognize", - "multi_instance", - "__main__", - ]: + for name in ['login', 'auto_fetch', 'recognize', 'multi_instance', '__main__']: child_logger = logging.getLogger(name) child_logger.setLevel(logging.INFO) child_logger.propagate = True - + def update_log_filter(self, text): if text == "全部端口": self.text_edit_logger.set_target_port(None) @@ -612,11 +538,10 @@ def update_log_filter(self, text): for msg in self.text_edit_logger.log_history: if f"[{text}]" in msg or f"端口 {text}" in msg or text in msg: self.log_display.append_log(msg) - + @staticmethod def _state_to_chinese(state): - from src.game.auto_fetch import GameState - + from auto_fetch import GameState state_map = { GameState.MAIN_MENU: "主页", GameState.MODE_SELECTION_UNSELECTED: "模式", @@ -628,46 +553,36 @@ def _state_to_chinese(state): GameState.UNKNOWN: "过场", } return state_map.get(state, "过场动画") - + def _create_port_widget(self, port): row = QHBoxLayout() row.setContentsMargins(4, 2, 4, 2) row.setSpacing(6) - + label = QLabel(port) label.setFixedWidth(60) - label.setFont( - QFont("Consolas", 10) - if sys.platform == "win32" - else QFont("Courier New", 10) - ) + label.setFont(QFont("Consolas", 10) if sys.platform == "win32" else QFont("Courier New", 10)) row.addWidget(label) - + status_label = QLabel("已停止") status_label.setFixedWidth(80) row.addWidget(status_label) - + detail_label = QLabel("") - detail_label.setFont( - QFont("Consolas", 9) - if sys.platform == "win32" - else QFont("Courier New", 9) - ) + detail_label.setFont(QFont("Consolas", 9) if sys.platform == "win32" else QFont("Courier New", 9)) row.addWidget(detail_label, 1) - + toggle_btn = QPushButton("启动") toggle_btn.setFixedWidth(50) - toggle_btn.clicked.connect( - lambda checked, p=port: self._toggle_port(p) - ) + toggle_btn.clicked.connect(lambda checked, p=port: self._toggle_port(p)) row.addWidget(toggle_btn) - + frame = QFrame() frame.setLayout(row) frame.setFrameShape(QFrame.Shape.StyledPanel) - + return frame, status_label, detail_label, toggle_btn - + def _toggle_port(self, port): if port in self.instances: instance = self.instances[port] @@ -679,7 +594,7 @@ def _toggle_port(self, port): else: game_mode = self.game_mode_combo.currentText() is_invest = self.invest_check.isChecked() - + def do_start(): if port in self.starting_ports: return @@ -690,66 +605,57 @@ def do_start(): instance.start(game_mode, is_invest) finally: self.starting_ports.discard(port) - + threading.Thread(target=do_start, daemon=True).start() - + def check_instances_crash(self): """检查实例是否崩溃,并尝试自动恢复""" current_time = time.time() - + # 遍历所有实例,检查崩溃情况 for port, instance in list(self.instances.items()): # 如果已经设置了停止事件,就不进行崩溃检测 if instance.stop_event.is_set(): continue - + # 检查活动时间(崩溃检测) inactive_time = current_time - instance.last_activity_time - + # 如果标记为运行但超过 3 分钟没有活动,视为崩溃 - if ( - instance.status in ["正在运行", "连接中", "登录中"] - and inactive_time > 180 - ): - logger.warning( - f"[{instance.serial}] 检测到无活动超过 {inactive_time:.0f} 秒,可能已崩溃,尝试重启" - ) + if instance.status in ["正在运行", "连接中", "登录中"] and inactive_time > 180: + logger.warning(f"[{instance.serial}] 检测到无活动超过 {inactive_time:.0f} 秒,可能已崩溃,尝试重启") self._restart_crashed_instance(port, instance) # 检查 auto_fetch 线程是否实际还在运行 elif instance.status == "正在运行" and instance.auto_fetch: if not instance.auto_fetch.auto_fetch_running: - logger.warning( - f"[{instance.serial}] auto_fetch_running 为 False,可能已意外停止" - ) + logger.warning(f"[{instance.serial}] auto_fetch_running 为 False,可能已意外停止") self._restart_crashed_instance(port, instance) - + def _restart_crashed_instance(self, port, instance): """重启崩溃的实例""" try: # 保存设置 game_mode = instance.game_mode if instance.game_mode else "30人" - is_invest = ( - instance.is_invest if instance.is_invest is not None else False - ) - + is_invest = instance.is_invest if instance.is_invest is not None else False + # 先停止(强制) instance.stop() - + # 从字典中清除 if port in self.instances: del self.instances[port] - + # 延迟重新启动 logger.info(f"[{instance.serial}] 准备重新启动...") - + def restart_task(): if port in self.starting_ports: logger.warning(f"端口 {port} 已在启动中,跳过重启") return - + logger.info(f"[{instance.serial}] 正在重新启动...") self.starting_ports.add(port) - + try: new_instance = DeviceInstance(port) self.instances[port] = new_instance @@ -760,108 +666,98 @@ def restart_task(): logger.error(f"[{instance.serial}] 崩溃后重启失败") finally: self.starting_ports.discard(port) - + threading.Thread(target=restart_task, daemon=True).start() except Exception as e: logger.error(f"重启崩溃实例时出错: {str(e)}") - + def update_display(self): input_ports = self._parse_ports(self.ports_input.text()) - - if not hasattr(self, "_last_input_ports"): + + if not hasattr(self, '_last_input_ports'): self._last_input_ports = [] - + ports_changed = input_ports != self._last_input_ports - + if ports_changed: current_text = self.port_combo.currentText() self.port_combo.clear() self.port_combo.addItem("全部端口") for port in input_ports: self.port_combo.addItem(port) - + if input_ports: if current_text in input_ports: self.port_combo.setCurrentText(current_text) else: self.port_combo.setCurrentIndex(1) self._last_input_ports = input_ports.copy() - + # 重建端口控件 for w in self.port_widgets.values(): - w["frame"].setParent(None) + w['frame'].setParent(None) self.port_widgets.clear() - + for i in range(self.status_layout.count() - 1): item = self.status_layout.itemAt(i) if item.widget(): item.widget().setParent(None) - + for port in input_ports: - frame, status_label, detail_label, toggle_btn = ( - self._create_port_widget(port) - ) + frame, status_label, detail_label, toggle_btn = self._create_port_widget(port) idx = self.status_layout.count() - 1 self.status_layout.insertWidget(idx, frame) self.port_widgets[port] = { - "frame": frame, - "status_label": status_label, - "detail_label": detail_label, - "toggle_btn": toggle_btn, + 'frame': frame, + 'status_label': status_label, + 'detail_label': detail_label, + 'toggle_btn': toggle_btn, } - + any_running = False for port in input_ports: if port not in self.port_widgets: continue - + widgets = self.port_widgets[port] - + if port in self.instances: instance = self.instances[port] - is_running = ( - instance.auto_fetch - and instance.auto_fetch.auto_fetch_running - ) - + is_running = instance.auto_fetch and instance.auto_fetch.auto_fetch_running + if is_running: any_running = True af = instance.auto_fetch - elapsed = ( - time.time() - af.start_time if af.start_time else 0 - ) + elapsed = time.time() - af.start_time if af.start_time else 0 hours, remainder = divmod(elapsed, 3600) minutes, _ = divmod(remainder, 60) - + state_name = "过场动画" - if hasattr(af, "last_state") and af.last_state: + if hasattr(af, 'last_state') and af.last_state: state_name = self._state_to_chinese(af.last_state) - - widgets["status_label"].setText(f"运行中·{state_name}") - widgets["detail_label"].setText( + + widgets['status_label'].setText(f"运行中·{state_name}") + widgets['detail_label'].setText( f"填写: {af.total_fill_count} | 错误: {af.incorrect_fill_count} | " f"预测: {af.current_prediction:.2f} | 时长: {int(hours)}h {int(minutes)}m" ) - widgets["toggle_btn"].setText("停止") + widgets['toggle_btn'].setText("停止") else: - widgets["status_label"].setText(instance.status) - widgets["detail_label"].setText("") + widgets['status_label'].setText(instance.status) + widgets['detail_label'].setText("") is_starting = instance.status in ("连接中", "登录中") - widgets["toggle_btn"].setText( - "停止" if is_starting else "启动" - ) + widgets['toggle_btn'].setText("停止" if is_starting else "启动") else: - widgets["status_label"].setText("已停止") - widgets["detail_label"].setText("") - widgets["toggle_btn"].setText("启动") - + widgets['status_label'].setText("已停止") + widgets['detail_label'].setText("") + widgets['toggle_btn'].setText("启动") + self.package_btn.setEnabled(not any_running) def closeEvent(self, event): self.stop_all() event.accept() - if __name__ == "__main__": app = QApplication(sys.argv) window = MultiInstanceManager() diff --git a/vendor/bin/platform-tools/AdbWinApi.dll b/platform-tools/AdbWinApi.dll similarity index 100% rename from vendor/bin/platform-tools/AdbWinApi.dll rename to platform-tools/AdbWinApi.dll diff --git a/vendor/bin/platform-tools/AdbWinUsbApi.dll b/platform-tools/AdbWinUsbApi.dll similarity index 100% rename from vendor/bin/platform-tools/AdbWinUsbApi.dll rename to platform-tools/AdbWinUsbApi.dll diff --git a/vendor/bin/platform-tools/NOTICE.txt b/platform-tools/NOTICE.txt similarity index 100% rename from vendor/bin/platform-tools/NOTICE.txt rename to platform-tools/NOTICE.txt diff --git a/vendor/bin/platform-tools/adb.exe b/platform-tools/adb.exe similarity index 100% rename from vendor/bin/platform-tools/adb.exe rename to platform-tools/adb.exe diff --git a/vendor/bin/platform-tools/etc1tool.exe b/platform-tools/etc1tool.exe similarity index 100% rename from vendor/bin/platform-tools/etc1tool.exe rename to platform-tools/etc1tool.exe diff --git a/vendor/bin/platform-tools/fastboot.exe b/platform-tools/fastboot.exe similarity index 100% rename from vendor/bin/platform-tools/fastboot.exe rename to platform-tools/fastboot.exe diff --git a/vendor/bin/platform-tools/hprof-conv.exe b/platform-tools/hprof-conv.exe similarity index 100% rename from vendor/bin/platform-tools/hprof-conv.exe rename to platform-tools/hprof-conv.exe diff --git a/vendor/bin/platform-tools/libwinpthread-1.dll b/platform-tools/libwinpthread-1.dll similarity index 100% rename from vendor/bin/platform-tools/libwinpthread-1.dll rename to platform-tools/libwinpthread-1.dll diff --git a/vendor/bin/platform-tools/make_f2fs.exe b/platform-tools/make_f2fs.exe similarity index 100% rename from vendor/bin/platform-tools/make_f2fs.exe rename to platform-tools/make_f2fs.exe diff --git a/vendor/bin/platform-tools/make_f2fs_casefold.exe b/platform-tools/make_f2fs_casefold.exe similarity index 100% rename from vendor/bin/platform-tools/make_f2fs_casefold.exe rename to platform-tools/make_f2fs_casefold.exe diff --git a/vendor/bin/platform-tools/mke2fs.conf b/platform-tools/mke2fs.conf similarity index 100% rename from vendor/bin/platform-tools/mke2fs.conf rename to platform-tools/mke2fs.conf diff --git a/vendor/bin/platform-tools/mke2fs.exe b/platform-tools/mke2fs.exe similarity index 100% rename from vendor/bin/platform-tools/mke2fs.exe rename to platform-tools/mke2fs.exe diff --git a/vendor/bin/platform-tools/source.properties b/platform-tools/source.properties similarity index 100% rename from vendor/bin/platform-tools/source.properties rename to platform-tools/source.properties diff --git a/vendor/bin/platform-tools/sqlite3.exe b/platform-tools/sqlite3.exe similarity index 100% rename from vendor/bin/platform-tools/sqlite3.exe rename to platform-tools/sqlite3.exe diff --git a/src/models/predict.py b/predict.py similarity index 61% rename from src/models/predict.py rename to predict.py index 8e14cc4..59edb44 100644 --- a/src/models/predict.py +++ b/predict.py @@ -1,6 +1,4 @@ import re -import sys -import importlib from datetime import datetime from functools import cache from pathlib import Path @@ -9,37 +7,11 @@ import torch import logging -from src.core.config import MONSTER_COUNT -from src.core.config import FIELD_FEATURE_COUNT +from config import MONSTER_COUNT +from config import FIELD_FEATURE_COUNT logger = logging.getLogger(__name__) - -def _register_legacy_model_aliases(): - """ - 为旧版 pickle 模型提供模块路径兼容: - 例如历史权重里记录的是 `models.model`,而当前代码已迁移到 `src.models.model`。 - """ - legacy_to_new = { - "models": "src.models", - "models.model": "src.models.model", - "models.muon": "src.models.muon", - } - - for legacy_name, new_name in legacy_to_new.items(): - if legacy_name in sys.modules: - continue - try: - sys.modules[legacy_name] = importlib.import_module(new_name) - except Exception as e: - logger.debug( - "兼容模块别名注册失败: %s -> %s, %s", - legacy_name, - new_name, - e, - ) - - def get_device(prefer_gpu=True): """ prefer_gpu (bool): 是否优先尝试使用GPU @@ -48,10 +20,7 @@ def get_device(prefer_gpu=True): if torch.cuda.is_available(): logger.info("Use torch with cuda") return torch.device("cuda") - elif ( - hasattr(torch.backends, "mps") - and torch.backends.mps.is_available() - ): + elif hasattr(torch.backends, "mps") and torch.backends.mps.is_available(): logger.info("Use torch with mps") return torch.device("mps") # Apple Silicon GPU elif hasattr(torch, "xpu") and torch.xpu.is_available(): # Intel GPU @@ -60,7 +29,6 @@ def get_device(prefer_gpu=True): logger.info("Use torch with cpu") return torch.device("cpu") - class CannotModel: def __init__(self, model_path="models"): self.device = get_device() @@ -81,11 +49,7 @@ def _resolve_model_path(self, path): if Path(path).is_dir(): logger.info(f"Searching for the latest model in directory: {path}") model_dir = Path(path) - models = [ - f - for f in model_dir.iterdir() - if f.suffix == ".pth" and f.is_file() - ] + models = [f for f in model_dir.iterdir() if f.suffix == ".pth" and f.is_file()] if not models: logger.error(f"No model files (.pth) found in {path}") @@ -100,20 +64,12 @@ def _resolve_model_path(self, path): match = pattern.match(model_file_path.name) if match: model_type = match.group(1) - timestamp_str = match.group( - 2 - ) # Group 2 captures the timestamp + timestamp_str = match.group(2) # Group 2 captures the timestamp try: model_time = datetime.strptime( timestamp_str, "%Y_%m_%d_%H_%M_%S" ) - valid_models.append( - ( - model_time, - priority.get(model_type, 3), - model_file_path, - ) - ) + valid_models.append((model_time, priority.get(model_type, 3), model_file_path)) except ValueError: continue # Ignore files with malformed timestamps @@ -143,9 +99,6 @@ def load_model(self): rf"未找到训练好的模型文件 {self.model_path},请先训练模型" ) - # 兼容项目重构前保存的整模型 pickle 路径 - _register_legacy_model_aliases() - try: model = torch.load( self.model_path, @@ -153,7 +106,9 @@ def load_model(self): weights_only=False, ) except TypeError: # 如果旧版本 PyTorch 不认识 weights_only - model = torch.load(self.model_path, map_location=self.device) + model = torch.load( + self.model_path, map_location=self.device + ) model.eval() self.model = model.to(self.device) @@ -162,20 +117,16 @@ def load_model(self): if "missing keys" in str(e): error_msg += "\n可能是模型结构不匹配,请重新训练模型" raise e # 无法继续运行,退出程序 - - def export_onnx(self, outputpath, monster_count=MONSTER_COUNT): + + def export_onnx(self,outputpath, monster_count=MONSTER_COUNT): # 确保模型在 CPU 上(避免设备不一致) self.model = self.model.cpu() self.model.eval() # 生成虚拟输入(与模型同设备) device = next(self.model.parameters()).device - dummy_left_counts = torch.randint( - 0, 10, (1, monster_count), dtype=torch.int16, device=device - ) - dummy_right_counts = torch.randint( - 0, 10, (1, monster_count), dtype=torch.int16, device=device - ) + dummy_left_counts = torch.randint(0, 10, (1, monster_count), dtype=torch.int16, device=device) + dummy_right_counts = torch.randint(0, 10, (1, monster_count), dtype=torch.int16, device=device) # 获取符号和绝对值张量(确保在相同设备) left_signs = torch.sign(dummy_left_counts.to(torch.int64)).to(device) @@ -184,14 +135,9 @@ def export_onnx(self, outputpath, monster_count=MONSTER_COUNT): right_counts = torch.abs(dummy_right_counts.to(torch.int64)).to(device) # 导出参数 - input_names = [ - "left_signs", - "left_counts", - "right_signs", - "right_counts", - ] - dynamic_axes = {name: {0: "batch_size"} for name in input_names} - dynamic_axes["output"] = {0: "batch_size"} + input_names = ["left_signs", "left_counts", "right_signs", "right_counts"] + dynamic_axes = {name: {0: 'batch_size'} for name in input_names} + dynamic_axes["output"] = {0: 'batch_size'} # 导出 ONNX torch.onnx.export( @@ -202,14 +148,10 @@ def export_onnx(self, outputpath, monster_count=MONSTER_COUNT): output_names=["output"], dynamic_axes=dynamic_axes, opset_version=20, - verbose=True, # 开启详细输出便于调试 + verbose=True # 开启详细输出便于调试 ) - def get_prediction( - self, - left_counts: np.typing.ArrayLike, - right_counts: np.typing.ArrayLike, - ): + def get_prediction(self, left_counts: np.typing.ArrayLike, right_counts: np.typing.ArrayLike): if self.model is None: raise RuntimeError("模型未正确初始化") @@ -259,34 +201,20 @@ def get_prediction_with_terrain(self, full_features: np.typing.ArrayLike): raise RuntimeError("模型未正确初始化") # 检查特征向量长度 - expected_length = ( - MONSTER_COUNT * 2 + FIELD_FEATURE_COUNT * 2 - ) # 77L + 6L + 77R + 6R = 166 + expected_length = MONSTER_COUNT * 2 + FIELD_FEATURE_COUNT * 2 # 77L + 6L + 77R + 6R = 166 if len(full_features) != expected_length: - logger.warning( - f"特征向量长度不匹配: 期望{expected_length}, 实际{len(full_features)}" - ) + logger.warning(f"特征向量长度不匹配: 期望{expected_length}, 实际{len(full_features)}") # 如果长度不匹配,回退到原始方法 left_counts = full_features[:MONSTER_COUNT] - right_counts = full_features[MONSTER_COUNT : MONSTER_COUNT * 2] + right_counts = full_features[MONSTER_COUNT:MONSTER_COUNT*2] return self.get_prediction(left_counts, right_counts) # 提取各个部分 left_monsters = full_features[:MONSTER_COUNT] # 1L-77L - left_terrain = full_features[ - MONSTER_COUNT : MONSTER_COUNT + FIELD_FEATURE_COUNT - ] # 78L-83L - right_monsters = full_features[ - MONSTER_COUNT - + FIELD_FEATURE_COUNT : MONSTER_COUNT * 2 - + FIELD_FEATURE_COUNT - ] # 1R-77R - right_terrain = full_features[ - MONSTER_COUNT * 2 - + FIELD_FEATURE_COUNT : MONSTER_COUNT * 2 - + FIELD_FEATURE_COUNT * 2 - ] # 78R-83R - + left_terrain = full_features[MONSTER_COUNT:MONSTER_COUNT+FIELD_FEATURE_COUNT] # 78L-83L + right_monsters = full_features[MONSTER_COUNT+FIELD_FEATURE_COUNT:MONSTER_COUNT*2+FIELD_FEATURE_COUNT] # 1R-77R + right_terrain = full_features[MONSTER_COUNT*2+FIELD_FEATURE_COUNT:MONSTER_COUNT*2+FIELD_FEATURE_COUNT*2] # 78R-83R + # 合并怪物特征和地形特征(按照训练时的格式) left_counts = np.concatenate([left_monsters, left_terrain]) right_counts = np.concatenate([right_monsters, right_terrain]) @@ -294,62 +222,27 @@ def get_prediction_with_terrain(self, full_features: np.typing.ArrayLike): # 转换为张量并处理符号和绝对值 # 对于怪物特征,使用符号和绝对值 # 对于地形特征,不需要符号处理(地形特征本身就是0/1值) - left_monster_signs = torch.sign( - torch.tensor(left_monsters, dtype=torch.int16) - ) - left_terrain_signs = torch.ones_like( - torch.tensor(left_terrain, dtype=torch.int16) - ) # 地形特征符号为1 - left_signs = ( - torch.cat([left_monster_signs, left_terrain_signs]) - .unsqueeze(0) - .to(self.device) - ) - - left_monster_counts = torch.abs( - torch.tensor(left_monsters, dtype=torch.int16) - ) - left_terrain_counts = torch.tensor( - left_terrain, dtype=torch.int16 - ) # 地形特征直接使用原值 - left_counts_tensor = ( - torch.cat([left_monster_counts, left_terrain_counts]) - .unsqueeze(0) - .to(self.device) - ) - - right_monster_signs = torch.sign( - torch.tensor(right_monsters, dtype=torch.int16) - ) - right_terrain_signs = torch.ones_like( - torch.tensor(right_terrain, dtype=torch.int16) - ) # 地形特征符号为1 - right_signs = ( - torch.cat([right_monster_signs, right_terrain_signs]) - .unsqueeze(0) - .to(self.device) - ) - - right_monster_counts = torch.abs( - torch.tensor(right_monsters, dtype=torch.int16) - ) - right_terrain_counts = torch.tensor( - right_terrain, dtype=torch.int16 - ) # 地形特征直接使用原值 - right_counts_tensor = ( - torch.cat([right_monster_counts, right_terrain_counts]) - .unsqueeze(0) - .to(self.device) - ) + left_monster_signs = torch.sign(torch.tensor(left_monsters, dtype=torch.int16)) + left_terrain_signs = torch.ones_like(torch.tensor(left_terrain, dtype=torch.int16)) # 地形特征符号为1 + left_signs = torch.cat([left_monster_signs, left_terrain_signs]).unsqueeze(0).to(self.device) + + left_monster_counts = torch.abs(torch.tensor(left_monsters, dtype=torch.int16)) + left_terrain_counts = torch.tensor(left_terrain, dtype=torch.int16) # 地形特征直接使用原值 + left_counts_tensor = torch.cat([left_monster_counts, left_terrain_counts]).unsqueeze(0).to(self.device) + + right_monster_signs = torch.sign(torch.tensor(right_monsters, dtype=torch.int16)) + right_terrain_signs = torch.ones_like(torch.tensor(right_terrain, dtype=torch.int16)) # 地形特征符号为1 + right_signs = torch.cat([right_monster_signs, right_terrain_signs]).unsqueeze(0).to(self.device) + + right_monster_counts = torch.abs(torch.tensor(right_monsters, dtype=torch.int16)) + right_terrain_counts = torch.tensor(right_terrain, dtype=torch.int16) # 地形特征直接使用原值 + right_counts_tensor = torch.cat([right_monster_counts, right_terrain_counts]).unsqueeze(0).to(self.device) # 预测流程 with torch.no_grad(): # 使用修改后的模型前向传播流程,现在包含地形特征 prediction = self.model( - left_signs, - left_counts_tensor, - right_signs, - right_counts_tensor, + left_signs, left_counts_tensor, right_signs, right_counts_tensor ).item() # 确保预测值在有效范围内 diff --git a/src/models/predict_onnx.py b/predict_onnx.py similarity index 74% rename from src/models/predict_onnx.py rename to predict_onnx.py index 6ae999d..31a527f 100644 --- a/src/models/predict_onnx.py +++ b/predict_onnx.py @@ -5,12 +5,11 @@ import numpy as np import logging -from src.core.config import MONSTER_COUNT -from src.core.config import FIELD_FEATURE_COUNT +from config import MONSTER_COUNT +from config import FIELD_FEATURE_COUNT logger = logging.getLogger(__name__) - class CannotModel: def __init__(self, model_path="models"): self.model_path = self._resolve_model_path(model_path) @@ -36,7 +35,7 @@ def _resolve_model_path(self, path): if default_path.exists(): logger.info(f"Found default model: {default_path}") return str(default_path) - + logger.error(f"No valid ONNX model files found in {path}") return str(default_path) @@ -51,42 +50,36 @@ def load_model(self): """加载 ONNX 模型""" try: if not os.path.exists(self.model_path): - raise FileNotFoundError( - f"未找到 ONNX 模型文件 {self.model_path}" - ) - + raise FileNotFoundError(f"未找到 ONNX 模型文件 {self.model_path}") + # 配置会话选项 sess_options = ort.SessionOptions() - sess_options.graph_optimization_level = ( - ort.GraphOptimizationLevel.ORT_ENABLE_ALL - ) - + sess_options.graph_optimization_level = ort.GraphOptimizationLevel.ORT_ENABLE_ALL + # 创建会话(默认使用 CPU) self.session = ort.InferenceSession( self.model_path, sess_options, - providers=["CPUExecutionProvider"], + providers=['CPUExecutionProvider'] ) - + except Exception as e: raise RuntimeError(f"ONNX 模型加载失败: {str(e)}") - def get_prediction( - self, left_counts: np.ndarray, right_counts: np.ndarray - ): + def get_prediction(self, left_counts: np.ndarray, right_counts: np.ndarray): if self.session is None: raise RuntimeError("模型未正确初始化") - + def validate_input(arr): """验证并转换输入数据""" # 转换为 int64 类型 arr = arr.astype(np.int64) - + # 添加批次维度(如果输入是单样本) if arr.ndim == 1: arr = arr[np.newaxis, :] # shape: (1, 56) return arr - + # 处理符号和绝对值,以匹配导出的模型输入 left_signs_arr = np.sign(left_counts).astype(np.int64) left_counts_arr = np.abs(left_counts).astype(np.int64) @@ -97,60 +90,47 @@ def validate_input(arr): "left_signs": validate_input(left_signs_arr), "left_counts": validate_input(left_counts_arr), "right_signs": validate_input(right_signs_arr), - "right_counts": validate_input(right_counts_arr), + "right_counts": validate_input(right_counts_arr) } - + # 执行推理 try: output = self.session.run( - output_names=["output"], input_feed=inputs + output_names=["output"], + input_feed=inputs ) # output 是一个列表,output[0] 是形状为 (batch_size, 1) 的数组 prediction = output[0].flatten()[0] except Exception as e: raise RuntimeError(f"推理失败: {str(e)}") - + # 后处理(与原逻辑一致) if np.isnan(prediction) or np.isinf(prediction): logger.warning("警告: 预测结果包含NaN或Inf,返回默认值0.5") prediction = 0.5 - + prediction = np.clip(prediction, 0.0, 1.0) return float(prediction) - + def get_prediction_with_terrain(self, full_features: np.ndarray): """使用包含地形特征的完整特征向量进行预测(ONNX版本)""" if self.session is None: raise RuntimeError("模型未正确初始化") # 检查特征向量长度 - expected_length = ( - MONSTER_COUNT * 2 + FIELD_FEATURE_COUNT * 2 - ) # 77L + 6L + 77R + 6R = 166 + expected_length = MONSTER_COUNT * 2 + FIELD_FEATURE_COUNT * 2 # 77L + 6L + 77R + 6R = 166 if len(full_features) != expected_length: - logger.warning( - f"特征向量长度不匹配: 期望{expected_length}, 实际{len(full_features)}" - ) + logger.warning(f"特征向量长度不匹配: 期望{expected_length}, 实际{len(full_features)}") # 如果长度不匹配,回退到原始方法 left_counts = full_features[:MONSTER_COUNT] - right_counts = full_features[MONSTER_COUNT : MONSTER_COUNT * 2] + right_counts = full_features[MONSTER_COUNT:MONSTER_COUNT*2] return self.get_prediction(left_counts, right_counts) # 提取各个部分 left_monsters = full_features[:MONSTER_COUNT] # 1L-77L - left_terrain = full_features[ - MONSTER_COUNT : MONSTER_COUNT + FIELD_FEATURE_COUNT - ] # 78L-83L - right_monsters = full_features[ - MONSTER_COUNT - + FIELD_FEATURE_COUNT : MONSTER_COUNT * 2 - + FIELD_FEATURE_COUNT - ] # 1R-77R - right_terrain = full_features[ - MONSTER_COUNT * 2 - + FIELD_FEATURE_COUNT : MONSTER_COUNT * 2 - + FIELD_FEATURE_COUNT * 2 - ] # 78R-83R + left_terrain = full_features[MONSTER_COUNT:MONSTER_COUNT+FIELD_FEATURE_COUNT] # 78L-83L + right_monsters = full_features[MONSTER_COUNT+FIELD_FEATURE_COUNT:MONSTER_COUNT*2+FIELD_FEATURE_COUNT] # 1R-77R + right_terrain = full_features[MONSTER_COUNT*2+FIELD_FEATURE_COUNT:MONSTER_COUNT*2+FIELD_FEATURE_COUNT*2] # 78R-83R # 处理左侧特征 left_monster_signs = np.sign(left_monsters).astype(np.int64) @@ -158,21 +138,15 @@ def get_prediction_with_terrain(self, full_features: np.ndarray): left_signs = np.concatenate([left_monster_signs, left_terrain_signs]) left_monster_counts = np.abs(left_monsters).astype(np.int64) - left_counts = np.concatenate( - [left_monster_counts, left_terrain.astype(np.int64)] - ) + left_counts = np.concatenate([left_monster_counts, left_terrain.astype(np.int64)]) # 处理右侧特征 right_monster_signs = np.sign(right_monsters).astype(np.int64) right_terrain_signs = np.ones_like(right_terrain).astype(np.int64) - right_signs = np.concatenate( - [right_monster_signs, right_terrain_signs] - ) + right_signs = np.concatenate([right_monster_signs, right_terrain_signs]) right_monster_counts = np.abs(right_monsters).astype(np.int64) - right_counts = np.concatenate( - [right_monster_counts, right_terrain.astype(np.int64)] - ) + right_counts = np.concatenate([right_monster_counts, right_terrain.astype(np.int64)]) def validate_input(arr): """验证并转换输入数据""" @@ -185,13 +159,14 @@ def validate_input(arr): "left_signs": validate_input(left_signs), "left_counts": validate_input(left_counts), "right_signs": validate_input(right_signs), - "right_counts": validate_input(right_counts), + "right_counts": validate_input(right_counts) } # 执行推理 try: output = self.session.run( - output_names=["output"], input_feed=inputs + output_names=["output"], + input_feed=inputs ) # output[0] 是形状为 (batch_size, 1) 的数组 prediction = output[0].flatten()[0] @@ -204,4 +179,4 @@ def validate_input(arr): prediction = 0.5 prediction = np.clip(prediction, 0.0, 1.0) - return float(prediction) + return float(prediction) \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index f7776a7..286692d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "CannotMax-Greenvine" -version = "2.0.0" +version = "1.0.8" description = "这是一个基于深度学习的明日方舟游戏辅助工具,用于自动识别游戏画面中的单位并预测战斗结果。" readme = "README.md" requires-python = ">=3.10" @@ -21,7 +21,7 @@ dependencies = [ ] [dependency-groups] -dev = ["onnx>=1.19.0", "onnxscript>=0.7.0", "types-toml", "pandas-stubs", "pyinstaller>=6.15.0"] +dev = ["onnx>=1.19.0", "onnxscript>=0.7.0", "pyinstaller>=6.15.0"] [project.optional-dependencies] cpu = ["torch", "torchvision"] diff --git a/src/recognition/recognize.py b/recognize.py similarity index 81% rename from src/recognition/recognize.py rename to recognize.py index d021439..72ae417 100644 --- a/src/recognition/recognize.py +++ b/recognize.py @@ -5,16 +5,15 @@ from PIL import ImageGrab from rapidocr import RapidOCR, EngineType -from src.core.config import MONSTER_DATA, MONSTER_IMAGES, MONSTER_COUNT -from src.core.paths import ensure_tmp_images_dir, image_path -from . import find_monster_zone -from src.game.winrt_capture import WinRTScreenCapture +from config import MONSTER_DATA, MONSTER_IMAGES, MONSTER_COUNT +import find_monster_zone +from winrt_capture import WinRTScreenCapture logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) # 是否启用debug模式 -INTELLIGENT_WORKERS_DEBUG = True +intelligent_workers_debug = True # 数字区域相对坐标 relative_regions_nums = [ @@ -35,7 +34,6 @@ (0.8700, 0.05, 1.0000, 0.80), ] - def get_rapidocr_engine(prefer_gpu=False): """ prefer_gpu (bool): 是否优先尝试使用GPU @@ -43,7 +41,6 @@ def get_rapidocr_engine(prefer_gpu=False): try: if prefer_gpu: import torch - if torch.cuda.is_available(): return RapidOCR( params={ @@ -59,21 +56,11 @@ def get_rapidocr_engine(prefer_gpu=False): # 如果没有GPU可用,使用CPU onnxruntime return RapidOCR() - class RecognizeMonster: - ROI_RELATIVE = [ - (0.2464, 0.8410), - (0.7542, 0.9510), - ] # 16:9下怪物区域相对坐标 - - def __init__( - self, - method: str = "ADB", - window_name: str | None = None, - monitor_index: int | None = None, - ): + ROI_RELATIVE = [(0.2464, 0.8410), (0.7542, 0.9510)] # 16:9下怪物区域相对坐标 + def __init__(self, method: str = "ADB", window_name: str | None = None, monitor_index: int | None = None): self.method = method - self.main_roi = [(0, 0), (1919, 1079)] # 主区域坐标 + self.main_roi = [(0, 0), (1919, 1079)] # 主区域坐标 # 鼠标交互全局变量 self.roi_box = [] self.drawing = False @@ -100,12 +87,12 @@ def __init__( self.main_roi = [(0, 0), (w - 1, h - 1)] except Exception as e: logger.exception("WinRT capture init failed: %s", e) - self._winrt = None # 将 _winrt 设置为 None,表示初始化失败 - raise # 重新抛出异常,以便上层捕获 + self._winrt = None # 将 _winrt 设置为 None,表示初始化失败 + raise # 重新抛出异常,以便上层捕获 else: logger.info("WIN 模式未指定窗口或显示器,将使用 PIL 作为回退") - def mouse_callback(self, event, x: int, y: int, flags, param): + def mouse_callback(self, event, x:int, y:int, flags, param): if event == cv2.EVENT_LBUTTONDOWN: self.roi_box = [(x, y)] self.drawing = True @@ -135,15 +122,8 @@ def select_roi(self): return None # 添加操作提示 - cv2.putText( - img, - "Drag to select area | ENTER:confirm | ESC:retry", - (10, 30), - cv2.FONT_HERSHEY_SIMPLEX, - 0.7, - (0, 0, 255), - 2, - ) + cv2.putText(img, "Drag to select area | ENTER:confirm | ESC:retry", + (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) # 显示窗口 cv2.namedWindow("Select ROI", cv2.WINDOW_NORMAL) @@ -152,7 +132,7 @@ def select_roi(self): cv2.imshow("Select ROI", img) # 添加示例图片(要后弹出才看得见) - example_img = cv2.imread(str(image_path("eg"))) + example_img = cv2.imread("images/eg.png") # 显示示例图片在单独的窗口中 cv2.imshow("example", example_img) @@ -172,9 +152,7 @@ def select_roi(self): self.roi_box = [] continue - def find_best_match( - target: cv2.typing.MatLike, ref_images: dict[int, cv2.typing.MatLike] - ): + def find_best_match(target: cv2.typing.MatLike, ref_images: dict[int, cv2.typing.MatLike]): """ 模板匹配找到最佳匹配的参考图像 :param target: 目标图像 @@ -213,7 +191,7 @@ def get_manual_screenshot(self) -> cv2.typing.MatLike: screenshot = cv2.cvtColor(screenshot, cv2.COLOR_RGB2BGR) try: # 手动框选的截图需先识别目标区域 - cv2.imwrite(str(ensure_tmp_images_dir() / "zone1.png"), screenshot) + cv2.imwrite(f"images/tmp/zone1.png", screenshot) d_avatar, d_nums = find_monster_zone.cutFrame(screenshot) height, width, _ = screenshot.shape divisors = np.array([width, height, width, height]) @@ -228,10 +206,7 @@ def get_manual_screenshot(self) -> cv2.typing.MatLike: y_min = max(0, y_min) # 假如找到过能用main_roi的就存起来 logger.info(f"识别到目标区域:{[(x_min, y_min), (x_max, y_max)]}") - self.main_roi = [ - (x1 + x_min, y1 + y_min), - (x1 + x_max, y1 + y_max), - ] + self.main_roi = [(x1 + x_min, y1 + y_min), (x1 + x_max, y1 + y_max)] screenshot = screenshot[y_min:y_max, x_min:x_max] logger.info(f"区域更新为: {self.main_roi}") except Exception as e: @@ -282,9 +257,9 @@ def process_regions( main_height = screenshot.shape[0] main_width = screenshot.shape[1] - if INTELLIGENT_WORKERS_DEBUG: # 如果处于debug模式 + if intelligent_workers_debug: # 如果处于debug模式 # 存储模板图像用于debug - cv2.imwrite(str(ensure_tmp_images_dir() / "zone.png"), screenshot) + cv2.imwrite(f"images/tmp/zone.png", screenshot) # 遍历所有区域 for idx, rel in enumerate(relative_regions): @@ -299,23 +274,14 @@ def process_regions( sub_roi = screenshot[ry1:ry2, rx1:rx2] # 图像匹配 - matched_id, confidence = find_best_match( - sub_roi, self.ref_images - ) - logger.info( - f"target: {idx} matched_id: {matched_id}, confidence: {confidence:.4f}" - ) + matched_id, confidence = find_best_match(sub_roi, self.ref_images) + logger.info(f"target: {idx} matched_id: {matched_id}, confidence: {confidence:.4f}") if matched_id != 0 and confidence < matched_threshold: raise ValueError(f"模板匹配置信度过低: {confidence}") except Exception as e: logger.exception(f"区域 {idx} 匹配失败: {str(e)}") results.append( - { - "region_id": idx, - "matched_id": matched_id, - "number": "N/A", - "error": str(e), - } + {"region_id": idx, "matched_id": matched_id, "number": "N/A", "error": str(e)} ) continue try: @@ -329,30 +295,20 @@ def process_regions( # 提取OCR识别用的子区域 sub_roi_num = screenshot[ry1_num:ry2_num, rx1_num:rx2_num] processed = preprocess(sub_roi_num) # 二值化预处理 - processed = crop_to_min_bounding_rect( - processed - ) # 去除多余黑框 - processed = add_black_border( - processed, border_size=3 - ) # 加上3像素黑框 + processed = crop_to_min_bounding_rect(processed) # 去除多余黑框 + processed = add_black_border(processed, border_size=3) # 加上3像素黑框 # OCR识别(保留优化后的处理逻辑) number, ocr_confidence = self.do_num_ocr(processed) if number != "" and ocr_confidence < ocr_threshold: raise ValueError(f"OCR置信度过低: {ocr_confidence}") - if INTELLIGENT_WORKERS_DEBUG: # 如果处于debug模式 + if intelligent_workers_debug: # 如果处于debug模式 # 存储模板图像用于debug - cv2.imwrite( - str(ensure_tmp_images_dir() / f"target_{idx}.png"), - sub_roi, - ) + cv2.imwrite(f"images/tmp/target_{idx}.png", sub_roi) # 存储OCR图像用于debug - cv2.imwrite( - str(ensure_tmp_images_dir() / f"number_{idx}.png"), - processed, - ) + cv2.imwrite(f"images/tmp/number_{idx}.png", processed) if number == "" and matched_id != 0: raise ValueError("发现有怪物但无数量异常数据!") @@ -370,22 +326,13 @@ def process_regions( except Exception as e: logger.exception(f"区域 {idx} OCR识别失败: {str(e)}") results.append( - { - "region_id": idx, - "matched_id": matched_id, - "number": "N/A", - "error": str(e), - } + {"region_id": idx, "matched_id": matched_id, "number": "N/A", "error": str(e)} ) return results - + def do_num_ocr(self, img: cv2.typing.MatLike): - result = self.rapidocr_eng( - img, use_det=False, use_cls=False, use_rec=True - ) - logger.info( - f"OCR: text: '{result.txts[0]}', score: {result.scores[0]}" - ) + result = self.rapidocr_eng(img, use_det=False, use_cls=False, use_rec=True) + logger.info(f"OCR: text: '{result.txts[0]}', score: {result.scores[0]}") if result.txts[0] != "" and not result.txts[0].isdigit(): raise ValueError(f"OCR识别结果不是数字: '{result.txts[0]}'") return result.txts[0], result.scores[0] @@ -411,9 +358,7 @@ def crop_to_min_bounding_rect(image: cv2.typing.MatLike): else: gray = image # 寻找轮廓 - contours, _ = cv2.findContours( - gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE - ) + contours, _ = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 如果没有找到轮廓就直接返回原图 if not contours: return image @@ -450,9 +395,7 @@ def preprocess(img: cv2.typing.MatLike): closed = bright_mask # 去除细小噪声:过滤不够大的连通区域 - contours, _ = cv2.findContours( - closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE - ) + contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for contour in contours: x, y, w, h = cv2.boundingRect(contour) if w <= 1: @@ -465,9 +408,7 @@ def preprocess(img: cv2.typing.MatLike): return closed -def find_best_match( - target: cv2.typing.MatLike, ref_images: dict[int, cv2.typing.MatLike] -): +def find_best_match(target: cv2.typing.MatLike, ref_images: dict[int, cv2.typing.MatLike]): """ 模板匹配找到最佳匹配的参考图像 :param target: 目标图像 @@ -503,35 +444,30 @@ def load_ref_images(ref_dir="images"): for i in range(MONSTER_COUNT + 1): # path = os.path.join(ref_dir, f"{i}.png") # if os.path.exists(path): - # img = cv2.imread(path, cv2.IMREAD_COLOR_BGR) + # img = cv2.imread(path, cv2.IMREAD_COLOR_BGR) if i == 0: img = MONSTER_IMAGES.get("empty") else: img = MONSTER_IMAGES.get(MONSTER_DATA["原始名称"][i]) if img is None: - logger.error( - f"无法加载参考图片 i={i}, 名称={MONSTER_DATA['原始名称'][i] if i > 0 else 'empty'}" - ) + logger.error(f"无法加载参考图片 i={i}, 名称={MONSTER_DATA['原始名称'][i] if i > 0 else 'empty'}") continue # 裁切模板匹配图像比例 img_crop = img[ - int(img.shape[0] * 0.16) : int( - img.shape[0] * 0.80 - ), # 高度取靠上部分 - int(img.shape[1] * 0.18) : int( - img.shape[1] * 0.82 - ), # 宽度与高度一致 + int(img.shape[0] * 0.16) : int(img.shape[0] * 0.80), # 高度取靠上部分 + int(img.shape[1] * 0.18) : int(img.shape[1] * 0.82), # 宽度与高度一致 ] # 调整参考图像大小以匹配目标图像 ref_resized = cv2.resize(img_crop, (74, 74)) ref_resized = ref_resized[0:70, :] - if INTELLIGENT_WORKERS_DEBUG: # 如果处于debug模式 + if intelligent_workers_debug: # 如果处于debug模式 # 存储模板图像用于debug - tmp_dir = ensure_tmp_images_dir() - cv2.imwrite(str(tmp_dir / f"xref_{i}.png"), ref_resized) + if not os.path.exists("images/tmp"): + os.makedirs("images/tmp") + cv2.imwrite(f"images/tmp/xref_{i}.png", ref_resized) ref_images[i] = ref_resized return ref_images diff --git a/src/analysis/sim_mc.py b/sim_mc.py similarity index 67% rename from src/analysis/sim_mc.py rename to sim_mc.py index c1efc7c..df80f9e 100644 --- a/src/analysis/sim_mc.py +++ b/sim_mc.py @@ -1,33 +1,25 @@ -from collections import Counter +from collections import Counter, defaultdict from concurrent.futures import ThreadPoolExecutor -from pathlib import Path import queue import threading +import time import os import copy from enum import Enum, auto import tkinter as tk - # from tkinter import messagebox # messagebox 已被自定义提示替代,可以注释或移除 from PIL import Image, ImageTk - -import json -import random -import sys - - - -if __name__ == "__main__": - sys.path.insert(0, str(Path(__file__).parent.parent.parent)) - from src.simulation.battle_field import Battlefield - from src.core.config import MONSTER_DATA, MONSTER_IMAGES, MONSTER_COUNT - from src.core.paths import DATA_DIR, PROJECT_ROOT, simulation_path - from src.simulation.utils import Faction -else: - from ..simulation.battle_field import Battlefield - from ..core.config import MONSTER_DATA, MONSTER_IMAGES, MONSTER_COUNT - from ..core.paths import DATA_DIR, PROJECT_ROOT, simulation_path - from ..simulation.utils import Faction +import math +from simulator.battle_field import Battlefield # 确保 Battlefield 已导入 +from simulator.monsters import MonsterFactory # 确保 MonsterFactory 已导入 +from simulator.utils import MONSTER_MAPPING, REVERSE_MONSTER_MAPPING, Faction # 根据你的实际路径调整 +from simulator.vector2d import FastVector # 确保 FastVector 已导入 +from unit import Unit # 确保 Unit 已导入 +import json # REMOVED_TEAM_INTERFACE: Added missing import for the main block +import random # REMOVED_TEAM_INTERFACE: Added missing import for the main block +import sys # Import sys for stdin +from simulator.monsters import AttackState, Monster, MonsterFactory +from recognize import MONSTER_COUNT class AppState(Enum): @@ -46,19 +38,11 @@ def __init__(self, ui_update_callback): def transition_to(self, new_state): """状态转换并触发UI更新""" allowed_transitions = { - AppState.INITIAL: [ - AppState.INITIAL, - AppState.SETUP, - AppState.ENDED, - ], - AppState.SETUP: [ - AppState.INITIAL, - AppState.SETUP, - AppState.SIMULATING, - ], + AppState.INITIAL: [AppState.INITIAL, AppState.SETUP, AppState.ENDED], + AppState.SETUP: [AppState.INITIAL, AppState.SETUP, AppState.SIMULATING], AppState.SIMULATING: [AppState.PAUSED, AppState.ENDED], AppState.PAUSED: [AppState.SIMULATING, AppState.SETUP], - AppState.ENDED: [AppState.INITIAL, AppState.SETUP], + AppState.ENDED: [AppState.INITIAL, AppState.SETUP] } if new_state in allowed_transitions[self.state]: @@ -70,55 +54,47 @@ def transition_to(self, new_state): def get_control_states(self): """返回各控件的状态字典""" states = { - "deploy": {"state": tk.NORMAL, "text": "部署怪物"}, - "confirm_start": {"state": tk.DISABLED}, - "pause": {"state": tk.DISABLED, "text": "暂停"}, - "restore": {"state": tk.DISABLED}, - "speed_entry": {"state": tk.NORMAL}, - "clear": {"state": tk.NORMAL}, - "timer": {"text": ""}, + 'deploy': {'state': tk.NORMAL, 'text': '部署怪物'}, + 'confirm_start': {'state': tk.DISABLED}, + 'pause': {'state': tk.DISABLED, 'text': '暂停'}, + 'restore': {'state': tk.DISABLED}, + 'speed_entry': {'state': tk.NORMAL}, + 'clear': {'state': tk.NORMAL}, + 'timer': {'text': ''} } if self.state == AppState.INITIAL: pass elif self.state == AppState.SETUP: - states.update( - { - "deploy": {"state": tk.NORMAL, "text": "重新部署"}, - "confirm_start": {"state": tk.NORMAL}, - "timer": {"text": "未开始"}, - } - ) + states.update({ + 'deploy': {'state': tk.NORMAL, 'text': '重新部署'}, + 'confirm_start': {'state': tk.NORMAL}, + 'timer': {'text': '未开始'} + }) elif self.state == AppState.SIMULATING: - states.update( - { - "deploy": {"state": tk.DISABLED, "text": "重新部署"}, - "confirm_start": {"state": tk.DISABLED}, - "pause": {"state": tk.NORMAL, "text": "暂停"}, - "clear": {"state": tk.DISABLED}, - } - ) + states.update({ + 'deploy': {'state': tk.DISABLED, 'text': '重新部署'}, + 'confirm_start': {'state': tk.DISABLED}, + 'pause': {'state': tk.NORMAL, 'text': '暂停'}, + 'clear': {'state': tk.DISABLED}, + }) elif self.state == AppState.PAUSED: - states.update( - { - "restore": {"state": tk.NORMAL}, - "pause": {"state": tk.NORMAL, "text": "继续"}, - "deploy": {"state": tk.NORMAL, "text": "重新部署"}, - } - ) + states.update({ + 'restore': {'state': tk.NORMAL}, + 'pause': {'state': tk.NORMAL, 'text': '继续'}, + 'deploy': {'state': tk.NORMAL, 'text': '重新部署'} + }) elif self.state == AppState.ENDED: - states.update( - { - "deploy": {"state": tk.DISABLED, "text": "重新部署"}, - "restore": {"state": tk.NORMAL}, - "pause": {"state": tk.DISABLED, "text": "暂停"}, - "timer": {"text": "战斗结束"}, - } - ) + states.update({ + 'deploy': {'state': tk.DISABLED, 'text': '重新部署'}, + 'restore': {'state': tk.NORMAL}, + 'pause': {'state': tk.DISABLED, 'text': '暂停'}, + 'timer': {'text': '战斗结束'} + }) return states @@ -169,16 +145,6 @@ def __init__(self, master: tk.Tk, battle_data): self.state_machine.transition_to(AppState.INITIAL) self.enter_setup_phase() - def _resolve_monster_icon_key(self, monster_name: str) -> str: - """根据怪物名称解析图标文件名。""" - if monster_name in self.monster_icon_key_map: - return self.monster_icon_key_map[monster_name] - - if monster_name in MONSTER_IMAGES: - return monster_name - - return self.default_icon_key - def update_ui_state(self): """根据当前状态更新所有控件状态""" states = self.state_machine.get_control_states() @@ -191,10 +157,8 @@ def hide_window(self): def load_assets(self): self.icons = {} - self.monster_icon_key_map = {} - self.default_icon_key = "empty" if "empty" in MONSTER_IMAGES else "" try: - with open(simulation_path("monsters.json"), encoding="utf-8") as f: + with open("simulator/monsters.json", encoding='utf-8') as f: self.monster_data = json.load(f)["monsters"] except FileNotFoundError: print("错误: monsters.json 未找到,请检查路径!") @@ -202,47 +166,21 @@ def load_assets(self): return - # 建立“名称/原始名称 -> 图标文件名”的兼容映射。 - for _, row in MONSTER_DATA.iterrows(): - monster_name = str(row["名称"]) - original_name = str(row["原始名称"]) - - icon_key = None - if original_name in MONSTER_IMAGES: - icon_key = original_name - elif monster_name in MONSTER_IMAGES: - icon_key = monster_name - - if icon_key is None: - icon_key = self.default_icon_key - - self.monster_icon_key_map[monster_name] = icon_key - self.monster_icon_key_map[original_name] = icon_key - - # 只为实际存在的图片创建 Tk 图像,避免访问旧的数字编号路径。 - for image_key, image_array in MONSTER_IMAGES.items(): + for i in range(self.num_monsters): + image_file_id = i + 1 try: - if image_array is None: - raise ValueError("图像数据为空") - - image = Image.fromarray(image_array[:, :, ::-1]) - image_40 = image.resize((40, 40)) - self.icons[image_key] = { - "red": ImageTk.PhotoImage(image_40, master=self.master), - "blue": ImageTk.PhotoImage( - image_40.transpose(Image.FLIP_LEFT_RIGHT), - master=self.master, - ), + image = Image.open(f'images/{image_file_id}.png') + self.icons[i] = { + "red": ImageTk.PhotoImage(image.resize((40, 40))), + "blue": ImageTk.PhotoImage(image.resize((40, 40)).transpose(Image.FLIP_LEFT_RIGHT)) } except Exception as e: - print(f"加载图标错误 (图标键: {image_key}): {str(e)}") - - if self.default_icon_key and self.default_icon_key not in self.icons: - fallback = Image.new("RGB", (40, 40), "gray") - self.icons[self.default_icon_key] = { - "red": ImageTk.PhotoImage(fallback, master=self.master), - "blue": ImageTk.PhotoImage(fallback, master=self.master), - } + # 同样,show_message_below_button 可能还不可用 + print(f"加载图标错误 (图标键: {i}, 文件名ID: {image_file_id}): {str(e)}") + self.icons[i] = { + "red": ImageTk.PhotoImage(Image.new("RGB", (40, 40), "gray")), + "blue": ImageTk.PhotoImage(Image.new("RGB", (40, 40), "gray")) + } def init_battlefield_for_setup(self): self.state_machine.transition_to(AppState.SETUP) @@ -253,8 +191,7 @@ def init_battlefield_for_setup(self): right_army_config = self.battle_data.get("right", {}) self.battle_field.setup_battle( - left_army_config, right_army_config, self.monster_data - ) + left_army_config, right_army_config, self.monster_data) while self.battle_field.gameTime < 6.0: result = self.battle_field.run_one_frame() if result: @@ -262,8 +199,7 @@ def init_battlefield_for_setup(self): def _normalize_outcome(self, outcome): try: - from src.simulation.utils import Faction - + from simulator.utils import Faction if outcome == Faction.LEFT: return "LEFT" if outcome == Faction.RIGHT: @@ -286,9 +222,7 @@ def create_widgets(self): self.message_label.pack(pady=2, anchor="w") # ====== 蒙特卡洛控制区 ====== - mc_frame = tk.LabelFrame( - self.master, text="蒙特卡洛模拟", padx=10, pady=8 - ) + mc_frame = tk.LabelFrame(self.master, text="蒙特卡洛模拟", padx=10, pady=8) mc_frame.pack(fill=tk.X, padx=10, pady=8) tk.Label(mc_frame, text="模拟次数:").grid(row=0, column=0, sticky="w") @@ -298,47 +232,36 @@ def create_widgets(self): self.mc_seed_var = tk.StringVar(value="") # 可选随机种子 tk.Label(mc_frame, text="随机种子(可空):").grid( - row=0, column=2, sticky="w", padx=(20, 0) - ) + row=0, column=2, sticky="w", padx=(20, 0)) self.mc_seed_entry = tk.Entry( - mc_frame, width=12, textvariable=self.mc_seed_var - ) + mc_frame, width=12, textvariable=self.mc_seed_var) self.mc_seed_entry.grid(row=0, column=3, sticky="w", padx=6) self.mc_run_button = tk.Button( - mc_frame, text="运行蒙卡", command=self.start_monte_carlo_threads - ) + mc_frame, text="运行蒙卡", command=self.start_monte_carlo_threads) self.mc_run_button.grid(row=0, column=4, padx=12) self.mc_stop_button = tk.Button( - mc_frame, - text="停止", - state=tk.DISABLED, - command=self.stop_monte_carlo_threads, - ) + mc_frame, text="停止", state=tk.DISABLED, command=self.stop_monte_carlo_threads) self.mc_stop_button.grid(row=0, column=5, padx=4) # ... self.mc_canvas = tk.Canvas(mc_frame, height=160, bg="white") - self.mc_canvas.grid( - row=2, column=0, columnspan=6, sticky="we", pady=(6, 2) - ) + self.mc_canvas.grid(row=2, column=0, columnspan=6, + sticky="we", pady=(6, 2)) self.mc_canvas.bind( - "", lambda e: self._redraw_mc_canvas() - ) # 动态重绘 + "", lambda e: self._redraw_mc_canvas()) # 动态重绘 # 结果文字 self.mc_result_text = tk.Text(mc_frame, height=6, width=70) self.mc_result_text.grid( - row=1, column=0, columnspan=5, pady=(8, 4), sticky="we" - ) + row=1, column=0, columnspan=5, pady=(8, 4), sticky="we") self.mc_result_text.configure(state=tk.DISABLED) # 简单条形图画布(显示胜负/平局分布) self.mc_canvas = tk.Canvas(mc_frame, height=160, bg="white") - self.mc_canvas.grid( - row=2, column=0, columnspan=5, sticky="we", pady=(6, 2) - ) + self.mc_canvas.grid(row=2, column=0, columnspan=5, + sticky="we", pady=(6, 2)) self.canvas = None def run_single_battle(self, left_cfg, right_cfg): @@ -359,8 +282,7 @@ def run_single_battle(self, left_cfg, right_cfg): outcome = "DRAW" else: try: - from src.simulation.utils import Faction - + from simulator.utils import Faction if result == Faction.LEFT: outcome = "LEFT" elif result == Faction.RIGHT: @@ -404,17 +326,13 @@ def start_monte_carlo_threads(self): try: seed_val = int(seed_txt) except ValueError: - self.show_message_below_button( - "随机种子需为整数或留空", is_error=True - ) + self.show_message_below_button("随机种子需为整数或留空", is_error=True) return - left_cfg = copy.deepcopy(self.battle_data.get("left", {})) + left_cfg = copy.deepcopy(self.battle_data.get("left", {})) right_cfg = copy.deepcopy(self.battle_data.get("right", {})) if not left_cfg or not right_cfg: - self.show_message_below_button( - "错误:左右双方任一为空,无法进行蒙卡", is_error=True - ) + self.show_message_below_button("错误:左右双方任一为空,无法进行蒙卡", is_error=True) return # 状态初始化 @@ -441,21 +359,16 @@ def start_monte_carlo_threads(self): # 关键:制造足够多的小任务(比如每个任务 10~50 次) # 这样就能频繁完成并推送结果,界面“按完成块”刷新 - TARGET_TASKS = min(max(32, workers * 16), runs) # 至少几十个分片 + TARGET_TASKS = min(max(32, workers * 16), runs) # 至少几十个分片 chunk = max(1, runs // TARGET_TASKS) remain = runs idx = 0 while remain > 0: n = min(chunk, remain) - fut = self.executor.submit( - self._mc_task, - n, - left_cfg, - right_cfg, - None if seed_val is None else seed_val + idx, - self.mc_stop_event, - ) + fut = self.executor.submit(self._mc_task, n, left_cfg, right_cfg, + None if seed_val is None else seed_val + idx, + self.mc_stop_event) # 回调里**不要**动 UI;只把结果丢进队列 def _on_done(f): @@ -538,13 +451,10 @@ def _mc_finish(self): self.show_message_below_button("蒙卡完成", is_error=False) else: self.show_message_below_button( - f"已停止(完成 {done}/{target} 次)", is_error=False - ) + f"已停止(完成 {done}/{target} 次)", is_error=False) self.mc_stop_event.clear() - def _render_mc_text_and_chart( - self, counts: Counter, done: int, target: int - ): + def _render_mc_text_and_chart(self, counts: Counter, done: int, target: int): left_win = counts.get("LEFT", 0) right_win = counts.get("RIGHT", 0) draw_cnt = counts.get("DRAW", 0) @@ -566,11 +476,7 @@ def _render_mc_text_and_chart( self.mc_result_text.configure(state=tk.DISABLED) # 图 - items = [ - ("左方胜", left_win), - ("右方胜", right_win), - ("平局", draw_cnt), - ] + items = [("左方胜", left_win), ("右方胜", right_win), ("平局", draw_cnt)] self.draw_mc_barchart(items, total=max(1, done)) # 避免除零 def _redraw_mc_canvas(self): @@ -578,11 +484,9 @@ def _redraw_mc_canvas(self): with self.mc_lock: counts = Counter(self._mc_counts) done = self._mc_total_done - items = [ - ("左方胜", counts.get("LEFT", 0)), - ("右方胜", counts.get("RIGHT", 0)), - ("平局", counts.get("DRAW", 0)), - ] + items = [("左方胜", counts.get("LEFT", 0)), + ("右方胜", counts.get("RIGHT", 0)), + ("平局", counts.get("DRAW", 0))] self.draw_mc_barchart(items, total=max(1, done)) def draw_mc_barchart(self, items, total): @@ -599,52 +503,44 @@ def draw_mc_barchart(self, items, total): H = int(c.winfo_height()) or 160 pad_x = 40 pad_y = 24 - bar_space = W - 2 * pad_x + bar_space = (W - 2*pad_x) bar_w = bar_space // max(1, len(items)) - 16 max_cnt = max(x[1] for x in items) or 1 # 坐标轴 - c.create_line(pad_x, H - pad_y, W - pad_x // 2, H - pad_y) # x轴 - c.create_line(pad_x, pad_y // 2, pad_x, H - pad_y) # y轴 + c.create_line(pad_x, H - pad_y, W - pad_x//2, H - pad_y) # x轴 + c.create_line(pad_x, pad_y//2, pad_x, H - pad_y) # y轴 for i, (label, cnt) in enumerate(items): x0 = pad_x + i * (bar_w + 16) + 8 x1 = x0 + bar_w # 高度按计数线性映射 h_ratio = cnt / max_cnt if max_cnt > 0 else 0.0 - bar_h = int((H - 2 * pad_y) * h_ratio) + bar_h = int((H - 2*pad_y) * h_ratio) y0 = H - pad_y - bar_h y1 = H - pad_y # 绘制条 c.create_rectangle(x0, y0, x1, y1, fill="#6aa84f", outline="") # 文本:计数与百分比 pct = f"{(cnt/total):.1%}" - c.create_text( - (x0 + x1) // 2, y0 - 10, text=f"{cnt} ({pct})", anchor="s" - ) + c.create_text((x0+x1)//2, y0-10, text=f"{cnt} ({pct})", anchor="s") # 类别名 - c.create_text( - (x0 + x1) // 2, H - pad_y + 12, text=label, anchor="n" - ) + c.create_text((x0+x1)//2, H - pad_y + 12, text=label, anchor="n") def refresh_canvas_display(self): if self.monte_carlo_mode: return # ... 原本的画网格/单位/连线/计时 等逻辑保持不变 - def show_message_below_button( - self, message, is_error=False, duration=5000 - ): + def show_message_below_button(self, message, is_error=False, duration=5000): """在按钮下方显示文字提示,并在指定时间后消失""" if self.message_label: self.message_label.config( - text=message, fg="red" if is_error else "black" - ) + text=message, fg="red" if is_error else "black") if self.message_timer_id: self.master.after_cancel(self.message_timer_id) self.message_timer_id = self.master.after( - duration, self.clear_message_below_button - ) + duration, self.clear_message_below_button) def clear_message_below_button(self): """清除提示信息""" @@ -665,13 +561,10 @@ def main(): root = tk.Tk() # root.withdraw() # 如果不需要立即隐藏主窗口,可以注释掉 - initial_battle_setup = { - "left": {"炮击组长": 3, "“庞贝”": 2}, - "right": {"沸血骑士团精锐": 6, "炽焰源石虫": 23}, - "result": "left", - } + initial_battle_setup = {"left": {"炮击组长": 3, "“庞贝”": 2}, "right": {"沸血骑士团精锐": 6, "炽焰源石虫": 23}, + "result": "left"} - sys.stdin.reconfigure(encoding="utf-8") + sys.stdin.reconfigure(encoding='utf-8') try: if not sys.stdin.isatty(): json_data = sys.stdin.read() @@ -683,9 +576,7 @@ def main(): else: print("stdin 是交互式终端,使用默认配置。") except json.JSONDecodeError: - print( - "错误: 无法解析 stdin 中的 JSON 数据,请检查格式,将使用默认配置。" - ) + print("错误: 无法解析 stdin 中的 JSON 数据,请检查格式,将使用默认配置。") except Exception as e: print(f"从 stdin 读取或解析时发生未知错误: {e},将使用默认配置。") @@ -696,37 +587,24 @@ def main(): if not app.monster_data: # 检查 monsters.json 是否加载成功 error_messages.append("错误: monsters.json 未找到或为空,请检查文件!") - if ( - len(initial_battle_setup.get("left", {})) == 0 - or len(initial_battle_setup.get("right", {})) == 0 - ): + if len(initial_battle_setup.get("left", {})) == 0 or len(initial_battle_setup.get("right", {})) == 0: error_messages.append("错误:至少一方的怪物列表为空!") problematic_monsters_found = [] - problematic_monster_names = [ - "矿脉守卫", - "提亚卡乌好战者", - "凋零萨卡兹", - "狂暴宿主组长", - "高能源石虫", - ] + problematic_monster_names = ["矿脉守卫", "提亚卡乌好战者", "凋零萨卡兹", "狂暴宿主组长", "高能源石虫"] for team_key in ["left", "right"]: for monster_name in initial_battle_setup.get(team_key, {}): if monster_name in problematic_monster_names: problematic_monsters_found.append( - f"{('左方' if team_key == 'left' else '右方')}存在问题怪物: {monster_name}" - ) + f"{('左方' if team_key == 'left' else '右方')}存在问题怪物: {monster_name}") if problematic_monsters_found: - error_messages.append( - "警告: " + "; ".join(problematic_monsters_found) - ) + error_messages.append("警告: " + "; ".join(problematic_monsters_found)) if error_messages: - app.show_message_below_button( - " | ".join(error_messages), is_error=True, duration=10000 - ) + app.show_message_below_button(" | ".join( + error_messages), is_error=True, duration=10000) if "monsters.json 未找到或为空" in " | ".join(error_messages): print("由于 monsters.json 缺失或错误,模拟器可能无法正常工作。") diff --git a/src/analysis/similar_history_match.py b/similar_history_match.py similarity index 74% rename from src/analysis/similar_history_match.py rename to similar_history_match.py index 286194f..ea9f1ff 100644 --- a/src/analysis/similar_history_match.py +++ b/similar_history_match.py @@ -1,9 +1,7 @@ import numpy as np import pandas as pd -from src.core.config import MONSTER_COUNT -from src.core.config import FIELD_FEATURE_COUNT -from src.core.paths import PROJECT_ROOT - +from config import MONSTER_COUNT +from config import FIELD_FEATURE_COUNT def cosine_similarity_manual(a, b): """手动实现余弦相似度,替代 sklearn 以减小打包体积""" @@ -15,11 +13,10 @@ def cosine_similarity_manual(a, b): dot = np.dot(a, b.T) return dot / (norm_a * norm_b.T) - class HistoryMatch: """错题本数据集的读取和处理类""" - def __init__(self, csv_path=PROJECT_ROOT / "data" / "arknights.csv"): + def __init__(self, csv_path="arknights.csv"): # 初始化时加载历史对局数据 self.csv_path = csv_path self.load_history_data() @@ -32,66 +29,43 @@ def load_history_data(self): """读取 CSV 文件,加载历史对局的左右阵容、地形及胜负标签""" try: df = pd.read_csv(self.csv_path, header=None, skiprows=1) - + # 新数据格式: [怪物L(77), 场地L(6), 怪物R(77), 场地R(6), Result, ImgPath] total_features = (MONSTER_COUNT + FIELD_FEATURE_COUNT) * 2 - + if df.shape[1] >= total_features + 1: # 至少包含特征和结果列 # 提取各部分特征 left_monster_end = MONSTER_COUNT left_field_end = MONSTER_COUNT + FIELD_FEATURE_COUNT - right_monster_end = ( - MONSTER_COUNT + FIELD_FEATURE_COUNT + MONSTER_COUNT - ) - right_field_end = ( - MONSTER_COUNT - + FIELD_FEATURE_COUNT - + MONSTER_COUNT - + FIELD_FEATURE_COUNT - ) - + right_monster_end = MONSTER_COUNT + FIELD_FEATURE_COUNT + MONSTER_COUNT + right_field_end = MONSTER_COUNT + FIELD_FEATURE_COUNT + MONSTER_COUNT + FIELD_FEATURE_COUNT + # 分别提取怪物和地形特征 - left_monsters = df.iloc[:, 0:left_monster_end].values.astype( - float - ) - left_terrain = df.iloc[ - :, left_monster_end:left_field_end - ].values.astype(float) - right_monsters = df.iloc[ - :, left_field_end:right_monster_end - ].values.astype(float) - right_terrain = df.iloc[ - :, right_monster_end:right_field_end - ].values.astype(float) - + left_monsters = df.iloc[:, 0:left_monster_end].values.astype(float) + left_terrain = df.iloc[:, left_monster_end:left_field_end].values.astype(float) + right_monsters = df.iloc[:, left_field_end:right_monster_end].values.astype(float) + right_terrain = df.iloc[:, right_monster_end:right_field_end].values.astype(float) + # 合并怪物特征(只使用怪物部分进行相似度计算) self.past_left = left_monsters self.past_right = right_monsters - + # 保存地形特征用于显示 self.past_left_terrain = left_terrain self.past_right_terrain = right_terrain - + # 胜负标签 self.labels = df.iloc[:, total_features].values else: # 兼容旧格式:只有怪物特征 - self.past_left = df.iloc[:, 0:MONSTER_COUNT].values.astype( - float - ) - self.past_right = df.iloc[ - :, MONSTER_COUNT : MONSTER_COUNT * 2 - ].values.astype(float) - self.labels = df.iloc[:, MONSTER_COUNT * 2].values - + self.past_left = df.iloc[:, 0:MONSTER_COUNT].values.astype(float) + self.past_right = df.iloc[:, MONSTER_COUNT:MONSTER_COUNT*2].values.astype(float) + self.labels = df.iloc[:, MONSTER_COUNT*2].values + # 地形特征为空 - self.past_left_terrain = np.zeros( - (len(self.past_left), FIELD_FEATURE_COUNT) - ) - self.past_right_terrain = np.zeros( - (len(self.past_right), FIELD_FEATURE_COUNT) - ) - + self.past_left_terrain = np.zeros((len(self.past_left), FIELD_FEATURE_COUNT)) + self.past_right_terrain = np.zeros((len(self.past_right), FIELD_FEATURE_COUNT)) + except Exception as e: print(f"加载历史数据失败: {e}") # 加载失败时,初始化为空数组 @@ -102,18 +76,14 @@ def load_history_data(self): self.labels = np.array([], dtype=str) # 构造历史对局特征: 左右数量之和与差的绝对值拼接(只使用怪物特征) - self.feat_past = np.hstack( - [ - self.past_left + self.past_right, - np.abs(self.past_left - self.past_right), - ] - ) + self.feat_past = np.hstack([ + self.past_left + self.past_right, + np.abs(self.past_left - self.past_right) + ]) # 历史对局总数 self.N_history = self.past_left.shape[0] - def render_similar_matches( - self, left_counts: np.ndarray, right_counts: np.ndarray - ): + def render_similar_matches(self, left_counts: np.ndarray, right_counts: np.ndarray): """返回与当前对局最相似的历史对局索引及胜率统计""" # 将输入转为浮点型数组 cur_left = left_counts.astype(float) @@ -126,9 +96,7 @@ def render_similar_matches( need_R_idx = np.nonzero(pres_R)[0] # 当前右侧有兵的索引 # 构造当前对局特征并计算与所有历史的余弦相似度 - feat_cur = np.hstack( - [cur_left + cur_right, np.abs(cur_left - cur_right)] - ).reshape(1, -1) + feat_cur = np.hstack([cur_left + cur_right, np.abs(cur_left - cur_right)]).reshape(1, -1) sims = cosine_similarity_manual(feat_cur, self.feat_past)[0] # 历史对局的存在布尔矩阵 @@ -137,18 +105,14 @@ def render_similar_matches( # 计算未镜像(missA, cntA)和镜像后(missB, cntB)的缺兵及数量差距 missA = np.sum(np.logical_xor(pres_L, hist_pres_L), axis=1) + np.sum( - np.logical_xor(pres_R, hist_pres_R), axis=1 - ) + np.logical_xor(pres_R, hist_pres_R), axis=1) cntA = np.sum(np.abs(self.past_left - cur_left), axis=1) + np.sum( - np.abs(self.past_right - cur_right), axis=1 - ) + np.abs(self.past_right - cur_right), axis=1) missB = np.sum(np.logical_xor(pres_L, hist_pres_R), axis=1) + np.sum( - np.logical_xor(pres_R, hist_pres_L), axis=1 - ) + np.logical_xor(pres_R, hist_pres_L), axis=1) cntB = np.sum(np.abs(self.past_right - cur_left), axis=1) + np.sum( - np.abs(self.past_left - cur_right), axis=1 - ) + np.abs(self.past_left - cur_right), axis=1) # 根据(miss, cnt)比较,决定是否对历史数据做镜像处理 swap = (missB < missA) | ((missB == missA) & (cntB < cntA)) @@ -167,27 +131,18 @@ def render_similar_matches( full_R = np.all(Rh[:, need_R_idx] == cur_right[need_R_idx], axis=1) # 计算需求索引处的数量差和 - diff_L = np.sum( - np.abs(Lh[:, need_L_idx] - cur_left[need_L_idx]), axis=1 - ) - diff_R = np.sum( - np.abs(Rh[:, need_R_idx] - cur_right[need_R_idx]), axis=1 - ) + diff_L = np.sum(np.abs(Lh[:, need_L_idx] - cur_left[need_L_idx]), axis=1) + diff_R = np.sum(np.abs(Rh[:, need_R_idx] - cur_right[need_R_idx]), axis=1) # 计算对手兵种在本方需求中的命中数,取最小值作为 match_other - hit_L = np.sum( - hist_pres_Rh[:, need_L_idx] & pres_L[need_L_idx], axis=1 - ) - hit_R = np.sum( - hist_pres_Lh[:, need_R_idx] & pres_R[need_R_idx], axis=1 - ) + hit_L = np.sum(hist_pres_Rh[:, need_L_idx] & pres_L[need_L_idx], axis=1) + hit_R = np.sum(hist_pres_Lh[:, need_R_idx] & pres_R[need_R_idx], axis=1) match_other = np.minimum(hit_L, hit_R) # 根据命中侧及是否完全匹配,选择对应的 qdiff_other qdiff_other = np.where( - (hit_R > 0) & (~full_R), - diff_R, - np.where((hit_L > 0) & (~full_L), diff_L, 0), + (hit_R > 0) & (~full_R), diff_R, + np.where((hit_L > 0) & (~full_L), diff_L, 0) ) # 批量计算分类所需的布尔向量 @@ -216,9 +171,7 @@ def render_similar_matches( # 且左右两侧比例相同,且比例不为 1(确保“数量均不同”) # 注意:当某侧不存在任意单位时,认为该侧比例为 1 且恒定 if need_L_idx.size > 0: - ratios_L = Lh[:, need_L_idx] / np.maximum( - cur_left[need_L_idx], 1e-12 - ) + ratios_L = Lh[:, need_L_idx] / np.maximum(cur_left[need_L_idx], 1e-12) rL_min = ratios_L.min(axis=1) rL_max = ratios_L.max(axis=1) uniform_L = np.isclose(rL_min, rL_max, rtol=1e-3, atol=1e-6) @@ -228,9 +181,7 @@ def render_similar_matches( rL = np.ones(self.N_history, dtype=float) if need_R_idx.size > 0: - ratios_R = Rh[:, need_R_idx] / np.maximum( - cur_right[need_R_idx], 1e-12 - ) + ratios_R = Rh[:, need_R_idx] / np.maximum(cur_right[need_R_idx], 1e-12) rR_min = ratios_R.min(axis=1) rR_max = ratios_R.max(axis=1) uniform_R = np.isclose(rR_min, rR_max, rtol=1e-3, atol=1e-6) @@ -240,9 +191,7 @@ def render_similar_matches( rR = np.ones(self.N_history, dtype=float) same_ratio = np.isclose(rL, rR, rtol=1e-3, atol=1e-6) - ratio_not_one = ~np.isclose( - rL, 1.0, rtol=1e-3, atol=1e-6 - ) # rL==rR 时即可代表两侧都不为1 + ratio_not_one = ~np.isclose(rL, 1.0, rtol=1e-3, atol=1e-6) # rL==rR 时即可代表两侧都不为1 proportional = uniform_L & uniform_R & same_ratio & ratio_not_one # 2类:同种类,数量均不同且成比例 @@ -266,44 +215,14 @@ def render_similar_matches( # 从前5条中计算左右胜率 top5 = top20[:5] - labs = np.where( - swap[top5], - np.where(self.labels[top5] == "L", "R", "L"), - self.labels[top5], - ) - tgtL = ( - need_L_idx[np.argmax(cur_left[need_L_idx])] - if need_L_idx.size - else None - ) - tgtR = ( - need_R_idx[np.argmax(cur_right[need_R_idx])] - if need_R_idx.size - else None - ) - - lw = np.sum( - [ - lab - == ( - "L" - if (Lh[i, tgtL] if tgtL is not None else 0) > 0 - else "R" - ) - for i, lab in zip(top5, labs) - ] - ) - rw = np.sum( - [ - lab - == ( - "L" - if (Lh[i, tgtR] if tgtR is not None else 0) > 0 - else "R" - ) - for i, lab in zip(top5, labs) - ] - ) + labs = np.where(swap[top5], np.where(self.labels[top5]=="L", "R", "L"), self.labels[top5]) + tgtL = need_L_idx[np.argmax(cur_left[need_L_idx])] if need_L_idx.size else None + tgtR = need_R_idx[np.argmax(cur_right[need_R_idx])] if need_R_idx.size else None + + lw = np.sum([lab == ("L" if (Lh[i, tgtL] if tgtL is not None else 0) > 0 else "R") + for i, lab in zip(top5, labs)]) + rw = np.sum([lab == ("L" if (Lh[i, tgtR] if tgtR is not None else 0) > 0 else "R") + for i, lab in zip(top5, labs)]) self.left_rate = lw / len(top5) if top5.size else 0 self.right_rate = rw / len(top5) if top5.size else 0 self.sims = sims @@ -316,24 +235,19 @@ def get_terrain_names(self, idx, is_swapped=False): """获取指定历史对局的地形名称""" if idx >= len(self.past_left_terrain): return "无地形" - + # 根据是否镜像选择地形特征 - terrain_features = ( - self.past_right_terrain[idx] - if is_swapped - else self.past_left_terrain[idx] - ) - + terrain_features = self.past_right_terrain[idx] if is_swapped else self.past_left_terrain[idx] + # 获取激活的地形特征索引 active_indices = np.where(terrain_features > 0)[0] - + if len(active_indices) == 0: return "无地形" - + # 尝试从FieldRecognizer获取实际的特征列名称 try: - from src.recognition.field_recognition import FieldRecognizer - + from field_recognition import FieldRecognizer field_recognizer = FieldRecognizer() if field_recognizer.is_ready(): feature_columns = field_recognizer.get_feature_columns() @@ -384,13 +298,11 @@ def get_terrain_names(self, idx, is_swapped=False): # 如果无法识别,使用原名称的简化版本 simple_name = full_name.replace("_", "") active_terrains.append(simple_name) - - return ( - "+".join(active_terrains) if active_terrains else "无地形" - ) + + return "+".join(active_terrains) if active_terrains else "无地形" except Exception: pass - + # 备用硬编码映射(如果无法获取FieldRecognizer) # 与main.py的terrain_display_mapping保持一致 terrain_names = { @@ -405,14 +317,14 @@ def get_terrain_names(self, idx, is_swapped=False): 8: "顶部弩炮", 9: "侧边弩炮", 10: "侧边火炮", - 11: "顶部火炮", + 11: "顶部火炮" } - + # 获取所有激活地形的名称 active_terrains = [] for i in active_indices: if i < len(terrain_names): active_terrains.append(terrain_names[i]) - + # 如果有多个地形,用"+"连接 return "+".join(active_terrains) if active_terrains else "无地形" diff --git a/src/ui/similar_history_match_ui.py b/simular_history_match_ui.py similarity index 85% rename from src/ui/similar_history_match_ui.py rename to simular_history_match_ui.py index dd8753b..6ddf18c 100644 --- a/src/ui/similar_history_match_ui.py +++ b/simular_history_match_ui.py @@ -1,20 +1,11 @@ from PyQt6.QtCore import Qt -from PyQt6.QtWidgets import ( - QWidget, - QVBoxLayout, - QHBoxLayout, - QLabel, - QScrollArea, - QGraphicsDropShadowEffect, - QFrame, -) -from PyQt6.QtGui import QPixmap, QColor +from PyQt6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QScrollArea, QGraphicsDropShadowEffect, QFrame +from PyQt6.QtGui import QPixmap, QImage, QFont, QIcon, QPainter, QColor import numpy as np import logging -from src.analysis.similar_history_match import HistoryMatch -from src.core.config import MONSTER_COUNT, MONSTER_DATA -from src.core.paths import image_path +from similar_history_match import HistoryMatch +from config import MONSTER_COUNT, MONSTER_DATA logger = logging.getLogger(__name__) @@ -33,7 +24,8 @@ def init_ui(self): self.history_scroll_area = QScrollArea() self.history_scroll_area.setFixedWidth(540) self.history_scroll_area.setWidgetResizable(True) - self.history_scroll_area.setStyleSheet(""" + self.history_scroll_area.setStyleSheet( + """ QScrollBar:horizontal { background: rgba(0, 0, 0, 0); width: 12px; /* 宽度 */ @@ -78,7 +70,8 @@ def init_ui(self): min-height: 20px; border-radius: 6px; } - """) + """ + ) # 创建内容部件 self.history_widget = QWidget() @@ -121,28 +114,26 @@ def render_similar_matches(self, left_monsters, right_monsters): shadow.setOffset(2) # 偏移量(0表示均匀四周发光) title_label.setGraphicsEffect(shadow) - title_label.setStyleSheet(""" + title_label.setStyleSheet( + """ QWidget { border-radius: 0px; font-size: 24px; font-weight: bold; color: white; } - """) + """ + ) self.history_layout.addWidget(title_label) # 渲染每个历史对局 for idx in top_indices: - self.add_history_match( - idx, sims[idx], left_monsters, right_monsters - ) + self.add_history_match(idx, sims[idx], left_monsters, right_monsters) except Exception as e: logger.error(f"渲染历史对局失败: {str(e)}") - def add_history_match( - self, idx, similarity, left_monsters, right_monsters - ): + def add_history_match(self, idx, similarity, left_monsters, right_monsters): """添加单个历史对局到面板""" # 获取历史数据 left = self.history_match.past_left[idx] @@ -168,23 +159,25 @@ def add_history_match( setR_past = set(np.where(right > 0)[0]) # 判断是否需要镜像历史对局 - should_swap = ( - len(setL_cur ^ setR_past) + len(setR_cur ^ setL_past) - ) < (len(setL_cur ^ setL_past) + len(setR_cur ^ setR_past)) + should_swap = (len(setL_cur ^ setR_past) + len(setR_cur ^ setL_past)) < ( + len(setL_cur ^ setL_past) + len(setR_cur ^ setR_past) + ) # 获取地形名称 terrain_name = self.history_match.get_terrain_names(idx, should_swap) # 创建对局容器 match_widget = QWidget() - match_widget.setStyleSheet(""" + match_widget.setStyleSheet( + """ QWidget { background-color: rgba(50, 50, 50, 150); border-radius: 10px; padding: 0px; margin: 5px; } - """) + """ + ) match_widget.setFixedSize(500, 170) # 增加高度以容纳地形信息 match_layout = QVBoxLayout(match_widget) @@ -206,7 +199,8 @@ def add_history_match( # 添加地形信息显示 terrain_label = QLabel(f"地形: {terrain_name}") - terrain_label.setStyleSheet(""" + terrain_label.setStyleSheet( + """ QLabel { color: #CCCCCC; font: 10px Microsoft YaHei; @@ -215,7 +209,8 @@ def add_history_match( border-radius: 3px; margin: 2px; } - """) + """ + ) terrain_label.setAlignment(Qt.AlignmentFlag.AlignCenter) match_layout.addWidget(terrain_label) @@ -224,14 +219,16 @@ def add_history_match( def create_team_widget(self, side, counts, is_winner): """创建单个队伍显示部件""" team_widget = QWidget() - team_widget.setStyleSheet(f""" + team_widget.setStyleSheet( + f""" QWidget {{ background-color: {'rgba(250, 250, 50, 150)' if is_winner else 'rgba(50, 50, 50, 100)'}; border-radius: 8px; padding: 0px; margin: 0px; }} - """) + """ + ) layout = QVBoxLayout(team_widget) @@ -243,14 +240,16 @@ def create_team_widget(self, side, counts, is_winner): shadow01.setOffset(3) # 偏移量(0表示均匀四周发光) ops_widget.setGraphicsEffect(shadow01) - ops_widget.setStyleSheet(""" + ops_widget.setStyleSheet( + """ QWidget { background-color: rgba(0, 0, 0, 0); border-radius: 0px; padding: 0px; margin: 0px; } - """) + """ + ) ops_layout = QHBoxLayout(ops_widget) ops_layout.setSpacing(5) ops_layout.setContentsMargins(0, 0, 0, 0) @@ -259,9 +258,7 @@ def create_team_widget(self, side, counts, is_winner): if count > 0: # 创建干员显示 op_widget = QWidget() - op_widget.setStyleSheet( - "background-color: rgba(0, 0, 0, 0); padding: 0px 0;margin: 0px;" - ) + op_widget.setStyleSheet("background-color: rgba(0, 0, 0, 0); padding: 0px 0;margin: 0px;") op_layout = QVBoxLayout(op_widget) op_layout.setContentsMargins(0, 0, 0, 0) op_layout.setAlignment(Qt.AlignmentFlag.AlignCenter) @@ -271,15 +268,10 @@ def create_team_widget(self, side, counts, is_winner): img_label.setFixedSize(60, 60) img_label.setAlignment(Qt.AlignmentFlag.AlignCenter) try: - pixmap = QPixmap( - str(image_path(MONSTER_DATA['原始名称'][i + 1])) - ) + pixmap = QPixmap(f"images/{MONSTER_DATA['原始名称'][i+1]}.png") if not pixmap.isNull(): pixmap = pixmap.scaled( - 60, - 60, - Qt.AspectRatioMode.KeepAspectRatio, - Qt.TransformationMode.SmoothTransformation, + 60, 60, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation ) img_label.setPixmap(pixmap) except: @@ -288,11 +280,13 @@ def create_team_widget(self, side, counts, is_winner): # 数量标签 count_label = QLabel(str(int(count))) count_label.setAlignment(Qt.AlignmentFlag.AlignCenter) - count_label.setStyleSheet(""" + count_label.setStyleSheet( + """ color: #EDEDED; font: bold 20px SimHei; min-width: 20px; - """) + """ + ) op_layout.addWidget(img_label, stretch=3) op_layout.addWidget(count_label, stretch=1) diff --git a/simulator/.gitignore b/simulator/.gitignore new file mode 100644 index 0000000..763624e --- /dev/null +++ b/simulator/.gitignore @@ -0,0 +1 @@ +__pycache__/* \ No newline at end of file diff --git a/src/simulation/README.md b/simulator/README.md similarity index 100% rename from src/simulation/README.md rename to simulator/README.md diff --git a/src/core/__init__.py b/simulator/__init__.py similarity index 100% rename from src/core/__init__.py rename to simulator/__init__.py diff --git a/src/simulation/arknights.csv b/simulator/arknights.csv similarity index 100% rename from src/simulation/arknights.csv rename to simulator/arknights.csv diff --git a/src/simulation/battle_field.py b/simulator/battle_field.py similarity index 60% rename from src/simulation/battle_field.py rename to simulator/battle_field.py index 81b7828..7ba4abd 100644 --- a/src/simulation/battle_field.py +++ b/simulator/battle_field.py @@ -1,6 +1,9 @@ +import json +import math import random import time import numpy as np +from enum import Enum import logging from typing import TYPE_CHECKING @@ -11,13 +14,9 @@ if TYPE_CHECKING: from .monsters import Monster - + from .monsters import MonsterFactory -from .utils import ( - VIRTUAL_TIME_DELTA, - Faction, - SpatialHash, -) +from .utils import VIRTUAL_TIME_DELTA, BuffEffect, BuffType, Faction, SpatialHash from .zone import PoisonZone # 场景参数 @@ -25,14 +24,14 @@ SPAWN_AREA = 2 # 阵营出生区域宽度 +from collections import defaultdict from .projectiles import ProjectileManager - class Battlefield: def __init__(self, monster_data): - self.monsters: list[Monster] = [] - self.alive_monsters: list[Monster] = [] - self.hash_grid: SpatialHash = SpatialHash(self, cell_size=0.5) + self.monsters : list[Monster] = [] + self.alive_monsters : list[Monster] = [] + self.hash_grid : SpatialHash = SpatialHash(self, cell_size=0.5) self.HIT_BOX_RADIUS = 0.2 self.round = 0 @@ -52,105 +51,89 @@ def __init__(self, monster_data): self.current_spawn_left = 0 self.current_spawn_right = 0 - def query_monster(self, target_position, radius) -> list["Monster"]: + def query_monster(self, target_position, radius) -> list['Monster']: results = [] if len(self.alive_monsters) < (radius / self.hash_grid.cell_size) ** 2: for m in self.alive_monsters: - if ( - m.is_alive - and (m.position - target_position).magnitude <= radius - ): + if m.is_alive and (m.position - target_position).magnitude <= radius: results.append(m) else: - for monster_id in self.hash_grid.query_neighbors( - target_position, radius - ): - m = self.get_monster_with_id(monster_id) - if ( - m.is_alive - and (m.position - target_position).magnitude <= radius - ): + for id in self.hash_grid.query_neighbors(target_position, radius): + m = self.get_monster_with_id(id) + if m.is_alive and (m.position - target_position).magnitude <= radius: results.append(m) return results - def append_monster(self, monster: "Monster"): + def append_monster(self, monster : 'Monster'): """添加一个怪物到战场""" - monster_id = self.globalId - monster.id = monster_id + id = self.globalId + monster.id = id self.globalId += 1 self.monsters.append(monster) self.hash_grid.insert(monster.position, monster.id) - - def append_monster_name(self, name, faction, pos) -> "Monster": + + def append_monster_name(self, name, faction, pos) -> 'Monster': """添加一个怪物到战场,只需要名字""" data = next((m for m in self.monster_data if m["名字"] == name), None) - monster_id = self.globalId + id = self.globalId monster = MonsterFactory.create_monster(data, faction, pos, self) - monster.id = monster_id + monster.id = id self.globalId += 1 self.monsters.append(monster) self.hash_grid.insert(monster.position, monster.id) return monster - def get_monster_with_id(self, monster_id) -> "Monster": - return self.monsters[monster_id] - + def get_monster_with_id(self, id) -> 'Monster': + return self.monsters[id] + def setup_battle(self, left_army, right_army, monster_data): """二维战场初始化""" # 左阵营生成在左上区域 - for name, count in left_army.items(): + for (name, count) in left_army.items(): data = next((m for m in monster_data if m["名字"] == name), None) if data is None: raise ValueError(f"左侧怪物 {name} 在 monster_data 中未找到!") for _ in range(count): pos = FastVector( - random.uniform(0, 0.5), random.uniform(0, MAP_SIZE[1]) - ) - self.monster_temporal_area_left.append( - MonsterFactory.create_monster( - data, Faction.LEFT, pos, self - ) + random.uniform(0, 0.5), + random.uniform(0, MAP_SIZE[1]) ) + self.monster_temporal_area_left.append( MonsterFactory.create_monster(data, Faction.LEFT, pos, self)) # 右阵营生成在右下区域 - for name, count in right_army.items(): + for (name, count) in right_army.items(): data = next((m for m in monster_data if m["名字"] == name), None) if data is None: raise ValueError(f"右侧怪物 {name} 在 monster_data 中未找到!") for _ in range(count): pos = FastVector( - random.uniform(MAP_SIZE[0] - 0.5, MAP_SIZE[0]), - random.uniform(0, MAP_SIZE[1]), - ) - self.monster_temporal_area_right.append( - MonsterFactory.create_monster( - data, Faction.RIGHT, pos, self - ) + random.uniform(MAP_SIZE[0]-0.5, MAP_SIZE[0]), + random.uniform(0, MAP_SIZE[1]) ) + self.monster_temporal_area_right.append(MonsterFactory.create_monster(data, Faction.RIGHT, pos, self)) self.alive_monsters = self.monsters self.gameTime = 0 + self.current_spawn = 0 random.shuffle(self.monster_temporal_area_left) random.shuffle(self.monster_temporal_area_right) return True def check_victory(self): """检查胜利条件""" - if self.current_spawn_left < len( - self.monster_temporal_area_left - ) or self.current_spawn_right < len(self.monster_temporal_area_right): + if self.current_spawn_left < len(self.monster_temporal_area_left) or self.current_spawn_right < len(self.monster_temporal_area_right): return None alive_factions = set() for m in self.alive_monsters: if m.is_alive: alive_factions.add(m.faction) - + if len(alive_factions) == 1: return list(alive_factions)[0] elif len(alive_factions) == 0: return Faction.LEFT return None - + def check_zone(self): new_zone = [] # 检查场地效果 @@ -168,23 +151,12 @@ def run_one_frame(self): self.round += 1 if self.round < 40 or self.round > 90: - if ( - self.current_spawn_left < len(self.monster_temporal_area_left) - and self.round % 2 == 0 - ): - self.append_monster( - self.monster_temporal_area_left[self.current_spawn_left] - ) + if self.current_spawn_left < len(self.monster_temporal_area_left) and self.round % 2 == 0: + self.append_monster(self.monster_temporal_area_left[self.current_spawn_left]) self.current_spawn_left += 1 - if ( - self.current_spawn_right - < len(self.monster_temporal_area_right) - and self.round % 2 == 0 - ): - self.append_monster( - self.monster_temporal_area_right[self.current_spawn_right] - ) + if self.current_spawn_right < len(self.monster_temporal_area_right) and self.round % 2 == 0: + self.append_monster(self.monster_temporal_area_right[self.current_spawn_right]) self.current_spawn_right += 1 self.check_zone() @@ -200,27 +172,21 @@ def run_one_frame(self): self.alive_monsters = [m for m in self.monsters if m.is_alive] winner = self.check_victory() if winner: - logger.info("\nVictory for %s!", winner.name) - left = len( - [ - m - for m in self.alive_monsters - if m.is_alive and m.faction == Faction.LEFT - ] - ) - logger.info("左边存活%s / 右边存活%s", left, len(self.alive_monsters) - left) + logger.info(f"\nVictory for {winner.name}!") + left = len([m for m in self.alive_monsters if m.is_alive and m.faction == Faction.LEFT]) + logger.info(f"左边存活{left} / 右边存活{len(self.alive_monsters) - left}") return winner - + self.gameTime += VIRTUAL_TIME_DELTA return None - + def run_battle(self, visualize=False): """运行战斗直到决出胜负""" while True: if visualize and self.round % 30 == 0: self.print_battlefield() time.sleep(1) - + result = self.run_one_frame() if result != None: return result @@ -229,33 +195,29 @@ def danger_zone_size(self): if self.gameTime < 40: return 0 return int((self.gameTime - 40) / 20) + 1 - + def add_new_zone(self, zone): self.effect_zones.append(zone) def print_battlefield(self): """二维战场可视化""" - grid = np.full((MAP_SIZE[1] * 2, MAP_SIZE[0] * 2), ".", dtype="U2") - + grid = np.full((MAP_SIZE[1] * 2, MAP_SIZE[0] * 2), '.', dtype='U2') + for m in self.alive_monsters: if m.is_alive: - x = np.minimum( - np.maximum(0, int(m.position.x * 2)), MAP_SIZE[0] * 2 - 1 - ) - y = np.minimum( - np.maximum(0, int(m.position.y * 2)), MAP_SIZE[1] * 2 - 1 - ) - symbol = "L" if m.faction == Faction.LEFT else "R" - if grid[y, x] != "." and symbol != grid[y, x]: - symbol = "X" + x = np.minimum(np.maximum(0, int(m.position.x * 2)), MAP_SIZE[0]*2-1) + y = np.minimum(np.maximum(0, int(m.position.y * 2)), MAP_SIZE[1]*2-1) + symbol = 'L' if m.faction == Faction.LEFT else 'R' + if grid[y, x] != '.' and symbol != grid[y, x]: + symbol = 'X' if m.char_icon != "": symbol = m.char_icon grid[y, x] = symbol - - logger.info("\nRound %s", self.round) + + logger.info(f"\nRound {self.round}") for row in grid: - logger.info(" ".join(row)) + logger.info(' '.join(row)) def get_grid(self, target): x, y = int(target.position.x), int(target.position.y) - return x, y + return x, y \ No newline at end of file diff --git a/src/simulation/elemental.py b/simulator/elemental.py similarity index 82% rename from src/simulation/elemental.py rename to simulator/elemental.py index 2e00207..41a0c90 100644 --- a/src/simulation/elemental.py +++ b/simulator/elemental.py @@ -1,9 +1,13 @@ +from enum import Enum +import math + +import numpy as np + from .utils import DamageType, ElementType, debug_print, lerp class ElementAccumulator: """多元素损伤容器""" - def __init__(self, owner): self.accumulators = {et: 0.0 for et in ElementType} self.active_burst = None @@ -14,17 +18,15 @@ def accumulate(self, element: ElementType, value: float): """累积元素损伤""" if self.active_burst: return # 爆条期间暂停累积 - + self.accumulators[element] += value limits = 2000 if self.owner.boss else 1000 if self.accumulators[element] >= limits: self.accumulators[element] = 0 self.active_burst = ElementBurst(element, self.owner) - class ElementBurst: """爆条效果控制器""" - def __init__(self, trigger_element: ElementType, owner): self.owner = owner self.start_time = owner.battlefield.gameTime @@ -49,20 +51,14 @@ def _init_effect_params(self): elif self.trigger_element == ElementType.FIRE: self.duration = 10 dmg = 7000 - debug_print( - f"{self.owner.name}{self.owner.id} 灼燃发期间受到{dmg}点伤害" - ) + debug_print(f"{self.owner.name}{self.owner.id} 灼燃发期间受到{dmg}点伤害") self.owner.take_damage(dmg, DamageType.TRUE) self.owner.magic_resist -= 20 @property def progress(self): """效果进度百分比""" - return min( - 1.0, - (self.owner.battlefield.gameTime - self.start_time) - / self.duration, - ) + return min(1.0, (self.owner.battlefield.gameTime - self.start_time) / self.duration) def on_clear(self): if self.trigger_element == ElementType.FIRE: @@ -73,27 +69,19 @@ def update_effect(self, deltaTime): if self.trigger_element == ElementType.NECRO_RIGHT: # 虚弱效果衰减 self.owner.attack_multiplier = lerp(0.5, 1, self.progress) - + # 持续伤害应用 self.dot_timer += deltaTime - self.owner.take_damage( - self.dot_damage * deltaTime, DamageType.TRUE - ) + self.owner.take_damage(self.dot_damage * deltaTime, DamageType.TRUE) if self.dot_timer >= 1.0: - debug_print( - f"{self.owner.name}{self.owner.id} 凋亡损伤爆发期间受到{self.dot_damage}伤害" - ) + debug_print(f"{self.owner.name}{self.owner.id} 凋亡损伤爆发期间受到{self.dot_damage}伤害") self.dot_timer = 0 elif self.trigger_element == ElementType.NECRO_LEFT: # 持续伤害应用 self.dot_timer += deltaTime - self.owner.take_damage( - self.dot_damage * deltaTime, DamageType.TRUE - ) + self.owner.take_damage(self.dot_damage * deltaTime, DamageType.TRUE) if self.dot_timer >= 1.0: - debug_print( - f"{self.owner.name}{self.owner.id} 凋亡损伤爆发期间受到{self.dot_damage}伤害" - ) + debug_print(f"{self.owner.name}{self.owner.id} 凋亡损伤爆发期间受到{self.dot_damage}伤害") self.dot_timer = 0 @@ -103,25 +91,25 @@ def update_effect(self, deltaTime): # self.resistances = {et: 0.0 for et in ElementType} # self.active_effects = [] # self.hp = max_hp - + # def take_element_damage(self, element: ElementType, base_damage: float): # # 计算实际伤害(考虑抗性) # resistance = self.resistances.get(element, 0) # actual_damage = base_damage * (1 - resistance) # self.hp -= actual_damage - + # # 累积30%基础伤害作为元素损伤 # self.element_system.accumulate(element, base_damage * 0.3) - + # def set_element_resistance(self, element: ElementType, value: float): # """设置元素抗性(0.0-1.0)""" # self.resistances[element] = max(0, min(1.0, value)) - + # def update(self): # """每帧更新状态""" # # 处理爆条队列 # self.element_system.process_burst() - + # # 更新激活中的爆条效果 # if burst := self.element_system.active_burst: # if time.time() - burst.start_time > burst.duration: @@ -133,4 +121,4 @@ def update_effect(self, deltaTime): # """清除爆条残留效果""" # self.element_system.active_burst = None # for elem in ElementType: -# self.resistances[elem] = 0.0 +# self.resistances[elem] = 0.0 \ No newline at end of file diff --git a/src/simulation/monsters.json b/simulator/monsters.json similarity index 100% rename from src/simulation/monsters.json rename to simulator/monsters.json diff --git a/src/simulation/monsters.py b/simulator/monsters.py similarity index 80% rename from src/simulation/monsters.py rename to simulator/monsters.py index 7878046..d9a1122 100644 --- a/src/simulation/monsters.py +++ b/simulator/monsters.py @@ -1,5 +1,8 @@ +from dataclasses import dataclass, field +import json import math import random +import time from enum import Enum from typing import List import numpy as np @@ -11,16 +14,10 @@ from .projectiles import AOEType, AOE炸弹, AOE炸弹锁定 if TYPE_CHECKING: - from .battle_field import Battlefield + from battle_field import Battlefield from .elemental import ElementAccumulator, ElementType -from .utils import ( - BuffEffect, - BuffType, - DamageType, - calculate_normal_dmg, - debug_print, -) +from .utils import BuffEffect, BuffType, DamageType, calculate_normal_dmg, debug_print, Faction from .zone import WineZone @@ -31,7 +28,7 @@ class AttackState(Enum): class AttackAnimation: - def __init__(self, 前摇时间, 后摇时间, 等待时间, monster: "Monster"): + def __init__(self, 前摇时间, 后摇时间, 等待时间, monster: 'Monster'): self.前摇时间 = 前摇时间 self.后摇时间 = 后摇时间 self.等待时间 = 等待时间 @@ -52,13 +49,7 @@ def idle_time(self): class TargetSelector: @staticmethod - def select_targets( - attacker, - battlefield, - need_in_range=False, - max_targets=2, - reverse=False, - ): + def select_targets(attacker, battlefield, need_in_range=False, max_targets=2, reverse=False): """ 带嘲讽等级的目标选择算法 优先级: 攻击范围内最高嘲讽等级 > 同等级最近目标 > 全局最近目标 @@ -70,11 +61,9 @@ def select_targets( # if m.can_be_target() # and m.faction != attacker.faction] # else: - enemies: list[Monster] = [ - m - for m in battlefield.alive_monsters - if m.can_be_target() and m.faction != attacker.faction - ] + enemies: list[Monster] = [m for m in battlefield.alive_monsters + if m.can_be_target() + and m.faction != attacker.faction] # battlefield.query_monster(attacker.position, attacker.attack_range if need_in_range else 9999) # enemies = if not enemies: @@ -87,40 +76,34 @@ def select_targets( in_range = dist <= attacker.attack_range if not need_in_range or (need_in_range and in_range): - enemy_info.append( - { - "enemy": enemy, - "distance": dist, - "aggro": enemy.aggro if in_range else 0, - } - ) + enemy_info.append({ + "enemy": enemy, + "distance": dist, + "aggro": enemy.aggro if in_range else 0 + }) # 按照优先级排序:嘲讽降序 -> 距离升序 if reverse: - sorted_enemies = sorted(enemy_info, key=lambda x: (-x["distance"])) + sorted_enemies = sorted(enemy_info, + key=lambda x: (-x["distance"])) else: - sorted_enemies = sorted( - enemy_info, key=lambda x: (-x["aggro"], x["distance"]) - ) + sorted_enemies = sorted(enemy_info, + key=lambda x: (-x["aggro"], x["distance"])) count = np.minimum(max_targets, len(sorted_enemies)) # 选择前N个目标 return [e["enemy"] for e in sorted_enemies[:count]] @staticmethod - def select_targets_lowest_health( - attacker, battlefield, need_in_range=False, max_targets=2 - ): + def select_targets_lowest_health(attacker, battlefield, need_in_range=False, max_targets=2): """ 带嘲讽等级的目标选择算法 优先级: 攻击范围内最高嘲讽等级 > 同等级最近目标 > 全局最近目标 """ # 获取所有有效敌人 - enemies: list[Monster] = [ - m - for m in battlefield.alive_monsters - if m.can_be_target() and m.faction != attacker.faction - ] + enemies: list[Monster] = [m for m in battlefield.alive_monsters + if m.can_be_target() + and m.faction != attacker.faction] if not enemies: return [] @@ -132,20 +115,16 @@ def select_targets_lowest_health( in_range = dist <= attacker.attack_range if not need_in_range or (need_in_range and in_range): - enemy_info.append( - { - "enemy": enemy, - "distance": dist, - "aggro": enemy.aggro if in_range else 0, - "health_ratio": enemy.health / enemy.max_health, - } - ) + enemy_info.append({ + "enemy": enemy, + "distance": dist, + "aggro": enemy.aggro if in_range else 0, + "health_ratio": enemy.health / enemy.max_health + }) # 按照优先级排序:嘲讽降序 -> 距离升序 - sorted_enemies = sorted( - enemy_info, - key=lambda x: (x["health_ratio"], -x["aggro"], x["distance"]), - ) + sorted_enemies = sorted(enemy_info, + key=lambda x: (x["health_ratio"], -x["aggro"], x["distance"])) count = np.minimum(max_targets, len(sorted_enemies)) # 选择前N个目标 @@ -166,9 +145,7 @@ def apply(self, effect): if effect.type in self.owner.immunity: return # 处理效果叠加逻辑 - existing = next( - (e for e in self.effects if e.type == effect.type), None - ) + existing = next((e for e in self.effects if e.type == effect.type), None) # # 已经冰冻住了就不要施加寒冷效果了 # if effect.type == BuffType.CHILL: @@ -179,18 +156,8 @@ def apply(self, effect): # 寒冷效果叠加就会变成冰冻 if effect.type == BuffType.CHILL: existing.duration = 0 - self.apply( - BuffEffect( - BuffType.FROZEN, - effect.duration, - effect.source, - effect.stacks, - effect.data, - ) - ) - debug_print( - f"{self.owner.name}{self.owner.id} 被 {effect.source.name} 冰冻了!" - ) + self.apply(BuffEffect(BuffType.FROZEN, effect.duration, effect.source, effect.stacks, effect.data)) + debug_print(f"{self.owner.name}{self.owner.id} 被 {effect.source.name} 冰冻了!") return # 其他效果刷新时间 @@ -227,38 +194,25 @@ def _process_dot(self, delta_time): # self.fire_dmg_counter += delta_time # if self.fire_dmg_counter >= 0.33: # self.fire_dmg_counter = 0 - damage = calculate_normal_dmg( - 0, self.owner.magic_resist, 60 * delta_time, DamageType.MAGIC - ) + damage = calculate_normal_dmg(0, self.owner.magic_resist, 60 * delta_time, DamageType.MAGIC) self.owner.take_damage(damage, DamageType.MAGIC) - corrupt = next( - (e for e in self.effects if e.type == BuffType.CORRUPT), None - ) + corrupt = next((e for e in self.effects if e.type == BuffType.CORRUPT), None) if corrupt: # 每秒造成伤害 # self.corrupt_dmg_counter += delta_time # if self.corrupt_dmg_counter >= 1: # self.corrupt_dmg_counter = 0 - damage = calculate_normal_dmg( - 0, self.owner.magic_resist, 100 * delta_time, DamageType.MAGIC - ) + damage = calculate_normal_dmg(0, self.owner.magic_resist, 100 * delta_time, DamageType.MAGIC) self.owner.take_damage(damage, DamageType.MAGIC) - power_stone = next( - (e for e in self.effects if e.type == BuffType.POWER_STONE), None - ) + power_stone = next((e for e in self.effects if e.type == BuffType.POWER_STONE), None) if power_stone: self.power_stay_counter += delta_time - damage = ( - 0.005 - * self.owner.max_health - * self.power_stay_counter - * delta_time - ) + damage = 0.005 * self.owner.max_health * self.power_stay_counter * delta_time if self.owner.take_damage(damage, DamageType.TRUE): pass - # debug_print(f"{self.owner.name}{self.owner.id} 受到了毒圈的{damage}伤害") + #debug_print(f"{self.owner.name}{self.owner.id} 受到了毒圈的{damage}伤害") def _init_effect(self, effect): """初始化效果""" @@ -331,9 +285,7 @@ def __init__(self, data, faction, position, battlefield): self.attack_range = data["攻击范围"]["数值"] self.move_speed = data["移速"]["数值"] self.traits = data["特性"] - self.attack_type = ( - DamageType.PHYSICAL if data["类型"] == "物理" else DamageType.MAGIC - ) + self.attack_type = DamageType.PHYSICAL if data["类型"] == "物理" else DamageType.MAGIC self.char_icon = data.get("符号", "") self.id = -1 self.attack_speed = 100 @@ -349,7 +301,7 @@ def __init__(self, data, faction, position, battlefield): self.frozen = False self.dizzy = False self.invincible = False - self.battlefield: "Battlefield" = battlefield + self.battlefield: 'Battlefield' = battlefield self.status_system = StatusSystem(self) self.element_system = ElementAccumulator(self) self.attack_multiplier = 1 @@ -408,9 +360,7 @@ def increase_skill_cd(self, delta_time): def increase_attack_cd(self, delta_time): """增加攻击技力、攻击频率计算""" - self.attack_time_counter += delta_time * ( - np.maximum(10, np.minimum(self.attack_speed, 600)) / 100 - ) + self.attack_time_counter += delta_time * (np.maximum(10, np.minimum(self.attack_speed, 600)) / 100) def move_toward_enemy(self, delta_time): """根据阵营向对方移动""" @@ -429,9 +379,7 @@ def move_toward_enemy(self, delta_time): # 标准化移动向量并应用速度 norm_direction = direction.normalize() if not self.blocked and self.attack_state == AttackState.等待: - self.velocity = ( - self.velocity * 7 + norm_direction * self.move_speed - ) / 8 + self.velocity = (self.velocity * 7 + norm_direction * self.move_speed) / 8 RADIUS = self.battlefield.HIT_BOX_RADIUS selfRadius = RADIUS * 0.2 if self.blocked else RADIUS @@ -455,12 +403,7 @@ def move_toward_enemy(self, delta_time): depth = selfRadius + radius2 - dist if dist < selfRadius + radius2: # 发生碰撞,挤出 - self.velocity -= ( - dir - * (depth + 0.02) - * hardness1 - / (hardness1 + hardness2) - ) + self.velocity -= dir * (depth + 0.02) * hardness1 / (hardness1 + hardness2) # m.velocity += dir * (depth + 0.02) * hardness2 / (hardness1 + hardness2) def do_move(self, delta_time): @@ -503,10 +446,7 @@ def can_attack(self, delta_time): if self.attack_state == AttackState.前摇: if in_range: self.increase_attack_cd(delta_time) - if ( - self.attack_time_counter - >= self.attack_animation.windup_time - ): + if self.attack_time_counter >= self.attack_animation.windup_time: self.attack_state = AttackState.后摇 return True else: @@ -540,12 +480,8 @@ def update(self, delta_time): self.status_system.update(delta_time) self.update_elemental(delta_time) - if ( - self.target is None - or not self.target.can_be_target() - or (self.target.position - self.position).magnitude - > self.attack_range - ): + if self.target is None or not self.target.can_be_target() or ( + self.target.position - self.position).magnitude > self.attack_range: # 寻找新目标 self.target = self.find_target() @@ -567,9 +503,7 @@ def update(self, delta_time): def find_target(self): """寻找最近的可攻击目标""" - targets = TargetSelector.select_targets( - self, self.battlefield, need_in_range=False, max_targets=1 - ) + targets = TargetSelector.select_targets(self, self.battlefield, need_in_range=False, max_targets=1) if len(targets) > 0: return targets[0] return None @@ -585,21 +519,15 @@ def attack(self, target, gameTime): target.on_hit(self, damage) def apply_damage_to_target(self, target, damage) -> bool: - debug_print( - f"{self.name}{self.id} 对 {target.name}{target.id} 造成{damage}点{self.attack_type}伤害" - ) + debug_print(f"{self.name}{self.id} 对 {target.name}{target.id} 造成{damage}点{self.attack_type}伤害") if target.take_damage(damage, self.attack_type): return True - debug_print( - f"{self.name}{self.id} 没有对 {target.name}{target.id}造成伤害" - ) + debug_print(f"{self.name}{self.id} 没有对 {target.name}{target.id}造成伤害") return False def calculate_damage(self, target, damage): """计算伤害值""" - return calculate_normal_dmg( - target.phy_def, target.magic_resist, damage, self.attack_type - ) + return calculate_normal_dmg(target.phy_def, target.magic_resist, damage, self.attack_type) # if self.attack_type == "物理": # return calculate_normal_dmg(target.phy_def, 0, damage, False) # # return np.maximum(damage - target.phy_def, int(damage * 0.05)) @@ -637,7 +565,6 @@ def on_attack(self, target, damage): target.phy_def = max(0, target.phy_def - 15) debug_print(f"{self.name} 使 {target.name} 防御力降低15") return True - # def apply_damage_to_target(self, target, damage): # if super().apply_damage_to_target(target, damage): # # 实现减防特性 @@ -656,17 +583,8 @@ def on_death(self): debug_print(f"{self.name} 即将自爆!") self.battlefield.projectiles_manager.spawn_projectile( - AOE炸弹( - 0.2, - self.get_attack_power() * 4, - DamageType.PHYSICAL, - self, - self.position, - name="源石虫爆炸", - aoeType=AOEType.Circle, - radius=1.25, - ) - ) + AOE炸弹(0.2, self.get_attack_power() * 4, DamageType.PHYSICAL, self, self.position, name="源石虫爆炸", + aoeType=AOEType.Circle, radius=1.25)) # for m in self.battlefield.monsters: # if m.faction != self.faction and m.is_alive: # distance = np.linalg.norm(m.position - self.position) @@ -682,9 +600,7 @@ class 炽焰源石虫(Monster): def apply_damage_to_target(self, target: Monster, damage): if super().apply_damage_to_target(target, damage): - target.element_system.accumulate( - ElementType.FIRE, self.get_attack_power() - ) + target.element_system.accumulate(ElementType.FIRE, self.get_attack_power()) return True return False @@ -704,7 +620,9 @@ def on_death(self): m.take_damage(dmg, self.attack_type) # 施加10秒寒冷效果 chill = BuffEffect( - type=BuffType.CHILL, duration=10, source=self + type=BuffType.CHILL, + duration=10, + source=self ) m.status_system.apply(chill) debug_print(f"{m.name} 受到{dmg}点爆炸伤害") @@ -721,7 +639,11 @@ def on_hit(self, attacker, damage): super().on_hit(attacker, damage) # 触发加速特性 if self.is_alive and self.speed_boost_counter <= 0: - speed = BuffEffect(type=BuffType.SPEEDUP, duration=2, source=self) + speed = BuffEffect( + type=BuffType.SPEEDUP, + duration=2, + source=self + ) self.status_system.apply(speed) self.speed_boost_counter = 7.0 debug_print(f"{self.name} 进入极速状态!") @@ -756,14 +678,10 @@ def on_death(self): def spawn_small(self): debug_print(f"{self.name} 释放小喷蛛") - self.battlefield.append_monster_name( - "小喷蛛", - self.faction, - self.position - + FastVector( - random.uniform(-1, 1) * 0.2, random.uniform(-1, 1) * 0.2 - ), - ) + self.battlefield.append_monster_name("小喷蛛", self.faction, self.position + FastVector( + random.uniform(-1, 1) * 0.2, + random.uniform(-1, 1) * 0.2 + )) class 提亚卡乌好战者(Monster): @@ -874,10 +792,7 @@ def attack(self, target, gameTime): debug_print(f"{self.name} 进入防御模式") def on_extra_update(self, delta_time): - if ( - self.stage == 1 - and self.battlefield.gameTime - self.last_attack_time >= 20.0 - ): + if self.stage == 1 and self.battlefield.gameTime - self.last_attack_time >= 20.0: self.phy_def -= 300 self.move_speed = self.original_speed self.defenseMode = False @@ -915,9 +830,7 @@ def calculate_damage(self, target, damage): target_def = target.phy_def if self.attack_count >= 4: target_def = target_def * 0.4 - return calculate_normal_dmg( - target_def, target.magic_resist, damage, DamageType.PHYSICAL - ) + return calculate_normal_dmg(target_def, target.magic_resist, damage, DamageType.PHYSICAL) class 高塔术师(Monster): @@ -927,36 +840,22 @@ def on_spawn(self): self.attack_animation = AttackAnimation(0.07, 0.13, 0.8, self) def attack(self, target, gameTime): - targets = TargetSelector.select_targets( - self, self.battlefield, need_in_range=True, max_targets=2 - ) + targets = TargetSelector.select_targets(self, self.battlefield, need_in_range=True, max_targets=2) if len(targets) == 0: return for t in targets: self.battlefield.projectiles_manager.spawn_projectile( - AOE炸弹锁定( - 0.1, - self.get_attack_power(), - DamageType.MAGIC, - self, - t, - name="爆裂魔法", - aoeType=AOEType.Grid8, - ) - ) + AOE炸弹锁定(0.1, self.get_attack_power(), DamageType.MAGIC, self, t, name="爆裂魔法", + aoeType=AOEType.Grid8)) debug_print(f"{self.name}{self.id} 射出爆裂魔法") def get_aoe_targets(self, target): - aoe_targets = [ - m - for m in self.battlefield.monsters - if m.is_alive - and m.faction != self.faction - and abs(m.position.x - target.position.x) <= 1 - and abs(m.position.y - target.position.y) <= 1 - ] + aoe_targets = [m for m in self.battlefield.monsters + if m.is_alive and m.faction != self.faction + and abs(m.position.x - target.position.x) <= 1 + and abs(m.position.y - target.position.y) <= 1] return aoe_targets @@ -985,16 +884,16 @@ def apply_damage_to_target(self, target, damage): if self.attack_count % 3 == 0: # 施加寒冷效果 chill = BuffEffect( - type=BuffType.CHILL, duration=5, source=self + type=BuffType.CHILL, + duration=5, + source=self ) target.status_system.apply(chill) return True return False def attack(self, target, gameTime): - targets = TargetSelector.select_targets( - self, self.battlefield, need_in_range=True, max_targets=2 - ) + targets = TargetSelector.select_targets(self, self.battlefield, need_in_range=True, max_targets=2) if len(targets) == 0: return @@ -1017,9 +916,7 @@ def on_hit(self, attacker, damage): damage = self.calculate_damage(attacker, 300) if self.apply_damage_to_target(attacker, damage): attacker.on_hit(self, damage) - debug_print( - f"{self.name}{self.id} 对 {attacker.name}{attacker.id} 造成{damage}伤害" - ) + debug_print(f"{self.name}{self.id} 对 {attacker.name}{attacker.id} 造成{damage}伤害") class 庞贝(Monster): @@ -1040,9 +937,8 @@ def get_max_skill_bar(self): return 10 def attack(self, target, gameTime): - targets: list[Monster] = TargetSelector.select_targets( - self, self.battlefield, need_in_range=True, max_targets=4 - ) + targets: list[Monster] = TargetSelector.select_targets(self, self.battlefield, need_in_range=True, + max_targets=4) if len(targets) == 0: return @@ -1050,9 +946,11 @@ def attack(self, target, gameTime): damage = self.calculate_damage(m, self.get_attack_power()) if self.apply_damage_to_target(m, damage): m.on_hit(self, damage) - m.status_system.apply( - BuffEffect(type=BuffType.FIRE, duration=10, source=self) - ) + m.status_system.apply(BuffEffect( + type=BuffType.FIRE, + duration=10, + source=self + )) def on_extra_update(self, delta_time): if not self.rage_mode and self.health < 0.5 * self.max_health: @@ -1060,19 +958,10 @@ def on_extra_update(self, delta_time): self.attack_speed += 40 debug_print(f"{self.name} 进入狂暴模式") self.ring_attack_counter += delta_time - targets = TargetSelector.select_targets( - self, self.battlefield, need_in_range=False, max_targets=9999 - ) - if ( - len(targets) > 0 - and (targets[0].position - self.position).magnitude < 0.8 - ): + targets = TargetSelector.select_targets(self, self.battlefield, need_in_range=False, max_targets=9999) + if len(targets) > 0 and (targets[0].position - self.position).magnitude < 0.8: if self.ring_attack_counter >= 10.0: - targets = [ - t - for t in targets - if (t.position - self.position).magnitude < 1.4 - ] + targets = [t for t in targets if (t.position - self.position).magnitude < 1.4] for tar in targets: dmg = self.calculate_damage(tar, 1000) if self.apply_damage_to_target(tar, dmg): @@ -1084,9 +973,11 @@ class 食腐狗(Monster): """食腐狗""" def on_attack(self, target, damage): - target.status_system.apply( - BuffEffect(type=BuffType.CORRUPT, duration=10, source=self) - ) + target.status_system.apply(BuffEffect( + type=BuffType.CORRUPT, + duration=10, + source=self + )) class 鼠鼠(Monster): @@ -1099,7 +990,11 @@ def on_hit(self, attacker, damage): super().on_hit(attacker, damage) # 触发加速特性 if self.is_alive and self.speed_boost_counter <= 0: - speed = BuffEffect(type=BuffType.SPEEDUP, duration=5, source=self) + speed = BuffEffect( + type=BuffType.SPEEDUP, + duration=5, + source=self + ) self.status_system.apply(speed) self.speed_boost_counter = 15.0 debug_print(f"{self.name}{self.id} 进入极速状态!") @@ -1118,23 +1013,14 @@ def on_spawn(self): def on_extra_update(self, delta_time): if self.first_attack: - targets: list[Monster] = TargetSelector.select_targets( - self, self.battlefield, need_in_range=True, max_targets=1 - ) + targets: list[Monster] = TargetSelector.select_targets(self, self.battlefield, need_in_range=True, + max_targets=1) if len(targets) == 0: return self.battlefield.projectiles_manager.spawn_projectile( - AOE炸弹锁定( - 0.2, - self.get_attack_power() * 1.5, - DamageType.MAGIC, - self, - targets[0], - name="“投石机”", - aoeType=AOEType.Grid4, - ) - ) + AOE炸弹锁定(0.2, self.get_attack_power() * 1.5, DamageType.MAGIC, self, targets[0], name="“投石机”", + aoeType=AOEType.Grid4)) self.attack_range = 0.8 self.first_attack = False debug_print(f"{self.name}{self.id} 投掷雪球") @@ -1163,12 +1049,12 @@ def apply_damage_to_target(self, target, damage): # 每第四下攻击会眩晕对面7秒 if self.attack_count % 4 == 0: dizzy = BuffEffect( - type=BuffType.DIZZY, duration=7, source=self + type=BuffType.DIZZY, + duration=7, + source=self ) target.status_system.apply(dizzy) - debug_print( - f"{self.name}{self.id} 眩晕了 {target.name}{target.id}" - ) + debug_print(f"{self.name}{self.id} 眩晕了 {target.name}{target.id}") return True return False @@ -1198,9 +1084,8 @@ def attack(self, target, gameTime): if self.stage == 0: self.on_attack(target, 0) if self.attack_count % 4 == 0: - targets: list[Monster] = TargetSelector.select_targets( - self, self.battlefield, need_in_range=True, max_targets=2 - ) + targets: list[Monster] = TargetSelector.select_targets(self, self.battlefield, need_in_range=True, + max_targets=2) if len(targets) == 0: return @@ -1208,11 +1093,11 @@ def attack(self, target, gameTime): damage = self.calculate_damage(m, self.get_attack_power()) if self.apply_damage_to_target(m, damage): m.on_hit(self, damage) - m.status_system.apply( - BuffEffect( - type=BuffType.DIZZY, duration=3, source=self - ) - ) + m.status_system.apply(BuffEffect( + type=BuffType.DIZZY, + duration=3, + source=self + )) else: super().attack(target, gameTime) return @@ -1229,9 +1114,7 @@ def attack(self, target, gameTime): def calculate_damage(self, target: Monster, damage): if self.stage == 1 and self.attack_count % 4 == 0: target_def = target.phy_def * 0.4 - return calculate_normal_dmg( - target_def, target.magic_resist, damage, DamageType.PHYSICAL - ) + return calculate_normal_dmg(target_def, target.magic_resist, damage, DamageType.PHYSICAL) return super().calculate_damage(target, damage) def on_death(self): @@ -1251,9 +1134,15 @@ def on_death(self): self.health = self.max_health self.status_system.reset() switch_stage = BuffEffect( - type=BuffType.INVINCIBLE2, duration=4, source=self + type=BuffType.INVINCIBLE2, + duration=4, + source=self + ) + dizzy = BuffEffect( + type=BuffType.DIZZY, + duration=4, + source=self ) - dizzy = BuffEffect(type=BuffType.DIZZY, duration=4, source=self) # 转阶段 self.status_system.apply(switch_stage) self.status_system.apply(dizzy) @@ -1324,10 +1213,7 @@ def on_extra_update(self, delta_time): if self.stage == 1: # 蓄力5秒后造成攻击力200%法术伤害 - if ( - self.charging_counter >= 5 - or not self.locked_target.can_be_target() - ): + if self.charging_counter >= 5 or not self.locked_target.can_be_target(): self.stage = 2 self.move_speed = self.original_move_speed self.skill_counter = 0 @@ -1339,9 +1225,7 @@ def on_extra_update(self, delta_time): debug_print(f"{self.name}{self.id} 退出蓄力") if self.locked_target.can_be_target(): - damage = self.calculate_damage( - self.locked_target, self.get_attack_power() * 2 - ) + damage = self.calculate_damage(self.locked_target, self.get_attack_power() * 2) self.on_attack(self.locked_target, damage) if self.apply_damage_to_target(self.locked_target, damage): self.locked_target.on_hit(self, damage) @@ -1397,12 +1281,10 @@ def on_extra_update(self, delta_time): self.stage = 1 self.move_speed = 0 self.charging_counter = 0 - # self.target_pos = self.target.position - self.target_pos = FastVector( - self.target.position.x, self.target.position.y - ) + #self.target_pos = self.target.position + self.target_pos = FastVector(self.target.position.x, self.target.position.y) debug_print(f"{self.name}{self.id} 开始蓄力") - # debug_print(f"{self.name}{self.id} 锁定的坐标是{self.target_pos.x},{self.target_pos.y}") + #debug_print(f"{self.name}{self.id} 锁定的坐标是{self.target_pos.x},{self.target_pos.y}") if self.stage == 1: # 蓄力7秒后造成攻击力250%法术伤害 if self.charging_counter >= 7: @@ -1410,21 +1292,15 @@ def on_extra_update(self, delta_time): self.move_speed = self.original_move_speed self.skill_counter = 0 self.charging_counter = 0 - # debug_print(f"{self.name}{self.id} 轰炸的中心是{self.target_pos.x},{self.target_pos.y}") + #debug_print(f"{self.name}{self.id} 轰炸的中心是{self.target_pos.x},{self.target_pos.y}") for m in self.battlefield.monsters: if m.faction != self.faction and m.can_be_target(): - # 改为max(5|x|,|y|)<=2.5∪max(|x|,5|y|)<=2.5∪max(|x|,|y|)<=1.5 - x = int( - math.floor(m.position.x - self.target_pos.x + 0.5) - ) - y = int( - math.floor(m.position.y - self.target_pos.y + 0.5) - ) + #改为max(5|x|,|y|)<=2.5∪max(|x|,5|y|)<=2.5∪max(|x|,|y|)<=1.5 + x = int(math.floor(m.position.x - self.target_pos.x + 0.5)) + y = int(math.floor(m.position.y - self.target_pos.y + 0.5)) if abs(x) + abs(y) <= 2: - dmg = self.calculate_damage( - m, self.get_attack_power() * 2.5 - ) + dmg = self.calculate_damage(m, self.get_attack_power() * 2.5) if self.apply_damage_to_target(m, dmg): m.on_hit(self, dmg) @@ -1522,31 +1398,19 @@ def get_hit_enemies(self): # 列坐标匹配(同一垂直方向) if abs(x - self_x) <= 0.5: - if ( - m.position.y > self.position.y - and m.position.y - self.position.y < smallest_up - ): + if m.position.y > self.position.y and m.position.y - self.position.y < smallest_up: smallest_up = m.position.y - self.position.y smallest_up_target = m - if ( - m.position.y < self.position.y - and self.position.y - m.position.y < smallest_down - ): + if m.position.y < self.position.y and self.position.y - m.position.y < smallest_down: smallest_down = self.position.y - m.position.y smallest_down_target = m # 行坐标匹配(同一水平方向) if abs(y - self_y) <= 0.5: - if ( - m.position.x > self.position.x - and m.position.x - self.position.x < smallest_right - ): + if m.position.x > self.position.x and m.position.x - self.position.x < smallest_right: smallest_right = m.position.x - self.position.x smallest_right_target = m - if ( - m.position.x < self.position.x - and self.position.x - m.position.x < smallest_left - ): + if m.position.x < self.position.x and self.position.x - m.position.x < smallest_left: smallest_left = self.position.x - m.position.x smallest_left_target = m @@ -1587,8 +1451,7 @@ def on_spawn(self): class AttackNode: """攻击节点数据类""" - - __slots__ = ["target", "damage_multiplier"] # 优化内存使用 + __slots__ = ['target', 'damage_multiplier'] # 优化内存使用 def __init__(self, target, multiplier): self.target = target @@ -1607,9 +1470,7 @@ def chain_attack(self, initial_target: Monster) -> list[AttackNode]: current_multiplier = 1.0 # 添加初始攻击 - attack_chain.append( - self.AttackNode(current_target, current_multiplier) - ) + attack_chain.append(self.AttackNode(current_target, current_multiplier)) visited.add(current_target.id) # 执行最多4次跳跃 @@ -1617,12 +1478,8 @@ def chain_attack(self, initial_target: Monster) -> list[AttackNode]: # 寻找下一个候选目标 candidates = self._find_candidates( current_target.position, - [ - m - for m in self.battlefield.alive_monsters - if m.can_be_target() and m.faction != self.faction - ], - visited, + [m for m in self.battlefield.alive_monsters if m.can_be_target() and m.faction != self.faction], + visited ) if not candidates: @@ -1641,9 +1498,10 @@ def chain_attack(self, initial_target: Monster) -> list[AttackNode]: return attack_chain - def _find_candidates( - self, origin: FastVector, enemies: List["Monster"], visited: set - ) -> List[tuple]: + def _find_candidates(self, + origin: FastVector, + enemies: List['Monster'], + visited: set) -> List[tuple]: """ 查找有效候选目标 :param origin: 当前攻击源点坐标 (x, y) @@ -1676,25 +1534,25 @@ def attack(self, target, gameTime): node.target.on_hit(self, dmg) # 所有人都有一样的凋亡损伤 t = ElementType.NECRO_RIGHT - node.target.element_system.accumulate( - t, self.get_attack_power() * 0.3 - ) + node.target.element_system.accumulate(t, self.get_attack_power() * 0.3) # debug_print(f"{self.name}{self.id} 对 {node.target.name}{node.target.id} 造成{dmg}点魔法伤害") def on_death(self): debug_print(f"{self.name} 变成大君之赐") - m = self.battlefield.append_monster_name( - "大君之赐", - self.faction, - self.position - + FastVector( - random.uniform(-1, 1) * 0.2, random.uniform(-1, 1) * 0.2 - ), - ) + m = self.battlefield.append_monster_name("大君之赐", self.faction, self.position + FastVector( + random.uniform(-1, 1) * 0.2, + random.uniform(-1, 1) * 0.2 + )) switch_stage = BuffEffect( - type=BuffType.INVINCIBLE2, duration=1, source=self + type=BuffType.INVINCIBLE2, + duration=1, + source=self + ) + dizzy = BuffEffect( + type=BuffType.DIZZY, + duration=1, + source=self ) - dizzy = BuffEffect(type=BuffType.DIZZY, duration=1, source=self) # 转阶段 m.status_system.apply(switch_stage) m.status_system.apply(dizzy) @@ -1722,11 +1580,7 @@ def on_spawn(self): def on_extra_update(self, delta_time): self.decay_timer += delta_time - if ( - self.decay_timer > 3.5 - and abs(round(self.decay_timer - 3.5) - (self.decay_timer - 3.5)) - < 0.001 - ): + if self.decay_timer > 3.5 and abs(round(self.decay_timer - 3.5) - (self.decay_timer - 3.5)) < 0.001: if self.attack_stack > 0: self.attack_stack -= 2 self.attack_multiplier -= 0.3 @@ -1765,23 +1619,14 @@ def on_spawn(self): self.attack_animation = AttackAnimation(0.05, 0.15, 0.8, self) def attack(self, target, gameTime): - targets: list[Monster] = TargetSelector.select_targets( - self, self.battlefield, need_in_range=True, max_targets=1 - ) + targets: list[Monster] = TargetSelector.select_targets(self, self.battlefield, need_in_range=True, + max_targets=1) if len(targets) == 0: return self.battlefield.projectiles_manager.spawn_projectile( - AOE炸弹锁定( - 0.2, - self.get_attack_power(), - self.attack_type, - self, - targets[0], - name="火箭弹", - aoeType=AOEType.Grid8, - ) - ) + AOE炸弹锁定(0.2, self.get_attack_power(), self.attack_type, self, targets[0], name="火箭弹", + aoeType=AOEType.Grid8)) debug_print(f"{self.name}{self.id} 开炮") @@ -1803,16 +1648,8 @@ def on_extra_update(self, delta_time): distance = direction.magnitude if distance <= self.attack_range: self.battlefield.projectiles_manager.spawn_projectile( - AOE炸弹锁定( - 0.2, - self.get_attack_power() * 2, - self.attack_type, - self, - self.target, - name="火箭弹", - aoeType=AOEType.Grid8, - ) - ) + AOE炸弹锁定(0.2, self.get_attack_power() * 2, self.attack_type, self, self.target, + name="火箭弹", aoeType=AOEType.Grid8)) self.stage = 1 debug_print(f"{self.name}{self.id} 射出火箭弹") @@ -1863,9 +1700,7 @@ def get_max_skill_bar(self): return super().get_max_skill_bar() def lock_target(self): - targets = TargetSelector.select_targets( - self, self.battlefield, need_in_range=True, max_targets=1 - ) + targets = TargetSelector.select_targets(self, self.battlefield, need_in_range=True, max_targets=1) if len(targets) > 0: return targets[0] return None @@ -1888,30 +1723,21 @@ def on_extra_update(self, delta_time): self.skill_counter = 0 else: # 法术伤害 - dmg = self.calculate_damage( - self.locked_target, - self.get_attack_power() * 0.4 * delta_time, - ) + dmg = self.calculate_damage(self.locked_target, self.get_attack_power() * 0.4 * delta_time) if self.apply_damage_to_target(self.locked_target, dmg): self.locked_target.on_hit(self, dmg) - # debug_print(f"{self.locked_target.name}{self.locked_target.id} 受到 {self.name}{self.id} 的{dmg}点法术伤害") + # debug_print(f"{self.locked_target.name}{self.locked_target.id} 受到 {self.name}{self.id} 的{dmg}点法术伤害") # 蓄力完成的凋亡损伤 - if ( - self.locked_target.can_be_target() - and self.charging_counter2 >= 8.0 - ): + if self.locked_target.can_be_target() and self.charging_counter2 >= 8.0: for m in self.get_aoe_targets(self.locked_target): dmg = self.get_attack_power() * 2.2 - m.element_system.accumulate( - ElementType.NECRO_RIGHT, dmg - ) - debug_print( - f"{m.name}{m.id} 受到 {self.name}{self.id} 的{dmg}点凋亡损伤" - ) + m.element_system.accumulate(ElementType.NECRO_RIGHT, dmg) + debug_print(f"{m.name}{m.id} 受到 {self.name}{self.id} 的{dmg}点凋亡损伤") self.stage = 0 self.move_speed = self.original_move_speed self.locked_target = None self.charging_counter2 = 0 + def get_aoe_targets(self, target): # 这个是获取|dx|<=1,|dy|<=1范围内的目标,是个矩形 @@ -1922,21 +1748,13 @@ def get_aoe_targets(self, target): # 十字:|dx|≤0.5∪|dy|≤0.5 # 矩形:max(|dx|,|dy|)≤1.5 # 十字与矩形取交集 - aoe_targets = [ - m - for m in self.battlefield.monsters - if m.is_alive - and m.faction != self.faction - and np.maximum( - abs(m.position.x - target.position.x), - abs(m.position.y - target.position.y), - ) - <= 1.5 - and ( - abs(m.position.x - target.position.x) <= 0.5 - or abs(m.position.y - target.position.y) <= 0.5 - ) - ] + aoe_targets = [m for m in self.battlefield.monsters + if m.is_alive + and m.faction != self.faction + and np.maximum(abs(m.position.x - target.position.x), + abs(m.position.y - target.position.y)) <= 1.5 + and (abs(m.position.x - target.position.x) <= 0.5 or abs( + m.position.y - target.position.y) <= 0.5)] return aoe_targets def attack(self, target, gameTime): @@ -1947,9 +1765,7 @@ def attack(self, target, gameTime): self.on_attack(target, damage) if self.apply_damage_to_target(target, damage): t = ElementType.NECRO_RIGHT - target.element_system.accumulate( - t, self.get_attack_power() * 0.25 - ) + target.element_system.accumulate(t, self.get_attack_power() * 0.25) target.on_hit(self, damage) @@ -2011,9 +1827,7 @@ def on_spawn(self): """标枪恐鱼穿刺者""" def attack(self, target, gameTime): - targets = TargetSelector.select_targets_lowest_health( - self, self.battlefield, need_in_range=True, max_targets=1 - ) + targets = TargetSelector.select_targets_lowest_health(self, self.battlefield, need_in_range=True, max_targets=1) if len(targets) == 0: return self.target = targets[0] @@ -2078,9 +1892,7 @@ def attack(self, target: Monster, gameTime): # 丢出酒桶以后 self.move_speed /= 3 self.stage = 1 - self.battlefield.add_new_zone( - WineZone(target.position, self.battlefield, 12, self.faction) - ) + self.battlefield.add_new_zone(WineZone(target.position, self.battlefield, 12, self.faction)) class 复仇者(Monster): @@ -2139,9 +1951,9 @@ def on_extra_update(self, delta_time): def on_death(self): enemies = enemies = [ - m - for m in self.battlefield.monsters - if m.can_be_target() and m.faction != self.faction + m for m in self.battlefield.monsters + if m.can_be_target() + and m.faction != self.faction ] if not enemies: return @@ -2179,7 +1991,9 @@ def on_extra_update(self, delta_time): self.move_speed = self.origial_move_speed * 3 self.speed_up_timer = 0 switch_stage = BuffEffect( - type=BuffType.INVINCIBLE, duration=10, source=self + type=BuffType.INVINCIBLE, + duration=10, + source=self ) self.status_system.apply(switch_stage) @@ -2235,32 +2049,21 @@ def increase_skill_cd(self, delta_time): if self.stage == 0: if self.target: for m in self.get_aoe_targets(self.target): - damage = self.calculate_damage( - m, self.get_attack_power() * 2 - ) + damage = self.calculate_damage(m, self.get_attack_power() * 2) if self.apply_damage_to_target(m, damage): m.on_hit(self, damage) self.skill1_timer = 0 elif self.stage == 2: # 第二形态还会对最远目标释放一次 - targets = TargetSelector.select_targets( - self, - self.battlefield, - need_in_range=False, - max_targets=1, - reverse=True, - ) + targets = TargetSelector.select_targets(self, self.battlefield, need_in_range=False, max_targets=1, + reverse=True) if len(targets) > 0: for m in self.get_aoe_targets(self.target): - damage = self.calculate_damage( - m, self.get_attack_power() * 2 - ) + damage = self.calculate_damage(m, self.get_attack_power() * 2) if self.apply_damage_to_target(m, damage): m.on_hit(self, damage) for m in self.get_aoe_targets(targets[0]): - damage = self.calculate_damage( - m, self.get_attack_power() * 2 - ) + damage = self.calculate_damage(m, self.get_attack_power() * 2) if self.apply_damage_to_target(m, damage): m.on_hit(self, damage) self.skill1_timer = 0 @@ -2274,9 +2077,7 @@ def increase_skill_cd(self, delta_time): if self.shield_timer > 15: if self.shield > 0: for m in self.get_aoe_targets_skill2(): - damage = self.calculate_damage( - m, self.get_attack_power() * 8 - ) + damage = self.calculate_damage(m, self.get_attack_power() * 8) if self.apply_damage_to_target(m, damage): m.on_hit(self, damage) self.shield = 0 @@ -2289,9 +2090,7 @@ def increase_skill_cd(self, delta_time): if self.shield_timer > 15: if self.shield > 0: for m in self.get_aoe_targets_skill2(): - damage = self.calculate_damage( - m, self.get_attack_power() * 12 - ) + damage = self.calculate_damage(m, self.get_attack_power() * 12) if self.apply_damage_to_target(m, damage): m.on_hit(self, damage) self.shield = 0 @@ -2301,24 +2100,15 @@ def increase_skill_cd(self, delta_time): # 十字aoe判定 def get_aoe_targets(self, target): - aoe_targets = [ - m - for m in self.battlefield.monsters - if m.is_alive - and m.faction != self.faction - and abs(m.position.x - target.position.x) <= 2 - and abs(m.position.y - target.position.y) <= 2 - ] + aoe_targets = [m for m in self.battlefield.monsters + if m.is_alive and m.faction != self.faction + and abs(m.position.x - target.position.x) <= 2 and abs(m.position.y - target.position.y) <= 2] return aoe_targets def get_aoe_targets_skill2(self): - aoe_targets = [ - m - for m in self.battlefield.monsters - if m.is_alive - and m.faction != self.faction - and (m.position - self.position).magnitude < 3 - ] + aoe_targets = [m for m in self.battlefield.monsters + if m.is_alive and m.faction != self.faction + and (m.position - self.position).magnitude < 3] return aoe_targets def take_damage(self, damage, attack_type) -> bool: @@ -2394,17 +2184,16 @@ class MonsterFactory: "雷德": 雷德, "自在": 自在, # "扎罗": 扎罗, + # 添加更多映射... - "炮击组长": 炮击组长, + "炮击组长": 炮击组长 } @classmethod def create_monster(cls, data, faction, position, battlefield): monster_type = data["名字"] if monster_type in cls._monster_classes: - m = cls._monster_classes[monster_type]( - data, faction, position, battlefield - ) + m = cls._monster_classes[monster_type](data, faction, position, battlefield) m.on_spawn() return m else: diff --git a/src/simulation/projectiles.py b/simulator/projectiles.py similarity index 52% rename from src/simulation/projectiles.py rename to simulator/projectiles.py index d31a249..15c0882 100644 --- a/src/simulation/projectiles.py +++ b/simulator/projectiles.py @@ -10,18 +10,11 @@ if TYPE_CHECKING: # 仅用于IDE类型提示,不会真实导入 - from .monsters import Monster + from .monsters import Monster from .battle_field import Battlefield - class Projectile: - def __init__( - self, - max_lifetime, - damage: float, - damageType: DamageType, - source: "Monster", - ): + def __init__(self, max_lifetime, damage : float, damageType : DamageType, source : "Monster"): self.lifetime = 0 self.max_lifetime = max_lifetime self.is_alive = True @@ -34,17 +27,9 @@ def update(self, delta_time, battle_field): """需被子类重写""" raise NotImplementedError - # 组件类型实现 class HomingProjectile(Projectile): - def __init__( - self, - max_lifetime, - damage: float, - damageType: DamageType, - source: "Monster", - target_enemy: "Monster", - ): + def __init__(self, max_lifetime, damage : float, damageType : DamageType, source : "Monster", target_enemy: "Monster"): super().__init__(max_lifetime, damage, damageType, source) self.target = target_enemy # 敌人对象引用 @@ -52,26 +37,18 @@ def update(self, delta_time, battle_field): if not self.target.is_alive: self.is_alive = False return - + self.lifetime += delta_time if self.lifetime >= self.max_lifetime: self.on_timeout(battle_field) self.is_alive = False - + def on_timeout(self, battle_field): """需被子类重写""" raise NotImplementedError - class TimedProjectile(Projectile): - def __init__( - self, - max_lifetime, - damage: float, - damageType: DamageType, - source: "Monster", - target_position, - ): + def __init__(self, max_lifetime, damage : float, damageType : DamageType, source : "Monster", target_position): super().__init__(max_lifetime, damage, damageType, source) self.target_pos = FastVector(target_position.x, target_position.y) @@ -87,12 +64,12 @@ def on_impact(self, battle_field): class ProjectileManager: - def __init__(self, battle_field: "Battlefield"): + def __init__(self, battle_field : 'Battlefield'): self.projectiles = [] self.global_id_counter = 0 self.battle_field = battle_field - def spawn_projectile(self, projectile: Projectile): + def spawn_projectile(self, projectile : Projectile): """使用对象池创建射弹""" self.projectiles.append(projectile) projectile.id = self.global_id_counter @@ -111,114 +88,61 @@ class AOEType(Enum): Grid8 = "八格" Circle = "圆形" - -def get_aoe_targets(source, target_pos, battle_field: "Battlefield"): +def get_aoe_targets(source, target_pos, battle_field: 'Battlefield'): if source.aoe_Type == AOEType.Grid8: - aoe_targets = [ - m - for m in battle_field.alive_monsters - if m.is_alive - and m.faction != source.source.faction - and np.maximum( - abs(m.position.x - target_pos.x), - abs(m.position.y - target_pos.y), - ) - <= 1 - ] + aoe_targets = [m for m in battle_field.alive_monsters + if m.is_alive and m.faction != source.source.faction + and np.maximum(abs(m.position.x - target_pos.x), abs(m.position.y - target_pos.y)) <= 1] elif source.aoe_Type == AOEType.Grid4: - aoe_targets = [ - m - for m in battle_field.alive_monsters - if m.is_alive - and m.faction != source.source.faction - and abs(int(math.floor(m.position.x - target_pos.x + 0.5))) - + abs(int(math.floor(m.position.y - target_pos.y + 0.5))) - <= 1 - ] + aoe_targets = [m for m in battle_field.alive_monsters + if m.is_alive and m.faction != source.source.faction + and abs(int(math.floor(m.position.x - target_pos.x + 0.5))) + abs(int(math.floor(m.position.y - target_pos.y + 0.5))) <= 1] elif source.aoe_Type == AOEType.Circle: - aoe_targets = [ - m - for m in battle_field.query_monster(target_pos, source.radius) - if m.is_alive and m.faction != source.source.faction - ] + aoe_targets = [m for m in battle_field.query_monster(target_pos, source.radius) + if m.is_alive and m.faction != source.source.faction] return aoe_targets - class AOE炸弹(TimedProjectile): - def __init__( - self, - max_lifetime, - damage: float, - damageType: DamageType, - source: "Monster", - target_position, - name: str, - aoeType: AOEType, - radius=1, - ): - super().__init__( - max_lifetime, damage, damageType, source, target_position - ) + def __init__(self, max_lifetime, damage : float, damageType : DamageType, source : "Monster", target_position, name : str, aoeType : AOEType, radius=1): + super().__init__(max_lifetime, damage, damageType, source, target_position) self.name = name self.aoe_Type = aoeType self.radius = radius - def apply_damage_to_target(self, m: "Monster", damage): - debug_print( - f"{self.source.name}{self.source.id} 的{self.name}对 {m.name}{m.id} 造成{damage}点{self.damage_type}伤害" - ) + def apply_damage_to_target(self, m : 'Monster', damage): + debug_print(f"{self.source.name}{self.source.id} 的{self.name}对 {m.name}{m.id} 造成{damage}点{self.damage_type}伤害") if m.take_damage(damage, self.damage_type): return True - debug_print( - f"{self.source.name}{self.source.id} 的{self.name}没有对 {m.name}{m.id}造成伤害" - ) + debug_print(f"{self.source.name}{self.source.id} 的{self.name}没有对 {m.name}{m.id}造成伤害") return False - def on_impact(self, battle_field: "Battlefield"): + def on_impact(self, battle_field:'Battlefield'): aoe_targets = get_aoe_targets(self, self.target_pos, battle_field) for m in aoe_targets: - damage = calculate_normal_dmg( - m.phy_def, m.magic_resist, self.damage, self.damage_type - ) + damage = calculate_normal_dmg(m.phy_def, m.magic_resist, self.damage, self.damage_type) if self.apply_damage_to_target(m, damage): m.on_hit(self.source, damage) - + class AOE炸弹锁定(HomingProjectile): - def __init__( - self, - max_lifetime, - damage: float, - damageType: DamageType, - source: "Monster", - target: "Monster", - name: str, - aoeType: AOEType, - radius=1, - ): + def __init__(self, max_lifetime, damage : float, damageType : DamageType, source : "Monster", target : 'Monster', name : str, aoeType : AOEType, radius=1): super().__init__(max_lifetime, damage, damageType, source, target) self.name = name self.aoe_Type = aoeType self.radius = radius - def apply_damage_to_target(self, m: "Monster", damage): - debug_print( - f"{self.source.name}{self.source.id} 的{self.name}对 {m.name}{m.id} 造成{damage}点{self.damage_type}伤害" - ) + def apply_damage_to_target(self, m : 'Monster', damage): + debug_print(f"{self.source.name}{self.source.id} 的{self.name}对 {m.name}{m.id} 造成{damage}点{self.damage_type}伤害") if m.take_damage(damage, self.damage_type): return True - debug_print( - f"{self.source.name}{self.source.id} 的{self.name}没有对 {m.name}{m.id}造成伤害" - ) + debug_print(f"{self.source.name}{self.source.id} 的{self.name}没有对 {m.name}{m.id}造成伤害") return False - def on_timeout(self, battle_field: "Battlefield"): + def on_timeout(self, battle_field:'Battlefield'): # if not self.target.can_be_target(): # return aoe_targets = get_aoe_targets(self, self.target.position, battle_field) for m in aoe_targets: - damage = calculate_normal_dmg( - m.phy_def, m.magic_resist, self.damage, self.damage_type - ) + damage = calculate_normal_dmg(m.phy_def, m.magic_resist, self.damage, self.damage_type) if self.apply_damage_to_target(m, damage): m.on_hit(self.source, damage) diff --git a/simulator/scene.json b/simulator/scene.json new file mode 100644 index 0000000..39a51eb --- /dev/null +++ b/simulator/scene.json @@ -0,0 +1,58 @@ +{ + "left": + [ + { "name": "酸液源石虫·α", "count": 0 }, + { "name": "高能源石虫", "count": 0 }, + { "name": "阿咬", "count": 0 }, + { "name": "狂暴的猎狗pro", "count": 0 }, + { "name": "提亚卡乌好战者", "count": 0 }, + { "name": "污染躯壳", "count": 0 }, + { "name": "大盾哥", "count": 0 }, + { "name": "宿主流浪者", "count": 0 }, + { "name": "光剑", "count": 4 }, + { "name": "泥岩巨像", "count": 0 }, + { "name": "呼啸骑士团学徒", "count": 0 }, + { "name": "萨卡兹大剑手", "count": 0 }, + { "name": "狂暴宿主组长", "count": 0 }, + { "name": "海螺", "count": 0 }, + { "name": "拳手囚犯", "count": 0 }, + { "name": "高塔术师", "count": 0 }, + { "name": "冰原术师", "count": 0 }, + { "name": "矿脉守卫", "count": 0 }, + { "name": "“庞贝”", "count": 0 }, + { "name": "绵羊", "count": 0 }, + { "name": "食腐狗", "count": 0 }, + { "name": "温顺的武装驮兽", "count": 3 }, + { "name": "鼠鼠", "count": 4 }, + { "name": "“投石机”", "count": 0 }, + { "name": "船长", "count": 0 } + ], + "right": + [ + { "name": "酸液源石虫·α", "count": 0 }, + { "name": "高能源石虫", "count": 0 }, + { "name": "阿咬", "count": 0 }, + { "name": "狂暴的猎狗pro", "count": 0 }, + { "name": "提亚卡乌好战者", "count": 0 }, + { "name": "污染躯壳", "count": 0 }, + { "name": "大盾哥", "count": 0 }, + { "name": "宿主流浪者", "count": 0 }, + { "name": "光剑", "count": 0 }, + { "name": "泥岩巨像", "count": 0 }, + { "name": "呼啸骑士团学徒", "count": 0 }, + { "name": "萨卡兹大剑手", "count": 0 }, + { "name": "狂暴宿主组长", "count": 0 }, + { "name": "海螺", "count": 0 }, + { "name": "拳手囚犯", "count": 11 }, + { "name": "高塔术师", "count": 0 }, + { "name": "冰原术师", "count": 0 }, + { "name": "矿脉守卫", "count": 0 }, + { "name": "“庞贝”", "count": 3 }, + { "name": "绵羊", "count": 9 }, + { "name": "食腐狗", "count": 0 }, + { "name": "温顺的武装驮兽", "count": 0 }, + { "name": "鼠鼠", "count": 0 }, + { "name": "“投石机”", "count": 0 }, + { "name": "船长", "count": 0 } + ] +} \ No newline at end of file diff --git a/src/simulation/simulate.py b/simulator/simulate.py similarity index 60% rename from src/simulation/simulate.py rename to simulator/simulate.py index fd38d9c..8b3a58b 100644 --- a/src/simulation/simulate.py +++ b/simulator/simulate.py @@ -1,4 +1,9 @@ import json +import math +import random +import time +from enum import Enum +import numpy as np import pandas as pd from tqdm import tqdm @@ -14,82 +19,66 @@ def process_battle_data(csv_path): """ # 读取CSV文件(假设没有表头) df = pd.read_csv(csv_path, header=1) - + # 数据结构化处理 battle_records = [] - + for _, row in df.iterrows(): # 分解左右阵营数据 - left_data = row[0:56] # 1-56列 (0-based索引0-55) + left_data = row[0:56] # 1-56列 (0-based索引0-55) right_data = row[56:112] # 56-112列 (0-based索引56-111) - winner = row[112] # 69列 (0-based索引112) - + winner = row[112] # 69列 (0-based索引112) + # 构建阵营字典(ID从1开始) - left_army = { - MONSTER_MAPPING[i]: int(count) - for i, count in enumerate(left_data) - if count > 0 - } - right_army = { - MONSTER_MAPPING[i]: int(count) - for i, count in enumerate(right_data) - if count > 0 - } - + left_army = {MONSTER_MAPPING[i]: int(count) for i, count in enumerate(left_data) if count > 0} + right_army = {MONSTER_MAPPING[i]: int(count) for i, count in enumerate(right_data) if count > 0} + # 构建记录格式 battle_record = { "left": left_army, "right": right_army, - "result": "left" if winner == "L" else "right", + "result": "left" if winner == 'L' else "right" } - + battle_records.append(battle_record) - + return battle_records - def main(): """主函数""" # 加载怪物数据 - with open("arknight/monsters.json", encoding="utf-8") as f: + with open("arknight/monsters.json", encoding='utf-8') as f: monster_data = json.load(f)["monsters"] - + # with open("scene.json", encoding='utf-8') as f: # scene_config = json.load(f) # 使用示例,直接修改这里的csv文件就可以跑模拟 battle_data = process_battle_data("arknight/56fin2_66k.csv") + win = 0 matches = 0 for scene_config in tqdm(battle_data): if VISUALIZATION_MODE: - scene_config = { - "left": {"宿主流浪者": 7, "污染躯壳": 14, "凋零萨卡兹": 5}, - "right": {"大喷蛛": 4, "杰斯顿·威廉姆斯": 1, "衣架": 10}, - "result": "right", - } + scene_config = {"left": {"宿主流浪者": 7, "污染躯壳": 14, "凋零萨卡兹": 5}, "right": {"大喷蛛": 4, "杰斯顿·威廉姆斯": 1, "衣架": 10}, "result": "right"} + - # { "left": { "护盾哥": 5, "污染躯壳": 11, "船长": 5 }, "right": { "炮击组长": 4, "沸血骑士团精锐": 4, "雪境精锐": 4}, "result": "left" } + #{ "left": { "护盾哥": 5, "污染躯壳": 11, "船长": 5 }, "right": { "炮击组长": 4, "沸血骑士团精锐": 4, "雪境精锐": 4}, "result": "left" } # 用户配置 left_army = scene_config["left"] right_army = scene_config["right"] - + # 初始化战场 leftWins = 0 for i in range(3): battlefield = Battlefield(monster_data) - if not battlefield.setup_battle( - left_army, right_army, monster_data - ): + if not battlefield.setup_battle(left_army, right_army, monster_data): continue - + # 开始战斗 - if ( - battlefield.run_battle(visualize=VISUALIZATION_MODE) - == Faction.LEFT - ): + if battlefield.run_battle(visualize=VISUALIZATION_MODE) == Faction.LEFT: leftWins += 1 if leftWins >= 2: break @@ -97,15 +86,14 @@ def main(): break left_win = leftWins >= 2 - - if (left_win and scene_config["result"] == "left") or ( - not left_win and scene_config["result"] == "right" - ): + + if (left_win and scene_config["result"] == "left") or (not left_win and scene_config["result"] == "right"): win += 1 else: - with open("errors.json", encoding="utf-8", mode="+a") as f: + with open("errors.json", encoding='utf-8', mode='+a') as f: f.write(json.dumps(scene_config, ensure_ascii=False)) - f.write("\n") + f.write('\n') + matches += 1 print(f"当前胜率:{win} / {matches}") diff --git a/simulator/stats.py b/simulator/stats.py new file mode 100644 index 0000000..95becc6 --- /dev/null +++ b/simulator/stats.py @@ -0,0 +1,172 @@ +import json +from collections import defaultdict +import numpy as np +import pandas as pd +from scipy.stats import fisher_exact +import matplotlib.pyplot as plt + +# 配置中文字体 +plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] +plt.rcParams['axes.unicode_minus'] = False + + +def calculate_significance(row): + """计算修正后的统计显著性""" + # 关键参数 + error_total = row['under_estimate'] + row['over_estimate'] # 错误样本总次数 + correct_total = row['total'] - error_total # 正确样本总次数 + + # 过滤无效数据 + if error_total == 0 or correct_total == 0: + return np.nan + + # 低估检验(单侧) + contingency_under = [ + [row['under_estimate'], row['over_estimate']], + [0, correct_total] + ] + _, under_p = fisher_exact(contingency_under, alternative='greater') + + # 高估检验(单侧) + contingency_over = [ + [row['over_estimate'], row['under_estimate']], + [0, correct_total] + ] + _, over_p = fisher_exact(contingency_over, alternative='greater') + + return under_p + over_p + +def analyze_monster_balance(data_path): + # 初始化统计容器 + stats = defaultdict(lambda: { + 'total': 0, # 总出现次数 + 'error': 0, # 错误预测中出现次数 + 'under_estimate': 0, # 低估计数(实际应胜但预测失败) + 'over_estimate': 0 # 高估计数(实际应败但预测成功) + }) + + # 数据加载与分析 + with open(data_path, encoding='utf-8') as f: + for line in f: + record = json.loads(line.strip()) + actual = record['result'] + pred = record['pred'] + + for side in ["left", "right"]: + for monster, count in record[side].items(): + # 基础统计 + stats[monster]['total'] += 1 + + # 仅统计预测错误的情况 + if pred != actual: + stats[monster]['error'] += 1 + + # 判断估计方向 + if (side == actual): + stats[monster]['under_estimate'] += 1 + elif (side != actual): + stats[monster]['over_estimate'] += 1 + + # 构建分析数据框 + df = pd.DataFrame.from_dict(stats, orient='index') + df = df[df['total'] > 0] # 过滤无效数据 + + # 计算统计指标 + df['error_rate'] = df['error'] / df['total'] + df['bias_score'] = (df['under_estimate'] - df['over_estimate']) / df['total'] + df['abs_bias'] = abs(df['bias_score']) + + # # Fisher精确检验 + # def apply_fisher(row): + # contingency = [ + # [row['under_estimate'], row['over_estimate']], + # [row['total'] - row['under_estimate'], + # row['total'] - row['over_estimate']] + # ] + # _, p_value = fisher_exact(contingency) + # return p_value + + df['p_value'] = df.apply(calculate_significance, axis=1) + + # 筛选显著结果 (p<0.04 且总出现次数>1) + valid = df[(df['p_value'] < 0.04) & (df['total'] >= 1)] + + # 生成可视化 + plot_monster_bias(valid) + + return valid.sort_values('abs_bias', ascending=False) + +def plot_monster_bias(df): + plt.figure(figsize=(12, 8)) + + # 设置颜色映射 + colors = np.where(df['bias_score'] > 0, + '#4C72B0', # 蓝色表示低估 + '#DD8452') # 橙色表示高估 + + # 绘制条形图 + bars = plt.barh(df.index, df['bias_score'], color=colors) + + # 添加统计标注 + for bar, (_, row) in zip(bars, df.iterrows()): + plt.text(bar.get_width() + 0.02, + bar.get_y() + bar.get_height()/2, + f"p={row['p_value']:.3f}\nN={row['total']}", + va='center') + + # 图表装饰 + plt.axvline(0, color='gray', linestyle='--') + plt.title('怪物数值平衡性分析', fontsize=14) + plt.xlabel('偏差分数(正值表示低估,负值表示高估)') + plt.ylabel('怪物名称') + plt.xlim(-1.1, 1.1) + plt.grid(axis='x', alpha=0.3) + plt.tight_layout() + plt.savefig('monster_balance.png', dpi=300) + plt.close() + +# 执行分析 +if __name__ == "__main__": + result_df = analyze_monster_balance("../errors.json") + + # 打印格式化结果 + print("="*60) + print(f"{'怪物名称':<10}\t{'偏差方向':<8}\t{'偏差分数':<8}\t{'p值':<10}\t{'样本量'}") + print("-"*60) + for name, row in result_df.iterrows(): + direction = "低估" if row['bias_score'] > 0 else "高估" + print(f"{name:<10}\t{direction:<8}\t{row['bias_score']:.2f}{'*' if row['p_value']<0.01 else '':<4}" + f"\t{row['p_value']:.3f}\t{'':<6}\t{row['total']}") + + plot_monster_bias(result_df) + +with open("../errors.json", encoding='utf-8') as f: + data = f.read() + +counter = defaultdict(int) +power_counter = defaultdict(int) +err_counter = defaultdict(int) + +for line in data.strip().split('\n'): + record = json.loads(line) + result = record['result'] + pred = record['pred'] + for side in ["left", "right"]: + for monster, count in record[side].items(): + counter[monster] += 1 + if pred != result: + if side == result: + # 应该获胜却没有获胜,有低估的可能性 + power_counter[monster] += 1 + else: + # 不该获胜的获胜了,有高估的可能性 + power_counter[monster] -= 1 + err_counter[monster] += 1 + +sorted_monsters = sorted(err_counter.items(), key=lambda x: (-x[1] / counter[x[0]], x[0])) + +for monster, count in sorted_monsters: + str = "低估" if power_counter[monster] > 0 else "高估" + total = counter[monster] + err_total = count + print(f"{monster}: {err_total}/{total} = {err_total/total} 估计值:【{str}】{-power_counter[monster] / total * 100}") \ No newline at end of file diff --git a/src/simulation/utils.py b/simulator/utils.py similarity index 80% rename from src/simulation/utils.py rename to simulator/utils.py index d6d2ec6..d078175 100644 --- a/src/simulation/utils.py +++ b/simulator/utils.py @@ -1,9 +1,11 @@ + + from collections import defaultdict from dataclasses import dataclass, field from enum import Enum import logging import math -import csv # 添加csv模块导入 +import csv # 添加csv模块导入 import numpy as np @@ -19,17 +21,14 @@ VISUALIZATION_MODE = True - def debug_print(msg): if VISUALIZATION_MODE: print(msg) - class Faction(Enum): LEFT = 0 RIGHT = 1 - class DamageType(Enum): PHYSICAL = "物理" MAGIC = "法术" @@ -38,7 +37,6 @@ class DamageType(Enum): def __str__(self): return self.value # 直接返回值字符串 - class BuffType(Enum): CHILL = 0 FROZEN = 1 @@ -47,17 +45,15 @@ class BuffType(Enum): CORRUPT = 4 SPEEDUP = 5 DIZZY = 6 - POWER_STONE = 7 # 源石地板 - WINE = 8 # 酒桶的效果 - INVINCIBLE2 = 9 # 转阶段无敌,不会被设为目标 - + POWER_STONE = 7 # 源石地板 + WINE = 8 # 酒桶的效果 + INVINCIBLE2 = 9 # 转阶段无敌,不会被设为目标 class ElementType(Enum): NECRO_LEFT = "凋亡左" # 凋亡元素(原凋亡损伤) NECRO_RIGHT = "凋亡右" # 凋亡元素(原凋亡损伤) FIRE = "灼燃" - def lerp(a, b, x): return a + (b - a) * x @@ -71,10 +67,9 @@ class BuffEffect: data: dict = field(default_factory=dict) -VIRTUAL_TIME_STEP = 30 # 30帧相当于一秒 +VIRTUAL_TIME_STEP = 30 # 30帧相当于一秒 VIRTUAL_TIME_DELTA = 1.0 / VIRTUAL_TIME_STEP - def calculate_normal_dmg(defense, magic_resist, dmg, damageType: DamageType): """计算伤害值""" if damageType == DamageType.PHYSICAL: @@ -83,30 +78,30 @@ def calculate_normal_dmg(defense, magic_resist, dmg, damageType: DamageType): return np.maximum(dmg * 0.05, dmg * (1.0 - magic_resist / 100)) elif damageType == DamageType.TRUE: return dmg - + class SpatialHash: - def __init__(self, battle_field: "Battlefield", cell_size=0.5): + def __init__(self, battle_field : 'Battlefield', cell_size=0.5): self.cell_size = cell_size self.grid = defaultdict(set) # 使用集合避免重复 self.battle_field = battle_field # 记录战场,用来索引敌人信息 self.position_map = {} # 记录每个对象的老位置键 - def _pos_to_key(self, position: FastVector) -> tuple: + def _pos_to_key(self, position : FastVector) -> tuple: """将坐标转换为网格键""" return ( int(math.floor(position.x / self.cell_size)), - int(math.floor(position.y / self.cell_size)), + int(math.floor(position.y / self.cell_size)) ) - def insert(self, position: FastVector, id): + def insert(self, position : FastVector, id): """插入或更新对象位置""" new_key = self._pos_to_key(position) # 如果位置未变化,直接返回 if id in self.position_map and self.position_map[id] == new_key: return - + # 移除旧位置的记录 if id in self.position_map: old_key = self.position_map[id] @@ -122,18 +117,18 @@ def query_neighbors(self, position: FastVector, radius: float) -> set: """查询指定半径内的邻居""" center_x, center_y = (position.x, position.y) neighbors = set() - + # 生成需要检测的网格范围 min_i = int((center_x - radius) / self.cell_size) max_i = int((center_x + radius) / self.cell_size) min_j = int((center_y - radius) / self.cell_size) max_j = int((center_y + radius) / self.cell_size) - + # 遍历所有可能包含邻居的网格 for i in range(min_i, max_i + 1): for j in range(min_j, max_j + 1): neighbors.update(self.grid.get((i, j), set())) - + return neighbors def batch_update(self, updates: dict): @@ -141,33 +136,27 @@ def batch_update(self, updates: dict): for obj_id, pos in updates.items(): self.insert(obj_id, pos) - -def load_monster_mapping_from_csv(file_path="src/resources/data/monster.csv"): +def load_monster_mapping_from_csv(file_path='monster.csv'): """从CSV文件加载怪物ID和原始名称的映射""" mapping = {} try: - with open(file_path, mode="r", encoding="utf-8-sig") as csvfile: + with open(file_path, mode='r', encoding='utf-8-sig') as csvfile: reader = csv.DictReader(csvfile) for row in reader: try: - monster_id = int(row["id"]) - 1 # 转为0-based索引 - original_name = row["原始名称"] + monster_id = int(row['id']) - 1 # 转为0-based索引 + original_name = row['原始名称'] mapping[monster_id] = original_name except ValueError: - print( - f"Skipping row due to invalid ID or missing '原始名称': {row}" - ) + print(f"Skipping row due to invalid ID or missing '原始名称': {row}") except FileNotFoundError: print(f"Error: {file_path} not found. Using empty monster mapping.") except Exception as e: logger.exception(f"Error loading monster mapping from CSV: {e}") return mapping - # ID与怪物名称映射表 -MONSTER_MAPPING = load_monster_mapping_from_csv( - "src/resources/data/monster_greenvine.csv" -) +MONSTER_MAPPING = load_monster_mapping_from_csv('monster_greenvine.csv') # 创建反向映射字典(名字到ID) -REVERSE_MONSTER_MAPPING = {name: id for id, name in MONSTER_MAPPING.items()} +REVERSE_MONSTER_MAPPING = {name: id for id, name in MONSTER_MAPPING.items()} \ No newline at end of file diff --git a/src/simulation/vector2d.py b/simulator/vector2d.py similarity index 85% rename from src/simulation/vector2d.py rename to simulator/vector2d.py index 4841d93..a55ee2b 100644 --- a/src/simulation/vector2d.py +++ b/simulator/vector2d.py @@ -1,6 +1,5 @@ import math from typing import Tuple - # import numpy as np # from numba.experimental import jitclass # from numba import float64 @@ -20,103 +19,101 @@ # # 基础运算 # def __add__(self, other: 'Vector2D') -> 'Vector2D': # return Vector2D(self.x + other.x, self.y + other.y) - + # def __sub__(self, other: 'Vector2D') -> 'Vector2D': # return Vector2D(self.x - other.x, self.y - other.y) - + # def __mul__(self, scalar: float) -> 'Vector2D': # return Vector2D(self.x * scalar, self.y * scalar) - + # # 高性能运算方法 # @property # def magnitude(self) -> float: # """模长计算优化(SIMD加速)""" # return math.hypot(self.x, self.y) # 使用hypot避免溢出 - + # def normalized(self) -> 'Vector2D': # """单位向量(零除保护)""" # mag = self.magnitude # return Vector2D(self.x/mag, self.y/mag) if mag != 0 else Vector2D(0, 0) - + # def dot(self, other: 'Vector2D') -> float: # """点积(寄存器优化)""" # return self.x*other.x + self.y*other.y - + # def rotate(self, radians: float) -> 'Vector2D': # """旋转优化(预计算sin/cos)""" # c = math.cos(radians) # s = math.sin(radians) # return Vector2D(self.x*c - self.y*s, self.x*s + self.y*c) - # 纯Python优化方案(兼容性更好) class FastVector: - __slots__ = ("x", "y") # 减少内存占用约40% - + __slots__ = ('x', 'y') # 减少内存占用约40% + def __init__(self, x: float, y: float): self.x = x self.y = y - - def __sub__(self, other: "FastVector") -> "FastVector": + + def __sub__(self, other: 'FastVector') -> 'FastVector': return self.__class__(self.x - other.x, self.y - other.y) - def __add__(self, other: "FastVector") -> "FastVector": + def __add__(self, other: 'FastVector') -> 'FastVector': return self.__class__(self.x + other.x, self.y + other.y) - - def __truediv__(self, other: float) -> "FastVector": + + def __truediv__(self, other: float) -> 'FastVector': return self.__class__(self.x / other, self.y / other) - - def __mul__(self, other: float) -> "FastVector": + + def __mul__(self, other: float) -> 'FastVector': return self.__class__(self.x * other, self.y * other) - - def __iadd__(self, other: "FastVector") -> "FastVector": + + def __iadd__(self, other: 'FastVector') -> 'FastVector': """就地加法优化(减少对象创建)""" self.x += other.x self.y += other.y return self - + @property def magnitude_sq(self) -> float: """平方模长(避免开平方)""" return self.x**2 + self.y**2 - + @property def magnitude(self) -> float: """模长""" return math.sqrt(self.x**2 + self.y**2) - - def distance_to(self, other: "FastVector") -> float: + + def distance_to(self, other: 'FastVector') -> float: """快速距离计算""" dx = self.x - other.x dy = self.y - other.y return math.hypot(dx, dy) - + def as_tuple(self) -> Tuple[float, float]: """缓存友好表示""" return (self.x, self.y) - def normalize(self) -> "FastVector": + def normalize(self) -> 'FastVector': d = self.magnitude if d != 0: self.x /= d self.y /= d return self - # # 性能对比测试 # if __name__ == '__main__': # from timeit import timeit - + # # 测试用例 # v1 = Vector2D(3.0, 4.0) # v2 = Vector2D(2.0, 1.0) - + # # Numba版本性能 # print("Numba Add:", timeit(lambda: v1 + v2, number=1_000_000)) # print("Numba Mag:", timeit(lambda: v1.magnitude, number=1_000_000)) - + # # 纯Python版本性能 # fv1 = FastVector(3.0, 4.0) # fv2 = FastVector(2.0, 1.0) # print("Python Add:", timeit(lambda: fv1 + fv2, number=1_000_000)) -# print("Python Mag:", timeit(lambda: fv1.magnitude_sq, number=1_000_000)) +# print("Python Mag:", timeit(lambda: fv1.magnitude_sq, number=1_000_000)) \ No newline at end of file diff --git a/src/simulation/zone.py b/simulator/zone.py similarity index 70% rename from src/simulation/zone.py rename to simulator/zone.py index 4522636..4bc5569 100644 --- a/src/simulation/zone.py +++ b/simulator/zone.py @@ -1,21 +1,23 @@ +from typing import List, Dict, Set from dataclasses import dataclass +import math +import time + +import numpy as np from .vector2d import FastVector from .utils import VIRTUAL_TIME_DELTA, BuffEffect, BuffType - class ZoneType: - POISON = 0 # 毒圈 - WINE = 1 # 酒桶区域 - + POISON = 0 #毒圈 + WINE = 1 #酒桶区域 @dataclass class ZoneEffect: type: str duration: float - class EffectZone: def __init__(self, zone_type: str, position, battle_field): self.zone_type = zone_type @@ -43,46 +45,37 @@ def apply_effect(self, target): raise NotImplementedError def remove_effect(self, target): - """移除区域效果""" + """移除区域效果""" raise NotImplementedError - class PoisonZone(EffectZone): def __init__(self, battle_field): super().__init__(ZoneType.POISON, FastVector(0, 0), battle_field) def apply_effect(self, target): # 添加或更新持续伤害效果 - target.status_system.apply( - BuffEffect( - type=BuffType.POWER_STONE, - duration=VIRTUAL_TIME_DELTA * 2, - source=self, - ) - ) + target.status_system.apply(BuffEffect( + type=BuffType.POWER_STONE, + duration=VIRTUAL_TIME_DELTA * 2, + source=self + )) def contains(self, target) -> bool: """判断点是否在区域内""" if self.battle_field.danger_zone_size() > 0: size = self.battle_field.danger_zone_size() - if ( - target.position.x < size + 1 - or target.position.x > self.battle_field.map_size[0] - size - 1 - ) or ( - target.position.y < size - or target.position.y > self.battle_field.map_size[1] - size - ): + if (target.position.x < size + 1 or target.position.x > self.battle_field.map_size[0] - size - 1)\ + or (target.position.y < size or target.position.y > self.battle_field.map_size[1] - size): return True return False - - + class WineZone(EffectZone): def __init__(self, position, battle_field, duration, faction): super().__init__(ZoneType.WINE, position, battle_field) self.duration = duration self.radius = 2 self.faction = faction - + def should_clear(self, delta_time) -> bool: """场地效果清除逻辑""" return self.duration <= 0 @@ -93,16 +86,12 @@ def update(self, delta_time): def apply_effect(self, target): # 添加或更新持续伤害效果 - target.status_system.apply( - BuffEffect( - type=BuffType.WINE, - duration=VIRTUAL_TIME_DELTA * 2, - source=self, - ) - ) + target.status_system.apply(BuffEffect( + type=BuffType.WINE, + duration=VIRTUAL_TIME_DELTA * 2, + source=self + )) def contains(self, target) -> bool: """判断点是否在区域内""" - return ( - target.position - self.position - ).magnitude <= self.radius and target.faction == self.faction + return (target.position - self.position).magnitude <= self.radius and target.faction == self.faction \ No newline at end of file diff --git a/specialmonster.py b/specialmonster.py new file mode 100644 index 0000000..708cd64 --- /dev/null +++ b/specialmonster.py @@ -0,0 +1,37 @@ +class SpecialMonsterHandler: + """ + 可按照格式自行添加特殊怪物的留言信息: + 格式: + 怪物ID: { + 'name': '怪物名称', # 可留空 + 'win_message': '胜利时显示的消息', # 可留空 + 'lose_message': '失败时显示的消息', # 可留空 + } + """ + def __init__(self): + self.special_monsters = { + 1: { + 'name': '狗神', + 'win_message': "全军出击,我咬死你!", + 'lose_message': "牙崩了牙崩了" + }, + } + + def check_special_monsters(self, left_monsters, right_monsters, winner): + messages = [] + + for monster_id, config in self.special_monsters.items(): + left_has = left_monsters[str(monster_id)].text().isdigit() and int(left_monsters[str(monster_id)].text()) > 0 + right_has = right_monsters[str(monster_id)].text().isdigit() and int(right_monsters[str(monster_id)].text()) > 0 + + if left_has or right_has: + if winner == "左方" and left_has and config['win_message']: + messages.append(config['win_message']) + elif winner == "右方" and right_has and config['win_message']: + messages.append(config['win_message']) + elif winner == "右方" and left_has and config['lose_message']: + messages.append(config['lose_message']) + elif winner == "左方" and right_has and config['lose_message']: + messages.append(config['lose_message']) + + return "\n".join(messages) \ No newline at end of file diff --git a/src/analysis/winning_rate_statistics.py b/src/analysis/winning_rate_statistics.py deleted file mode 100644 index 1daa56c..0000000 --- a/src/analysis/winning_rate_statistics.py +++ /dev/null @@ -1,1131 +0,0 @@ -import pandas as pd -from math import sqrt -from collections import defaultdict -from src.core.config import MONSTER_COUNT, FIELD_FEATURE_COUNT, MONSTER_DATA -from src.core.paths import image_path, PROJECT_ROOT - -FIELD_FEATURE_COUNT = 0 - - -def load_data(): - """加载数据""" - df = pd.read_csv( - PROJECT_ROOT / "data" / "arknights.csv", header=None, low_memory=False - ) - # 设置列名 - monster_cols_left = [f"L{i+1}" for i in range(MONSTER_COUNT)] - field_cols_left = [f"FL{i+1}" for i in range(FIELD_FEATURE_COUNT)] - monster_cols_right = [f"R{i+1}" for i in range(MONSTER_COUNT)] - field_cols_right = [f"FR{i+1}" for i in range(FIELD_FEATURE_COUNT)] - - df.columns = ( - monster_cols_left - + field_cols_left - + monster_cols_right - + field_cols_right - + ["Result", "ImgPath"] - ) - return df - - -def get_monster_name(monster_id): - """根据怪物ID获取怪物名称""" - if monster_id in MONSTER_DATA.index: - return MONSTER_DATA.loc[monster_id]["名称"] - return f"怪物{monster_id}" - - -def get_monster_original_name(monster_id): - """根据怪物ID获取怪物原始名称(用于匹配图片)""" - if monster_id in MONSTER_DATA.index: - return MONSTER_DATA.loc[monster_id]["原始名称"] - return f"怪物{monster_id}" - - -def monster_image_uri(monster_name): - path = image_path(monster_name) - if not path.exists(): - path = image_path("empty") - return path.resolve().as_uri() - - -def monster_img_tag(monster_name, size): - uri = monster_image_uri(monster_name) - empty_uri = monster_image_uri("empty") - return ( - f'' - ) - - -def calculate_all_monster_win_rates(df): - """计算所有怪物的胜率""" - monster_stats = {} - total_matches = len(df) - - for i in range(1, MONSTER_COUNT + 1): - try: - # 转换数据类型并过滤 - df[f"L{i}"] = pd.to_numeric(df[f"L{i}"], errors="coerce").fillna(0) - df[f"R{i}"] = pd.to_numeric(df[f"R{i}"], errors="coerce").fillna(0) - - # 左方统计 - left_games = df[df[f"L{i}"] != 0] - left_wins = len(left_games[left_games["Result"] == "L"]) - left_total = len(left_games) - - # 右方统计 - right_games = df[df[f"R{i}"] != 0] - right_wins = len(right_games[right_games["Result"] == "R"]) - right_total = len(right_games) - except Exception as e: - print(f"处理怪物{i}时出错: {e}") - continue - - # 合并统计 - total_games = left_total + right_total - total_wins = left_wins + right_wins - - if total_games > 0: - monster_name = get_monster_name(i) - win_rate = total_wins / total_games - participation_rate = ( - total_games / total_matches if total_matches > 0 else 0 - ) - monster_stats[monster_name] = { - "怪物ID": i, - "胜场": total_wins, - "总场数": total_games, - "胜率": win_rate, - "参战率": participation_rate, - } - - return pd.DataFrame(monster_stats).T.sort_values("胜率", ascending=False) - - -def analyze_monster_combinations(df): - """分析怪物配合效果""" - # 初始化数据结构 - single_stats = defaultdict(lambda: {"appearances": 0, "wins": 0}) - pair_stats = defaultdict(lambda: {"co_occurrences": 0, "co_wins": 0}) - - for _, record in df.iterrows(): - victory_side = record["Result"] - - # 获取左右两方的怪物 - left_monsters = [] - right_monsters = [] - - for i in range(1, MONSTER_COUNT + 1): - try: - left_val = ( - float(record[f"L{i}"]) if pd.notna(record[f"L{i}"]) else 0 - ) - right_val = ( - float(record[f"R{i}"]) if pd.notna(record[f"R{i}"]) else 0 - ) - - if left_val > 0: - left_monsters.append(i) - if right_val > 0: - right_monsters.append(i) - except (ValueError, TypeError): - continue - - # 确定胜利队伍和失败队伍 - if victory_side == "L": - win_team, lose_team = left_monsters, right_monsters - else: - win_team, lose_team = right_monsters, left_monsters - - # 更新单怪统计(胜利方) - for monster in win_team: - single_stats[monster]["appearances"] += 1 - single_stats[monster]["wins"] += 1 - - # 更新单怪统计(失败方) - for monster in lose_team: - single_stats[monster]["appearances"] += 1 - - # 更新双怪组合统计(胜利方) - for i in range(len(win_team)): - for j in range(i + 1, len(win_team)): - x, y = sorted((win_team[i], win_team[j])) - pair_stats[(x, y)]["co_occurrences"] += 1 - pair_stats[(x, y)]["co_wins"] += 1 - - # 更新双怪组合统计(失败方) - for i in range(len(lose_team)): - for j in range(i + 1, len(lose_team)): - x, y = sorted((lose_team[i], lose_team[j])) - pair_stats[(x, y)]["co_occurrences"] += 1 - - # 计算最佳配合 - results = [] - total_battles = len(df) - - for (x, y), stats in pair_stats.items(): - if stats["co_occurrences"] < 10: # 过滤低频组合 - continue - - # 组合胜率 - xy_win_rate = stats["co_wins"] / stats["co_occurrences"] - - # 单怪胜率 - if ( - single_stats[x]["appearances"] > 0 - and single_stats[y]["appearances"] > 0 - ): - x_win_rate = ( - single_stats[x]["wins"] / single_stats[x]["appearances"] - ) - y_win_rate = ( - single_stats[y]["wins"] / single_stats[y]["appearances"] - ) - - # 提升度 - 简化计算,不使用卡方检验 - expected_win_rate = sqrt(x_win_rate * y_win_rate) - lift = ( - xy_win_rate / expected_win_rate if expected_win_rate > 0 else 0 - ) - - if ( - lift > 1.1 - and xy_win_rate > max(x_win_rate, y_win_rate) - and stats["co_occurrences"] >= 20 - ): - x_name = get_monster_name(x) - y_name = get_monster_name(y) - results.append( - { - "组合": f"{x_name}+{y_name}", - "怪物1": x_name, - "怪物2": y_name, - "ID1": x, - "ID2": y, - "提升度": lift, - "组合胜率": xy_win_rate, - "出场次数": stats["co_occurrences"], - "获胜次数": stats["co_wins"], - } - ) - - # 按提升度排序 - results.sort(key=lambda x: -x["提升度"]) - return pd.DataFrame(results) - - -def find_countered_monsters(df): - """寻找被克制的怪物前五个""" - counter_stats = defaultdict(lambda: {"total_matchups": 0, "losses": 0}) - - for _, record in df.iterrows(): - victory_side = record["Result"] - - # 获取左右两方的怪物 - left_monsters = [] - right_monsters = [] - - for i in range(1, MONSTER_COUNT + 1): - try: - left_val = ( - float(record[f"L{i}"]) if pd.notna(record[f"L{i}"]) else 0 - ) - right_val = ( - float(record[f"R{i}"]) if pd.notna(record[f"R{i}"]) else 0 - ) - - if left_val > 0: - left_monsters.append(i) - if right_val > 0: - right_monsters.append(i) - except (ValueError, TypeError): - continue - - # 分析对战情况 - for left_monster in left_monsters: - for right_monster in right_monsters: - # 左方怪物的统计 - counter_stats[left_monster]["total_matchups"] += 1 - if victory_side == "R": # 左方败北 - counter_stats[left_monster]["losses"] += 1 - - # 右方怪物的统计 - counter_stats[right_monster]["total_matchups"] += 1 - if victory_side == "L": # 右方败北 - counter_stats[right_monster]["losses"] += 1 - - # 计算被克制率 - countered_results = [] - for monster_id, stats in counter_stats.items(): - if stats["total_matchups"] >= 20: # 至少20场对战 - loss_rate = stats["losses"] / stats["total_matchups"] - monster_name = get_monster_name(monster_id) - countered_results.append( - { - "怪物": monster_name, - "怪物ID": monster_id, - "被克制率": loss_rate, - "败场": stats["losses"], - "总对战数": stats["total_matchups"], - } - ) - - # 按被克制率排序(降序) - countered_results.sort(key=lambda x: -x["被克制率"]) - return pd.DataFrame(countered_results[:5]) - - -def analyze_individual_monster_relations(df): - """分析每个怪物的详细关系:最佳队友、克制关系、被克制关系""" - monster_relations = {} - - # 初始化数据结构 - single_stats = defaultdict(lambda: {"appearances": 0, "wins": 0}) - pair_stats = defaultdict(lambda: {"co_occurrences": 0, "co_wins": 0}) - counter_stats = defaultdict( - lambda: defaultdict(lambda: {"matchups": 0, "wins": 0}) - ) - - for _, record in df.iterrows(): - victory_side = record["Result"] - - # 获取左右两方的怪物 - left_monsters = [] - right_monsters = [] - - for i in range(1, MONSTER_COUNT + 1): - try: - left_val = ( - float(record[f"L{i}"]) if pd.notna(record[f"L{i}"]) else 0 - ) - right_val = ( - float(record[f"R{i}"]) if pd.notna(record[f"R{i}"]) else 0 - ) - - if left_val > 0: - left_monsters.append(i) - if right_val > 0: - right_monsters.append(i) - except (ValueError, TypeError): - continue - - # 确定胜利队伍和失败队伍 - if victory_side == "L": - win_team, lose_team = left_monsters, right_monsters - else: - win_team, lose_team = right_monsters, left_monsters - - # 更新单怪统计 - for monster in win_team: - single_stats[monster]["appearances"] += 1 - single_stats[monster]["wins"] += 1 - - for monster in lose_team: - single_stats[monster]["appearances"] += 1 - - # 更新队友统计 - for i in range(len(win_team)): - for j in range(i + 1, len(win_team)): - x, y = sorted((win_team[i], win_team[j])) - pair_stats[(x, y)]["co_occurrences"] += 1 - pair_stats[(x, y)]["co_wins"] += 1 - - for i in range(len(lose_team)): - for j in range(i + 1, len(lose_team)): - x, y = sorted((lose_team[i], lose_team[j])) - pair_stats[(x, y)]["co_occurrences"] += 1 - - # 更新克制关系统计 - for winner in win_team: - for loser in lose_team: - counter_stats[winner][loser]["matchups"] += 1 - counter_stats[winner][loser]["wins"] += 1 - counter_stats[loser][winner]["matchups"] += 1 - - # 为每个怪物分析关系 - for monster_id in range(1, MONSTER_COUNT + 1): - monster_name = get_monster_name(monster_id) - - if single_stats[monster_id]["appearances"] < 10: # 数据量太少 - continue - - # 分析最佳队友 - best_teammates = [] - for (x, y), stats in pair_stats.items(): - if x == monster_id or y == monster_id: - partner_id = y if x == monster_id else x - if stats["co_occurrences"] >= 5: # 至少5次合作 - combo_win_rate = stats["co_wins"] / stats["co_occurrences"] - - # 计算提升度 - if ( - single_stats[monster_id]["appearances"] > 0 - and single_stats[partner_id]["appearances"] > 0 - ): - monster_win_rate = ( - single_stats[monster_id]["wins"] - / single_stats[monster_id]["appearances"] - ) - partner_win_rate = ( - single_stats[partner_id]["wins"] - / single_stats[partner_id]["appearances"] - ) - expected_win_rate = sqrt( - monster_win_rate * partner_win_rate - ) - - if expected_win_rate > 0: - lift = combo_win_rate / expected_win_rate - if lift > 1.0: - best_teammates.append( - { - "partner_id": partner_id, - "partner_name": get_monster_name( - partner_id - ), - "lift": lift, - "combo_win_rate": combo_win_rate, - "occurrences": stats["co_occurrences"], - } - ) - - best_teammates.sort(key=lambda x: -x["lift"]) - - # 分析克制关系 - counters = [] # 该怪物克制的 - countered_by = [] # 克制该怪物的 - - for opponent_id in counter_stats[monster_id]: - stats = counter_stats[monster_id][opponent_id] - if stats["matchups"] >= 5: - win_rate = stats["wins"] / stats["matchups"] - if win_rate > 0.6: # 胜率超过60%认为克制 - counters.append( - { - "opponent_id": opponent_id, - "opponent_name": get_monster_name(opponent_id), - "win_rate": win_rate, - "matchups": stats["matchups"], - } - ) - - for opponent_id in range(1, MONSTER_COUNT + 1): - if ( - opponent_id in counter_stats - and monster_id in counter_stats[opponent_id] - ): - stats = counter_stats[opponent_id][monster_id] - if stats["matchups"] >= 5: - lose_rate = stats["wins"] / stats["matchups"] - if lose_rate > 0.6: # 对方胜率超过60%认为被克制 - countered_by.append( - { - "opponent_id": opponent_id, - "opponent_name": get_monster_name(opponent_id), - "lose_rate": lose_rate, - "matchups": stats["matchups"], - } - ) - - counters.sort(key=lambda x: -x["win_rate"]) - countered_by.sort(key=lambda x: -x["lose_rate"]) - - monster_relations[monster_id] = { - "name": monster_name, - "best_teammates": best_teammates[:3], - "counters": counters[:3], - "countered_by": countered_by[:3], - } - - return monster_relations - - -def get_terrain_feature_columns(): - """获取地形特征列名""" - import json - import re - from collections import defaultdict - - try: - # 加载类别映射 - class_map_path = "tools/battlefield_recognize/class_to_idx.json" - with open(class_map_path, "r", encoding="utf-8") as f: - class_to_idx = json.load(f) - - # 使用与data_cleaning_with_field_recognize_gpu.py相同的逻辑 - grouped_elements = defaultdict(list) - for class_name in class_to_idx.keys(): - if class_name.endswith("_none"): - continue - condensed_name = re.sub(r"_left_", "_", class_name) - condensed_name = re.sub(r"_right_", "_", condensed_name) - grouped_elements[condensed_name].append(class_name) - - # 返回排序后的特征列名 - return sorted(grouped_elements.keys()) - except Exception as e: - print(f"无法获取地形特征列名,使用默认值: {e}") - # 如果无法获取,返回默认列表 - return [ - "altar_vertical_altar", - "block_parallel_block", - "block_vertical_altar_shape1", - "block_vertical_altar_shape2", - "block_vertical_block_shape1", - "block_vertical_block_shape2", - "coil_narrow_coil", - "coil_wide_coil", - "crossbow_top_crossbow", - "fire_side_crossbow", - "fire_side_fire", - "fire_top_fire", - ] - - -def analyze_terrain_effects(df): - """分析地形对怪物的影响""" - terrain_effects = [] - - # 获取实际的地形特征列名 - terrain_feature_columns = get_terrain_feature_columns() - - # 地形显示名称映射 - terrain_display_mapping = { - "altar_vertical_altar": "垂直祭坛", - "block_parallel_block": "平行方块阻挡", - "block_vertical_altar_shape1": "垂直祭坛形阻挡1", - "block_vertical_altar_shape2": "垂直祭坛形阻挡2", - "block_vertical_block_shape1": "垂直方块阻挡1", - "block_vertical_block_shape2": "垂直方块阻挡2", - "coil_narrow_coil": "窄型线圈装置", - "coil_wide_coil": "宽型线圈装置", - "crossbow_top_crossbow": "顶部弩炮", - "fire_side_crossbow": "侧边弩炮", - "fire_side_fire": "侧边火炮", - "fire_top_fire": "顶部火炮", - } - - for terrain_idx, terrain_key in enumerate(terrain_feature_columns): - terrain_name = terrain_display_mapping.get(terrain_key, terrain_key) - - for monster_idx in range(1, MONSTER_COUNT + 1): - monster_name = get_monster_name(monster_idx) - - # 转换数据类型 - df[f"FL{terrain_idx+1}"] = pd.to_numeric( - df[f"FL{terrain_idx+1}"], errors="coerce" - ).fillna(0) - df[f"FR{terrain_idx+1}"] = pd.to_numeric( - df[f"FR{terrain_idx+1}"], errors="coerce" - ).fillna(0) - df[f"L{monster_idx}"] = pd.to_numeric( - df[f"L{monster_idx}"], errors="coerce" - ).fillna(0) - df[f"R{monster_idx}"] = pd.to_numeric( - df[f"R{monster_idx}"], errors="coerce" - ).fillna(0) - - # 有地形时的表现 - terrain_left_games = df[ - (df[f"FL{terrain_idx+1}"] == 1) & (df[f"L{monster_idx}"] > 0) - ] - terrain_right_games = df[ - (df[f"FR{terrain_idx+1}"] == 1) & (df[f"R{monster_idx}"] > 0) - ] - - terrain_total = len(terrain_left_games) + len(terrain_right_games) - if terrain_total < 5: # 数据量太少 - continue - - terrain_wins = len( - terrain_left_games[terrain_left_games["Result"] == "L"] - ) + len(terrain_right_games[terrain_right_games["Result"] == "R"]) - terrain_win_rate = terrain_wins / terrain_total - - # 无地形时的表现 - normal_left_games = df[ - (df[f"FL{terrain_idx+1}"] == 0) & (df[f"L{monster_idx}"] > 0) - ] - normal_right_games = df[ - (df[f"FR{terrain_idx+1}"] == 0) & (df[f"R{monster_idx}"] > 0) - ] - - normal_total = len(normal_left_games) + len(normal_right_games) - if normal_total < 5: - continue - - normal_wins = len( - normal_left_games[normal_left_games["Result"] == "L"] - ) + len(normal_right_games[normal_right_games["Result"] == "R"]) - normal_win_rate = normal_wins / normal_total - - # 计算影响程度 - effect = terrain_win_rate - normal_win_rate - - if abs(effect) >= 0.05: # 胜率差异超过5%才记录 - terrain_effects.append( - { - "地形": terrain_name, - "怪物": monster_name, - "怪物ID": monster_idx, - "地形胜率": terrain_win_rate, - "普通胜率": normal_win_rate, - "影响程度": effect, - "地形场次": terrain_total, - "普通场次": normal_total, - } - ) - - # 按影响程度绝对值排序 - terrain_effects.sort(key=lambda x: -abs(x["影响程度"])) - return pd.DataFrame(terrain_effects[:20]) # 增加到前20个 - - -def analyze_device_counter_effects(df): - """分析五个装置对怪物的克制效果""" - device_counter_results = {} - - # 获取实际的地形特征列名 - terrain_feature_columns = get_terrain_feature_columns() - - # 定义五个装置类别及其对应的地形特征 - device_categories = { - "altar": { - "name": "祭坛", - "features": [f for f in terrain_feature_columns if "altar" in f], - "description": "祭坛类装置", - }, - "block": { - "name": "箱子/阻挡", - "features": [f for f in terrain_feature_columns if "block" in f], - "description": "方块阻挡类装置", - }, - "coil": { - "name": "电桩", - "features": [f for f in terrain_feature_columns if "coil" in f], - "description": "线圈电桩装置", - }, - "crossbow": { - "name": "弩箭", - "features": [ - f for f in terrain_feature_columns if "crossbow" in f - ], - "description": "弩炮装置", - }, - "fire": { - "name": "火炮", - "features": [f for f in terrain_feature_columns if "fire" in f], - "description": "火炮装置", - }, - } - - for device_key, device_info in device_categories.items(): - device_name = device_info["name"] - device_features = device_info["features"] - - if not device_features: - continue - - device_effects = [] - - # 对每个怪物分析该装置的克制效果 - for monster_idx in range(1, MONSTER_COUNT + 1): - monster_name = get_monster_name(monster_idx) - - # 收集该装置所有特征的统计数据 - total_device_games = 0 - total_device_wins = 0 - total_normal_games = 0 - total_normal_wins = 0 - - for terrain_key in device_features: - if terrain_key not in terrain_feature_columns: - continue - - terrain_idx = terrain_feature_columns.index(terrain_key) - - # 转换数据类型 - df[f"FL{terrain_idx+1}"] = pd.to_numeric( - df[f"FL{terrain_idx+1}"], errors="coerce" - ).fillna(0) - df[f"FR{terrain_idx+1}"] = pd.to_numeric( - df[f"FR{terrain_idx+1}"], errors="coerce" - ).fillna(0) - df[f"L{monster_idx}"] = pd.to_numeric( - df[f"L{monster_idx}"], errors="coerce" - ).fillna(0) - df[f"R{monster_idx}"] = pd.to_numeric( - df[f"R{monster_idx}"], errors="coerce" - ).fillna(0) - - # 有该装置时的表现 - device_left_games = df[ - (df[f"FL{terrain_idx+1}"] == 1) - & (df[f"L{monster_idx}"] > 0) - ] - device_right_games = df[ - (df[f"FR{terrain_idx+1}"] == 1) - & (df[f"R{monster_idx}"] > 0) - ] - - device_games_count = len(device_left_games) + len( - device_right_games - ) - device_wins_count = len( - device_left_games[device_left_games["Result"] == "L"] - ) + len( - device_right_games[device_right_games["Result"] == "R"] - ) - - # 无该装置时的表现 - normal_left_games = df[ - (df[f"FL{terrain_idx+1}"] == 0) - & (df[f"L{monster_idx}"] > 0) - ] - normal_right_games = df[ - (df[f"FR{terrain_idx+1}"] == 0) - & (df[f"R{monster_idx}"] > 0) - ] - - normal_games_count = len(normal_left_games) + len( - normal_right_games - ) - normal_wins_count = len( - normal_left_games[normal_left_games["Result"] == "L"] - ) + len( - normal_right_games[normal_right_games["Result"] == "R"] - ) - - total_device_games += device_games_count - total_device_wins += device_wins_count - total_normal_games += normal_games_count - total_normal_wins += normal_wins_count - - # 计算整体效果 - if ( - total_device_games >= 10 and total_normal_games >= 10 - ): # 确保有足够的数据 - device_win_rate = total_device_wins / total_device_games - normal_win_rate = total_normal_wins / total_normal_games - effect = device_win_rate - normal_win_rate - - # 计算克制程度(负值表示被该装置克制) - counter_effect = -effect # 装置对怪物的克制效果 - - if abs(effect) >= 0.05: # 胜率差异超过5%才记录 - device_effects.append( - { - "怪物": monster_name, - "怪物ID": monster_idx, - "装置胜率": device_win_rate, - "普通胜率": normal_win_rate, - "克制程度": counter_effect, # 正值表示被该装置克制 - "装置场次": total_device_games, - "普通场次": total_normal_games, - "效果类型": ( - "被克制" if counter_effect > 0 else "克制装置" - ), - } - ) - - # 按克制程度排序(被克制程度最高的在前) - device_effects.sort(key=lambda x: -x["克制程度"]) - device_counter_results[device_key] = { - "name": device_name, - "description": device_info["description"], - "features": device_features, - "effects": device_effects[:10], # 取前10个被克制最严重的怪物 - } - - return device_counter_results - - -def create_html_table( - df, columns, title, is_combo=False, monster_relations=None -): - """创建带有怪物头像的HTML表格""" - html = f"

{title}

\n\n" - - # 表头 - if is_combo: - html += "" - else: - html += "" - - for col in columns: - html += f"" - - # 如果是胜率表且有关系数据,添加额外的列 - if not is_combo and monster_relations and title == "所有怪物胜率排行榜": - html += "" - - html += "\n" - - # 表格内容 - row_number = 1 - for idx, row in df.iterrows(): - html += "" - - # 怪物图片和名称 - monster_id = None - if is_combo and "ID1" in row and "ID2" in row: - monster1_name = get_monster_name(row["ID1"]) - monster2_name = get_monster_name(row["ID2"]) - monster1_orig = get_monster_original_name(row["ID1"]) - monster2_orig = get_monster_original_name(row["ID2"]) - html += f"""""" - elif "怪物ID" in row: - monster_name = get_monster_name(row["怪物ID"]) - monster_orig = get_monster_original_name(row["怪物ID"]) - display_name = row.get("怪物", monster_name) - monster_id = row["怪物ID"] - html += f"""""" - else: - # 对于胜率表,使用索引作为怪物名称 - monster_name = idx - # 尝试从怪物数据中获取ID - monster_orig = monster_name - for mid in range(1, MONSTER_COUNT + 1): - if get_monster_name(mid) == monster_name: - monster_id = mid - monster_orig = get_monster_original_name(mid) - break - html += f"""""" - - # 数据列 - for col in columns: - value = row[col] - if isinstance(value, float): - if "率" in col or "程度" in col: - html += f"" - else: - html += f"" - else: - html += f"" - - # 如果是胜率表且有关系数据,添加关系信息 - if ( - not is_combo - and monster_relations - and title == "所有怪物胜率排行榜" - and monster_id - ): - relations = monster_relations.get(int(monster_id), {}) - - # 最佳队友 - html += "" - - # 克制关系 - html += "" - - # 被克制关系 - html += "" - - html += "\n" - row_number += 1 - - html += "
组合怪物{col}最佳队友克制被克制
- {row_number}. - {monster_img_tag(monster1_orig, 30)} - {monster1_name}
- {monster_img_tag(monster2_orig, 30)} - {monster2_name} -
- {row_number}. - {monster_img_tag(monster_orig, 50)} - {display_name} - - {row_number}. - {monster_img_tag(monster_orig, 50)} - {monster_name} - {value:.2%}{value:.2f}{value}" - if ( - relations - and "best_teammates" in relations - and relations["best_teammates"] - ): - teammates = [] - for teammate in relations["best_teammates"]: - teammate_orig = get_monster_original_name( - teammate["partner_id"] - ) - teammates.append(f"""
- {monster_img_tag(teammate_orig, 20)} - {teammate['partner_name']} ({teammate['lift']:.2f}x) -
""") - html += "".join(teammates) - else: - html += "暂无数据" - html += "
" - if relations and "counters" in relations and relations["counters"]: - counters = [] - for counter in relations["counters"]: - counter_orig = get_monster_original_name( - counter["opponent_id"] - ) - counters.append(f"""
- {monster_img_tag(counter_orig, 20)} - {counter['opponent_name']} ({counter['win_rate']:.0%}) -
""") - html += "".join(counters) - else: - html += "暂无数据" - html += "
" - if ( - relations - and "countered_by" in relations - and relations["countered_by"] - ): - countered = [] - for counter in relations["countered_by"]: - counter_orig = get_monster_original_name( - counter["opponent_id"] - ) - countered.append(f"""
- {monster_img_tag(counter_orig, 20)} - {counter['opponent_name']} ({counter['lose_rate']:.0%}) -
""") - html += "".join(countered) - else: - html += "暂无数据" - html += "
\n" - return html - - -def create_device_counter_html(device_counter_effects): - """创建装置克制效果的HTML表格""" - html = "

装置克制效果统计

\n" - - for device_key, device_data in device_counter_effects.items(): - if not device_data["effects"]: - continue - - device_name = device_data["name"] - device_description = device_data["description"] - effects = device_data["effects"] - - html += f"

{device_name}({device_description})

\n" - html += "\n" - html += "" - html += "\n" - - row_number = 1 - for effect in effects: - monster_name = effect["怪物"] - monster_orig = get_monster_original_name(effect["怪物ID"]) - html += f""" - - - - - - - - \n""" - row_number += 1 - - html += "
怪物克制程度装置胜率普通胜率装置场次普通场次效果类型
- {row_number}. - {monster_img_tag(monster_orig, 40)} - {monster_name} - {effect['克制程度']:.2%}{effect['装置胜率']:.2%}{effect['普通胜率']:.2%}{effect['装置场次']}{effect['普通场次']}{effect['效果类型']}
\n
\n" - - return html - - -def generate_comprehensive_report(): - """生成综合统计报告""" - print("正在加载数据...") - df = load_data() - - print("正在计算怪物胜率...") - win_rates = calculate_all_monster_win_rates(df) - - print("正在分析怪物配合...") - combinations = analyze_monster_combinations(df) - - print("正在分析被克制关系...") - countered = find_countered_monsters(df) - - if FIELD_FEATURE_COUNT > 0: - print("正在分析地形效果...") - terrain_effects = analyze_terrain_effects(df) - - print("正在分析装置克制效果...") - device_counter_effects = analyze_device_counter_effects(df) - else: - print("地形特征数量为0,跳过地形分析...") - terrain_effects = pd.DataFrame() - device_counter_effects = {} - - print("正在分析个体怪物关系...") - monster_relations = analyze_individual_monster_relations(df) - - # 创建HTML报告 - total_battles = len(df) - monster_count = MONSTER_COUNT - field_count = FIELD_FEATURE_COUNT - - html = f""" - - - - - - -

明日方舟争锋频道绿藤城

-
-

数据概览:

-
    -
  • 总战斗记录:{total_battles} 场
  • -
  • 统计怪物数量:{monster_count} 种
  • -
  • 地形特征数量:{field_count} 种
  • -
-
-""" - - # 1. 所有怪物胜率 - if not win_rates.empty: - html += create_html_table( - win_rates, - ["胜场", "总场数", "胜率", "参战率"], - "所有怪物胜率排行榜", - monster_relations=monster_relations, - ) - else: - html += "

所有怪物胜率排行榜

暂无数据

" - - # 2. 最佳配合 - if not combinations.empty: - html += create_html_table( - combinations.head(20), - ["提升度", "组合胜率", "出场次数"], - "最佳怪物配合TOP20", - is_combo=True, - ) - else: - html += "

最佳怪物配合

暂无足够的配合数据

" - - # 4. 地形效果 - if not terrain_effects.empty: - html += create_html_table( - terrain_effects, - ["地形", "地形胜率", "普通胜率", "影响程度"], - "地形影响最大的怪物TOP20", - ) - else: - html += "

地形影响

暂无足够的地形数据

" - - # 5. 装置克制效果 - if device_counter_effects: - html += create_device_counter_html(device_counter_effects) - else: - html += "

装置克制效果统计

暂无足够的装置数据

" - - timestamp = pd.Timestamp.now().strftime("%Y-%m-%d %H:%M:%S") - html += f""" -
-

报告生成时间:{timestamp}

-

注:数据基于历史战斗记录,仅供参考

-
- - -""" - - # 保存报告 - with open("comprehensive_monster_report.html", "w", encoding="utf-8") as f: - f.write(html) - - print("统计报告已生成:comprehensive_monster_report.html") - - # 也输出到控制台 - print("\n=== 怪物胜率TOP10 ===") - print(win_rates.head(10).to_string()) - - if not combinations.empty: - print("\n=== 最佳配合TOP10 ===") - print( - combinations.head(10)[ - ["组合", "提升度", "组合胜率", "出场次数"] - ].to_string() - ) - - # 输出装置克制效果 - if device_counter_effects: - print("\n=== 装置克制效果统计 ===") - for device_key, device_data in device_counter_effects.items(): - if device_data["effects"]: - print( - f"\n{device_data['name']}({device_data['description']})最克制的怪物TOP5:" - ) - for i, effect in enumerate(device_data["effects"][:5]): - print( - f" {i+1}. {effect['怪物']} - 克制程度: {effect['克制程度']:.2%} ({effect['效果类型']})" - ) - - if not terrain_effects.empty: - print("\n=== 地形影响TOP10 ===") - print( - terrain_effects.head(10)[ - ["地形", "怪物", "影响程度", "地形胜率", "普通胜率"] - ].to_string() - ) - - -if __name__ == "__main__": - generate_comprehensive_report() diff --git a/src/core/paths.py b/src/core/paths.py deleted file mode 100644 index 4c9dbec..0000000 --- a/src/core/paths.py +++ /dev/null @@ -1,38 +0,0 @@ -from pathlib import Path - - -PROJECT_ROOT = Path(__file__).resolve().parents[2] -SRC_DIR = PROJECT_ROOT / "src" -RESOURCES_DIR = SRC_DIR / "resources" -ASSETS_DIR = RESOURCES_DIR / "assets" -IMAGES_DIR = ASSETS_DIR / "images" -PROCESS_IMAGES_DIR = IMAGES_DIR / "process" -TMP_IMAGES_DIR = IMAGES_DIR / "tmp" -DATA_DIR = RESOURCES_DIR / "data" -SIMULATION_DIR = SRC_DIR / "simulation" -TOOLS_DIR = SRC_DIR / "tools" - - -def resource_path(*parts: str) -> Path: - return RESOURCES_DIR.joinpath(*parts) - - -def image_path(name: str) -> Path: - return IMAGES_DIR / f"{name}.png" - - -def process_image_path(name: str | int) -> Path: - return PROCESS_IMAGES_DIR / f"{name}.png" - - -def data_path(name: str) -> Path: - return DATA_DIR / name - - -def simulation_path(name: str) -> Path: - return SIMULATION_DIR / name - - -def ensure_tmp_images_dir() -> Path: - TMP_IMAGES_DIR.mkdir(parents=True, exist_ok=True) - return TMP_IMAGES_DIR diff --git a/src/data/__init__.py b/src/data/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/game/__init__.py b/src/game/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/models/__init__.py b/src/models/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/recognition/__init__.py b/src/recognition/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/recognition/specialmonster.py b/src/recognition/specialmonster.py deleted file mode 100644 index 31b9eb5..0000000 --- a/src/recognition/specialmonster.py +++ /dev/null @@ -1,44 +0,0 @@ -class SpecialMonsterHandler: - """ - 可按照格式自行添加特殊怪物的留言信息: - 格式: - 怪物ID: { - 'name': '怪物名称', # 可留空 - 'win_message': '胜利时显示的消息', # 可留空 - 'lose_message': '失败时显示的消息', # 可留空 - } - """ - - def __init__(self): - self.special_monsters = { - 1: { - "name": "狗神", - "win_message": "全军出击,我咬死你!", - "lose_message": "牙崩了牙崩了", - }, - } - - def check_special_monsters(self, left_monsters, right_monsters, winner): - messages = [] - - for monster_id, config in self.special_monsters.items(): - left_has = ( - left_monsters[str(monster_id)].text().isdigit() - and int(left_monsters[str(monster_id)].text()) > 0 - ) - right_has = ( - right_monsters[str(monster_id)].text().isdigit() - and int(right_monsters[str(monster_id)].text()) > 0 - ) - - if left_has or right_has: - if winner == "左方" and left_has and config["win_message"]: - messages.append(config["win_message"]) - elif winner == "右方" and right_has and config["win_message"]: - messages.append(config["win_message"]) - elif winner == "右方" and left_has and config["lose_message"]: - messages.append(config["lose_message"]) - elif winner == "左方" and right_has and config["lose_message"]: - messages.append(config["lose_message"]) - - return "\n".join(messages) diff --git a/src/resources/config/maa_option.json b/src/resources/config/maa_option.json deleted file mode 100644 index 5de39ef..0000000 --- a/src/resources/config/maa_option.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "draw_quality": 85, - "logging": true, - "save_draw": false, - "save_on_error": true, - "stdout_level": 2 -} \ No newline at end of file diff --git a/src/simulation/__init__.py b/src/simulation/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/simulation/scene.json b/src/simulation/scene.json deleted file mode 100644 index 2463240..0000000 --- a/src/simulation/scene.json +++ /dev/null @@ -1,206 +0,0 @@ -{ - "left": [ - { - "name": "酸液源石虫·α", - "count": 0 - }, - { - "name": "高能源石虫", - "count": 0 - }, - { - "name": "阿咬", - "count": 0 - }, - { - "name": "狂暴的猎狗pro", - "count": 0 - }, - { - "name": "提亚卡乌好战者", - "count": 0 - }, - { - "name": "污染躯壳", - "count": 0 - }, - { - "name": "大盾哥", - "count": 0 - }, - { - "name": "宿主流浪者", - "count": 0 - }, - { - "name": "光剑", - "count": 4 - }, - { - "name": "泥岩巨像", - "count": 0 - }, - { - "name": "呼啸骑士团学徒", - "count": 0 - }, - { - "name": "萨卡兹大剑手", - "count": 0 - }, - { - "name": "狂暴宿主组长", - "count": 0 - }, - { - "name": "海螺", - "count": 0 - }, - { - "name": "拳手囚犯", - "count": 0 - }, - { - "name": "高塔术师", - "count": 0 - }, - { - "name": "冰原术师", - "count": 0 - }, - { - "name": "矿脉守卫", - "count": 0 - }, - { - "name": "“庞贝”", - "count": 0 - }, - { - "name": "绵羊", - "count": 0 - }, - { - "name": "食腐狗", - "count": 0 - }, - { - "name": "温顺的武装驮兽", - "count": 3 - }, - { - "name": "鼠鼠", - "count": 4 - }, - { - "name": "“投石机”", - "count": 0 - }, - { - "name": "船长", - "count": 0 - } - ], - "right": [ - { - "name": "酸液源石虫·α", - "count": 0 - }, - { - "name": "高能源石虫", - "count": 0 - }, - { - "name": "阿咬", - "count": 0 - }, - { - "name": "狂暴的猎狗pro", - "count": 0 - }, - { - "name": "提亚卡乌好战者", - "count": 0 - }, - { - "name": "污染躯壳", - "count": 0 - }, - { - "name": "大盾哥", - "count": 0 - }, - { - "name": "宿主流浪者", - "count": 0 - }, - { - "name": "光剑", - "count": 0 - }, - { - "name": "泥岩巨像", - "count": 0 - }, - { - "name": "呼啸骑士团学徒", - "count": 0 - }, - { - "name": "萨卡兹大剑手", - "count": 0 - }, - { - "name": "狂暴宿主组长", - "count": 0 - }, - { - "name": "海螺", - "count": 0 - }, - { - "name": "拳手囚犯", - "count": 11 - }, - { - "name": "高塔术师", - "count": 0 - }, - { - "name": "冰原术师", - "count": 0 - }, - { - "name": "矿脉守卫", - "count": 0 - }, - { - "name": "“庞贝”", - "count": 3 - }, - { - "name": "绵羊", - "count": 9 - }, - { - "name": "食腐狗", - "count": 0 - }, - { - "name": "温顺的武装驮兽", - "count": 0 - }, - { - "name": "鼠鼠", - "count": 0 - }, - { - "name": "“投石机”", - "count": 0 - }, - { - "name": "船长", - "count": 0 - } - ] -} \ No newline at end of file diff --git a/src/simulation/stats.py b/src/simulation/stats.py deleted file mode 100644 index 8ab77cf..0000000 --- a/src/simulation/stats.py +++ /dev/null @@ -1,191 +0,0 @@ -import json -from collections import defaultdict -import numpy as np -import pandas as pd -from scipy.stats import fisher_exact -import matplotlib.pyplot as plt - -# 配置中文字体 -plt.rcParams["font.sans-serif"] = ["Microsoft YaHei"] -plt.rcParams["axes.unicode_minus"] = False - - -def calculate_significance(row): - """计算修正后的统计显著性""" - # 关键参数 - error_total = ( - row["under_estimate"] + row["over_estimate"] - ) # 错误样本总次数 - correct_total = row["total"] - error_total # 正确样本总次数 - - # 过滤无效数据 - if error_total == 0 or correct_total == 0: - return np.nan - - # 低估检验(单侧) - contingency_under = [ - [row["under_estimate"], row["over_estimate"]], - [0, correct_total], - ] - _, under_p = fisher_exact(contingency_under, alternative="greater") - - # 高估检验(单侧) - contingency_over = [ - [row["over_estimate"], row["under_estimate"]], - [0, correct_total], - ] - _, over_p = fisher_exact(contingency_over, alternative="greater") - - return under_p + over_p - - -def analyze_monster_balance(data_path): - # 初始化统计容器 - stats = defaultdict( - lambda: { - "total": 0, # 总出现次数 - "error": 0, # 错误预测中出现次数 - "under_estimate": 0, # 低估计数(实际应胜但预测失败) - "over_estimate": 0, # 高估计数(实际应败但预测成功) - } - ) - - # 数据加载与分析 - with open(data_path, encoding="utf-8") as f: - for line in f: - record = json.loads(line.strip()) - actual = record["result"] - pred = record["pred"] - - for side in ["left", "right"]: - for monster, count in record[side].items(): - # 基础统计 - stats[monster]["total"] += 1 - - # 仅统计预测错误的情况 - if pred != actual: - stats[monster]["error"] += 1 - - # 判断估计方向 - if side == actual: - stats[monster]["under_estimate"] += 1 - elif side != actual: - stats[monster]["over_estimate"] += 1 - - # 构建分析数据框 - df = pd.DataFrame.from_dict(stats, orient="index") - df = df[df["total"] > 0] # 过滤无效数据 - - # 计算统计指标 - df["error_rate"] = df["error"] / df["total"] - df["bias_score"] = (df["under_estimate"] - df["over_estimate"]) / df[ - "total" - ] - df["abs_bias"] = abs(df["bias_score"]) - - # # Fisher精确检验 - # def apply_fisher(row): - # contingency = [ - # [row['under_estimate'], row['over_estimate']], - # [row['total'] - row['under_estimate'], - # row['total'] - row['over_estimate']] - # ] - # _, p_value = fisher_exact(contingency) - # return p_value - - df["p_value"] = df.apply(calculate_significance, axis=1) - - # 筛选显著结果 (p<0.04 且总出现次数>1) - valid = df[(df["p_value"] < 0.04) & (df["total"] >= 1)] - - # 生成可视化 - plot_monster_bias(valid) - - return valid.sort_values("abs_bias", ascending=False) - - -def plot_monster_bias(df): - plt.figure(figsize=(12, 8)) - - # 设置颜色映射 - colors = np.where( - df["bias_score"] > 0, "#4C72B0", "#DD8452" # 蓝色表示低估 - ) # 橙色表示高估 - - # 绘制条形图 - bars = plt.barh(df.index, df["bias_score"], color=colors) - - # 添加统计标注 - for bar, (_, row) in zip(bars, df.iterrows()): - plt.text( - bar.get_width() + 0.02, - bar.get_y() + bar.get_height() / 2, - f"p={row['p_value']:.3f}\nN={row['total']}", - va="center", - ) - - # 图表装饰 - plt.axvline(0, color="gray", linestyle="--") - plt.title("怪物数值平衡性分析", fontsize=14) - plt.xlabel("偏差分数(正值表示低估,负值表示高估)") - plt.ylabel("怪物名称") - plt.xlim(-1.1, 1.1) - plt.grid(axis="x", alpha=0.3) - plt.tight_layout() - plt.savefig("monster_balance.png", dpi=300) - plt.close() - - -# 执行分析 -if __name__ == "__main__": - result_df = analyze_monster_balance("../errors.json") - - # 打印格式化结果 - print("=" * 60) - print( - f"{'怪物名称':<10}\t{'偏差方向':<8}\t{'偏差分数':<8}\t{'p值':<10}\t{'样本量'}" - ) - print("-" * 60) - for name, row in result_df.iterrows(): - direction = "低估" if row["bias_score"] > 0 else "高估" - print( - f"{name:<10}\t{direction:<8}\t{row['bias_score']:.2f}{'*' if row['p_value']<0.01 else '':<4}" - f"\t{row['p_value']:.3f}\t{'':<6}\t{row['total']}" - ) - - plot_monster_bias(result_df) - -with open("../errors.json", encoding="utf-8") as f: - data = f.read() - -counter = defaultdict(int) -power_counter = defaultdict(int) -err_counter = defaultdict(int) - -for line in data.strip().split("\n"): - record = json.loads(line) - result = record["result"] - pred = record["pred"] - for side in ["left", "right"]: - for monster, count in record[side].items(): - counter[monster] += 1 - if pred != result: - if side == result: - # 应该获胜却没有获胜,有低估的可能性 - power_counter[monster] += 1 - else: - # 不该获胜的获胜了,有高估的可能性 - power_counter[monster] -= 1 - err_counter[monster] += 1 - -sorted_monsters = sorted( - err_counter.items(), key=lambda x: (-x[1] / counter[x[0]], x[0]) -) - -for monster, count in sorted_monsters: - str = "低估" if power_counter[monster] > 0 else "高估" - total = counter[monster] - err_total = count - print( - f"{monster}: {err_total}/{total} = {err_total/total} 估计值:【{str}】{-power_counter[monster] / total * 100}" - ) diff --git a/src/tools/battlefield_composite/extract_webm_frames.py b/src/tools/battlefield_composite/extract_webm_frames.py deleted file mode 100644 index 3b667d7..0000000 --- a/src/tools/battlefield_composite/extract_webm_frames.py +++ /dev/null @@ -1,93 +0,0 @@ -import logging -from pathlib import Path -import subprocess - -monster_name = { - "弧光锋卫长": "Arc_Frontliner_Leader", - "炮击组长": "Mortar_Gunner_Leader", - "复仇者": "Hateful_Avenger", - "重装防御者": "Heavy_Defender", - "“庞贝”": "Pompeii", - "冰原术师": "Icefield_Caster", - "沸血骑士团精锐": "Bloodboil_Knightclub_Elite", - "高塔术师": "Spire_Caster", - "固海凿石者": "Ocean_Stonecutter", - # "呼啸骑士团学徒" : "Roar_Knightclub_Trainee", - "湖畔志愿者": "Lakeside_Volunteer", - "杰斯顿·威廉姆斯": "Jesselton_Williams", - "酸液源石虫·α": "Acid_Originium_Slug_α", - "神射手囚犯": "Elite_Sniper_Prisoner", - "拳手囚犯": "Pugilist_Prisoner", - "染污躯壳": "Tainted_Carcass", - "泥岩巨像": "Mudrock_Colossus", - "狂暴的猎狗pro": "Rabid_Hound_Pro", - "宿主拾荒者": "Possessed_Veteran_Junkman", - "狂暴宿主组长": "Enraged_Possessed_Leader", - "萨卡兹大剑手": "Sarkaz_Greatswordsman", - "矿脉守卫": "Vein_Guardian", - "山海众窥魅人": "Shanhaizhong_Seer", - "提亚卡乌好战者": "Tiacauh_Fanatic", - "码头水手": "Dockworker", - "变异巨岩蛛": "Mutant_Giant_Rock_Spider", - "萨卡兹子裔链术师": "Sarkaz_Heirbearer_Chain_Caster", - "温顺的武装驮兽": "Armored_Burdenbeast", - "木裂战士": "Shattered_Champion", - "深溟裂礁者": "Nethersea_Reefbreaker", - "山雪鬼": "Tschäggättä", - "高普尼克": "Gopnik", - "冰爆源石虫": "Infused_Glacial_Originium_Slug", - "反装甲步兵": "Anti-Armor_Infantry", - "“钳钳生风”": "Consortium_of_Pincers", - "富营养的穿刺者": "Nourished_Piercer", - "高级武装人员": "Senior_Armed_Militant", - "朗姆酒推荐者": "Rum_Connoisseur", - "烈酒级醒酒助手": "Whiskey-Grade_Waker-Upper", - "萨卡兹王庭军术师": "Sarkaz_Royal_Court_Caster", - # "灰尾香主" : "Greytail_Leader", - "阵地击人手": "Field_Bludgeoner", - "源石畸变体": "Originiutant", - "提亚卡乌破坏王": "Tiacauh_Annihilator", - "逐腐兽": "Rotchaser", - "高能源石虫": "Infused_Originium_Slug", - "风情街“星术师”": "Fashion_Street_Stellar_Caster", - "田鼷力士": "Fieldmus_Bruiser", - "残党萨克斯手": "Remnant_Saxophonist", - "散华骑士团学徒": "Nova_Knightclub_Trainee", - "“阿咬”": "Bitey", - # "“门”" : "", - "“投石机”": "Catapult", - # "“复仇者”" : '"Hateful Avenger"', - # "扎罗,“狼之主”" : "Zaaro", - # "“自在”" : "Free", - # "灼热源石虫" : "Blazing_Originium_Slug", - # "萨卡兹子裔责罚者" : "Sarkaz_Heirbearer_Punisher", - # "" : "", -} - - -def extract_webm(webm_path: Path, output_folder: Path): - extract_webm_cmd = ( - f'ffmpeg -c:v libvpx -i "{webm_path}" "{output_folder}/frame%d.png"' - ) - subprocess.run(extract_webm_cmd, shell=True, check=True) - - -def main(): - webm_folder = "./tools/battlefield_composite/monster_images" - for webm_path in Path(webm_folder).glob("*.webm"): - name_split = webm_path.parts[-1].split("-") - print(name_split) - if (name := monster_name.get(name_split[0])) is not None: - output_directory = webm_path.parent / (name + "-" + name_split[3]) - print(output_directory) - if not output_directory.exists(): - output_directory.mkdir(exist_ok=True) - extract_webm(webm_path, output_directory) - else: - logging.warning(f"{output_directory} already exists") - else: - logging.error(f"Name: {name_split[0]} not found!") - - -if __name__ == "__main__": - main() diff --git a/src/tools/data_washer_new.py b/src/tools/data_washer_new.py deleted file mode 100644 index cf1ef85..0000000 --- a/src/tools/data_washer_new.py +++ /dev/null @@ -1,1383 +0,0 @@ -import logging -from pathlib import Path -import cv2 -import numpy as np -import csv -import os -import sys -from src.recognition import recognize -import tqdm - -MONSTER_NUM = 56 -black_list_rows = [] - - -def merge(nums): - if not nums: - return "" - intervals = [] - start = end = nums[0] - for num in nums[1:]: - if num == end + 1: - end = num - else: - intervals.append((start, end)) - start = end = num - intervals.append((start, end)) # 添加最后一个区间 - - parts = [] - for s, e in intervals: - if s == e: - parts.append(str(s)) - else: - parts.append(f"{s}-{e}") - return ",".join(parts) - - -def is_continuous_sublist(sub, main): - return any( - sub == main[i : i + len(sub)] for i in range(len(main) - len(sub) + 1) - ) - - -def remove_duplicate_subsequences_easy(listdata, threshold=3): - record = [] - for i in range(len(listdata) - threshold - 1): - if is_continuous_sublist( - listdata[i + 1 : i + threshold + 2], listdata[: i + threshold + 1] - ): - record.extend(list(range(i + 1, i + threshold + 2))) - reco_last = list(set(record)) - reco_last.sort() - processed_data = [ - listdata[j] for j in range(len(listdata)) if j not in reco_last - ] - return processed_data, reco_last - - -def remove_duplicate_subsequences(arr, threshold=3): - """ - 处理二维数组版本,将每行视为独立元素,避免内存溢出 - :param arr: 二维np数组,形状为(N, D) - :param threshold: 需要删除的连续重复子序列最小长度 - :return: 去重后的数组,被删除的索引列表 - """ - if arr.ndim != 2: - raise ValueError("输入必须是二维数组") - - n = arr.shape[0] - print(arr[9]) - # 哈希化每行以便快速比较 - dtype = np.dtype((np.void, arr.dtype.itemsize * arr.shape[1])) - hashed_arr = np.ascontiguousarray(arr).view(dtype).flatten() - - # 初始化滚动数组和列最大值记录 - prev_row = np.zeros(n, dtype=int) - max_per_col = np.zeros(n, dtype=int) - targ = 10 - for i in range(n): - # 生成当前行比较掩码 - equal_mask = hashed_arr[i] == hashed_arr - - # 计算当前行DP值 - curr_row = np.zeros(n, dtype=int) - curr_row[0] = equal_mask[0] # 处理j=0 - - if i > 0: - # 向量化计算j>=1的情况 - curr_row[1:] = np.where(equal_mask[1:], prev_row[:-1] + 1, 0) - - # 更新列最大值(只考虑i<=j的情况) - col_mask = np.arange(n) > i - max_per_col = np.maximum(max_per_col, curr_row * col_mask) - - # 滚动更新 - prev_row = curr_row - if i * 100 / n >= targ: - print("检查重复数据,处理进度: {:.1f}%: ".format(i * 100 / n)) - targ += 10 - - # 确定有效列并生成删除索引 - valid_cols = np.where(max_per_col >= threshold)[0] - to_remove = set() - - for j in valid_cols: - length = max_per_col[j] - start = max(0, j - length) - to_remove.update(range(start, j + 1)) - - final_indices = sorted(to_remove) - return np.delete(arr, final_indices, axis=0), final_indices - - -def isfloat(value): - try: - float(value) - return True - except ValueError: - return False - - -def read_and_remove_zeros(filename, MONSTER_NUM=56): - """ - 输入数据文件名 - 输出去0和空之后的数组,和删去的行号列表 - """ - data = [] - datafull = [] - row_id = 0 - kong = [] - short = [] - lines_num = MONSTER_NUM * 2 - with open(filename, "r") as file: - csv_reader = csv.reader(file) - for row in csv_reader: - if len(row) < lines_num + 1: - short.append(row_id) - data.append([0] * lines_num) - datafull.append([0] * lines_num) - # 分离数字部分和末尾的字母 - elif isfloat(row[0]) and "" not in row[:lines_num]: - numbers = list( - map(int, map(float, row[:lines_num])) - ) # 转换为整数列表 - vals = row[lines_num:] - datafull.append(numbers + vals) - data.append(numbers) - else: - kong.append(row_id) - data.append([0] * lines_num) - datafull.append([0] * lines_num) - # 把这一行转化为全0行暂时录入 - row_id += 1 - print("原数据总长度:", len(datafull)) - print("数据长度过短的行:", merge(short)) - print("含有不合法数据的行:", merge(kong)) - - np_array = np.array(data) - # 去除全零行 - all_zeros = [] - for i in range(np_array.shape[0]): - if np.all(np_array[i][MONSTER_NUM:] == 0) or np.all( - np_array[i][:MONSTER_NUM] == 0 - ): - all_zeros.append(i) - # np.delete(np_array, all_zeros, axis=0) - - data_new = [ - datafull[j] for j in range(len(datafull)) if j not in all_zeros - ] - - all_zeros_idx = [i for i in all_zeros if i not in kong + short] - print("一侧数据全为0的行:", merge(all_zeros_idx)) - print("筛选后数据总长度:", len(data_new)) - return data_new, all_zeros, len(datafull) - - -def do_duplicate(listdata): - if listdata == []: - return [], [] - num_data = [ - list(map(int, map(float, i[: MONSTER_NUM * 2]))) for i in listdata - ] - np_num_data = np.array(num_data) - _, remove_list = remove_duplicate_subsequences(np_num_data, threshold=3) - # print(remove_list) - result = [ - listdata[j] for j in range(len(listdata)) if j not in remove_list - ] - return result, remove_list - - -def ori_pos(n, del1, del2): - remaining_after_first = [i for i in range(n) if i not in del1] - second_deleted_original = [remaining_after_first[t] for t in del2] - all_deleted = del1 + second_deleted_original - all_deleted.sort() - return all_deleted, second_deleted_original - - -def view_monster_counts(listdata): - if listdata == []: - return True, [], [] - wrong_counts = [] - num_left = [list(map(int, map(float, i[:MONSTER_NUM]))) for i in listdata] - num_right = [ - list(map(int, map(float, i[MONSTER_NUM : MONSTER_NUM * 2]))) - for i in listdata - ] - print(len(num_left[0]), len(num_right[0])) - black_listed = False - MONSTER_MIN = 0 - MONSTER_MAX = 100 - MONSTER_LIMIT = { - 0: [range(0, 100), "狗", False], - 1: [range(0, 50), "红虫", False], - 2: [range(0, 30), "大盾", False], - 3: [range(0, 30), "大剑", False], - 6: [range(0, 6), "庞贝", False], - 8: [range(0, 4), "石头人", False], - 27: [range(0, 4), "杰斯顿", False], - 28: [[0], "自在", True], - 29: [[0], "狼主", True], - 30: [[0], "雷德", True], # 三大boss全设为0 - } - ind = 0 - for i1, i2 in zip(num_left, num_right): - for x1 in i1: - if x1 < MONSTER_MIN: - print(f"{ind}行左侧发现小于0的数据!") - if ind not in wrong_counts: - wrong_counts.append(ind) - if x1 > MONSTER_MAX: - print(f"{ind}行左侧发现大于100的数据!") - if ind not in wrong_counts: - wrong_counts.append(ind) - for x2 in i2: - if x2 < MONSTER_MIN: - print(f"{ind}行右侧发现小于0的数据!") - if ind not in wrong_counts: - wrong_counts.append(ind) - if x2 > MONSTER_MAX: - print(f"{ind}行右侧发现大于100的数据!") - if ind not in wrong_counts: - wrong_counts.append(ind) - for j in MONSTER_LIMIT: - if i1[j] not in MONSTER_LIMIT[j][0]: - print(f"{ind}行左侧发现{MONSTER_LIMIT[j][1]},数量:{i1[j]}") - if ind not in wrong_counts: - wrong_counts.append(ind) - if MONSTER_LIMIT[j][2] and not black_listed: - black_listed = True - print(f"确认为30人数据,文档加入黑名单。") - if i2[j] not in MONSTER_LIMIT[j][0]: - print(f"{ind}行右侧发现{MONSTER_LIMIT[j][1]},数量:{i2[j]}") - if ind not in wrong_counts: - wrong_counts.append(ind) - if MONSTER_LIMIT[j][2] and not black_listed: - black_listed = True - print(f"确认为30人数据,文档加入黑名单。") - ind += 1 - processed_data = [ - listdata[j] for j in range(len(listdata)) if j not in wrong_counts - ] - mwdata = is_list_true_np(processed_data) - processed_data2 = [ - processed_data[j] - for j in range(len(processed_data)) - if j not in mwdata - ] - print(f"怪物信息不符合权重分配的数据行:{mwdata}") - return black_listed, wrong_counts, mwdata, processed_data2 - - -def del_duplicate_by_time(listdata, delete_no_time=True): - ind = 0 - no_time = [] - timedata = [] - wrong_time = [] - for i in listdata: - if len(i) < MONSTER_NUM * 2 + 2 or i[-1] == "N/A": - no_time.append(ind) - ind += 1 - print(merge(no_time), "行:未发现时间戳!") - data_with_time = [ - listdata[j] for j in range(len(listdata)) if j not in no_time - ] - ind = 0 - for i in data_with_time: - if i[-1] not in timedata: - timedata.append(i[-1]) - else: - wrong_time.append(ind) - print( - f"{timedata.index(i[-1])}行与{ind}行发现同名截图,文件名:{i[-1]}" - ) - ind += 1 - if not delete_no_time: - # 先找到wrongtime元素的原始位置,再从原列表删除 - remaining_after_first = [ - i for i in range(len(listdata)) if i not in no_time - ] - second_deleted_original = [ - remaining_after_first[t] for t in wrong_time - ] - data_with_time_ok = [ - listdata[j] - for j in range(len(listdata)) - if j not in second_deleted_original - ] - wrong_time = second_deleted_original - else: - data_with_time_ok = [ - data_with_time[j] - for j in range(len(data_with_time)) - if j not in wrong_time - ] - return data_with_time_ok, no_time, wrong_time - - -def savecsv(listdata, outputfile): - # 处理数字转换 - processed = [] - for row in listdata: - new_row = [] - for item in row: - if isinstance(item, (int, float)): - new_row.append(int(item)) - else: - new_row.append(item) - processed.append(new_row) - - # 写入CSV文件 - with open(outputfile, "w", newline="") as f: - csv.writer(f).writerows(processed) - print(f"已保存至{outputfile}") - - -def find_csv_files(root_dir): - csv_files = [] - for root, dirs, files in os.walk(root_dir): - for file in files: - if file.lower().endswith(".csv"): - csv_path = os.path.join(root, file) - csv_files.append(csv_path) - return csv_files - - -def easydata2data(easydata): - # 测试用函数 - # easydata格式:[[[序号,数量][序号,数量][序号,数量]],[[序号,数量][序号,数量][序号,数量]],结果],没有的序号和数量留-1,序号是真实序号 - datalist = [0] * MONSTER_NUM * 2 - for i in easydata[0]: - if i[0] > 0: - datalist[i[0] - 1] = i[1] - for i in easydata[1]: - if i[0] > 0: - datalist[i[0] - 1 + MONSTER_NUM] = i[1] - datalist.extend(easydata[2]) - return datalist - - -def find_where_from(easydata, floder_path): - # easydata格式:[[[序号,数量][序号,数量][序号,数量]],[[序号,数量][序号,数量][序号,数量]],结果],没有的序号和数量留-1,序号是真实序号 - datalist = [0] * MONSTER_NUM * 2 - from_list = [] - for i in easydata[0]: - if i[0] > 0: - datalist[i[0] - 1] = i[1] - for i in easydata[1]: - if i[0] > 0: - datalist[i[0] - 1 + MONSTER_NUM] = i[1] - datalist.extend(easydata[2]) - print(datalist) - csvlist = find_csv_files(floder_path) - for c in csvlist: - print(c) - for c in csvlist: - print(f"正在检查:{c}…………………………") - lines_num = MONSTER_NUM * 2 - datafull = [] - row_id = 0 - with open(c, "r") as file: - csv_reader = csv.reader(file) - for row in csv_reader: - if ( - isfloat(row[0]) - and "" not in row[:lines_num] - and len(row) > lines_num - ): - numbers = list( - map(int, map(float, row[:lines_num])) - ) # 转换为整数列表 - vals = [row[lines_num]] - if datalist == numbers + vals: - from_list.append([c, row_id + 1]) - print(f"数据来源于:{c},第{row_id+1}行!") - row_id += 1 - str_from = "" - if from_list != []: - str_from = "\n".join( - [i[0] + "第:" + str(i[1]) + "行" for i in from_list] - ) - print(f"可能的数据来源:{str_from}") - - -def is_distance_not_over_60(a, b, c, d): - # a, b = interval1 - # c, d = interval2 - # 判断区间是否有交集 - if max(a, c) <= min(b, d): - return True # 有交集时距离为0,未超过60 - # 计算不重叠时的间隔 - if b < c: - distance = c - b # interval1在左,interval2在右 - else: - distance = a - d # interval2在左,interval1在右 - return distance <= 60 - - -def is_list_true_np(fulllist): - cost_list = [ - [2, 0], - [2, 0.1], - [7, 0], - [7, 0], - [3, 0.1], - [10, 0], - [25, 15], - [22, 0], - [25, 100], - [7, 0], - [5, 0.2], - [7, 0], - [2, 0], - [15, 2], - [13, 0], - [12, 1.5], - [6, 0.2], - [18, 3], - [15, 3], - [18, 1], - [11, 0], - [10, 1], - [16, 0], - [5, 0.5], - [15, 2], - [14, 0], - [30, 0], - [35, 100], - [-1, -1], - [-1, -1], - [-1, -1], - [6, 0.5], - [6, 0], - [16, 0], - [15, 5], - [11, 0], - [26, 0], - [15, 0], - [4, 0.1], - [10, 0], - [21, 0], - [5, 0.2], - [18, 0], - [9, 1.5], - [8, 0.5], - [16, 0], - [21, 0], - [7, 0], - [36, 10], - [10, 2], - [30, 15], - [25, 0], - [27, 0], - [32, 6], - [25, 50], - [15, 5], - ] - round_cost_list = [ - [50, 70], - [70, 90], - [90, 110], - [110, 130], - [120, 160], - [140, 180], - [160, 200], - [170, 230], - [190, 250], - [210, 270], - ] - - # Convert to numpy arrays - cost_arr = np.array(cost_list) - round_cost_arr = np.array(round_cost_list) - round_low = round_cost_arr[:, 0] - round_high = round_cost_arr[:, 1] - - # Validity mask for cost entries not equal to [-1, -1] - valid_mask = np.all(cost_arr != [-1, -1], axis=1) - - # Split the input into left and right parts - fulllist_np = np.array([i[:112] for i in fulllist], dtype=np.float64) - N = fulllist_np.shape[0] - left_part = fulllist_np[:, :56] - right_part = fulllist_np[:, 56:112] - - # Calculate valid entries (cost not [-1,-1] and count >0) - valid_left = valid_mask[np.newaxis, :] & (left_part > 0) - valid_right = valid_mask[np.newaxis, :] & (right_part > 0) - - # Compute mincostL and maxcostL for left - left_min_terms = ( - (left_part - 1) * cost_arr[np.newaxis, :, 0] - + ((left_part - 1) * (left_part - 2) * cost_arr[np.newaxis, :, 1]) / 2 - + 0.01 - ) * valid_left - mincostL = left_min_terms.sum(axis=1) - - left_max_terms = ( - (left_part + 1) * cost_arr[np.newaxis, :, 0] - + (left_part * (left_part + 1) * cost_arr[np.newaxis, :, 1]) / 2 - - 0.01 - ) * valid_left - maxcostL = left_max_terms.sum(axis=1) - - # Compute mincostR and maxcostR for right - right_min_terms = ( - (right_part - 1) * cost_arr[np.newaxis, :, 0] - + ((right_part - 1) * (right_part - 2) * cost_arr[np.newaxis, :, 1]) - / 2 - + 0.01 - ) * valid_right - mincostR = right_min_terms.sum(axis=1) - - right_max_terms = ( - (right_part + 1) * cost_arr[np.newaxis, :, 0] - + (right_part * (right_part + 1) * cost_arr[np.newaxis, :, 1]) / 2 - - 0.01 - ) * valid_right - maxcostR = right_max_terms.sum(axis=1) - - # Check overlap with round costs - left_low = np.maximum(mincostL[:, np.newaxis], round_low) - left_high = np.minimum(maxcostL[:, np.newaxis], round_high) - left_cond = left_low <= left_high - - right_low = np.maximum(mincostR[:, np.newaxis], round_low) - right_high = np.minimum(maxcostR[:, np.newaxis], round_high) - right_cond = right_low <= right_high - - both_cond = left_cond & right_cond - any_round = np.any(both_cond, axis=1) - - # Get indices where no round condition is satisfied - false_indices = np.where(~any_round)[0].tolist() - return false_indices - - -def is_list_true(onelist): - roundlist = [] - # 费用和附加费用,写死在代码里吧,不想读文件了。 - cost_list = [ - [2, 0], - [2, 0.1], - [7, 0], - [7, 0], - [3, 0.1], - [10, 0], - [25, 15], - [22, 0], - [25, 100], - [7, 0], - [5, 0.2], - [7, 0], - [2, 0], - [15, 2], - [13, 0], - [12, 1.5], - [6, 0.2], - [18, 3], - [15, 3], - [18, 1], - [11, 0], - [10, 1], - [16, 0], - [5, 0.5], - [15, 2], - [14, 0], - [30, 0], - [35, 100], - [-1, -1], - [-1, -1], - [-1, -1], - [6, 0.5], - [6, 0], - [16, 0], - [15, 5], - [11, 0], - [26, 0], - [15, 0], - [4, 0.1], - [10, 0], - [21, 0], - [5, 0.2], - [18, 0], - [9, 1.5], - [8, 0.5], - [16, 0], - [21, 0], - [7, 0], - [36, 10], - [10, 2], - [30, 15], - [25, 0], - [27, 0], - [32, 6], - [25, 50], - [15, 5], - ] - # - round_cost_list = [ - [50, 70], - [70, 90], - [90, 110], - [110, 130], - [120, 160], - [140, 180], - [160, 200], - [170, 230], - [190, 250], - [210, 270], - ] - left = onelist[:MONSTER_NUM] - right = onelist[MONSTER_NUM : MONSTER_NUM * 2] - # result = onelist[MONSTER_NUM*2] - # print(left,right,result) - mincostL = sum( - [ - (left[i] - 1) * cost_list[i][0] - + (left[i] - 1) * (left[i] - 2) * cost_list[i][1] / 2 - + 0.01 - for i in range(len(left)) - if (cost_list[i] != [-1, -1]) and (left[i] > 0) - ] - ) - maxcostL = sum( - [ - (left[i] + 1) * cost_list[i][0] - + left[i] * (left[i] + 1) * cost_list[i][1] / 2 - - 0.01 - for i in range(len(left)) - if (cost_list[i] != [-1, -1]) and (left[i] > 0) - ] - ) - mincostR = sum( - [ - (right[i] - 1) * cost_list[i][0] - + (right[i] - 1) * (right[i] - 2) * cost_list[i][1] / 2 - + 0.01 - for i in range(len(right)) - if (cost_list[i] != [-1, -1]) and (right[i] > 0) - ] - ) - maxcostR = sum( - [ - (right[i] + 1) * cost_list[i][0] - + right[i] * (right[i] + 1) * cost_list[i][1] / 2 - - 0.01 - for i in range(len(right)) - if (cost_list[i] != [-1, -1]) and (right[i] > 0) - ] - ) - print(mincostL, maxcostL, mincostR, maxcostR) - for i in range(len(round_cost_list)): - if max(mincostL, round_cost_list[i][0]) <= min( - maxcostL, round_cost_list[i][1] - ) and max(mincostR, round_cost_list[i][0]) <= min( - maxcostR, round_cost_list[i][1] - ): - roundlist.append(i) - if roundlist != []: - return True - else: - print(f"{onelist}is not true!!!") - return False - # return is_distance_not_over_60(mincostL,maxcostL,mincostR,maxcostR) - - -def recognize_review( - data, img_floder, matched_threshold=0.1, ocr_threshold=0.5 -): - print("正在进行识别数据检查") - print("data行数:", len(data)) - ref_row = [0] * (recognize.MONSTER_COUNT * 2) - need_delete = [False] * len(data) - for idx, row in tqdm.tqdm( - enumerate(data), total=len(data), desc="Processing rows" - ): - ref_row = [0] * (recognize.MONSTER_COUNT * 2) - try: - img_name = row[recognize.MONSTER_COUNT * 2 + 1] - img_path = img_floder / Path(img_name) - if not img_path.exists(): - print(f"未找到对应的图像: {img_name} ") - continue - img = cv2.imread(img_path) - main_roi = ((0, 0), (img.shape[1], img.shape[0])) - results = recognize.process_regions( - main_roi, img, matched_threshold, ocr_threshold - ) - # 处理结果 - for res in results: - if "error" in res: - print( - f"识别失败 行号: {idx}, 图片: {img_name}, 错误类型: {res['error']}", - file=sys.stderr, - ) - break - if res["matched_id"]: - if res["region_id"] < 3: - ref_row[res["matched_id"] - 1] = int(res["number"]) - else: - ref_row[res["matched_id"] - 1 + MONSTER_NUM] = int( - res["number"] - ) - else: - # 检查数据行是否与参考行匹配 - data_row = row[0 : recognize.MONSTER_COUNT * 2] - if data_row != ref_row: - print( - f"找到不匹配的数据行: {idx} 行,对应图片文件: {img_name}", - file=sys.stderr, - ) - print(f"识别结果 : {ref_row}", file=sys.stderr) - print(f"文件数据 : {data_row}", file=sys.stderr) - need_delete[idx] = True - else: - need_delete[idx] = False - except Exception as e: - logging.exception(f"Error processing line {idx}", e) - need_delete[idx] = True - newdata = [row for idx, row in enumerate(data) if not need_delete[idx]] - deleted = [idx for idx, del_flag in enumerate(need_delete) if del_flag] - return newdata, deleted - - -# newdata,deleted,ori_len = read_and_remove_zeros('0502.csv',MONSTER_NUM=56) -# _,inc = remove_duplicate_subsequences() -# print('数据例:',newdata[:3]) -# result,deleted2 = do_duplicate(newdata) -# print(deleted,deleted2) -# dt = ori_pos(ori_len,deleted,deleted2) -# print(dt) -# print('筛选后数据总长度:',len(result)) -# view_monster_counts(newdata) -# del_duplicate_by_time(newdata) - - -def process_full( - filename, - do_remove_duplicate_subsequences=False, - delete_no_time=True, - open_black_list=True, - re_recognize_imgs=False, - img_floder="", - matched_threshold=0.1, - ocr_threshold=0.5, -): - wrong_type_list = [] - newdata, deleted0, ori_len = read_and_remove_zeros( - filename, MONSTER_NUM=56 - ) - deleted1 = [] - if do_remove_duplicate_subsequences: - newdata, deleted1 = do_duplicate(newdata) - newdata, deleted2, deleted3 = del_duplicate_by_time( - newdata, delete_no_time - ) - if not delete_no_time: - deleted2 = [] - black_listed, deleted4, deleted5, newdata = view_monster_counts(newdata) - deleted6 = [] - if re_recognize_imgs: - newdata, deleted6 = recognize_review( - newdata, img_floder, matched_threshold, ocr_threshold - ) - deleted7 = [] - if open_black_list: - newdata, deleted7 = process_black_list(newdata) - - dl = deleted0 - flag = 0 - for i in [ - deleted1, - deleted2, - deleted3, - deleted4, - deleted5, - deleted6, - deleted7, - ]: - if i != []: - dl, secori = ori_pos(ori_len, dl, i) - if flag == 0: - wrong_type_list.append( - ["不合法的数据:", merge([i + 1 for i in deleted0])] - ) - wrong_type_list.append( - ["重复出现的连续数据*:", merge([i + 1 for i in secori])] - ) - elif flag == 1: - wrong_type_list.append( - ["未包含时间轴的数据:", merge([i + 1 for i in secori])] - ) - elif flag == 2: - wrong_type_list.append( - ["时间轴信息重复的数据:", merge([i + 1 for i in secori])] - ) - elif flag == 3: - wrong_type_list.append( - ["怪物信息错误的数据:", merge([i + 1 for i in secori])] - ) - elif flag == 4: - wrong_type_list.append( - [ - "不符合出怪权重规则的数据:", - merge([i + 1 for i in secori]), - ] - ) - elif flag == 5: - wrong_type_list.append( - ["经图片识别错误的数据*:", merge([i + 1 for i in secori])] - ) - elif flag == 6: - wrong_type_list.append( - ["黑名单内数据:", merge([i + 1 for i in secori])] - ) - flag += 1 - return black_listed, newdata, dl, wrong_type_list - - -def test1(): - black_listed, newdata, dl, wrong_type_list = process_full( - "0502processed.csv" - ) - dllist = [i + 1 for i in dl] - print(f"删除了{dllist}行的数据") - for i in wrong_type_list: - print(i) - savecsv(newdata, "0502processed2.csv") - - -def process_floder( - flodername, - savefilename, - lastsavefilename, - do_remove_duplicate_subsequences=True, - delete_no_time=True, - open_black_list=True, - re_recognize_imgs=False, - img_floder="", - matched_threshold=0.1, - ocr_threshold=0.5, -): - """ - 输入: - flodername:需要处理的文件夹名 - savefilename:全部整合保存到的文件名(不进行总去重) - lastsavefilename:全部整合并去重保存到的最终文件名 - do_remove_duplicate_subsequences:是否清理连续3个以上重复元素的重复序列 - delete_no_time:是否删除没有时间戳的数据行 - """ - global black_list_rows - full_data_list = [] - csvlist = find_csv_files(flodername) - for csv in csvlist: - print(csv) - for csv in csvlist: - print(f"正在处理:{csv}…………………………") - black_listed, newdata, dl, wrong_type_list = process_full( - csv, - do_remove_duplicate_subsequences, - delete_no_time, - open_black_list, - re_recognize_imgs, - img_floder, - matched_threshold, - ocr_threshold, - ) - dllist = [i + 1 for i in dl] - print(f"删除了{merge(dllist)}行的数据") - for i in wrong_type_list: - print(i) - if not black_listed: - # 未进黑名单则合并至全部数据 - full_data_list += newdata - else: - print(f"该数据为30人局数据,自动进入黑名单,不计入总数据!") - if len(newdata) < 5000: # 不是整合数据 - black_list_rows += newdata - savecsv(full_data_list, savefilename) - black_listed, newdata, dl, wrong_type_list = process_full( - savefilename, - do_remove_duplicate_subsequences, - delete_no_time, - open_black_list, - re_recognize_imgs, - img_floder, - matched_threshold, - ocr_threshold, - ) - # 保存后再总处理去重 - dllist = [i + 1 for i in dl] - print(f"删除了{merge(dllist)}行的数据") - for i in wrong_type_list: - print(i) - savecsv(newdata, lastsavefilename) - - -def process_black_list(full_data): - # 黑名单里所有的数据检测到重复的就删 - global black_list_rows - delete_rows = [] - ok_data = [] - idx = 0 - for i in full_data: - if i in black_list_rows: - delete_rows.append(idx) - else: - ok_data.append(i) - idx += 1 - print(f"黑名单内数据:{merge(delete_rows)}") - return ok_data, delete_rows - - -def process_file( - filename, - savefilename, - do_remove_duplicate_subsequences=True, - delete_no_time=True, - open_black_list=True, - re_recognize_imgs=False, - img_floder="", - matched_threshold=0.1, - ocr_threshold=0.5, -): - """ - 输入: - filename:需要处理的文件名 - savefilename:处理后保存到的文件名 - do_remove_duplicate_subsequences:是否清理连续3个以上重复元素的重复序列 - delete_no_time:是否删除没有时间戳的数据行 - """ - black_listed, newdata, dl, wrong_type_list = process_full( - filename, - do_remove_duplicate_subsequences, - delete_no_time, - open_black_list, - re_recognize_imgs, - img_floder, - matched_threshold, - ocr_threshold, - ) - # 保存后再总处理去重 - dllist = [i + 1 for i in dl] - print(f"删除了{merge(dllist)}行的数据") - for i in wrong_type_list: - print(i) - savecsv(newdata, savefilename) - - -# process_floder(r'D:\Backup\Downloads\arcdata','arcdata_fullaa.csv','arcdata_full_washed_plus.csv') - -import tkinter as tk -from tkinter import ttk, filedialog, messagebox -import sys -import threading -import queue - - -class RedirectText(object): - def __init__(self, text_widget, log_file="processing.log"): - self.text_widget = text_widget - self.log_file = log_file - self.queue = queue.Queue() - self.root = text_widget.master - self.lock = threading.Lock() - - # 初始化日志文件 - self.setup_logfile() - - def setup_logfile(self): - try: - # 使用追加模式打开日志文件 - self.log_fd = open(self.log_file, "a", encoding="utf-8") - except Exception as e: - self.log_fd = None - self.write(f"无法打开日志文件: {str(e)}\n") - - def write(self, message): - # 写入日志文件(带线程锁) - with self.lock: - if self.log_fd: - try: - self.log_fd.write(message) - self.log_fd.flush() # 确保立即写入磁盘 - except Exception as e: - self.log_fd = None - self.queue.put(f"日志写入失败: {str(e)}\n") - - # 写入队列供界面显示 - self.queue.put(message) - self.root.after(100, self.update_text) - - def update_text(self): - while not self.queue.empty(): - msg = self.queue.get_nowait() - self.text_widget.insert(tk.END, msg) - self.text_widget.see(tk.END) - - def flush(self): - pass - - def close_logfile(self): - with self.lock: - if self.log_fd: - self.log_fd.close() - self.log_fd = None - - -class ProcessingThread(threading.Thread): - def __init__(self, func, args=(), kwargs={}, callback=None): - super().__init__() - self.func = func - self.args = args - self.kwargs = kwargs - self.callback = callback - self.daemon = True - self.exception = None - - def run(self): - try: - self.func(*self.args, **self.kwargs) - except Exception as e: - self.exception = e - finally: - if self.callback: - self.callback(self.exception) - - -def create_gui(): - root = tk.Tk() - root.title("数据搅拌机") - root.geometry("800x600") - - # 在此处定义关闭事件处理函数(推荐位置) - def on_close(): - sys.stdout.close_logfile() # 关闭日志文件 - if messagebox.askokcancel( - "退出", "确定要退出程序吗?" - ): # 添加确认对话框 - root.destroy() # 销毁窗口 - - # 绑定关闭事件处理 - root.protocol("WM_DELETE_WINDOW", on_close) - - # 创建文本输出区域 - output_text = tk.Text(root, wrap=tk.WORD) - output_text.grid( - row=3, column=0, columnspan=2, padx=10, pady=10, sticky="nsew" - ) - sys.stdout = RedirectText(output_text, "data_processing.log") - - # 处理文件夹的Frame - folder_frame = ttk.LabelFrame( - root, - text="处理文件夹(处理文件夹及其所有子文件夹下的CSV文件,并合并为一个)", - ) - folder_frame.grid(row=0, column=0, padx=10, pady=5, sticky="ew") - - # 处理文件夹的组件 - ttk.Label(folder_frame, text="选择文件夹:").grid( - row=0, column=0, padx=5, sticky="w" - ) - folder_path = tk.StringVar() - folder_entry = ttk.Entry(folder_frame, textvariable=folder_path, width=40) - folder_entry.grid(row=0, column=1, padx=5) - ttk.Button( - folder_frame, - text="浏览", - command=lambda: folder_path.set(filedialog.askdirectory()), - ).grid(row=0, column=2, padx=5) - - ttk.Label(folder_frame, text="中间保存文件(不进行最终去重):").grid( - row=1, column=0, padx=5, sticky="w" - ) - interim_save = tk.StringVar() - ttk.Entry(folder_frame, textvariable=interim_save, width=40).grid( - row=1, column=1, padx=5 - ) - ttk.Button( - folder_frame, - text="浏览", - command=lambda: interim_save.set( - filedialog.asksaveasfilename( - defaultextension=".csv", - filetypes=[("CSV文件", "*.csv"), ("所有文件", "*.*")], - ) - ), - ).grid(row=1, column=2, padx=5) - - ttk.Label(folder_frame, text="最终保存文件:").grid( - row=2, column=0, padx=5, sticky="w" - ) - final_save = tk.StringVar() - ttk.Entry(folder_frame, textvariable=final_save, width=40).grid( - row=2, column=1, padx=5 - ) - ttk.Button( - folder_frame, - text="浏览", - command=lambda: final_save.set( - filedialog.asksaveasfilename( - defaultextension=".csv", - filetypes=[("CSV文件", "*.csv"), ("所有文件", "*.*")], - ) - ), - ).grid(row=2, column=2, padx=5) - - # 复选框 - remove_dup = tk.BooleanVar(value=False) - ttk.Checkbutton( - folder_frame, - text="不依赖时间戳清理重复子序列(在大数据集会非常慢,通常关闭)", - variable=remove_dup, - ).grid(row=3, column=0, columnspan=3, sticky="w") - - del_time = tk.BooleanVar(value=True) - ttk.Checkbutton( - folder_frame, text="删除无时间戳数据", variable=del_time - ).grid(row=4, column=0, columnspan=3, sticky="w") - - open_black = tk.BooleanVar(value=True) - ttk.Checkbutton( - folder_frame, - text="将黑名单文件内的所有数据行同时加入黑名单", - variable=open_black, - ).grid(row=5, column=0, columnspan=3, sticky="w") - - # 修改后的图片识别行(将复选框和阈值输入放在同一行) - re_recognize_var = tk.BooleanVar(value=False) - ttk.Checkbutton( - folder_frame, - text="启用图片二次识别(必须指定图片路径)", - variable=re_recognize_var, - ).grid(row=6, column=0, padx=5, sticky="w") - - # 添加匹配阈值设置 - ttk.Label(folder_frame, text="匹配阈值:").grid( - row=6, column=1, padx=(20, 5), sticky="e" - ) - matched_threshold_var = tk.DoubleVar(value=0.1) - ttk.Entry(folder_frame, textvariable=matched_threshold_var, width=6).grid( - row=6, column=2, sticky="w" - ) - - # 添加OCR阈值设置 - ttk.Label(folder_frame, text="OCR阈值:").grid( - row=6, column=3, padx=(20, 5), sticky="e" - ) - ocr_threshold_var = tk.DoubleVar(value=0.5) - ttk.Entry(folder_frame, textvariable=ocr_threshold_var, width=6).grid( - row=6, column=4, sticky="w" - ) - - # 调整后续行号(原row=6改为row=7开始) - ttk.Label(folder_frame, text="图片文件夹路径:").grid( - row=7, column=0, padx=5, sticky="w" - ) - img_folder_path = tk.StringVar() - ttk.Entry(folder_frame, textvariable=img_folder_path, width=40).grid( - row=7, column=1, padx=5 - ) - ttk.Button( - folder_frame, - text="浏览", - command=lambda: img_folder_path.set(filedialog.askdirectory()), - ).grid(row=7, column=2, padx=5) - - # 调整处理文件夹按钮的行号 - - # 处理文件夹按钮 - folder_button = ttk.Button(folder_frame, text="执行处理") - folder_button.grid(row=8, column=0, columnspan=5, pady=5) - - # 处理文件的Frame - file_frame = ttk.LabelFrame(root, text="处理单个文件") - file_frame.grid(row=1, column=0, padx=10, pady=5, sticky="ew") - - # 处理文件的组件 - ttk.Label(file_frame, text="选择文件:").grid( - row=0, column=0, padx=5, sticky="w" - ) - file_path = tk.StringVar() - ttk.Entry(file_frame, textvariable=file_path, width=40).grid( - row=0, column=1, padx=5 - ) - ttk.Button( - file_frame, - text="浏览", - command=lambda: file_path.set(filedialog.askopenfilename()), - ).grid(row=0, column=2, padx=5) - - ttk.Label(file_frame, text="保存路径:").grid( - row=1, column=0, padx=5, sticky="w" - ) - save_path = tk.StringVar() - ttk.Entry(file_frame, textvariable=save_path, width=40).grid( - row=1, column=1, padx=5 - ) - ttk.Button( - file_frame, - text="浏览", - command=lambda: save_path.set( - filedialog.asksaveasfilename( - defaultextension=".csv", - filetypes=[("CSV文件", "*.csv"), ("所有文件", "*.*")], - ) - ), - ).grid(row=1, column=2, padx=5) - - # 复选框 - remove_dup_file = tk.BooleanVar(value=False) - ttk.Checkbutton( - file_frame, - text="不依赖时间戳清理重复子序列(在大数据集会非常慢,通常关闭)", - variable=remove_dup_file, - ).grid(row=2, column=0, columnspan=3, sticky="w") - - del_time_file = tk.BooleanVar(value=True) - ttk.Checkbutton( - file_frame, text="删除无时间戳数据", variable=del_time_file - ).grid(row=3, column=0, columnspan=3, sticky="w") - - open_black_file = tk.BooleanVar(value=True) - ttk.Checkbutton( - file_frame, - text="将黑名单文件内的所有数据行同时加入黑名单", - variable=open_black_file, - ).grid(row=4, column=0, columnspan=3, sticky="w") - - # 修改后的图片识别行 - re_recognize_file_var = tk.BooleanVar(value=False) - ttk.Checkbutton( - file_frame, - text="启用图片二次识别(必须指定图片路径)", - variable=re_recognize_file_var, - ).grid(row=5, column=0, padx=5, sticky="w") - - # 匹配阈值 - ttk.Label(file_frame, text="匹配阈值:").grid( - row=5, column=1, padx=(20, 5), sticky="e" - ) - matched_threshold_file_var = tk.DoubleVar(value=0.1) - ttk.Entry( - file_frame, textvariable=matched_threshold_file_var, width=6 - ).grid(row=5, column=2, sticky="w") - - # OCR阈值 - ttk.Label(file_frame, text="OCR阈值:").grid( - row=5, column=3, padx=(20, 5), sticky="e" - ) - ocr_threshold_file_var = tk.DoubleVar(value=0.5) - ttk.Entry(file_frame, textvariable=ocr_threshold_file_var, width=6).grid( - row=5, column=4, sticky="w" - ) - - # 调整后续行号 - ttk.Label(file_frame, text="图片文件夹路径:").grid( - row=6, column=0, padx=5, sticky="w" - ) - img_folder_file_path = tk.StringVar() - ttk.Entry(file_frame, textvariable=img_folder_file_path, width=40).grid( - row=6, column=1, padx=5 - ) - ttk.Button( - file_frame, - text="浏览", - command=lambda: img_folder_file_path.set(filedialog.askdirectory()), - ).grid(row=6, column=2, padx=5) - - # 调整处理文件按钮的行号 - - # 处理文件按钮 - file_button = ttk.Button(file_frame, text="执行处理") - file_button.grid(row=7, column=0, columnspan=5, pady=5) - - # 配置网格权重 - root.grid_rowconfigure(3, weight=1) - root.grid_columnconfigure(0, weight=1) - - # 按钮回调函数 - def process_folder_wrapper(): - folder = folder_path.get() - interim = interim_save.get() - final = final_save.get() - if not folder or not interim or not final: - messagebox.showerror("错误", "请填写所有路径") - return - - folder_button.config(state=tk.DISABLED) - - def callback(e): - folder_button.config(state=tk.NORMAL) - if e: - messagebox.showerror("错误", str(e)) - else: - messagebox.showinfo("完成", "文件夹处理完成") - - thread = ProcessingThread( - func=process_floder, - args=( - folder, - interim, - final, - remove_dup.get(), - del_time.get(), - open_black.get(), - re_recognize_var.get(), - Path(img_folder_path.get()), - matched_threshold_var.get(), - ocr_threshold_var.get(), - ), - callback=callback, - ) - thread.start() - - def process_file_wrapper(): - input_file = file_path.get() - output_file = save_path.get() - if not input_file or not output_file: - messagebox.showerror("错误", "请填写所有路径") - return - - file_button.config(state=tk.DISABLED) - - def callback(e): - file_button.config(state=tk.NORMAL) - if e: - messagebox.showerror("错误", str(e)) - else: - messagebox.showinfo("完成", "文件处理完成") - - thread = ProcessingThread( - func=process_file, - args=( - input_file, - output_file, - remove_dup_file.get(), - del_time_file.get(), - open_black_file.get(), - re_recognize_file_var.get(), - Path(img_folder_file_path.get()), - matched_threshold_file_var.get(), - ocr_threshold_file_var.get(), - ), - callback=callback, - ) - thread.start() - - # 绑定按钮命令 - folder_button.config(command=process_folder_wrapper) - file_button.config(command=process_file_wrapper) - - return root - - -if __name__ == "__main__": - # 请确保以下函数已经正确导入或定义: - # process_floder, process_file, find_csv_files, savecsv - - app = create_gui() - app.mainloop() diff --git a/src/ui/__init__.py b/src/ui/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/utils/__init__.py b/src/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/tools/HumanDataCheck.py b/tools/HumanDataCheck.py similarity index 58% rename from src/tools/HumanDataCheck.py rename to tools/HumanDataCheck.py index c593057..692187e 100644 --- a/src/tools/HumanDataCheck.py +++ b/tools/HumanDataCheck.py @@ -3,9 +3,6 @@ import csv import os -from src.core.paths import PROJECT_ROOT, image_path, data_path - - class ArknightsApp: def __init__(self, root): self.root = root @@ -17,15 +14,9 @@ def __init__(self, root): self.root.configure(bg=self.BG_COLOR) # 绑定快捷键 - self.root.bind( - "", lambda event: self.show_prev_row() - ) # 小键盘左键 - self.root.bind( - "", lambda event: self.show_next_row() - ) # 小键盘右键 - self.root.bind( - "", lambda event: self.delete_current_row() - ) # 删除键 + self.root.bind("", lambda event: self.show_prev_row()) # 小键盘左键 + self.root.bind("", lambda event: self.show_next_row()) # 小键盘右键 + self.root.bind("", lambda event: self.delete_current_row()) # 删除键 # 创建顶部和底部框架 self.top_frame = tk.Frame(root, bg=self.BG_COLOR) @@ -34,49 +25,28 @@ def __init__(self, root): self.bottom_frame.pack(pady=10) # 创建按钮 - btn_style = { - "bg": "#555555", - "fg": self.FG_COLOR, - "activebackground": "#777777", - "activeforeground": self.FG_COLOR, - } - self.next_button = tk.Button( - root, text="下一个", command=self.show_next_row, **btn_style - ) + btn_style = {"bg": "#555555", "fg": self.FG_COLOR, "activebackground": "#777777", "activeforeground": self.FG_COLOR} + self.next_button = tk.Button(root, text="下一个", command=self.show_next_row, **btn_style) self.next_button.pack(side=tk.RIGHT, padx=10, pady=10) - self.prev_button = tk.Button( - root, text="上一个", command=self.show_prev_row, **btn_style - ) + self.prev_button = tk.Button(root, text="上一个", command=self.show_prev_row, **btn_style) self.prev_button.pack(side=tk.RIGHT, padx=10, pady=10) - self.delete_button = tk.Button( - root, text="删除数据", command=self.delete_current_row, **btn_style - ) + self.delete_button = tk.Button(root, text="删除数据", command=self.delete_current_row, **btn_style) self.delete_button.pack(side=tk.RIGHT, padx=10, pady=10) # 添加行号显示和跳转功能 - self.row_label = tk.Label( - root, text="当前行号: 0", bg=self.BG_COLOR, fg=self.FG_COLOR - ) + self.row_label = tk.Label(root, text="当前行号: 0", bg=self.BG_COLOR, fg=self.FG_COLOR) self.row_label.pack(side=tk.LEFT, padx=10) - self.row_entry = tk.Entry( - root, - width=5, - bg="#555555", - fg=self.FG_COLOR, - insertbackground=self.FG_COLOR, - ) + self.row_entry = tk.Entry(root, width=5, bg="#555555", fg=self.FG_COLOR, insertbackground=self.FG_COLOR) self.row_entry.pack(side=tk.LEFT, padx=5) - self.jump_button = tk.Button( - root, text="跳转", command=self.jump_to_row, **btn_style - ) + self.jump_button = tk.Button(root, text="跳转", command=self.jump_to_row, **btn_style) self.jump_button.pack(side=tk.LEFT, padx=5) # 初始化数据 - self.data = self.read_csv(PROJECT_ROOT / "data" / "raw" / "arknights.csv") + self.data = self.read_csv("arknights.csv") self.current_row_index = 0 # 加载图片 @@ -91,7 +61,7 @@ def read_csv(self, file_path): with open(file_path, "r", encoding="utf-8") as csvfile: reader = csv.reader(csvfile) header = next(reader) - self.MONSTER_COUNT = sum(1 for col in header if col.endswith("L")) + self.MONSTER_COUNT = sum(1 for col in header if col.endswith('L')) for row in reader: data.append(row) return data @@ -99,12 +69,10 @@ def read_csv(self, file_path): def load_all_images(self): """加载所有图片""" images = {} - base_dir = os.path.dirname( - os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - ) - monster_csv_path = data_path("monster_greenvine.csv") - images_dir = data_path("images") - + base_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + monster_csv_path = os.path.join(base_dir, "monster_greenvine.csv") + images_dir = os.path.join(base_dir, "images") + id_to_name = {} try: with open(monster_csv_path, "r", encoding="utf-8-sig") as f: @@ -126,9 +94,7 @@ def load_all_images(self): else: # 尝试用“名称”列备用 try: - with open( - monster_csv_path, "r", encoding="utf-8-sig" - ) as f: + with open(monster_csv_path, "r", encoding="utf-8-sig") as f: reader = csv.reader(f) header = next(reader) id_idx = header.index("id") @@ -136,13 +102,9 @@ def load_all_images(self): for row in reader: if int(row[id_idx]) == i: alt_name = row[alt_name_idx] - alt_path = os.path.join( - images_dir, f"{alt_name}.png" - ) + alt_path = os.path.join(images_dir, f"{alt_name}.png") if os.path.exists(alt_path): - image = Image.open(alt_path).resize( - (80, 80) - ) + image = Image.open(alt_path).resize((80, 80)) images[str(i)] = ImageTk.PhotoImage(image) break except Exception: @@ -170,36 +132,16 @@ def show_row(self, row_index): value = float(value) if value > 0: # 仅显示非0值 if self.images.get(str(i)): - tk.Label( - self.top_frame, - image=self.images[str(i)], - bg=self.BG_COLOR, - ).grid(row=0, column=i - 1, padx=2) + tk.Label(self.top_frame, image=self.images[str(i)], bg=self.BG_COLOR).grid(row=0, column=i - 1, padx=2) else: - tk.Label( - self.top_frame, - text=f"ID:{i}", - font=("Arial", 12), - bg=self.BG_COLOR, - fg=self.FG_COLOR, - ).grid(row=0, column=i - 1, padx=2) - tk.Label( - self.top_frame, - text=str(int(value)), - font=("Arial", 16, "bold"), - bg=self.BG_COLOR, - fg=self.FG_COLOR, - ).grid(row=1, column=i - 1) + tk.Label(self.top_frame, text=f"ID:{i}", font=("Arial", 12), bg=self.BG_COLOR, fg=self.FG_COLOR).grid(row=0, column=i - 1, padx=2) + tk.Label(self.top_frame, text=str(int(value)), font=("Arial", 16, "bold"), bg=self.BG_COLOR, fg=self.FG_COLOR).grid(row=1, column=i - 1) except ValueError: - print( - f"Skipping invalid value: {row[i - 1]} at column {i - 1}" - ) + print(f"Skipping invalid value: {row[i - 1]} at column {i - 1}") # 插入空白间隔 gap_column = self.MONSTER_COUNT - 1 # 间隔列索引 - tk.Label(self.top_frame, text="", bg=self.BG_COLOR).grid( - row=0, column=gap_column, padx=50 - ) # 添加水平间距 + tk.Label(self.top_frame, text="", bg=self.BG_COLOR).grid(row=0, column=gap_column, padx=50) # 添加水平间距 # 显示右方怪物 for i in range(self.MONSTER_COUNT + 1, self.MONSTER_COUNT * 2 + 1): @@ -209,39 +151,21 @@ def show_row(self, row_index): if value > 0: # 仅显示非0值 img_idx = str(i - self.MONSTER_COUNT) if self.images.get(img_idx): - tk.Label( - self.top_frame, - image=self.images[img_idx], - bg=self.BG_COLOR, - ).grid(row=0, column=i - 1, padx=2) + tk.Label(self.top_frame, image=self.images[img_idx], bg=self.BG_COLOR).grid(row=0, column=i - 1, padx=2) else: - tk.Label( - self.top_frame, - text=f"ID:{img_idx}", - font=("Arial", 12), - bg=self.BG_COLOR, - fg=self.FG_COLOR, - ).grid(row=0, column=i - 1, padx=2) - tk.Label( - self.top_frame, - text=str(int(value)), - font=("Arial", 16, "bold"), - bg=self.BG_COLOR, - fg=self.FG_COLOR, - ).grid(row=1, column=i - 1) + tk.Label(self.top_frame, text=f"ID:{img_idx}", font=("Arial", 12), bg=self.BG_COLOR, fg=self.FG_COLOR).grid(row=0, column=i - 1, padx=2) + tk.Label(self.top_frame, text=str(int(value)), font=("Arial", 16, "bold"), bg=self.BG_COLOR, fg=self.FG_COLOR).grid(row=1, column=i - 1) except ValueError: - print( - f"Skipping invalid value: {row[i - 1]} at column {i - 1}" - ) + print(f"Skipping invalid value: {row[i - 1]} at column {i - 1}") # 清空底部框架内容 for widget in self.bottom_frame.winfo_children(): - widget.destroy() + widget.destroy() # 获取图片路径 base_dir = os.path.dirname(os.path.abspath(__file__)) img_name = row[-1] - + orig_path = os.path.join(base_dir, "images", img_name + ".jpg") res_path = os.path.join(base_dir, "images", img_name + "_result.jpg") @@ -251,11 +175,9 @@ def show_row(self, row_index): orig_path = os.path.join(base_dir, img_name + ".jpg") if not os.path.exists(orig_path): orig_path = None - + if not os.path.exists(res_path): - res_path = os.path.join( - base_dir, "images", img_name + "_result.png" - ) + res_path = os.path.join(base_dir, "images", img_name + "_result.png") if not os.path.exists(res_path): res_path = None @@ -270,78 +192,37 @@ def show_row(self, row_index): top = h * 0.8 right = w * 0.8 bottom = h - cropped_image = orig_image.crop( - (int(left), int(top), int(right), int(bottom)) - ) - + cropped_image = orig_image.crop((int(left), int(top), int(right), int(bottom))) + # 如果需要限制大小,可解除下面注释 # max_size = (800, 200) # cropped_image.thumbnail(max_size, Image.Resampling.LANCZOS) - + cropped_image_tk = ImageTk.PhotoImage(cropped_image) - tk.Label( - self.bottom_frame, image=cropped_image_tk, bg=self.BG_COLOR - ).pack(side=tk.TOP, pady=5) + tk.Label(self.bottom_frame, image=cropped_image_tk, bg=self.BG_COLOR).pack(side=tk.TOP, pady=5) self.bottom_frame.images.append(cropped_image_tk) else: - tk.Label( - self.bottom_frame, - text=f"找不到原图: {img_name}", - bg=self.BG_COLOR, - fg=self.FG_COLOR, - ).pack(side=tk.TOP, pady=5) + tk.Label(self.bottom_frame, text=f"找不到原图: {img_name}", bg=self.BG_COLOR, fg=self.FG_COLOR).pack(side=tk.TOP, pady=5) # 2. 显示 L/R 文字和色条(中间) result_text = row[self.MONSTER_COUNT * 2].strip() - tk.Label( - self.bottom_frame, - text=result_text, - font=("Arial", 20, "bold"), - bg=self.BG_COLOR, - fg=self.FG_COLOR, - ).pack(side=tk.TOP, pady=2) - + tk.Label(self.bottom_frame, text=result_text, font=("Arial", 20, "bold"), bg=self.BG_COLOR, fg=self.FG_COLOR).pack(side=tk.TOP, pady=2) + # 添加色彩长条 Canvas bar_width = 200 bar_height = 15 - color_bar = tk.Canvas( - self.bottom_frame, - width=bar_width, - height=bar_height, - highlightthickness=0, - bg=self.BG_COLOR, - ) + color_bar = tk.Canvas(self.bottom_frame, width=bar_width, height=bar_height, highlightthickness=0, bg=self.BG_COLOR) color_bar.pack(side=tk.TOP, pady=5) - - if result_text.upper() == "L": - color_bar.create_rectangle( - 0, 0, bar_width // 2, bar_height, fill="yellow", outline="" - ) - color_bar.create_rectangle( - bar_width // 2, - 0, - bar_width, - bar_height, - fill="gray", - outline="", - ) - elif result_text.upper() == "R": - color_bar.create_rectangle( - 0, 0, bar_width // 2, bar_height, fill="gray", outline="" - ) - color_bar.create_rectangle( - bar_width // 2, - 0, - bar_width, - bar_height, - fill="yellow", - outline="", - ) + + if result_text.upper() == 'L': + color_bar.create_rectangle(0, 0, bar_width // 2, bar_height, fill="yellow", outline="") + color_bar.create_rectangle(bar_width // 2, 0, bar_width, bar_height, fill="gray", outline="") + elif result_text.upper() == 'R': + color_bar.create_rectangle(0, 0, bar_width // 2, bar_height, fill="gray", outline="") + color_bar.create_rectangle(bar_width // 2, 0, bar_width, bar_height, fill="yellow", outline="") else: # 默认颜色(异常数据时) - color_bar.create_rectangle( - 0, 0, bar_width, bar_height, fill="gray", outline="" - ) + color_bar.create_rectangle(0, 0, bar_width, bar_height, fill="gray", outline="") # 3. 显示结果图(下方) if res_path: @@ -349,17 +230,10 @@ def show_row(self, row_index): max_size = (800, 400) res_image.thumbnail(max_size, Image.Resampling.LANCZOS) res_image_tk = ImageTk.PhotoImage(res_image) - tk.Label( - self.bottom_frame, image=res_image_tk, bg=self.BG_COLOR - ).pack(side=tk.TOP, pady=5) + tk.Label(self.bottom_frame, image=res_image_tk, bg=self.BG_COLOR).pack(side=tk.TOP, pady=5) self.bottom_frame.images.append(res_image_tk) else: - tk.Label( - self.bottom_frame, - text=f"找不到结果图", - bg=self.BG_COLOR, - fg=self.FG_COLOR, - ).pack(side=tk.TOP, pady=5) + tk.Label(self.bottom_frame, text=f"找不到结果图", bg=self.BG_COLOR, fg=self.FG_COLOR).pack(side=tk.TOP, pady=5) # 更新行号显示 self.row_label.config(text=f"当前行号: {row_index + 1}") @@ -398,7 +272,7 @@ def delete_current_row(self): # 获取当前行最后一列的图片路径 image_name = self.data[self.current_row_index][-1] base_dir = os.path.dirname(os.path.abspath(__file__)) - + # 删除相关的图片文件(如果存在) possible_exts = [".jpg", "_result.jpg", ".png", ""] for ext in possible_exts: @@ -409,14 +283,12 @@ def delete_current_row(self): del self.data[self.current_row_index] # 从内存中删除当前行 # 将修改后的数据写回 CSV 文件 - with open( - "arknights.csv", "w", newline="", encoding="utf-8" - ) as csvfile: + with open("arknights.csv", "w", newline="", encoding="utf-8") as csvfile: writer = csv.writer(csvfile) writer.writerow( - [f"{i}L" for i in range(1, self.MONSTER_COUNT + 1)] - + [f"{i}R" for i in range(1, self.MONSTER_COUNT + 1)] - + ["Result", "ImgPath"] + [f"{i}L" for i in range(1, self.MONSTER_COUNT + 1)] + + [f"{i}R" for i in range(1, self.MONSTER_COUNT + 1)] + + ["Result", "ImgPath"] ) writer.writerows(self.data) # 更新显示 @@ -429,4 +301,4 @@ def delete_current_row(self): if __name__ == "__main__": root = tk.Tk() app = ArknightsApp(root) - root.mainloop() + root.mainloop() \ No newline at end of file diff --git a/src/tools/battlefield_composite/.gitignore b/tools/battlefield_composite/.gitignore similarity index 100% rename from src/tools/battlefield_composite/.gitignore rename to tools/battlefield_composite/.gitignore diff --git a/src/tools/battlefield_composite/battlefield_composite.py b/tools/battlefield_composite/battlefield_composite.py similarity index 87% rename from src/tools/battlefield_composite/battlefield_composite.py rename to tools/battlefield_composite/battlefield_composite.py index becd82c..58dd16e 100644 --- a/src/tools/battlefield_composite/battlefield_composite.py +++ b/tools/battlefield_composite/battlefield_composite.py @@ -67,9 +67,7 @@ def get_random_png_frame(png_folder): # 随机选择一个png文件 random_png = random.choice(png_list) print(f"随机选择的PNG文件: {random_png}") - frame = cv2.imread( - str(random_png), cv2.IMREAD_UNCHANGED - ) # Read with alpha channel + frame = cv2.imread(str(random_png), cv2.IMREAD_UNCHANGED) # Read with alpha channel if frame is None: raise Exception(f"无法读取PNG文件: {random_png}") return frame @@ -125,10 +123,7 @@ def compose_frame(frame, background, x, y): # 进行alpha混合 for c in range(0, 3): - roi[:, :, c] = ( - roi[:, :, c] * (1 - alpha_channel) - + overlay_colors[:, :, c] * alpha_channel - ) + roi[:, :, c] = roi[:, :, c] * (1 - alpha_channel) + overlay_colors[:, :, c] * alpha_channel # 将结果放回原图 background[y_start:y_end, x_start:x_end] = roi @@ -138,9 +133,7 @@ def compose_frame(frame, background, x, y): def composite_random_frame(): # 读取战场背景图 - battlefield = cv2.imread( - "./tools/battlefield_composite/monster_images/IM-1.png" - ) + battlefield = cv2.imread("./tools/battlefield_composite/monster_images/IM-1.png") battlefield = cv2.resize(battlefield, (1920, 1080)) if battlefield is None: raise Exception("无法读取战场背景图") @@ -163,9 +156,7 @@ def composite_random_frame(): for i in range(10): x, y = frame_list[i] - frame = get_random_png_frame( - "./tools/battlefield_composite/monster_images/Arc_Frontliner_Leader-Move" - ) + frame = get_random_png_frame("./tools/battlefield_composite/monster_images/Arc_Frontliner_Leader-Move") # 缩放 factor = (y / bg_height) * 0.4 + 0.6 @@ -182,16 +173,9 @@ def composite_random_frame(): ellipse_x = int(x + center[0]) ellipse_y = int(y + center[1] + new_frame_height * 0.30) black = (0, 0, 0) - cv2.ellipse( - battlefield, - (ellipse_x, ellipse_y), - (int(new_frame_width * 0.100), int(new_frame_height * 0.025)), - 0, - 0, - 360, - black, - -1, - ) + cv2.ellipse(battlefield, (ellipse_x, ellipse_y), + (int(new_frame_width * 0.100), int(new_frame_height * 0.025)), + 0, 0, 360, black, -1) # 画框 cv2.rectangle(battlefield, (x, y), (x + x1, y + y1), (0, 255, 0), 2) @@ -212,10 +196,9 @@ def composite_random_frame(): # 将渐变掩码应用到图像上 battlefield = compose_frame(gradient_mask, battlefield, 0, 0) + # 保存结果 - cv2.imwrite( - "./tools/battlefield_composite/battlefield_composite.png", battlefield - ) + cv2.imwrite("./tools/battlefield_composite/battlefield_composite.png", battlefield) def crop_to_bounding_box(image): @@ -231,9 +214,7 @@ def crop_to_bounding_box(image): # 检查图像是否包含alpha通道 if image.shape[2] < 4: # 如果没有alpha通道,则无法进行基于透明度的裁切 - print( - "警告: 图像不包含alpha通道,无法进行基于透明度的裁切。返回原图。" - ) + print("警告: 图像不包含alpha通道,无法进行基于透明度的裁切。返回原图。") return image # 获取alpha通道 @@ -253,7 +234,7 @@ def crop_to_bounding_box(image): x, y, w, h = cv2.boundingRect(coords) # 裁切图像 - cropped_image = image[y : y + h, x : x + w] + cropped_image = image[y:y+h, x:x+w] center_x = image.shape[1] / 2 - x center_y = image.shape[0] / 2 - y center = (center_x, center_y) diff --git a/tools/battlefield_composite/extract_webm_frames.py b/tools/battlefield_composite/extract_webm_frames.py new file mode 100644 index 0000000..ca85e6a --- /dev/null +++ b/tools/battlefield_composite/extract_webm_frames.py @@ -0,0 +1,92 @@ +import logging +from pathlib import Path +import subprocess +import os + + +monster_name = { + "弧光锋卫长" : "Arc_Frontliner_Leader", + "炮击组长" : "Mortar_Gunner_Leader", + "复仇者" : "Hateful_Avenger", + "重装防御者" : "Heavy_Defender", + "“庞贝”" : "Pompeii", + "冰原术师" : "Icefield_Caster", + "沸血骑士团精锐" : "Bloodboil_Knightclub_Elite", + "高塔术师" : "Spire_Caster", + "固海凿石者" : "Ocean_Stonecutter", + # "呼啸骑士团学徒" : "Roar_Knightclub_Trainee", + "湖畔志愿者" : "Lakeside_Volunteer", + "杰斯顿·威廉姆斯" : "Jesselton_Williams", + "酸液源石虫·α" : "Acid_Originium_Slug_α", + "神射手囚犯" : "Elite_Sniper_Prisoner", + "拳手囚犯" : "Pugilist_Prisoner", + "染污躯壳" : "Tainted_Carcass", + "泥岩巨像" : "Mudrock_Colossus", + "狂暴的猎狗pro" : "Rabid_Hound_Pro", + "宿主拾荒者" : "Possessed_Veteran_Junkman", + "狂暴宿主组长" : "Enraged_Possessed_Leader", + "萨卡兹大剑手" : "Sarkaz_Greatswordsman", + "矿脉守卫" : "Vein_Guardian", + "山海众窥魅人" : "Shanhaizhong_Seer", + "提亚卡乌好战者" : "Tiacauh_Fanatic", + "码头水手" : "Dockworker", + "变异巨岩蛛" : "Mutant_Giant_Rock_Spider", + "萨卡兹子裔链术师" : "Sarkaz_Heirbearer_Chain_Caster", + "温顺的武装驮兽" : "Armored_Burdenbeast", + "木裂战士" : "Shattered_Champion", + "深溟裂礁者" : "Nethersea_Reefbreaker", + "山雪鬼" : "Tschäggättä", + "高普尼克" : "Gopnik", + "冰爆源石虫" : "Infused_Glacial_Originium_Slug", + "反装甲步兵" : "Anti-Armor_Infantry", + "“钳钳生风”" : "Consortium_of_Pincers", + "富营养的穿刺者" : "Nourished_Piercer", + "高级武装人员" : "Senior_Armed_Militant", + "朗姆酒推荐者" : "Rum_Connoisseur", + "烈酒级醒酒助手" : "Whiskey-Grade_Waker-Upper", + "萨卡兹王庭军术师" : "Sarkaz_Royal_Court_Caster", + # "灰尾香主" : "Greytail_Leader", + "阵地击人手" : "Field_Bludgeoner", + "源石畸变体" : "Originiutant", + "提亚卡乌破坏王" : "Tiacauh_Annihilator", + "逐腐兽" : "Rotchaser", + "高能源石虫" : "Infused_Originium_Slug", + "风情街“星术师”" : "Fashion_Street_Stellar_Caster", + "田鼷力士" : "Fieldmus_Bruiser", + "残党萨克斯手" : "Remnant_Saxophonist", + "散华骑士团学徒" : "Nova_Knightclub_Trainee", + "“阿咬”" : "Bitey", + # "“门”" : "", + "“投石机”" : "Catapult", + # "“复仇者”" : '"Hateful Avenger"', + # "扎罗,“狼之主”" : "Zaaro", + # "“自在”" : "Free", + # "灼热源石虫" : "Blazing_Originium_Slug", + # "萨卡兹子裔责罚者" : "Sarkaz_Heirbearer_Punisher", + # "" : "", +} + +def extract_webm(webm_path: Path, output_folder: Path): + extract_webm_cmd = f"ffmpeg -c:v libvpx -i \"{webm_path}\" \"{output_folder}/frame%d.png\"" + subprocess.run(extract_webm_cmd, shell=True, check=True) + + +def main(): + webm_folder = "./tools/battlefield_composite/monster_images" + for webm_path in Path(webm_folder).glob("*.webm"): + name_split = webm_path.parts[-1].split("-") + print(name_split) + if (name := monster_name.get(name_split[0])) is not None: + output_directory = webm_path.parent / (name + "-" + name_split[3]) + print(output_directory) + if not output_directory.exists(): + output_directory.mkdir(exist_ok=True) + extract_webm(webm_path, output_directory) + else: + logging.warning(f"{output_directory} already exists") + else: + logging.error(f"Name: {name_split[0]} not found!") + + +if __name__ == "__main__": + main() diff --git a/src/tools/battlefield_composite/monster_images/IM-1.png b/tools/battlefield_composite/monster_images/IM-1.png similarity index 100% rename from src/tools/battlefield_composite/monster_images/IM-1.png rename to tools/battlefield_composite/monster_images/IM-1.png diff --git a/src/tools/battlefield_composite/monster_images/battlefield_empty.jpg b/tools/battlefield_composite/monster_images/battlefield_empty.jpg similarity index 100% rename from src/tools/battlefield_composite/monster_images/battlefield_empty.jpg rename to tools/battlefield_composite/monster_images/battlefield_empty.jpg diff --git "a/src/tools/battlefield_composite/monster_images/\342\200\234\345\244\215\344\273\207\350\200\205\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\342\200\234\345\244\215\344\273\207\350\200\205\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\342\200\234\345\244\215\344\273\207\350\200\205\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\342\200\234\345\244\215\344\273\207\350\200\205\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\342\200\234\345\272\236\350\264\235\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\342\200\234\345\272\236\350\264\235\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\342\200\234\345\272\236\350\264\235\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\342\200\234\345\272\236\350\264\235\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\342\200\234\346\212\225\347\237\263\346\234\272\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-A_Move-x1.webm" "b/tools/battlefield_composite/monster_images/\342\200\234\346\212\225\347\237\263\346\234\272\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-A_Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\342\200\234\346\212\225\347\237\263\346\234\272\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-A_Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\342\200\234\346\212\225\347\237\263\346\234\272\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-A_Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\342\200\234\350\207\252\345\234\250\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\342\200\234\350\207\252\345\234\250\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\342\200\234\350\207\252\345\234\250\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\342\200\234\350\207\252\345\234\250\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\342\200\234\351\222\263\351\222\263\347\224\237\351\243\216\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\342\200\234\351\222\263\351\222\263\347\224\237\351\243\216\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\342\200\234\351\222\263\351\222\263\347\224\237\351\243\216\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\342\200\234\351\222\263\351\222\263\347\224\237\351\243\216\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\342\200\234\351\227\250\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\342\200\234\351\227\250\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\342\200\234\351\227\250\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\342\200\234\351\227\250\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\342\200\234\351\230\277\345\222\254\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\342\200\234\351\230\277\345\222\254\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\342\200\234\351\230\277\345\222\254\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\342\200\234\351\230\277\345\222\254\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\345\206\260\345\216\237\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\345\206\260\345\216\237\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\345\206\260\345\216\237\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\345\206\260\345\216\237\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\345\206\260\347\210\206\346\272\220\347\237\263\350\231\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\345\206\260\347\210\206\346\272\220\347\237\263\350\231\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\345\206\260\347\210\206\346\272\220\347\237\263\350\231\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\345\206\260\347\210\206\346\272\220\347\237\263\350\231\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\345\217\215\350\243\205\347\224\262\346\255\245\345\205\265-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_A-x1.webm" "b/tools/battlefield_composite/monster_images/\345\217\215\350\243\205\347\224\262\346\255\245\345\205\265-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_A-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\345\217\215\350\243\205\347\224\262\346\255\245\345\205\265-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_A-x1.webm" rename to "tools/battlefield_composite/monster_images/\345\217\215\350\243\205\347\224\262\346\255\245\345\205\265-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_A-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\345\217\230\345\274\202\345\267\250\345\262\251\350\233\233-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\345\217\230\345\274\202\345\267\250\345\262\251\350\233\233-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\345\217\230\345\274\202\345\267\250\345\262\251\350\233\233-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\345\217\230\345\274\202\345\267\250\345\262\251\350\233\233-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\345\221\274\345\225\270\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\345\221\274\345\225\270\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\345\221\274\345\225\270\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\345\221\274\345\225\270\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\345\233\272\346\265\267\345\207\277\347\237\263\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\345\233\272\346\265\267\345\207\277\347\237\263\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\345\233\272\346\265\267\345\207\277\347\237\263\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\345\233\272\346\265\267\345\207\277\347\237\263\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\345\244\215\344\273\207\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\345\244\215\344\273\207\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\345\244\215\344\273\207\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\345\244\215\344\273\207\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\345\256\277\344\270\273\346\213\276\350\215\222\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\345\256\277\344\270\273\346\213\276\350\215\222\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\345\256\277\344\270\273\346\213\276\350\215\222\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\345\256\277\344\270\273\346\213\276\350\215\222\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\345\257\214\350\220\245\345\205\273\347\232\204\347\251\277\345\210\272\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\345\257\214\350\220\245\345\205\273\347\232\204\347\251\277\345\210\272\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\345\257\214\350\220\245\345\205\273\347\232\204\347\251\277\345\210\272\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\345\257\214\350\220\245\345\205\273\347\232\204\347\251\277\345\210\272\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\345\261\261\346\265\267\344\274\227\347\252\245\351\255\205\344\272\272-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\345\261\261\346\265\267\344\274\227\347\252\245\351\255\205\344\272\272-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\345\261\261\346\265\267\344\274\227\347\252\245\351\255\205\344\272\272-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\345\261\261\346\265\267\344\274\227\347\252\245\351\255\205\344\272\272-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\345\261\261\351\233\252\351\254\274-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\345\261\261\351\233\252\351\254\274-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\345\261\261\351\233\252\351\254\274-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\345\261\261\351\233\252\351\254\274-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\345\274\247\345\205\211\351\224\213\345\215\253\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\345\274\247\345\205\211\351\224\213\345\215\253\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\345\274\247\345\205\211\351\224\213\345\215\253\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\345\274\247\345\205\211\351\224\213\345\215\253\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\211\216\347\275\227\357\274\214\342\200\234\347\213\274\344\271\213\344\270\273\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-A_Move-x1.webm" "b/tools/battlefield_composite/monster_images/\346\211\216\347\275\227\357\274\214\342\200\234\347\213\274\344\271\213\344\270\273\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-A_Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\211\216\347\275\227\357\274\214\342\200\234\347\213\274\344\271\213\344\270\273\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-A_Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\211\216\347\275\227\357\274\214\342\200\234\347\213\274\344\271\213\344\270\273\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-A_Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\213\263\346\211\213\345\233\232\347\212\257-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_red-x1.webm" "b/tools/battlefield_composite/monster_images/\346\213\263\346\211\213\345\233\232\347\212\257-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_red-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\213\263\346\211\213\345\233\232\347\212\257-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_red-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\213\263\346\211\213\345\233\232\347\212\257-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_red-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\217\220\344\272\232\345\215\241\344\271\214\345\245\275\346\210\230\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\346\217\220\344\272\232\345\215\241\344\271\214\345\245\275\346\210\230\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\217\220\344\272\232\345\215\241\344\271\214\345\245\275\346\210\230\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\217\220\344\272\232\345\215\241\344\271\214\345\245\275\346\210\230\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\217\220\344\272\232\345\215\241\344\271\214\347\240\264\345\235\217\347\216\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\346\217\220\344\272\232\345\215\241\344\271\214\347\240\264\345\235\217\347\216\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\217\220\344\272\232\345\215\241\344\271\214\347\240\264\345\235\217\347\216\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\217\220\344\272\232\345\215\241\344\271\214\347\240\264\345\235\217\347\216\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\225\243\345\215\216\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\346\225\243\345\215\216\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\225\243\345\215\216\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\225\243\345\215\216\351\252\221\345\243\253\345\233\242\345\255\246\345\276\222-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\234\227\345\247\206\351\205\222\346\216\250\350\215\220\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\346\234\227\345\247\206\351\205\222\346\216\250\350\215\220\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\234\227\345\247\206\351\205\222\346\216\250\350\215\220\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\234\227\345\247\206\351\205\222\346\216\250\350\215\220\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\234\250\350\243\202\346\210\230\345\243\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\346\234\250\350\243\202\346\210\230\345\243\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\234\250\350\243\202\346\210\230\345\243\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\234\250\350\243\202\346\210\230\345\243\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\235\260\346\226\257\351\241\277\302\267\345\250\201\345\273\211\345\247\206\346\226\257-\351\273\230\350\256\244-\346\210\230\346\226\227-C1_Move-x1.webm" "b/tools/battlefield_composite/monster_images/\346\235\260\346\226\257\351\241\277\302\267\345\250\201\345\273\211\345\247\206\346\226\257-\351\273\230\350\256\244-\346\210\230\346\226\227-C1_Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\235\260\346\226\257\351\241\277\302\267\345\250\201\345\273\211\345\247\206\346\226\257-\351\273\230\350\256\244-\346\210\230\346\226\227-C1_Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\235\260\346\226\257\351\241\277\302\267\345\250\201\345\273\211\345\247\206\346\226\257-\351\273\230\350\256\244-\346\210\230\346\226\227-C1_Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\237\223\346\261\241\350\272\257\345\243\263-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\346\237\223\346\261\241\350\272\257\345\243\263-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\237\223\346\261\241\350\272\257\345\243\263-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\237\223\346\261\241\350\272\257\345\243\263-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\256\213\345\205\232\350\220\250\345\205\213\346\226\257\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\346\256\213\345\205\232\350\220\250\345\205\213\346\226\257\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\256\213\345\205\232\350\220\250\345\205\213\346\226\257\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\256\213\345\205\232\350\220\250\345\205\213\346\226\257\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\262\270\350\241\200\351\252\221\345\243\253\345\233\242\347\262\276\351\224\220-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\346\262\270\350\241\200\351\252\221\345\243\253\345\233\242\347\262\276\351\224\220-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\262\270\350\241\200\351\252\221\345\243\253\345\233\242\347\262\276\351\224\220-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\262\270\350\241\200\351\252\221\345\243\253\345\233\242\347\262\276\351\224\220-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\263\245\345\262\251\345\267\250\345\203\217-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\346\263\245\345\262\251\345\267\250\345\203\217-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\263\245\345\262\251\345\267\250\345\203\217-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\263\245\345\262\251\345\267\250\345\203\217-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\267\261\346\272\237\350\243\202\347\244\201\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\346\267\261\346\272\237\350\243\202\347\244\201\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\267\261\346\272\237\350\243\202\347\244\201\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\267\261\346\272\237\350\243\202\347\244\201\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\270\251\351\241\272\347\232\204\346\255\246\350\243\205\351\251\256\345\205\275-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\346\270\251\351\241\272\347\232\204\346\255\246\350\243\205\351\251\256\345\205\275-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\270\251\351\241\272\347\232\204\346\255\246\350\243\205\351\251\256\345\205\275-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\270\251\351\241\272\347\232\204\346\255\246\350\243\205\351\251\256\345\205\275-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\271\226\347\225\224\345\277\227\346\204\277\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\346\271\226\347\225\224\345\277\227\346\204\277\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\271\226\347\225\224\345\277\227\346\204\277\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\271\226\347\225\224\345\277\227\346\204\277\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\346\272\220\347\237\263\347\225\270\345\217\230\344\275\223-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\346\272\220\347\237\263\347\225\270\345\217\230\344\275\223-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\346\272\220\347\237\263\347\225\270\345\217\230\344\275\223-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\346\272\220\347\237\263\347\225\270\345\217\230\344\275\223-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\347\201\260\345\260\276\351\246\231\344\270\273-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\347\201\260\345\260\276\351\246\231\344\270\273-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\347\201\260\345\260\276\351\246\231\344\270\273-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\347\201\260\345\260\276\351\246\231\344\270\273-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\347\202\256\345\207\273\347\273\204\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Attack-x1.webm" "b/tools/battlefield_composite/monster_images/\347\202\256\345\207\273\347\273\204\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Attack-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\347\202\256\345\207\273\347\273\204\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Attack-x1.webm" rename to "tools/battlefield_composite/monster_images/\347\202\256\345\207\273\347\273\204\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Attack-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\347\202\256\345\207\273\347\273\204\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\347\202\256\345\207\273\347\273\204\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\347\202\256\345\207\273\347\273\204\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\347\202\256\345\207\273\347\273\204\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\347\203\210\351\205\222\347\272\247\351\206\222\351\205\222\345\212\251\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\347\203\210\351\205\222\347\272\247\351\206\222\351\205\222\345\212\251\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\347\203\210\351\205\222\347\272\247\351\206\222\351\205\222\345\212\251\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\347\203\210\351\205\222\347\272\247\351\206\222\351\205\222\345\212\251\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\347\213\202\346\232\264\345\256\277\344\270\273\347\273\204\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\347\213\202\346\232\264\345\256\277\344\270\273\347\273\204\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\347\213\202\346\232\264\345\256\277\344\270\273\347\273\204\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\347\213\202\346\232\264\345\256\277\344\270\273\347\273\204\351\225\277-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\347\213\202\346\232\264\347\232\204\347\214\216\347\213\227pro-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" "b/tools/battlefield_composite/monster_images/\347\213\202\346\232\264\347\232\204\347\214\216\347\213\227pro-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\347\213\202\346\232\264\347\232\204\347\214\216\347\213\227pro-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" rename to "tools/battlefield_composite/monster_images/\347\213\202\346\232\264\347\232\204\347\214\216\347\213\227pro-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\347\224\260\351\274\267\345\212\233\345\243\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\347\224\260\351\274\267\345\212\233\345\243\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\347\224\260\351\274\267\345\212\233\345\243\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\347\224\260\351\274\267\345\212\233\345\243\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\347\237\277\350\204\211\345\256\210\345\215\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\347\237\277\350\204\211\345\256\210\345\215\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\347\237\277\350\204\211\345\256\210\345\215\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\347\237\277\350\204\211\345\256\210\345\215\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\347\245\236\345\260\204\346\211\213\345\233\232\347\212\257-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\347\245\236\345\260\204\346\211\213\345\233\232\347\212\257-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\347\245\236\345\260\204\346\211\213\345\233\232\347\212\257-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\347\245\236\345\260\204\346\211\213\345\233\232\347\212\257-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\350\220\250\345\215\241\345\205\271\345\244\247\345\211\221\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" "b/tools/battlefield_composite/monster_images/\350\220\250\345\215\241\345\205\271\345\244\247\345\211\221\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\350\220\250\345\215\241\345\205\271\345\244\247\345\211\221\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" rename to "tools/battlefield_composite/monster_images/\350\220\250\345\215\241\345\205\271\345\244\247\345\211\221\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\350\220\250\345\215\241\345\205\271\345\255\220\350\243\224\351\223\276\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\350\220\250\345\215\241\345\205\271\345\255\220\350\243\224\351\223\276\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\350\220\250\345\215\241\345\205\271\345\255\220\350\243\224\351\223\276\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\350\220\250\345\215\241\345\205\271\345\255\220\350\243\224\351\223\276\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\350\220\250\345\215\241\345\205\271\347\216\213\345\272\255\345\206\233\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\350\220\250\345\215\241\345\205\271\347\216\213\345\272\255\345\206\233\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\350\220\250\345\215\241\345\205\271\347\216\213\345\272\255\345\206\233\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\350\220\250\345\215\241\345\205\271\347\216\213\345\272\255\345\206\233\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\351\200\220\350\205\220\345\205\275-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\351\200\220\350\205\220\345\205\275-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\351\200\220\350\205\220\345\205\275-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\351\200\220\350\205\220\345\205\275-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\351\205\270\346\266\262\346\272\220\347\237\263\350\231\253\302\267\316\261-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" "b/tools/battlefield_composite/monster_images/\351\205\270\346\266\262\346\272\220\347\237\263\350\231\253\302\267\316\261-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\351\205\270\346\266\262\346\272\220\347\237\263\350\231\253\302\267\316\261-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" rename to "tools/battlefield_composite/monster_images/\351\205\270\346\266\262\346\272\220\347\237\263\350\231\253\302\267\316\261-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\351\207\215\350\243\205\351\230\262\345\276\241\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" "b/tools/battlefield_composite/monster_images/\351\207\215\350\243\205\351\230\262\345\276\241\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\351\207\215\350\243\205\351\230\262\345\276\241\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" rename to "tools/battlefield_composite/monster_images/\351\207\215\350\243\205\351\230\262\345\276\241\350\200\205-\351\273\230\350\256\244-\346\210\230\346\226\227-Move_Loop-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\351\230\265\345\234\260\345\207\273\344\272\272\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\351\230\265\345\234\260\345\207\273\344\272\272\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\351\230\265\345\234\260\345\207\273\344\272\272\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\351\230\265\345\234\260\345\207\273\344\272\272\346\211\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\351\243\216\346\203\205\350\241\227\342\200\234\346\230\237\346\234\257\345\270\210\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\351\243\216\346\203\205\350\241\227\342\200\234\346\230\237\346\234\257\345\270\210\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\351\243\216\346\203\205\350\241\227\342\200\234\346\230\237\346\234\257\345\270\210\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\351\243\216\346\203\205\350\241\227\342\200\234\346\230\237\346\234\257\345\270\210\342\200\235-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\351\253\230\345\241\224\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\351\253\230\345\241\224\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\351\253\230\345\241\224\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\351\253\230\345\241\224\346\234\257\345\270\210-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\351\253\230\346\231\256\345\260\274\345\205\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\351\253\230\346\231\256\345\260\274\345\205\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\351\253\230\346\231\256\345\260\274\345\205\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\351\253\230\346\231\256\345\260\274\345\205\213-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\351\253\230\347\272\247\346\255\246\350\243\205\344\272\272\345\221\230-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\351\253\230\347\272\247\346\255\246\350\243\205\344\272\272\345\221\230-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\351\253\230\347\272\247\346\255\246\350\243\205\344\272\272\345\221\230-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\351\253\230\347\272\247\346\255\246\350\243\205\344\272\272\345\221\230-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git "a/src/tools/battlefield_composite/monster_images/\351\253\230\350\203\275\346\272\220\347\237\263\350\231\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" "b/tools/battlefield_composite/monster_images/\351\253\230\350\203\275\346\272\220\347\237\263\350\231\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" similarity index 100% rename from "src/tools/battlefield_composite/monster_images/\351\253\230\350\203\275\346\272\220\347\237\263\350\231\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" rename to "tools/battlefield_composite/monster_images/\351\253\230\350\203\275\346\272\220\347\237\263\350\231\253-\351\273\230\350\256\244-\346\210\230\346\226\227-Move-x1.webm" diff --git a/src/tools/battlefield_recognize/class_to_idx.json b/tools/battlefield_recognize/class_to_idx.json similarity index 100% rename from src/tools/battlefield_recognize/class_to_idx.json rename to tools/battlefield_recognize/class_to_idx.json diff --git "a/src/tools/battlefield_recognize/\345\234\272\345\234\260\350\257\206\345\210\253\345\255\227\346\256\265\350\257\264\346\230\216.txt" "b/tools/battlefield_recognize/\345\234\272\345\234\260\350\257\206\345\210\253\345\255\227\346\256\265\350\257\264\346\230\216.txt" similarity index 100% rename from "src/tools/battlefield_recognize/\345\234\272\345\234\260\350\257\206\345\210\253\345\255\227\346\256\265\350\257\264\346\230\216.txt" rename to "tools/battlefield_recognize/\345\234\272\345\234\260\350\257\206\345\210\253\345\255\227\346\256\265\350\257\264\346\230\216.txt" diff --git a/src/tools/convert_model.py b/tools/convert_model.py similarity index 70% rename from src/tools/convert_model.py rename to tools/convert_model.py index db57d57..f55852b 100644 --- a/src/tools/convert_model.py +++ b/tools/convert_model.py @@ -1,22 +1,20 @@ import sys - sys.path.append(".") -from src.models import predict -from src.models import predict_onnx +import predict +from train import UnitAwareTransformer +import predict_onnx import numpy as np -from src.recognition.recognize import MONSTER_COUNT +from recognize import MONSTER_COUNT model_path = "models/best_model_full.pth" - def replace_suffix(s): - idx = s.rfind(".") + idx = s.rfind('.') if idx == -1: - return s + ".onnx" + return s + '.onnx' else: - return s[:idx] + ".onnx" - + return s[:idx] + '.onnx' output_path = replace_suffix(model_path) @@ -25,13 +23,13 @@ def replace_suffix(s): model.export_onnx(output_path) # 导出 ONNX 模型 print(f"模型已成功导出为 ONNX 格式,保存路径: {output_path}") -# 验证导出结果 +#验证导出结果 data_array = np.zeros(MONSTER_COUNT * 2, dtype=np.int64) data_array[28] = 16 data_array[MONSTER_COUNT + 30] = 22 left = data_array[:MONSTER_COUNT] right = data_array[MONSTER_COUNT:] -Onnxmodel = predict_onnx.CannotModel(model_path=output_path) +Onnxmodel = predict_onnx.CannotModel(model_path = output_path) prediction = Onnxmodel.get_prediction(left, right) print("预测结果:", prediction) diff --git a/src/tools/data_cleaning.py b/tools/data_cleaning.py similarity index 97% rename from src/tools/data_cleaning.py rename to tools/data_cleaning.py index dfa5da2..98f86c5 100644 --- a/src/tools/data_cleaning.py +++ b/tools/data_cleaning.py @@ -1,8 +1,6 @@ import pandas as pd import numpy as np -from src.core.paths import PROJECT_ROOT, simulation_path - def clean_data(file_path, output_path): print(f"开始清洗数据文件: {file_path}") @@ -220,6 +218,6 @@ def enhanced_clean(column_data, original_indices, col_idx): if __name__ == "__main__": - input_file = PROJECT_ROOT / "data" / "raw" / "arknights.csv" - output_file = PROJECT_ROOT / "data" / "processed" / "arknights_cleaned.csv" + input_file = "arknights.csv" + output_file = "arknights_cleaned.csv" clean_data(input_file, output_file) diff --git a/src/tools/data_cleaning_with_field_recognize.py b/tools/data_cleaning_with_field_recognize.py similarity index 61% rename from src/tools/data_cleaning_with_field_recognize.py rename to tools/data_cleaning_with_field_recognize.py index 3b0490d..7e1aa72 100644 --- a/src/tools/data_cleaning_with_field_recognize.py +++ b/tools/data_cleaning_with_field_recognize.py @@ -1,8 +1,6 @@ import pandas as pd import numpy as np import os - -from src.core.paths import simulation_path, PROJECT_ROOT import json import re from collections import defaultdict @@ -17,22 +15,22 @@ "altar_vertical": [ {"x": 910, "y": 174, "width": 95, "height": 104}, {"x": 910, "y": 429, "width": 102, "height": 108}, - {"x": 900, "y": 755, "width": 120, "height": 108}, + {"x": 900, "y": 755, "width": 120, "height": 108} ], "block_parallel": [ {"x": 694, "y": 240, "width": 530, "height": 122}, - {"x": 651, "y": 614, "width": 620, "height": 143}, + {"x": 651, "y": 614, "width": 620, "height": 143} ], "block_vertical": [ {"x": 647, "y": 233, "width": 153, "height": 523}, - {"x": 1112, "y": 239, "width": 159, "height": 514}, + {"x": 1112, "y": 239, "width": 159, "height": 514} ], "coil_narrow": [ {"x": 915, "y": 110, "width": 85, "height": 89}, {"x": 815, "y": 257, "width": 86, "height": 98}, {"x": 1024, "y": 258, "width": 79, "height": 98}, {"x": 790, "y": 643, "width": 97, "height": 102}, - {"x": 1031, "y": 639, "width": 102, "height": 108}, + {"x": 1031, "y": 639, "width": 102, "height": 108} ], "coil_wide": [ {"x": 719, "y": 181, "width": 81, "height": 89}, @@ -42,15 +40,21 @@ {"x": 1159, "y": 757, "width": 93, "height": 92}, {"x": 1257, "y": 533, "width": 94, "height": 102}, {"x": 1236, "y": 344, "width": 85, "height": 97}, - {"x": 1120, "y": 180, "width": 75, "height": 91}, + {"x": 1120, "y": 180, "width": 75, "height": 91} + ], + "crossbow_top": [ + {"x": 718, "y": 13, "width": 484, "height": 106} + ], + "fire_side_left": [ + {"x": 98, "y": 246, "width": 184, "height": 281} + ], + "fire_side_right": [ + {"x": 1656, "y": 430, "width": 235, "height": 315} ], - "crossbow_top": [{"x": 718, "y": 13, "width": 484, "height": 106}], - "fire_side_left": [{"x": 98, "y": 246, "width": 184, "height": 281}], - "fire_side_right": [{"x": 1656, "y": 430, "width": 235, "height": 315}], "fire_top": [ {"x": 532, "y": 17, "width": 188, "height": 97}, - {"x": 1325, "y": 14, "width": 60, "height": 100}, - ], + {"x": 1325, "y": 14, "width": 60, "height": 100} + ] } @@ -69,26 +73,19 @@ def softmax(x: np.ndarray) -> np.ndarray: return e_x / e_x.sum(axis=-1, keepdims=True) -def predict_scene( - session: ort.InferenceSession, - idx_to_class: dict, - image_path: str, - threshold: float = 0.5, -) -> list[str]: +def predict_scene(session: ort.InferenceSession, idx_to_class: dict, image_path: str, threshold: float = 0.5) -> list[ + str]: try: - full_image = Image.open(image_path).convert("RGB") + full_image = Image.open(image_path).convert('RGB') except Exception: return [] if full_image.size != (1920, 1080): return [] - input_name, output_name = ( - session.get_inputs()[0].name, - session.get_outputs()[0].name, - ) + input_name, output_name = session.get_inputs()[0].name, session.get_outputs()[0].name detected_classes = [] for location, boxes in ROI_COORDINATES.items(): for i, box in enumerate(boxes): - x, y, w, h = box["x"], box["y"], box["width"], box["height"] + x, y, w, h = box['x'], box['y'], box['width'], box['height'] roi_pil = full_image.crop((x, y, x + w, y + h)) input_tensor = preprocess_pil_image(roi_pil) outputs = session.run([output_name], {input_name: input_tensor}) @@ -97,7 +94,7 @@ def predict_scene( predicted_index = np.argmax(probabilities) if probabilities[predicted_index] >= threshold: predicted_class = idx_to_class[predicted_index] - if not predicted_class.endswith("_none"): + if not predicted_class.endswith('_none'): detected_classes.append(predicted_class) return detected_classes @@ -106,21 +103,14 @@ def predict_scene( # SECTION 2: 数据清洗主模块 (修改了最后的合并与保存部分) # ============================================================================== - -def clean_data( - file_path, - output_path, - screenshots_base_path, - onnx_model_path, - class_map_path, -): +def clean_data(file_path, output_path, screenshots_base_path, onnx_model_path, class_map_path): print(f"开始清洗数据文件: {file_path}") try: data = pd.read_csv(file_path, header=0) except FileNotFoundError: print(f"错误: 找不到数据文件 '{file_path}'") return - data["original_index"] = data.index + 1 + data['original_index'] = data.index + 1 # --- 原始清洗逻辑部分 (无变更) --- features = data.iloc[:, :-3] labels = data.iloc[:, -3] @@ -129,53 +119,36 @@ def clean_data( # ... (其余清洗逻辑与原脚本完全相同) last_row_features = features.iloc[-1].values last_row_valid = True - if abs(last_row_features[27]) > 6 or abs(last_row_features[61]) > 6: - last_row_valid = False - if np.any(np.abs(last_row_features) >= 100): - last_row_valid = False - if not last_row_valid: - print("错误: 最后一行不满足清洗条件") - return + if abs(last_row_features[27]) > 6 or abs(last_row_features[61]) > 6: last_row_valid = False + if np.any(np.abs(last_row_features) >= 100): last_row_valid = False + if not last_row_valid: print("错误: 最后一行不满足清洗条件"); return last_row = data.iloc[-1].copy() - rows_to_remove = [ - i - for i, row in enumerate(features.values) - if np.any(np.abs(row) >= 100) - ] + rows_to_remove = [i for i, row in enumerate(features.values) if np.any(np.abs(row) >= 100)] cleaned_data = data.drop(rows_to_remove).reset_index(drop=True) - if not (len(data) - 1 in rows_to_remove): - cleaned_data = cleaned_data.iloc[:-1] - if rows_to_remove: - cleaned_data = pd.concat( - [cleaned_data, pd.DataFrame([last_row] * len(rows_to_remove))], - ignore_index=True, - ) - cleaned_data = cleaned_data.drop_duplicates( - subset=cleaned_data.columns[:-3], keep="first" - ).reset_index(drop=True) - features_cleaned, labels_cleaned, pic_names_cleaned = ( - cleaned_data.iloc[:, :-3], - cleaned_data.iloc[:, -3], - cleaned_data.iloc[:, -2], - ) + if not (len(data) - 1 in rows_to_remove): cleaned_data = cleaned_data.iloc[:-1] + if rows_to_remove: cleaned_data = pd.concat([cleaned_data, pd.DataFrame([last_row] * len(rows_to_remove))], + ignore_index=True) + cleaned_data = cleaned_data.drop_duplicates(subset=cleaned_data.columns[:-3], keep='first').reset_index(drop=True) + features_cleaned, labels_cleaned, pic_names_cleaned = cleaned_data.iloc[:, :-3], cleaned_data.iloc[:, + -3], cleaned_data.iloc[:, -2] # ... (异常波动筛选逻辑完全相同) # --- 画面元素识别集成部分 (无变更) --- print("\n开始识别截图中的游戏元素...") try: session = ort.InferenceSession(onnx_model_path) - with open(class_map_path, "r", encoding="utf-8") as f: + with open(class_map_path, 'r', encoding='utf-8') as f: class_to_idx = json.load(f) idx_to_class = {v: k for k, v in class_to_idx.items()} except Exception as e: - print(f"错误:加载模型或class_map文件失败: {e}") + print(f"错误:加载模型或class_map文件失败: {e}"); return grouped_elements = defaultdict(list) for class_name in class_to_idx.keys(): - if class_name.endswith("_none"): + if class_name.endswith('_none'): continue - condensed_name = re.sub(r"_left_", "_", class_name) - condensed_name = re.sub(r"_right_", "_", condensed_name) + condensed_name = re.sub(r'_left_', '_', class_name) + condensed_name = re.sub(r'_right_', '_', condensed_name) grouped_elements[condensed_name].append(class_name) image_feature_columns = sorted(grouped_elements.keys()) print(f"将聚合生成 {len(image_feature_columns)} 个新特征列。") @@ -189,20 +162,14 @@ def clean_data( all_rows_image_data.append(row_image_data) continue try: - detected_full_names = set( - predict_scene(session, idx_to_class, image_path, threshold=0.5) - ) + detected_full_names = set(predict_scene(session, idx_to_class, image_path, threshold=0.5)) row_image_data = {} for condensed_name, full_names in grouped_elements.items(): num_positions = len(full_names) if num_positions == 1: - row_image_data[condensed_name] = ( - 1 if full_names[0] in detected_full_names else 0 - ) + row_image_data[condensed_name] = 1 if full_names[0] in detected_full_names else 0 else: - detections_in_group = [ - fn in detected_full_names for fn in full_names - ] + detections_in_group = [fn in detected_full_names for fn in full_names] num_detected = sum(detections_in_group) if num_detected == num_positions: row_image_data[condensed_name] = 1 @@ -225,9 +192,7 @@ def clean_data( # 1. 检查并拆分155个原始特征为L(77)和R(78)两组 if features_cleaned.shape[1] != 122: - print( - f"警告: 期望122个原始特征,但检测到{features_cleaned.shape[1]}个。将按前61列和剩余列进行分割。" - ) + print(f"警告: 期望122个原始特征,但检测到{features_cleaned.shape[1]}个。将按前61列和剩余列进行分割。") features_L = features_cleaned.iloc[:, :61] features_R = features_cleaned.iloc[:, 61:] @@ -237,43 +202,29 @@ def clean_data( num_r_features = features_R.shape[1] headers_L = [f"{i}L" for i in range(1, 62)] # 1L to 77L - headers_elements_L = [ - f"{i}L" for i in range(62, 62 + num_element_features) - ] + headers_elements_L = [f"{i}L" for i in range(62, 62 + num_element_features)] headers_R = [f"{i}R" for i in range(1, num_r_features + 1)] # 1R to 78R - headers_elements_R = [ - f"{i}R" - for i in range( - num_r_features + 1, num_r_features + 1 + num_element_features - ) - ] + headers_elements_R = [f"{i}R" for i in range(num_r_features + 1, num_r_features + 1 + num_element_features)] # 最终表头顺序 - final_headers = ( - headers_L - + headers_elements_L - + headers_R - + headers_elements_R - + ["Result", "ImgPath"] - ) + final_headers = (headers_L + headers_elements_L + + headers_R + headers_elements_R + + ['Result', 'ImgPath']) # 3. 为Series命名,以便在拼接时作为列名 - labels_cleaned.name = "Result" - pic_names_cleaned.name = "ImgPath" + labels_cleaned.name = 'Result' + pic_names_cleaned.name = 'ImgPath' # 4. 按照新的顺序拼接所有数据部分 - final_cleaned_data = pd.concat( - [ - features_L, # 1L-61L - image_data_df, # 12个元素特征 - features_R, # 1R-61R - image_data_df.copy(), # 12个元素特征 (副本) - labels_cleaned, # label - pic_names_cleaned, # screenshot_filename - ], - axis=1, - ) + final_cleaned_data = pd.concat([ + features_L, # 1L-61L + image_data_df, # 12个元素特征 + features_R, # 1R-61R + image_data_df.copy(), # 12个元素特征 (副本) + labels_cleaned, # label + pic_names_cleaned # screenshot_filename + ], axis=1) # 5. 将新生成的表头赋予DataFrame final_cleaned_data.columns = final_headers @@ -282,25 +233,17 @@ def clean_data( final_cleaned_data.to_csv(output_path, index=False, header=True) print(f"\n清洗和识别后的数据已保存到: {output_path}") - print( - f"最终数据维度: {final_cleaned_data.shape[0]} 行, {final_cleaned_data.shape[1]} 列" - ) + print(f"最终数据维度: {final_cleaned_data.shape[0]} 行, {final_cleaned_data.shape[1]} 列") print(f"已按要求生成自定义表头。") if __name__ == "__main__": # 路径配置与之前保持一致 - input_file = PROJECT_ROOT / "data" / "raw" / "arknights.csv" - output_file = PROJECT_ROOT / "data" / "processed" / "arknights_with_field_recognize_v2.csv" - screenshots_base_path = PROJECT_ROOT / "data" / "images" - - model_dir = PROJECT_ROOT / "models" / "battlefield_recognize" - onnx_model_path = os.path.join(model_dir, "field_recognize.onnx") - class_map_path = os.path.join(model_dir, "class_to_idx.json") - clean_data( - input_file, - output_file, - screenshots_base_path, - onnx_model_path, - class_map_path, - ) + input_file = r"arknights.csv" + output_file = r"arknights_with_field_recognize_v2.csv" + screenshots_base_path = r"images" + + model_dir = r"battlefield_recognize" + onnx_model_path = os.path.join(model_dir, 'field_recognize.onnx') + class_map_path = os.path.join(model_dir, 'class_to_idx.json') + clean_data(input_file, output_file, screenshots_base_path, onnx_model_path, class_map_path) \ No newline at end of file diff --git a/src/tools/data_cleaning_with_field_recognize_gpu.py b/tools/data_cleaning_with_field_recognize_gpu.py similarity index 61% rename from src/tools/data_cleaning_with_field_recognize_gpu.py rename to tools/data_cleaning_with_field_recognize_gpu.py index 2f12699..13ae6af 100644 --- a/src/tools/data_cleaning_with_field_recognize_gpu.py +++ b/tools/data_cleaning_with_field_recognize_gpu.py @@ -9,8 +9,6 @@ import torch.nn as nn from torchvision import models, transforms -from src.core.paths import simulation_path, PROJECT_ROOT - # ============================================================================== # SECTION 1: 游戏画面元素识别模块 (已修改为PyTorch+GPU) # ============================================================================== @@ -19,22 +17,22 @@ "altar_vertical": [ {"x": 910, "y": 174, "width": 95, "height": 104}, {"x": 910, "y": 429, "width": 102, "height": 108}, - {"x": 900, "y": 755, "width": 120, "height": 108}, + {"x": 900, "y": 755, "width": 120, "height": 108} ], "block_parallel": [ {"x": 694, "y": 240, "width": 530, "height": 122}, - {"x": 651, "y": 614, "width": 620, "height": 143}, + {"x": 651, "y": 614, "width": 620, "height": 143} ], "block_vertical": [ {"x": 647, "y": 233, "width": 153, "height": 523}, - {"x": 1112, "y": 239, "width": 159, "height": 514}, + {"x": 1112, "y": 239, "width": 159, "height": 514} ], "coil_narrow": [ {"x": 915, "y": 110, "width": 85, "height": 89}, {"x": 815, "y": 257, "width": 86, "height": 98}, {"x": 1024, "y": 258, "width": 79, "height": 98}, {"x": 790, "y": 643, "width": 97, "height": 102}, - {"x": 1031, "y": 639, "width": 102, "height": 108}, + {"x": 1031, "y": 639, "width": 102, "height": 108} ], "coil_wide": [ {"x": 719, "y": 181, "width": 81, "height": 89}, @@ -44,29 +42,35 @@ {"x": 1159, "y": 757, "width": 93, "height": 92}, {"x": 1257, "y": 533, "width": 94, "height": 102}, {"x": 1236, "y": 344, "width": 85, "height": 97}, - {"x": 1120, "y": 180, "width": 75, "height": 91}, + {"x": 1120, "y": 180, "width": 75, "height": 91} + ], + "crossbow_top": [ + {"x": 718, "y": 13, "width": 484, "height": 106} + ], + "fire_side_left": [ + {"x": 98, "y": 246, "width": 184, "height": 281} + ], + "fire_side_right": [ + {"x": 1656, "y": 430, "width": 235, "height": 315} ], - "crossbow_top": [{"x": 718, "y": 13, "width": 484, "height": 106}], - "fire_side_left": [{"x": 98, "y": 246, "width": 184, "height": 281}], - "fire_side_right": [{"x": 1656, "y": 430, "width": 235, "height": 315}], "fire_top": [ {"x": 532, "y": 17, "width": 188, "height": 97}, - {"x": 1325, "y": 14, "width": 60, "height": 100}, - ], + {"x": 1325, "y": 14, "width": 60, "height": 100} + ] } def predict_scene_pytorch( - model: nn.Module, - idx_to_class: dict, - image_path: str, - transform: transforms.Compose, - device: torch.device, - threshold: float = 0.5, + model: nn.Module, + idx_to_class: dict, + image_path: str, + transform: transforms.Compose, + device: torch.device, + threshold: float = 0.5 ) -> list[str]: """使用PyTorch模型对图片进行场景识别(GPU加速版)""" try: - full_image = Image.open(image_path).convert("RGB") + full_image = Image.open(image_path).convert('RGB') except Exception: return [] @@ -77,7 +81,7 @@ def predict_scene_pytorch( with torch.no_grad(): for location, boxes in ROI_COORDINATES.items(): for i, box in enumerate(boxes): - x, y, w, h = box["x"], box["y"], box["width"], box["height"] + x, y, w, h = box['x'], box['y'], box['width'], box['height'] roi_pil = full_image.crop((x, y, x + w, y + h)) input_tensor = transform(roi_pil).unsqueeze(0).to(device) outputs = model(input_tensor) @@ -87,7 +91,7 @@ def predict_scene_pytorch( if max_prob.item() >= threshold: predicted_class = idx_to_class[predicted_index] - if not predicted_class.endswith("_none"): + if not predicted_class.endswith('_none'): detected_classes.append(predicted_class) return detected_classes @@ -96,21 +100,14 @@ def predict_scene_pytorch( # SECTION 2: 数据清洗主模块 (修改了最后的合并与保存部分) # ============================================================================== - -def clean_data( - file_path, - output_path, - screenshots_base_path, - onnx_model_path, - class_map_path, -): +def clean_data(file_path, output_path, screenshots_base_path, onnx_model_path, class_map_path): print(f"开始清洗数据文件: {file_path}") try: data = pd.read_csv(file_path, header=0) except FileNotFoundError: print(f"错误: 找不到数据文件 '{file_path}'") return - data["original_index"] = data.index + 1 + data['original_index'] = data.index + 1 # --- 原始清洗逻辑部分 (无变更) --- features = data.iloc[:, :-3] @@ -120,35 +117,18 @@ def clean_data( # ... (其余清洗逻辑与原脚本完全相同) last_row_features = features.iloc[-1].values last_row_valid = True - if abs(last_row_features[27]) > 6 or abs(last_row_features[61]) > 6: - last_row_valid = False - if np.any(np.abs(last_row_features) >= 100): - last_row_valid = False - if not last_row_valid: - print("错误: 最后一行不满足清洗条件") - return + if abs(last_row_features[27]) > 6 or abs(last_row_features[61]) > 6: last_row_valid = False + if np.any(np.abs(last_row_features) >= 100): last_row_valid = False + if not last_row_valid: print("错误: 最后一行不满足清洗条件"); return last_row = data.iloc[-1].copy() - rows_to_remove = [ - i - for i, row in enumerate(features.values) - if np.any(np.abs(row) >= 100) - ] + rows_to_remove = [i for i, row in enumerate(features.values) if np.any(np.abs(row) >= 100)] cleaned_data = data.drop(rows_to_remove).reset_index(drop=True) - if not (len(data) - 1 in rows_to_remove): - cleaned_data = cleaned_data.iloc[:-1] - if rows_to_remove: - cleaned_data = pd.concat( - [cleaned_data, pd.DataFrame([last_row] * len(rows_to_remove))], - ignore_index=True, - ) - cleaned_data = cleaned_data.drop_duplicates( - subset=cleaned_data.columns[:-3], keep="first" - ).reset_index(drop=True) - features_cleaned, labels_cleaned, pic_names_cleaned = ( - cleaned_data.iloc[:, :-3], - cleaned_data.iloc[:, -3], - cleaned_data.iloc[:, -2], - ) + if not (len(data) - 1 in rows_to_remove): cleaned_data = cleaned_data.iloc[:-1] + if rows_to_remove: cleaned_data = pd.concat([cleaned_data, pd.DataFrame([last_row] * len(rows_to_remove))], + ignore_index=True) + cleaned_data = cleaned_data.drop_duplicates(subset=cleaned_data.columns[:-3], keep='first').reset_index(drop=True) + features_cleaned, labels_cleaned, pic_names_cleaned = cleaned_data.iloc[:, :-3], cleaned_data.iloc[:, + -3], cleaned_data.iloc[:, -2] # ... (异常波动筛选逻辑完全相同) # --- 画面元素识别集成部分 (修改为PyTorch+GPU) --- @@ -158,11 +138,11 @@ def clean_data( try: # 从ONNX路径生成对应的PTH路径 - pth_model_path = onnx_model_path.replace(".onnx", ".pth") + pth_model_path = onnx_model_path.replace('.onnx', '.pth') print(f"加载PyTorch模型: {pth_model_path}") # 加载类别映射 - with open(class_map_path, "r", encoding="utf-8") as f: + with open(class_map_path, 'r', encoding='utf-8') as f: class_to_idx = json.load(f) idx_to_class = {v: k for k, v in class_to_idx.items()} num_classes = len(class_to_idx) @@ -176,15 +156,11 @@ def clean_data( model.eval() # 定义图像转换 - transform = transforms.Compose( - [ - transforms.Resize((224, 224)), - transforms.ToTensor(), - transforms.Normalize( - mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225] - ), - ] - ) + transform = transforms.Compose([ + transforms.Resize((224, 224)), + transforms.ToTensor(), + transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) + ]) # 重新定义predict_scene函数使用PyTorch模型 def predict_scene(session, idx_to_class, image_path, threshold=0.5): @@ -198,10 +174,10 @@ def predict_scene(session, idx_to_class, image_path, threshold=0.5): grouped_elements = defaultdict(list) for class_name in class_to_idx.keys(): - if class_name.endswith("_none"): + if class_name.endswith('_none'): continue - condensed_name = re.sub(r"_left_", "_", class_name) - condensed_name = re.sub(r"_right_", "_", condensed_name) + condensed_name = re.sub(r'_left_', '_', class_name) + condensed_name = re.sub(r'_right_', '_', condensed_name) grouped_elements[condensed_name].append(class_name) image_feature_columns = sorted(grouped_elements.keys()) print(f"将聚合生成 {len(image_feature_columns)} 个新特征列。") @@ -215,20 +191,14 @@ def predict_scene(session, idx_to_class, image_path, threshold=0.5): all_rows_image_data.append(row_image_data) continue try: - detected_full_names = set( - predict_scene(None, idx_to_class, image_path, threshold=0.5) - ) + detected_full_names = set(predict_scene(None, idx_to_class, image_path, threshold=0.5)) row_image_data = {} for condensed_name, full_names in grouped_elements.items(): num_positions = len(full_names) if num_positions == 1: - row_image_data[condensed_name] = ( - 1 if full_names[0] in detected_full_names else 0 - ) + row_image_data[condensed_name] = 1 if full_names[0] in detected_full_names else 0 else: - detections_in_group = [ - fn in detected_full_names for fn in full_names - ] + detections_in_group = [fn in detected_full_names for fn in full_names] num_detected = sum(detections_in_group) if num_detected == num_positions: row_image_data[condensed_name] = 1 @@ -251,9 +221,7 @@ def predict_scene(session, idx_to_class, image_path, threshold=0.5): # 1. 检查并拆分155个原始特征为L(77)和R(78)两组 if features_cleaned.shape[1] != 122: - print( - f"警告: 期望122个原始特征,但检测到{features_cleaned.shape[1]}个。将按前61列和剩余列进行分割。" - ) + print(f"警告: 期望122个原始特征,但检测到{features_cleaned.shape[1]}个。将按前61列和剩余列进行分割。") features_L = features_cleaned.iloc[:, :61] features_R = features_cleaned.iloc[:, 61:] @@ -263,43 +231,29 @@ def predict_scene(session, idx_to_class, image_path, threshold=0.5): num_r_features = features_R.shape[1] headers_L = [f"{i}L" for i in range(1, 62)] # 1L to 61L - headers_elements_L = [ - f"{i}L" for i in range(62, 62 + num_element_features) - ] + headers_elements_L = [f"{i}L" for i in range(62, 62 + num_element_features)] headers_R = [f"{i}R" for i in range(1, num_r_features + 1)] # 1R to 61R - headers_elements_R = [ - f"{i}R" - for i in range( - num_r_features + 1, num_r_features + 1 + num_element_features - ) - ] + headers_elements_R = [f"{i}R" for i in range(num_r_features + 1, num_r_features + 1 + num_element_features)] # 最终表头顺序 - final_headers = ( - headers_L - + headers_elements_L - + headers_R - + headers_elements_R - + ["Result", "ImgPath"] - ) + final_headers = (headers_L + headers_elements_L + + headers_R + headers_elements_R + + ['Result', 'ImgPath']) # 3. 为Series命名,以便在拼接时作为列名 - labels_cleaned.name = "Result" - pic_names_cleaned.name = "ImgPath" + labels_cleaned.name = 'Result' + pic_names_cleaned.name = 'ImgPath' # 4. 按照新的顺序拼接所有数据部分 - final_cleaned_data = pd.concat( - [ - features_L, # 1L-61L - image_data_df, # 元素特征 - features_R, # 1R-61R - image_data_df.copy(), # 元素特征 (副本) - labels_cleaned, # label - pic_names_cleaned, # screenshot_filename - ], - axis=1, - ) + final_cleaned_data = pd.concat([ + features_L, # 1L-61L + image_data_df, # 元素特征 + features_R, # 1R-61R + image_data_df.copy(), # 元素特征 (副本) + labels_cleaned, # label + pic_names_cleaned # screenshot_filename + ], axis=1) # 5. 将新生成的表头赋予DataFrame final_cleaned_data.columns = final_headers @@ -308,34 +262,24 @@ def predict_scene(session, idx_to_class, image_path, threshold=0.5): final_cleaned_data.to_csv(output_path, index=False, header=True) print(f"\n清洗和识别后的数据已保存到: {output_path}") - print( - f"最终数据维度: {final_cleaned_data.shape[0]} 行, {final_cleaned_data.shape[1]} 列" - ) + print(f"最终数据维度: {final_cleaned_data.shape[0]} 行, {final_cleaned_data.shape[1]} 列") print(f"已按要求生成自定义表头。") if __name__ == "__main__": # 路径配置与之前保持一致 - input_file = PROJECT_ROOT / "data" / "raw" / "arknights.csv" - output_file = PROJECT_ROOT / "data" / "processed" / "arknights_with_field_recognize_v2.csv" - screenshots_base_path = PROJECT_ROOT / "data" / "images" + input_file = r"arknights.csv" + output_file = r"arknights_with_field_recognize_v2.csv" + screenshots_base_path = r"images" - model_dir = PROJECT_ROOT / "models" / "battlefield_recognize" - onnx_model_path = os.path.join(model_dir, "field_recognize.onnx") - class_map_path = os.path.join(model_dir, "class_to_idx.json") + model_dir = r"battlefield_recognize" + onnx_model_path = os.path.join(model_dir, 'field_recognize.onnx') + class_map_path = os.path.join(model_dir, 'class_to_idx.json') # 自动检查PTH文件是否存在 - pth_model_path = onnx_model_path.replace(".onnx", ".pth") + pth_model_path = onnx_model_path.replace('.onnx', '.pth') if not os.path.exists(pth_model_path): print(f"错误: 找不到对应的PTH模型文件 '{pth_model_path}'") - print( - f"请确保存在与ONNX同名的PTH文件: {os.path.basename(pth_model_path)}" - ) + print(f"请确保存在与ONNX同名的PTH文件: {os.path.basename(pth_model_path)}") else: - clean_data( - input_file, - output_file, - screenshots_base_path, - onnx_model_path, - class_map_path, - ) + clean_data(input_file, output_file, screenshots_base_path, onnx_model_path, class_map_path) \ No newline at end of file diff --git a/src/tools/data_nanWriter.py b/tools/data_nanWriter.py similarity index 94% rename from src/tools/data_nanWriter.py rename to tools/data_nanWriter.py index 0dc164a..ddd6ad4 100644 --- a/src/tools/data_nanWriter.py +++ b/tools/data_nanWriter.py @@ -2,13 +2,12 @@ import torch import numpy as np from tqdm import tqdm -from src.models.train import UnitAwareTransformer -from src.core.paths import simulation_path +from train import UnitAwareTransformer # 配置参数(需要与训练时一致) CONFIG = { - "csv_path": str(PROJECT_ROOT / "data" / "raw" / "arknights.csv"), - "model_path": str(PROJECT_ROOT / "models" / "best_model_full.pth"), + "csv_path": "arknights.csv", + "model_path": "models/best_model_full.pth", "max_feature_value": 300, "embed_dim": 128, "num_heads": 8, diff --git a/tools/data_washer_new.py b/tools/data_washer_new.py new file mode 100644 index 0000000..3f10486 --- /dev/null +++ b/tools/data_washer_new.py @@ -0,0 +1,904 @@ +import logging +from pathlib import Path +import cv2 +import numpy as np +import time +import csv +import os +import sys +import recognize +import tqdm + +MONSTER_NUM=56 +black_list_rows = [] + +def merge(nums): + if not nums: + return "" + intervals = [] + start = end = nums[0] + for num in nums[1:]: + if num == end + 1: + end = num + else: + intervals.append((start, end)) + start = end = num + intervals.append((start, end)) # 添加最后一个区间 + + parts = [] + for s, e in intervals: + if s == e: + parts.append(str(s)) + else: + parts.append(f"{s}-{e}") + return ','.join(parts) + +def is_continuous_sublist(sub, main): + return any(sub == main[i:i+len(sub)] for i in range(len(main) - len(sub) + 1)) + +def remove_duplicate_subsequences_easy(listdata, threshold=3): + record = [] + for i in range(len(listdata)-threshold-1): + if is_continuous_sublist(listdata[i+1:i+threshold+2], listdata[:i+threshold+1]): + record.extend(list(range(i+1,i+threshold+2))) + reco_last = list(set(record)) + reco_last.sort() + processed_data = [listdata[j] for j in range(len(listdata)) if j not in reco_last] + return processed_data, reco_last + +def remove_duplicate_subsequences(arr, threshold=3): + """ + 处理二维数组版本,将每行视为独立元素,避免内存溢出 + :param arr: 二维np数组,形状为(N, D) + :param threshold: 需要删除的连续重复子序列最小长度 + :return: 去重后的数组,被删除的索引列表 + """ + if arr.ndim != 2: + raise ValueError("输入必须是二维数组") + + n = arr.shape[0] + print(arr[9]) + # 哈希化每行以便快速比较 + dtype = np.dtype((np.void, arr.dtype.itemsize * arr.shape[1])) + hashed_arr = np.ascontiguousarray(arr).view(dtype).flatten() + + # 初始化滚动数组和列最大值记录 + prev_row = np.zeros(n, dtype=int) + max_per_col = np.zeros(n, dtype=int) + targ = 10 + for i in range(n): + # 生成当前行比较掩码 + equal_mask = (hashed_arr[i] == hashed_arr) + + # 计算当前行DP值 + curr_row = np.zeros(n, dtype=int) + curr_row[0] = equal_mask[0] # 处理j=0 + + if i > 0: + # 向量化计算j>=1的情况 + curr_row[1:] = np.where(equal_mask[1:], prev_row[:-1] + 1, 0) + + # 更新列最大值(只考虑i<=j的情况) + col_mask = np.arange(n) > i + max_per_col = np.maximum(max_per_col, curr_row * col_mask) + + # 滚动更新 + prev_row = curr_row + if i*100/n >= targ: + print("检查重复数据,处理进度: {:.1f}%: ".format(i*100/n)) + targ += 10 + + # 确定有效列并生成删除索引 + valid_cols = np.where(max_per_col >= threshold)[0] + to_remove = set() + + for j in valid_cols: + length = max_per_col[j] + start = max(0, j - length) + to_remove.update(range(start, j+1)) + + final_indices = sorted(to_remove) + return np.delete(arr, final_indices, axis=0), final_indices + +def isfloat(value): + try: + float(value) + return True + except ValueError: + return False + + +def read_and_remove_zeros(filename,MONSTER_NUM=56): + ''' + 输入数据文件名 + 输出去0和空之后的数组,和删去的行号列表 + ''' + data = [] + datafull = [] + row_id = 0 + kong = [] + short = [] + lines_num = MONSTER_NUM*2 + with open(filename, 'r') as file: + csv_reader = csv.reader(file) + for row in csv_reader: + if len(row) < lines_num + 1: + short.append(row_id) + data.append([0]*lines_num) + datafull.append([0]*lines_num) + # 分离数字部分和末尾的字母 + elif isfloat(row[0]) and '' not in row[:lines_num]: + numbers = list(map(int,map(float, row[:lines_num]))) # 转换为整数列表 + vals = row[lines_num:] + datafull.append(numbers+vals) + data.append(numbers) + else: + kong.append(row_id) + data.append([0]*lines_num) + datafull.append([0]*lines_num) + #把这一行转化为全0行暂时录入 + row_id += 1 + print('原数据总长度:',len(datafull)) + print('数据长度过短的行:',merge(short)) + print('含有不合法数据的行:',merge(kong)) + + np_array = np.array(data) + # 去除全零行 + all_zeros = [] + for i in range(np_array.shape[0]): + if np.all(np_array[i][MONSTER_NUM:] == 0) or np.all(np_array[i][:MONSTER_NUM] == 0): + all_zeros.append(i) + #np.delete(np_array, all_zeros, axis=0) + + data_new = [datafull[j] for j in range(len(datafull)) if j not in all_zeros] + + all_zeros_idx = [i for i in all_zeros if i not in kong+short] + print('一侧数据全为0的行:',merge(all_zeros_idx)) + print('筛选后数据总长度:',len(data_new)) + return data_new,all_zeros,len(datafull) + +def do_duplicate(listdata): + if listdata == []: + return [],[] + num_data = [list(map(int,map(float, i[:MONSTER_NUM*2]))) for i in listdata] + np_num_data = np.array(num_data) + _,remove_list = remove_duplicate_subsequences(np_num_data, threshold=3) + #print(remove_list) + result = [listdata[j] for j in range(len(listdata)) if j not in remove_list] + return result,remove_list + +def ori_pos(n,del1,del2): + remaining_after_first = [i for i in range(n) if i not in del1] + second_deleted_original = [remaining_after_first[t] for t in del2] + all_deleted = del1 + second_deleted_original + all_deleted.sort() + return all_deleted,second_deleted_original + +def view_monster_counts(listdata): + if listdata == []: + return True,[],[] + wrong_counts = [] + num_left = [list(map(int,map(float, i[:MONSTER_NUM]))) for i in listdata] + num_right = [list(map(int,map(float, i[MONSTER_NUM:MONSTER_NUM*2]))) for i in listdata] + print(len(num_left[0]),len(num_right[0])) + black_listed = False + MONSTER_MIN = 0 + MONSTER_MAX = 100 + MONSTER_LIMIT = { + 0:[range(0,100),'狗',False], + 1:[range(0,50),'红虫',False], + 2:[range(0,30),'大盾',False], + 3:[range(0,30),'大剑',False], + 6:[range(0,6),'庞贝',False], + 8:[range(0,4),'石头人',False], + 27:[range(0,4),'杰斯顿',False], + 28:[[0],'自在',True], + 29:[[0],'狼主',True], + 30:[[0],'雷德',True] #三大boss全设为0 + } + ind = 0 + for i1,i2 in zip(num_left,num_right): + for x1 in i1: + if x1 < MONSTER_MIN: + print(f'{ind}行左侧发现小于0的数据!') + if ind not in wrong_counts: + wrong_counts.append(ind) + if x1 > MONSTER_MAX: + print(f'{ind}行左侧发现大于100的数据!') + if ind not in wrong_counts: + wrong_counts.append(ind) + for x2 in i2: + if x2 < MONSTER_MIN: + print(f'{ind}行右侧发现小于0的数据!') + if ind not in wrong_counts: + wrong_counts.append(ind) + if x2 > MONSTER_MAX: + print(f'{ind}行右侧发现大于100的数据!') + if ind not in wrong_counts: + wrong_counts.append(ind) + for j in MONSTER_LIMIT: + if i1[j] not in MONSTER_LIMIT[j][0]: + print(f'{ind}行左侧发现{MONSTER_LIMIT[j][1]},数量:{i1[j]}') + if ind not in wrong_counts: + wrong_counts.append(ind) + if MONSTER_LIMIT[j][2] and not black_listed: + black_listed = True + print(f'确认为30人数据,文档加入黑名单。') + if i2[j] not in MONSTER_LIMIT[j][0]: + print(f'{ind}行右侧发现{MONSTER_LIMIT[j][1]},数量:{i2[j]}') + if ind not in wrong_counts: + wrong_counts.append(ind) + if MONSTER_LIMIT[j][2] and not black_listed: + black_listed = True + print(f'确认为30人数据,文档加入黑名单。') + ind += 1 + processed_data = [listdata[j] for j in range(len(listdata)) if j not in wrong_counts] + mwdata = is_list_true_np(processed_data) + processed_data2 = [processed_data[j] for j in range(len(processed_data)) if j not in mwdata] + print(f'怪物信息不符合权重分配的数据行:{mwdata}') + return black_listed,wrong_counts,mwdata,processed_data2 + +def del_duplicate_by_time(listdata,delete_no_time = True): + ind = 0 + no_time = [] + timedata = [] + wrong_time = [] + for i in listdata: + if len(i) < MONSTER_NUM*2+2 or i[-1] == 'N/A': + no_time.append(ind) + ind += 1 + print(merge(no_time),'行:未发现时间戳!') + data_with_time = [listdata[j] for j in range(len(listdata)) if j not in no_time] + ind = 0 + for i in data_with_time: + if i[-1] not in timedata: + timedata.append(i[-1]) + else: + wrong_time.append(ind) + print(f'{timedata.index(i[-1])}行与{ind}行发现同名截图,文件名:{i[-1]}') + ind += 1 + if not delete_no_time: + #先找到wrongtime元素的原始位置,再从原列表删除 + remaining_after_first = [i for i in range(len(listdata)) if i not in no_time] + second_deleted_original = [remaining_after_first[t] for t in wrong_time] + data_with_time_ok = [listdata[j] for j in range(len(listdata)) if j not in second_deleted_original] + wrong_time = second_deleted_original + else: + data_with_time_ok = [data_with_time[j] for j in range(len(data_with_time)) if j not in wrong_time] + return data_with_time_ok, no_time, wrong_time + +def savecsv(listdata,outputfile): + # 处理数字转换 + processed = [] + for row in listdata: + new_row = [] + for item in row: + if isinstance(item, (int, float)): + new_row.append(int(item)) + else: + new_row.append(item) + processed.append(new_row) + + # 写入CSV文件 + with open(outputfile, 'w', newline='') as f: + csv.writer(f).writerows(processed) + print(f'已保存至{outputfile}') + + +def find_csv_files(root_dir): + csv_files = [] + for root, dirs, files in os.walk(root_dir): + for file in files: + if file.lower().endswith('.csv'): + csv_path = os.path.join(root, file) + csv_files.append(csv_path) + return csv_files + +def easydata2data(easydata): + # 测试用函数 + # easydata格式:[[[序号,数量][序号,数量][序号,数量]],[[序号,数量][序号,数量][序号,数量]],结果],没有的序号和数量留-1,序号是真实序号 + datalist = [0]*MONSTER_NUM*2 + for i in easydata[0]: + if i[0] > 0: + datalist[i[0]-1] = i[1] + for i in easydata[1]: + if i[0] > 0: + datalist[i[0]-1+MONSTER_NUM] = i[1] + datalist.extend(easydata[2]) + return datalist + +def find_where_from(easydata,floder_path): + # easydata格式:[[[序号,数量][序号,数量][序号,数量]],[[序号,数量][序号,数量][序号,数量]],结果],没有的序号和数量留-1,序号是真实序号 + datalist = [0]*MONSTER_NUM*2 + from_list = [] + for i in easydata[0]: + if i[0] > 0: + datalist[i[0]-1] = i[1] + for i in easydata[1]: + if i[0] > 0: + datalist[i[0]-1+MONSTER_NUM] = i[1] + datalist.extend(easydata[2]) + print(datalist) + csvlist = find_csv_files(floder_path) + for c in csvlist: + print(c) + for c in csvlist: + print(f'正在检查:{c}…………………………') + lines_num = MONSTER_NUM*2 + datafull = [] + row_id = 0 + with open(c, 'r') as file: + csv_reader = csv.reader(file) + for row in csv_reader: + if isfloat(row[0]) and '' not in row[:lines_num] and len(row) > lines_num: + numbers = list(map(int,map(float, row[:lines_num]))) # 转换为整数列表 + vals = [row[lines_num]] + if datalist == numbers+vals: + from_list.append([c,row_id+1]) + print(f'数据来源于:{c},第{row_id+1}行!') + row_id += 1 + str_from = '' + if from_list != []: + str_from = "\n".join([i[0] + '第:' + str(i[1]) + '行' for i in from_list]) + print(f'可能的数据来源:{str_from}') + +def is_distance_not_over_60(a,b,c,d): + #a, b = interval1 + #c, d = interval2 + # 判断区间是否有交集 + if max(a, c) <= min(b, d): + return True # 有交集时距离为0,未超过60 + # 计算不重叠时的间隔 + if b < c: + distance = c - b # interval1在左,interval2在右 + else: + distance = a - d # interval2在左,interval1在右 + return distance <= 60 + +def is_list_true_np(fulllist): + cost_list = [ + [2,0], [2,0.1], [7,0], [7,0], [3,0.1], [10,0], [25,15], [22,0], [25,100], [7,0], + [5,0.2], [7,0], [2,0], [15,2], [13,0], [12,1.5], + [6,0.2], [18,3], [15,3], [18,1], [11,0], [10,1], [16,0], [5,0.5], [15,2], [14,0], + [30,0], [35,100], [-1,-1], [-1,-1], [-1,-1], [6,0.5], [6,0], + [16,0], [15,5], [11,0], [26,0], [15,0], [4,0.1], [10,0], [21,0], [5,0.2], + [18,0], [9,1.5], [8,0.5], [16,0], [21,0], [7,0], [36,10], [10,2], [30,15], + [25,0], [27,0], [32,6], [25,50], [15,5] + ] + round_cost_list = [[50,70],[70,90],[90,110],[110,130],[120,160],[140,180],[160,200],[170,230],[190,250],[210,270]] + + # Convert to numpy arrays + cost_arr = np.array(cost_list) + round_cost_arr = np.array(round_cost_list) + round_low = round_cost_arr[:, 0] + round_high = round_cost_arr[:, 1] + + # Validity mask for cost entries not equal to [-1, -1] + valid_mask = np.all(cost_arr != [-1, -1], axis=1) + + # Split the input into left and right parts + fulllist_np = np.array([i[:112] for i in fulllist], dtype=np.float64) + N = fulllist_np.shape[0] + left_part = fulllist_np[:, :56] + right_part = fulllist_np[:, 56:112] + + # Calculate valid entries (cost not [-1,-1] and count >0) + valid_left = valid_mask[np.newaxis, :] & (left_part > 0) + valid_right = valid_mask[np.newaxis, :] & (right_part > 0) + + # Compute mincostL and maxcostL for left + left_min_terms = ( + (left_part - 1) * cost_arr[np.newaxis, :, 0] + + ((left_part - 1) * (left_part - 2) * cost_arr[np.newaxis, :, 1]) / 2 + + 0.01 + ) * valid_left + mincostL = left_min_terms.sum(axis=1) + + left_max_terms = ( + (left_part + 1) * cost_arr[np.newaxis, :, 0] + + (left_part * (left_part + 1) * cost_arr[np.newaxis, :, 1]) / 2 - + 0.01 + ) * valid_left + maxcostL = left_max_terms.sum(axis=1) + + # Compute mincostR and maxcostR for right + right_min_terms = ( + (right_part - 1) * cost_arr[np.newaxis, :, 0] + + ((right_part - 1) * (right_part - 2) * cost_arr[np.newaxis, :, 1]) / 2 + + 0.01 + ) * valid_right + mincostR = right_min_terms.sum(axis=1) + + right_max_terms = ( + (right_part + 1) * cost_arr[np.newaxis, :, 0] + + (right_part * (right_part + 1) * cost_arr[np.newaxis, :, 1]) / 2 - + 0.01 + ) * valid_right + maxcostR = right_max_terms.sum(axis=1) + + # Check overlap with round costs + left_low = np.maximum(mincostL[:, np.newaxis], round_low) + left_high = np.minimum(maxcostL[:, np.newaxis], round_high) + left_cond = left_low <= left_high + + right_low = np.maximum(mincostR[:, np.newaxis], round_low) + right_high = np.minimum(maxcostR[:, np.newaxis], round_high) + right_cond = right_low <= right_high + + both_cond = left_cond & right_cond + any_round = np.any(both_cond, axis=1) + + # Get indices where no round condition is satisfied + false_indices = np.where(~any_round)[0].tolist() + return false_indices + +def is_list_true(onelist): + roundlist = [] + #费用和附加费用,写死在代码里吧,不想读文件了。 + cost_list = [[2,0],[2,0.1],[7,0],[7,0],[3,0.1],[10,0],[25,15],[22,0],[25,100],[7,0],[5,0.2],[7,0],[2,0],[15,2],[13,0],[12,1.5], + [6,0.2],[18,3],[15,3],[18,1],[11,0],[10,1],[16,0],[5,0.5],[15,2],[14,0],[30,0],[35,100],[-1,-1],[-1,-1],[-1,-1],[6,0.5],[6,0], + [16,0],[15,5],[11,0],[26,0],[15,0],[4,0.1],[10,0],[21,0],[5,0.2],[18,0],[9,1.5],[8,0.5],[16,0],[21,0],[7,0],[36,10],[10,2],[30,15], + [25,0],[27,0],[32,6],[25,50],[15,5]] + # + round_cost_list = [[50,70],[70,90],[90,110],[110,130],[120,160],[140,180],[160,200],[170,230],[190,250],[210,270]] + left = onelist[:MONSTER_NUM] + right = onelist[MONSTER_NUM:MONSTER_NUM*2] + #result = onelist[MONSTER_NUM*2] + #print(left,right,result) + mincostL = sum([(left[i]-1)*cost_list[i][0]+(left[i]-1)*(left[i]-2)*cost_list[i][1]/2+0.01 for i in range(len(left)) if (cost_list[i] != [-1,-1]) and (left[i] > 0)]) + maxcostL = sum([(left[i]+1)*cost_list[i][0]+left[i]*(left[i]+1)*cost_list[i][1]/2-0.01 for i in range(len(left)) if (cost_list[i] != [-1,-1]) and (left[i] > 0)]) + mincostR = sum([(right[i]-1)*cost_list[i][0]+(right[i]-1)*(right[i]-2)*cost_list[i][1]/2+0.01 for i in range(len(right)) if (cost_list[i] != [-1,-1]) and (right[i] > 0)]) + maxcostR = sum([(right[i]+1)*cost_list[i][0]+right[i]*(right[i]+1)*cost_list[i][1]/2-0.01 for i in range(len(right)) if (cost_list[i] != [-1,-1]) and (right[i] > 0)]) + print(mincostL,maxcostL,mincostR,maxcostR) + for i in range(len(round_cost_list)): + if max(mincostL, round_cost_list[i][0]) <= min(maxcostL, round_cost_list[i][1]) and max(mincostR, round_cost_list[i][0]) <= min(maxcostR, round_cost_list[i][1]): + roundlist.append(i) + if roundlist != []: + return True + else: + print(f'{onelist}is not true!!!') + return False + #return is_distance_not_over_60(mincostL,maxcostL,mincostR,maxcostR) + +def recognize_review(data,img_floder,matched_threshold = 0.1,ocr_threshold = 0.5): + print("正在进行识别数据检查") + print("data行数:",len(data)) + ref_row = [0] * (recognize.MONSTER_COUNT * 2) + need_delete = [False] * len(data) + for idx, row in tqdm.tqdm(enumerate(data), total=len(data), desc="Processing rows"): + ref_row = [0] * (recognize.MONSTER_COUNT * 2) + try: + img_name = row[recognize.MONSTER_COUNT * 2 + 1] + img_path = img_floder / Path(img_name) + if not img_path.exists(): + print(f"未找到对应的图像: {img_name} ") + continue + img = cv2.imread(img_path) + main_roi = ((0, 0), (img.shape[1], img.shape[0])) + results = recognize.process_regions(main_roi, img,matched_threshold,ocr_threshold) + # 处理结果 + for res in results: + if "error" in res: + print(f"识别失败 行号: {idx}, 图片: {img_name}, 错误类型: {res['error']}", file=sys.stderr) + break + if res["matched_id"]: + if res["region_id"] < 3: + ref_row[res["matched_id"] - 1] = int(res["number"]) + else: + ref_row[res["matched_id"] - 1 + MONSTER_NUM] = int(res["number"]) + else: + # 检查数据行是否与参考行匹配 + data_row = row[0 : recognize.MONSTER_COUNT * 2] + if data_row != ref_row: + print(f"找到不匹配的数据行: {idx} 行,对应图片文件: {img_name}", file=sys.stderr) + print(f"识别结果 : {ref_row}", file=sys.stderr) + print(f"文件数据 : {data_row}", file=sys.stderr) + need_delete[idx] = True + else: + need_delete[idx] = False + except Exception as e: + logging.exception(f"Error processing line {idx}", e) + need_delete[idx] = True + newdata = [row for idx, row in enumerate(data) if not need_delete[idx]] + deleted = [idx for idx, del_flag in enumerate(need_delete) if del_flag] + return newdata, deleted + +#newdata,deleted,ori_len = read_and_remove_zeros('0502.csv',MONSTER_NUM=56) +#_,inc = remove_duplicate_subsequences() +#print('数据例:',newdata[:3]) +#result,deleted2 = do_duplicate(newdata) +#print(deleted,deleted2) +#dt = ori_pos(ori_len,deleted,deleted2) +#print(dt) +#print('筛选后数据总长度:',len(result)) +#view_monster_counts(newdata) +#del_duplicate_by_time(newdata) + +def process_full(filename,do_remove_duplicate_subsequences = False,delete_no_time = True,open_black_list = True,re_recognize_imgs = False,img_floder = '',matched_threshold=0.1, ocr_threshold=0.5): + wrong_type_list = [] + newdata,deleted0,ori_len = read_and_remove_zeros(filename,MONSTER_NUM=56) + deleted1 = [] + if do_remove_duplicate_subsequences: + newdata,deleted1 = do_duplicate(newdata) + newdata, deleted2, deleted3 = del_duplicate_by_time(newdata,delete_no_time) + if not delete_no_time: + deleted2 = [] + black_listed,deleted4,deleted5,newdata = view_monster_counts(newdata) + deleted6 = [] + if re_recognize_imgs: + newdata, deleted6 = recognize_review(newdata,img_floder,matched_threshold, ocr_threshold) + deleted7 = [] + if open_black_list: + newdata,deleted7 = process_black_list(newdata) + + dl = deleted0 + flag = 0 + for i in [deleted1,deleted2,deleted3,deleted4,deleted5,deleted6,deleted7]: + if i != []: + dl,secori = ori_pos(ori_len,dl,i) + if flag == 0: + wrong_type_list.append(['不合法的数据:',merge([i + 1 for i in deleted0])]) + wrong_type_list.append(['重复出现的连续数据*:',merge([i + 1 for i in secori])]) + elif flag == 1: + wrong_type_list.append(['未包含时间轴的数据:',merge([i + 1 for i in secori])]) + elif flag == 2: + wrong_type_list.append(['时间轴信息重复的数据:',merge([i + 1 for i in secori])]) + elif flag == 3: + wrong_type_list.append(['怪物信息错误的数据:',merge([i + 1 for i in secori])]) + elif flag == 4: + wrong_type_list.append(['不符合出怪权重规则的数据:',merge([i + 1 for i in secori])]) + elif flag == 5: + wrong_type_list.append(['经图片识别错误的数据*:',merge([i + 1 for i in secori])]) + elif flag == 6: + wrong_type_list.append(['黑名单内数据:',merge([i + 1 for i in secori])]) + flag += 1 + return black_listed,newdata,dl,wrong_type_list + + +def test1(): + black_listed,newdata,dl,wrong_type_list = process_full('0502processed.csv') + dllist = [i + 1 for i in dl] + print(f'删除了{dllist}行的数据') + for i in wrong_type_list: + print(i) + savecsv(newdata,'0502processed2.csv') + +def process_floder(flodername,savefilename,lastsavefilename,do_remove_duplicate_subsequences = True,delete_no_time = True,open_black_list = True,re_recognize_imgs = False,img_floder = '',matched_threshold=0.1, ocr_threshold=0.5): + ''' + 输入: + flodername:需要处理的文件夹名 + savefilename:全部整合保存到的文件名(不进行总去重) + lastsavefilename:全部整合并去重保存到的最终文件名 + do_remove_duplicate_subsequences:是否清理连续3个以上重复元素的重复序列 + delete_no_time:是否删除没有时间戳的数据行 + ''' + global black_list_rows + full_data_list = [] + csvlist = find_csv_files(flodername) + for csv in csvlist: + print(csv) + for csv in csvlist: + print(f'正在处理:{csv}…………………………') + black_listed,newdata,dl,wrong_type_list = process_full(csv,do_remove_duplicate_subsequences,delete_no_time,open_black_list,re_recognize_imgs,img_floder,matched_threshold, ocr_threshold) + dllist = [i + 1 for i in dl] + print(f'删除了{merge(dllist)}行的数据') + for i in wrong_type_list: + print(i) + if not black_listed: + #未进黑名单则合并至全部数据 + full_data_list += newdata + else: + print(f'该数据为30人局数据,自动进入黑名单,不计入总数据!') + if len(newdata) < 5000:#不是整合数据 + black_list_rows += newdata + savecsv(full_data_list,savefilename) + black_listed,newdata,dl,wrong_type_list = process_full(savefilename,do_remove_duplicate_subsequences,delete_no_time,open_black_list,re_recognize_imgs,img_floder,matched_threshold, ocr_threshold) + #保存后再总处理去重 + dllist = [i + 1 for i in dl] + print(f'删除了{merge(dllist)}行的数据') + for i in wrong_type_list: + print(i) + savecsv(newdata,lastsavefilename) + +def process_black_list(full_data): + #黑名单里所有的数据检测到重复的就删 + global black_list_rows + delete_rows = [] + ok_data = [] + idx = 0 + for i in full_data: + if i in black_list_rows: + delete_rows.append(idx) + else: + ok_data.append(i) + idx += 1 + print(f'黑名单内数据:{merge(delete_rows)}') + return ok_data,delete_rows + + +def process_file(filename,savefilename,do_remove_duplicate_subsequences = True,delete_no_time = True,open_black_list = True,re_recognize_imgs = False,img_floder = '',matched_threshold=0.1, ocr_threshold=0.5): + ''' + 输入: + filename:需要处理的文件名 + savefilename:处理后保存到的文件名 + do_remove_duplicate_subsequences:是否清理连续3个以上重复元素的重复序列 + delete_no_time:是否删除没有时间戳的数据行 + ''' + black_listed,newdata,dl,wrong_type_list = process_full(filename,do_remove_duplicate_subsequences,delete_no_time,open_black_list,re_recognize_imgs,img_floder,matched_threshold, ocr_threshold) + #保存后再总处理去重 + dllist = [i + 1 for i in dl] + print(f'删除了{merge(dllist)}行的数据') + for i in wrong_type_list: + print(i) + savecsv(newdata,savefilename) + + +#process_floder(r'D:\Backup\Downloads\arcdata','arcdata_fullaa.csv','arcdata_full_washed_plus.csv') + +import tkinter as tk +from tkinter import ttk, filedialog, messagebox +import sys +import threading +import queue + +class RedirectText(object): + def __init__(self, text_widget, log_file="processing.log"): + self.text_widget = text_widget + self.log_file = log_file + self.queue = queue.Queue() + self.root = text_widget.master + self.lock = threading.Lock() + + # 初始化日志文件 + self.setup_logfile() + + def setup_logfile(self): + try: + # 使用追加模式打开日志文件 + self.log_fd = open(self.log_file, "a", encoding="utf-8") + except Exception as e: + self.log_fd = None + self.write(f"无法打开日志文件: {str(e)}\n") + + def write(self, message): + # 写入日志文件(带线程锁) + with self.lock: + if self.log_fd: + try: + self.log_fd.write(message) + self.log_fd.flush() # 确保立即写入磁盘 + except Exception as e: + self.log_fd = None + self.queue.put(f"日志写入失败: {str(e)}\n") + + # 写入队列供界面显示 + self.queue.put(message) + self.root.after(100, self.update_text) + + def update_text(self): + while not self.queue.empty(): + msg = self.queue.get_nowait() + self.text_widget.insert(tk.END, msg) + self.text_widget.see(tk.END) + + def flush(self): + pass + + def close_logfile(self): + with self.lock: + if self.log_fd: + self.log_fd.close() + self.log_fd = None + +class ProcessingThread(threading.Thread): + def __init__(self, func, args=(), kwargs={}, callback=None): + super().__init__() + self.func = func + self.args = args + self.kwargs = kwargs + self.callback = callback + self.daemon = True + self.exception = None + + def run(self): + try: + self.func(*self.args, **self.kwargs) + except Exception as e: + self.exception = e + finally: + if self.callback: + self.callback(self.exception) + + +def create_gui(): + root = tk.Tk() + root.title("数据搅拌机") + root.geometry("800x600") + + # 在此处定义关闭事件处理函数(推荐位置) + def on_close(): + sys.stdout.close_logfile() # 关闭日志文件 + if messagebox.askokcancel("退出", "确定要退出程序吗?"): # 添加确认对话框 + root.destroy() # 销毁窗口 + + # 绑定关闭事件处理 + root.protocol("WM_DELETE_WINDOW", on_close) + + # 创建文本输出区域 + output_text = tk.Text(root, wrap=tk.WORD) + output_text.grid(row=3, column=0, columnspan=2, padx=10, pady=10, sticky="nsew") + sys.stdout = RedirectText(output_text, "data_processing.log") + + # 处理文件夹的Frame + folder_frame = ttk.LabelFrame(root, text="处理文件夹(处理文件夹及其所有子文件夹下的CSV文件,并合并为一个)") + folder_frame.grid(row=0, column=0, padx=10, pady=5, sticky="ew") + + # 处理文件夹的组件 + ttk.Label(folder_frame, text="选择文件夹:").grid(row=0, column=0, padx=5, sticky="w") + folder_path = tk.StringVar() + folder_entry = ttk.Entry(folder_frame, textvariable=folder_path, width=40) + folder_entry.grid(row=0, column=1, padx=5) + ttk.Button(folder_frame, text="浏览", command=lambda: folder_path.set(filedialog.askdirectory())).grid(row=0, column=2, padx=5) + + ttk.Label(folder_frame, text="中间保存文件(不进行最终去重):").grid(row=1, column=0, padx=5, sticky="w") + interim_save = tk.StringVar() + ttk.Entry(folder_frame, textvariable=interim_save, width=40).grid(row=1, column=1, padx=5) + ttk.Button(folder_frame, text="浏览", command=lambda: interim_save.set(filedialog.asksaveasfilename(defaultextension=".csv",filetypes=[("CSV文件", "*.csv"), ("所有文件", "*.*")]))).grid(row=1, column=2, padx=5) + + ttk.Label(folder_frame, text="最终保存文件:").grid(row=2, column=0, padx=5, sticky="w") + final_save = tk.StringVar() + ttk.Entry(folder_frame, textvariable=final_save, width=40).grid(row=2, column=1, padx=5) + ttk.Button(folder_frame, text="浏览", command=lambda: final_save.set(filedialog.asksaveasfilename(defaultextension=".csv",filetypes=[("CSV文件", "*.csv"), ("所有文件", "*.*")]))).grid(row=2, column=2, padx=5) + + # 复选框 + remove_dup = tk.BooleanVar(value=False) + ttk.Checkbutton(folder_frame, text="不依赖时间戳清理重复子序列(在大数据集会非常慢,通常关闭)", variable=remove_dup).grid(row=3, column=0, columnspan=3, sticky="w") + + del_time = tk.BooleanVar(value=True) + ttk.Checkbutton(folder_frame, text="删除无时间戳数据", variable=del_time).grid(row=4, column=0, columnspan=3, sticky="w") + + open_black = tk.BooleanVar(value=True) + ttk.Checkbutton(folder_frame, text="将黑名单文件内的所有数据行同时加入黑名单", variable=open_black).grid(row=5, column=0, columnspan=3, sticky="w") + + # 修改后的图片识别行(将复选框和阈值输入放在同一行) + re_recognize_var = tk.BooleanVar(value=False) + ttk.Checkbutton(folder_frame, text="启用图片二次识别(必须指定图片路径)", variable=re_recognize_var).grid(row=6, column=0, padx=5, sticky="w") + + # 添加匹配阈值设置 + ttk.Label(folder_frame, text="匹配阈值:").grid(row=6, column=1, padx=(20,5), sticky="e") + matched_threshold_var = tk.DoubleVar(value=0.1) + ttk.Entry(folder_frame, textvariable=matched_threshold_var, width=6).grid(row=6, column=2, sticky="w") + + # 添加OCR阈值设置 + ttk.Label(folder_frame, text="OCR阈值:").grid(row=6, column=3, padx=(20,5), sticky="e") + ocr_threshold_var = tk.DoubleVar(value=0.5) + ttk.Entry(folder_frame, textvariable=ocr_threshold_var, width=6).grid(row=6, column=4, sticky="w") + + # 调整后续行号(原row=6改为row=7开始) + ttk.Label(folder_frame, text="图片文件夹路径:").grid(row=7, column=0, padx=5, sticky="w") + img_folder_path = tk.StringVar() + ttk.Entry(folder_frame, textvariable=img_folder_path, width=40).grid(row=7, column=1, padx=5) + ttk.Button(folder_frame, text="浏览", command=lambda: img_folder_path.set(filedialog.askdirectory())).grid(row=7, column=2, padx=5) + + # 调整处理文件夹按钮的行号 + + + # 处理文件夹按钮 + folder_button = ttk.Button(folder_frame, text="执行处理") + folder_button.grid(row=8, column=0, columnspan=5, pady=5) + + # 处理文件的Frame + file_frame = ttk.LabelFrame(root, text="处理单个文件") + file_frame.grid(row=1, column=0, padx=10, pady=5, sticky="ew") + + # 处理文件的组件 + ttk.Label(file_frame, text="选择文件:").grid(row=0, column=0, padx=5, sticky="w") + file_path = tk.StringVar() + ttk.Entry(file_frame, textvariable=file_path, width=40).grid(row=0, column=1, padx=5) + ttk.Button(file_frame, text="浏览", command=lambda: file_path.set(filedialog.askopenfilename())).grid(row=0, column=2, padx=5) + + ttk.Label(file_frame, text="保存路径:").grid(row=1, column=0, padx=5, sticky="w") + save_path = tk.StringVar() + ttk.Entry(file_frame, textvariable=save_path, width=40).grid(row=1, column=1, padx=5) + ttk.Button(file_frame, text="浏览", command=lambda: save_path.set(filedialog.asksaveasfilename(defaultextension=".csv",filetypes=[("CSV文件", "*.csv"), ("所有文件", "*.*")]))).grid(row=1, column=2, padx=5) + + # 复选框 + remove_dup_file = tk.BooleanVar(value=False) + ttk.Checkbutton(file_frame, text="不依赖时间戳清理重复子序列(在大数据集会非常慢,通常关闭)", variable=remove_dup_file).grid(row=2, column=0, columnspan=3, sticky="w") + + del_time_file = tk.BooleanVar(value=True) + ttk.Checkbutton(file_frame, text="删除无时间戳数据", variable=del_time_file).grid(row=3, column=0, columnspan=3, sticky="w") + + open_black_file = tk.BooleanVar(value=True) + ttk.Checkbutton(file_frame, text="将黑名单文件内的所有数据行同时加入黑名单", variable=open_black_file).grid(row=4, column=0, columnspan=3, sticky="w") + + # 修改后的图片识别行 + re_recognize_file_var = tk.BooleanVar(value=False) + ttk.Checkbutton(file_frame, text="启用图片二次识别(必须指定图片路径)", variable=re_recognize_file_var).grid(row=5, column=0, padx=5, sticky="w") + + # 匹配阈值 + ttk.Label(file_frame, text="匹配阈值:").grid(row=5, column=1, padx=(20,5), sticky="e") + matched_threshold_file_var = tk.DoubleVar(value=0.1) + ttk.Entry(file_frame, textvariable=matched_threshold_file_var, width=6).grid(row=5, column=2, sticky="w") + + # OCR阈值 + ttk.Label(file_frame, text="OCR阈值:").grid(row=5, column=3, padx=(20,5), sticky="e") + ocr_threshold_file_var = tk.DoubleVar(value=0.5) + ttk.Entry(file_frame, textvariable=ocr_threshold_file_var, width=6).grid(row=5, column=4, sticky="w") + + # 调整后续行号 + ttk.Label(file_frame, text="图片文件夹路径:").grid(row=6, column=0, padx=5, sticky="w") + img_folder_file_path = tk.StringVar() + ttk.Entry(file_frame, textvariable=img_folder_file_path, width=40).grid(row=6, column=1, padx=5) + ttk.Button(file_frame, text="浏览", command=lambda: img_folder_file_path.set(filedialog.askdirectory())).grid(row=6, column=2, padx=5) + + # 调整处理文件按钮的行号 + + + + # 处理文件按钮 + file_button = ttk.Button(file_frame, text="执行处理") + file_button.grid(row=7, column=0, columnspan=5, pady=5) + + # 配置网格权重 + root.grid_rowconfigure(3, weight=1) + root.grid_columnconfigure(0, weight=1) + + # 按钮回调函数 + def process_folder_wrapper(): + folder = folder_path.get() + interim = interim_save.get() + final = final_save.get() + if not folder or not interim or not final: + messagebox.showerror("错误", "请填写所有路径") + return + + folder_button.config(state=tk.DISABLED) + def callback(e): + folder_button.config(state=tk.NORMAL) + if e: + messagebox.showerror("错误", str(e)) + else: + messagebox.showinfo("完成", "文件夹处理完成") + + thread = ProcessingThread( + func=process_floder, + args=(folder, interim, final, remove_dup.get(), del_time.get(), open_black.get(),re_recognize_var.get(), Path(img_folder_path.get()),matched_threshold_var.get(), ocr_threshold_var.get()), + callback=callback + ) + thread.start() + + def process_file_wrapper(): + input_file = file_path.get() + output_file = save_path.get() + if not input_file or not output_file: + messagebox.showerror("错误", "请填写所有路径") + return + + file_button.config(state=tk.DISABLED) + def callback(e): + file_button.config(state=tk.NORMAL) + if e: + messagebox.showerror("错误", str(e)) + else: + messagebox.showinfo("完成", "文件处理完成") + + thread = ProcessingThread( + func=process_file, + args=(input_file, output_file, remove_dup_file.get(), del_time_file.get(), open_black_file.get(),re_recognize_file_var.get(), Path(img_folder_file_path.get()),matched_threshold_file_var.get(), ocr_threshold_file_var.get()), + callback=callback + ) + thread.start() + + # 绑定按钮命令 + folder_button.config(command=process_folder_wrapper) + file_button.config(command=process_file_wrapper) + + return root + +if __name__ == "__main__": + # 请确保以下函数已经正确导入或定义: + # process_floder, process_file, find_csv_files, savecsv + + app = create_gui() + app.mainloop() diff --git a/src/tools/package.py b/tools/package.py similarity index 93% rename from src/tools/package.py rename to tools/package.py index a6d6fd2..1552a14 100644 --- a/src/tools/package.py +++ b/tools/package.py @@ -19,8 +19,8 @@ def _configure_utf8_stdio(): CONFIG = { "venv_dir": ".venv", # 虚拟环境目录 "source_script": "main.py", # 主程序文件路径 - "icon_file": r"src/resources/assets/icons/icon_64x64.ico", # 图标文件路径 - "output_dir": "build/dist", # 输出目录 + "icon_file": r"ico/icon_64x64.ico", # 图标文件路径 + "output_dir": "output", # 输出目录 "console": True, "add_data": [ # 需要打包的附加数据 (r".venv/Lib/site-packages/rapidocr/default_models.yaml", "rapidocr"), @@ -32,10 +32,15 @@ def _configure_utf8_stdio(): r"C:\Windows\System32\msvcp140.dll", r"C:\Windows\System32\vcruntime140.dll", r"C:\Windows\System32\vcruntime140_1.dll", - "vendor/bin/platform-tools", + # "arknights.csv", + # "models/best_model_full.onnx", + "images", + "platform-tools", + "ico", "pyproject.toml", - "vendor/bin/maafw", - "src", + "monster.csv", + "monster_greenvine.csv", + "maafw", ], } @@ -90,7 +95,7 @@ def copy_additional_files(): # 确保目标目录存在 dest.mkdir(parents=True, exist_ok=True) # 特殊处理images目录,排除tmp和nums子目录 - if src.name == "images" and "resources" in str(src): + if src.name == "images": def ignore_func(dir, names): """忽略tmp和nums子目录""" diff --git a/src/models/train.py b/train.py similarity index 70% rename from src/models/train.py rename to train.py index 42a5654..81549b0 100644 --- a/src/models/train.py +++ b/train.py @@ -2,7 +2,6 @@ from functools import cache from datetime import datetime from pathlib import Path -import sys import matplotlib.pyplot as plt import numpy as np @@ -12,22 +11,11 @@ import torch.optim as optim from sklearn.model_selection import train_test_split from torch.utils.data import DataLoader, Dataset +from config import FIELD_FEATURE_COUNT, MONSTER_COUNT -# Handle both direct execution and module import -if __name__ == "__main__": - # Direct execution: add parent to path - sys.path.insert(0, str(Path(__file__).parent.parent.parent)) - from src.core.config import FIELD_FEATURE_COUNT, MONSTER_COUNT - from src.models.model import UnitAwareTransformer - from src.models.muon import get_muon_lion_optimizers - from src.core.paths import PROJECT_ROOT -else: - # Module import - from ..core.config import FIELD_FEATURE_COUNT, MONSTER_COUNT - from .model import UnitAwareTransformer - from .muon import get_muon_lion_optimizers - from ..core.paths import PROJECT_ROOT - +# 导入拆分到 models 文件夹中的模型和 Muon 优化器方法 +from models.model import UnitAwareTransformer +from models.muon import get_muon_lion_optimizers print(f"场地特征数量: {FIELD_FEATURE_COUNT}") @@ -43,10 +31,7 @@ def get_device(prefer_gpu=True): if prefer_gpu: if torch.cuda.is_available(): return torch.device("cuda") - elif ( - hasattr(torch.backends, "mps") - and torch.backends.mps.is_available() - ): + elif hasattr(torch.backends, "mps") and torch.backends.mps.is_available(): return torch.device("mps") # Apple Silicon GPU elif hasattr(torch, "xpu") and torch.xpu.is_available(): # Intel GPU return torch.device("xpu") @@ -56,46 +41,7 @@ def get_device(prefer_gpu=True): device = get_device() -def resolve_data_file(csv_file: str) -> Path: - """解析训练数据路径,支持相对路径和常见回退路径。""" - requested = Path(csv_file) - - candidates = [] - # 优先:用户显式传入的路径(绝对或当前工作目录相对) - if requested.is_absolute(): - candidates.append(requested) - else: - candidates.append(requested) - # 再尝试以项目根目录为基准 - candidates.append(PROJECT_ROOT / requested) - - # 默认回退候选(当前仓库标准位置) - candidates.append(PROJECT_ROOT / "data" / "train" / "arknights.csv") - - for path in candidates: - if path.exists() and path.is_file(): - resolved = path.resolve() - if Path(csv_file) != resolved: - print(f"训练数据路径已解析为: {resolved}") - return resolved - - unique_candidates = [] - seen = set() - for path in candidates: - text = str(path) - if text not in seen: - seen.add(text) - unique_candidates.append(text) - - raise FileNotFoundError( - "未找到训练数据文件,请检查路径。已尝试以下位置:\n" - + "\n".join(f"- {p}" for p in unique_candidates) - ) - - -def plot_learning_curve( - train_losses, val_losses, train_accs, val_accs, save_path -): +def plot_learning_curve(train_losses, val_losses, train_accs, val_accs, save_path): """绘制学习曲线并保存为图片""" epochs = range(1, len(train_losses) + 1) @@ -103,21 +49,21 @@ def plot_learning_curve( # 绘制 Loss 曲线 plt.subplot(1, 2, 1) - plt.plot(epochs, train_losses, "b-", label="Train Loss") - plt.plot(epochs, val_losses, "r-", label="Val Loss") - plt.title("Training and Validation Loss") - plt.xlabel("Epochs") - plt.ylabel("Loss") + plt.plot(epochs, train_losses, 'b-', label='Train Loss') + plt.plot(epochs, val_losses, 'r-', label='Val Loss') + plt.title('Training and Validation Loss') + plt.xlabel('Epochs') + plt.ylabel('Loss') plt.legend() plt.grid(True) # 绘制 Accuracy 曲线 plt.subplot(1, 2, 2) - plt.plot(epochs, train_accs, "b-", label="Train Acc") - plt.plot(epochs, val_accs, "r-", label="Val Acc") - plt.title("Training and Validation Accuracy") - plt.xlabel("Epochs") - plt.ylabel("Accuracy (%)") + plt.plot(epochs, train_accs, 'b-', label='Train Acc') + plt.plot(epochs, val_accs, 'r-', label='Val Acc') + plt.title('Training and Validation Accuracy') + plt.xlabel('Epochs') + plt.ylabel('Accuracy (%)') plt.legend() plt.grid(True) @@ -129,27 +75,21 @@ def plot_learning_curve( def preprocess_data(csv_file): """预处理CSV文件,将异常值修正为合理范围""" - csv_path = resolve_data_file(csv_file) - print(f"预处理数据文件: {csv_path}") + print(f"预处理数据文件: {csv_file}") # 读取CSV文件 - data = pd.read_csv(csv_path, header=None, skiprows=1) + data = pd.read_csv(csv_file, header=None, skiprows=1) print(f"原始数据形状: {data.shape}") # 检查数据形状 expected_columns = TOTAL_FEATURE_COUNT + 2 # +2 for Result and ImgPath if data.shape[1] != expected_columns: + print(f"数据列数不符!期望 {expected_columns} 列,实际 {data.shape[1]} 列") print( - f"数据列数不符!期望 {expected_columns} 列,实际 {data.shape[1]} 列" - ) - print( - f"期望格式: {MONSTER_COUNT}(怪物L) + {FIELD_FEATURE_COUNT}(场地L) + {MONSTER_COUNT}(怪物R) + {FIELD_FEATURE_COUNT}(场地R) + 1(Result) + 1(ImgPath)" - ) + f"期望格式: {MONSTER_COUNT}(怪物L) + {FIELD_FEATURE_COUNT}(场地L) + {MONSTER_COUNT}(怪物R) + {FIELD_FEATURE_COUNT}(场地R) + 1(Result) + 1(ImgPath)") raise Exception("数据格式不符") - data = data.iloc[ - :, 0 : TOTAL_FEATURE_COUNT + 1 - ] # 保留特征和结果列,去掉ImgPath + data = data.iloc[:, 0: TOTAL_FEATURE_COUNT + 1] # 保留特征和结果列,去掉ImgPath # 检查特征范围 features = data.iloc[:, :-1] @@ -179,35 +119,23 @@ def preprocess_data(csv_file): class ArknightsDataset(Dataset): def __init__(self, csv_file, max_value=None): - csv_path = resolve_data_file(csv_file) - data = pd.read_csv(csv_path, header=None, skiprows=1) + data = pd.read_csv(csv_file, header=None, skiprows=1) # 检查数据形状 expected_columns = TOTAL_FEATURE_COUNT + 2 # +2 for Result and ImgPath if data.shape[1] != expected_columns: - print( - f"数据列数不符!期望 {expected_columns} 列,实际 {data.shape[1]} 列" - ) + print(f"数据列数不符!期望 {expected_columns} 列,实际 {data.shape[1]} 列") raise Exception("数据格式不符") - data = data.iloc[ - :, 0 : TOTAL_FEATURE_COUNT + 1 - ] # 保留特征和结果列,去掉ImgPath + data = data.iloc[:, 0: TOTAL_FEATURE_COUNT + 1] # 保留特征和结果列,去掉ImgPath features = data.iloc[:, :-1].values.astype(np.float32) labels = data.iloc[:, -1].map({"L": 0, "R": 1}).values - labels = np.where((labels != 0) & (labels != 1), 0, labels).astype( - np.float32 - ) + labels = np.where((labels != 0) & (labels != 1), 0, labels).astype(np.float32) # 分割双方单位和场地特征 # 数据格式: [怪物L(77), 场地L(6), 怪物R(77), 场地R(6)] left_monster_end = MONSTER_COUNT left_field_end = MONSTER_COUNT + FIELD_FEATURE_COUNT right_monster_end = MONSTER_COUNT + FIELD_FEATURE_COUNT + MONSTER_COUNT - right_field_end = ( - MONSTER_COUNT - + FIELD_FEATURE_COUNT - + MONSTER_COUNT - + FIELD_FEATURE_COUNT - ) + right_field_end = MONSTER_COUNT + FIELD_FEATURE_COUNT + MONSTER_COUNT + FIELD_FEATURE_COUNT # 提取各部分特征 left_monster_features = features[:, :left_monster_end] @@ -216,26 +144,10 @@ def __init__(self, csv_file, max_value=None): right_field_features = features[:, right_monster_end:right_field_end] # 合并怪物特征和场地特征(场地特征直接使用,不取绝对值和符号) - left_counts = np.concatenate( - [np.abs(left_monster_features), left_field_features], axis=1 - ) - right_counts = np.concatenate( - [np.abs(right_monster_features), right_field_features], axis=1 - ) - left_signs = np.concatenate( - [ - np.sign(left_monster_features), - np.ones_like(left_field_features), - ], - axis=1, - ) - right_signs = np.concatenate( - [ - np.sign(right_monster_features), - np.ones_like(right_field_features), - ], - axis=1, - ) + left_counts = np.concatenate([np.abs(left_monster_features), left_field_features], axis=1) + right_counts = np.concatenate([np.abs(right_monster_features), right_field_features], axis=1) + left_signs = np.concatenate([np.sign(left_monster_features), np.ones_like(left_field_features)], axis=1) + right_signs = np.concatenate([np.sign(right_monster_features), np.ones_like(right_field_features)], axis=1) if max_value is not None: left_counts = np.clip(left_counts, 0, max_value) @@ -261,9 +173,7 @@ def __getitem__(self, idx): ) -def train_one_epoch( - model, train_loader, criterion, muon_opt, lion_opt, scaler=None -): +def train_one_epoch(model, train_loader, criterion, muon_opt, lion_opt, scaler=None): model.train() total_loss = 0 correct = 0 @@ -280,19 +190,19 @@ def train_one_epoch( # 检查输入数据 if ( - torch.isnan(ls).any() - or torch.isnan(lc).any() - or torch.isnan(rs).any() - or torch.isnan(rc).any() + torch.isnan(ls).any() + or torch.isnan(lc).any() + or torch.isnan(rs).any() + or torch.isnan(rc).any() ): print("警告: 输入数据包含NaN,跳过该批次") continue if ( - torch.isinf(ls).any() - or torch.isinf(lc).any() - or torch.isinf(rs).any() - or torch.isinf(rc).any() + torch.isinf(ls).any() + or torch.isinf(lc).any() + or torch.isinf(rs).any() + or torch.isinf(rc).any() ): print("警告: 输入数据包含Inf,跳过该批次") continue @@ -304,7 +214,7 @@ def train_one_epoch( try: with torch.amp.autocast_mode.autocast( - device_type=device.type, enabled=(scaler is not None) + device_type=device.type, enabled=(scaler is not None) ): outputs = model(ls, lc, rs, rc).squeeze() # 确保输出在合理范围内 @@ -331,18 +241,14 @@ def train_one_epoch( scaler.unscale_(muon_opt) scaler.unscale_(lion_opt) # 梯度裁剪,避免梯度爆炸 - torch.nn.utils.clip_grad_norm_( - model.parameters(), max_norm=1.0 - ) + torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) scaler.step(muon_opt) scaler.step(lion_opt) scaler.update() else: # 不使用混合精度 loss.backward() # 梯度裁剪,避免梯度爆炸 - torch.nn.utils.clip_grad_norm_( - model.parameters(), max_norm=1.0 - ) + torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) muon_opt.step() lion_opt.step() @@ -355,9 +261,7 @@ def train_one_epoch( print(f"警告: 训练过程中出错 - {str(e)}") continue - return total_loss / max(1, len(train_loader)), 100 * correct / max( - 1, total - ) + return total_loss / max(1, len(train_loader)), 100 * correct / max(1, total) def evaluate(model, data_loader, criterion): @@ -369,20 +273,19 @@ def evaluate(model, data_loader, criterion): with torch.no_grad(): for ls, lc, rs, rc, labels in data_loader: ls, lc, rs, rc, labels = [ - x.to(device, non_blocking=True) - for x in (ls, lc, rs, rc, labels) + x.to(device, non_blocking=True) for x in (ls, lc, rs, rc, labels) ] # 检查输入值范围 if ( - torch.isnan(ls).any() - or torch.isnan(lc).any() - or torch.isnan(rs).any() - or torch.isnan(rc).any() - or torch.isinf(ls).any() - or torch.isinf(lc).any() - or torch.isinf(rs).any() - or torch.isinf(rc).any() + torch.isnan(ls).any() + or torch.isnan(lc).any() + or torch.isnan(rs).any() + or torch.isnan(rc).any() + or torch.isinf(ls).any() + or torch.isinf(lc).any() + or torch.isinf(rs).any() + or torch.isinf(rc).any() ): print("警告: 评估时输入数据包含NaN或Inf,跳过该批次") continue @@ -393,14 +296,11 @@ def evaluate(model, data_loader, criterion): try: with torch.amp.autocast_mode.autocast( - device_type=device.type, enabled=(device.type == "cuda") + device_type=device.type, enabled=(device.type == "cuda") ): outputs = model(ls, lc, rs, rc).squeeze() # 确保输出在合理范围内 - if ( - torch.isnan(outputs).any() - or torch.isinf(outputs).any() - ): + if torch.isnan(outputs).any() or torch.isinf(outputs).any(): print("警告: 评估时模型输出包含NaN或Inf,跳过该批次") continue # 确保输出严格在0-1之间 @@ -445,7 +345,7 @@ def stratified_random_split(dataset, test_size=0.1, seed=42): def main(): # 配置参数 config = { - "data_file": str(PROJECT_ROOT / "data" / "train" / "arknights.csv"), + "data_file": "arknights.csv", "batch_size": 1024, "test_size": 0.1, "embed_dim": 256, @@ -456,11 +356,9 @@ def main(): "lion_lr": 3e-4 / 10, # 论文指出 Lion 优化器需要更小的学习率 "epochs": 50, "seed": 42, # 随机数种子 - "save_dir": PROJECT_ROOT / "models", # 存到哪里 + "save_dir": "models", # 存到哪里 "max_feature_value": 100, # 限制特征最大值,防止极端值造成不稳定 - "num_workers": ( - 0 if torch.cuda.is_available() else 0 - ), # 根据CUDA可用性设置num_workers + "num_workers": 0 if torch.cuda.is_available() else 0, # 根据CUDA可用性设置num_workers } # 创建保存目录 @@ -524,9 +422,7 @@ def main(): num_workers=config["num_workers"], ) val_loader = DataLoader( - val_dataset, - batch_size=config["batch_size"], - num_workers=config["num_workers"], + val_dataset, batch_size=config["batch_size"], num_workers=config["num_workers"] ) # 初始化模型 @@ -540,27 +436,16 @@ def main(): dropout=config["dropout"], # 传入 dropout ).to(device) - print( - f"模型使用特征数: 怪物({MONSTER_COUNT}) + 场地({FIELD_FEATURE_COUNT}) = {total_units}" - ) - print( - f"模型参数数量: {sum(p.numel() for p in model.parameters() if p.requires_grad)}" - ) + print(f"模型使用特征数: 怪物({MONSTER_COUNT}) + 场地({FIELD_FEATURE_COUNT}) = {total_units}") + print(f"模型参数数量: {sum(p.numel() for p in model.parameters() if p.requires_grad)}") # 损失函数和优化器 (引入 Muon 与 Lion) criterion = nn.MSELoss() muon_opt, lion_opt = get_muon_lion_optimizers( - model, - muon_lr=config["lr"], - lion_lr=config["lion_lr"], - weight_decay=1e-1, - ) - scheduler_muon = optim.lr_scheduler.CosineAnnealingLR( - muon_opt, T_max=config["epochs"] - ) - scheduler_lion = optim.lr_scheduler.CosineAnnealingLR( - lion_opt, T_max=config["epochs"] + model, muon_lr=config["lr"], lion_lr=config["lion_lr"], weight_decay=1e-1 ) + scheduler_muon = optim.lr_scheduler.CosineAnnealingLR(muon_opt, T_max=config["epochs"]) + scheduler_lion = optim.lr_scheduler.CosineAnnealingLR(lion_opt, T_max=config["epochs"]) # 训练历史记录 train_losses, val_losses, train_accs, val_accs = [], [], [], [] @@ -616,9 +501,7 @@ def main(): # }, os.path.join(config['save_dir'], 'latest_checkpoint.pth')) # 打印训练信息 - print( - f"Train Loss: {train_loss:.4f} | Acc: {train_acc:.2f}% Val Loss: {val_loss:.4f} | Acc: {val_acc:.2f}%" - ) + print(f"Train Loss: {train_loss:.4f} | Acc: {train_acc:.2f}% Val Loss: {val_loss:.4f} | Acc: {val_acc:.2f}%") # 计时 if epoch == 0: @@ -630,9 +513,7 @@ def main(): elapsed_time = current_time - start_time avg_epoch_time = elapsed_time / (epoch + 1) remaining_time = (avg_epoch_time * config["epochs"]) - elapsed_time - print( - f"Epoch Time: {epoch_duration:.2f}s, Estimated Remaining: {remaining_time / 60:.2f}min" - ) + print(f"Epoch Time: {epoch_duration:.2f}s, Estimated Remaining: {remaining_time / 60:.2f}min") epoch_start_time = current_time # Reset for next epoch print("-" * 40) @@ -645,17 +526,10 @@ def main(): for model_type in ["acc", "loss", "full"]: old_path = save_dir_path / f"best_model_{model_type}.pth" if old_path.exists(): - old_path.rename( - save_dir_path / f"best_model_{model_type}_{base_filename}" - ) - - plot_learning_curve( - train_losses, - val_losses, - train_accs, - val_accs, - save_dir_path / f"learning_curve_{base_filename}.png", - ) + old_path.rename(save_dir_path / f"best_model_{model_type}_{base_filename}") + + plot_learning_curve(train_losses, val_losses, train_accs, val_accs, + save_dir_path / f"learning_curve_{base_filename}.png") if __name__ == "__main__": diff --git a/src/utils/unit.py b/unit.py similarity index 94% rename from src/utils/unit.py rename to unit.py index 8e2be97..d4c290c 100644 --- a/src/utils/unit.py +++ b/unit.py @@ -1,4 +1,4 @@ -from src.core.constants import UNIT_CONFIG +from constants import UNIT_CONFIG # 添加这行导入 class Unit: def __init__(self, team, unit_id, x, y): diff --git a/uv.lock b/uv.lock index ad093bc..6c882ef 100644 --- a/uv.lock +++ b/uv.lock @@ -2,68 +2,68 @@ version = 1 revision = 3 requires-python = ">=3.10" resolution-markers = [ - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", @@ -94,12 +94,6 @@ resolution-markers = [ conflicts = [[ { package = "cannotmax-greenvine", extra = "cpu" }, { package = "cannotmax-greenvine", extra = "cu128" }, -], [ - { package = "cannotmax-greenvine", extra = "cpu" }, - { package = "cannotmax-greenvine", extra = "cu130" }, -], [ - { package = "cannotmax-greenvine", extra = "cu128" }, - { package = "cannotmax-greenvine", extra = "cu130" }, ]] [[package]] @@ -119,52 +113,45 @@ sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/3e/38/7859ff463 [[package]] name = "cannotmax-greenvine" -version = "2.0.0" +version = "1.0.8" source = { virtual = "." } dependencies = [ { name = "maafw" }, { name = "matplotlib" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "onnxruntime", version = "1.24.3", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "onnxruntime", version = "1.25.0", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "onnxruntime", version = "1.24.3", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "onnxruntime", version = "1.25.0", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "opencv-python" }, - { name = "pandas", version = "2.3.3", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "pandas", version = "3.0.2", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "pandas", version = "2.3.3", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "pandas", version = "3.0.2", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "pillow" }, { name = "pyqt6" }, { name = "pywin32" }, { name = "rapidocr" }, - { name = "scikit-learn", version = "1.7.2", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "scikit-learn", version = "1.8.0", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "scikit-learn", version = "1.7.2", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "scikit-learn", version = "1.8.0", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "toml" }, { name = "windows-capture" }, ] [package.optional-dependencies] cpu = [ - { name = "torch", version = "2.11.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "torch", version = "2.11.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "torchvision", version = "0.26.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "torchvision", version = "0.26.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "torch", version = "2.11.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(python_full_version < '3.11' and platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (python_full_version >= '3.11' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "torch", version = "2.11.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(python_full_version < '3.11' and platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version >= '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu')" }, + { name = "torchvision", version = "0.26.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(python_full_version < '3.11' and platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (python_full_version >= '3.11' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "torchvision", version = "0.26.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(python_full_version < '3.11' and platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version >= '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu')" }, ] cu128 = [ { name = "torch", version = "2.11.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" } }, { name = "torchvision", version = "0.26.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" } }, ] -cu130 = [ - { name = "torch", version = "2.11.0+cu130", source = { registry = "https://download.pytorch.org/whl/cu130" } }, - { name = "torchvision", version = "0.26.0+cu130", source = { registry = "https://download.pytorch.org/whl/cu130" } }, -] [package.dev-dependencies] dev = [ { name = "onnx" }, { name = "onnxscript" }, - { name = "pandas-stubs", version = "2.3.3.260113", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "pandas-stubs", version = "3.0.0.260204", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, { name = "pyinstaller" }, - { name = "types-toml" }, ] [package.metadata] @@ -183,21 +170,17 @@ requires-dist = [ { name = "toml" }, { name = "torch", marker = "extra == 'cpu'", index = "https://download.pytorch.org/whl/cpu", conflict = { package = "cannotmax-greenvine", extra = "cpu" } }, { name = "torch", marker = "extra == 'cu128'", specifier = ">=2.7.0", index = "https://download.pytorch.org/whl/cu128", conflict = { package = "cannotmax-greenvine", extra = "cu128" } }, - { name = "torch", marker = "extra == 'cu130'", specifier = ">=2.7.0", index = "https://download.pytorch.org/whl/cu130", conflict = { package = "cannotmax-greenvine", extra = "cu130" } }, { name = "torchvision", marker = "extra == 'cpu'", index = "https://download.pytorch.org/whl/cpu", conflict = { package = "cannotmax-greenvine", extra = "cpu" } }, { name = "torchvision", marker = "extra == 'cu128'", specifier = ">=0.22.0", index = "https://download.pytorch.org/whl/cu128", conflict = { package = "cannotmax-greenvine", extra = "cu128" } }, - { name = "torchvision", marker = "extra == 'cu130'", specifier = ">=0.22.0", index = "https://download.pytorch.org/whl/cu130", conflict = { package = "cannotmax-greenvine", extra = "cu130" } }, { name = "windows-capture" }, ] -provides-extras = ["cpu", "cu128", "cu130"] +provides-extras = ["cpu", "cu128"] [package.metadata.requires-dev] dev = [ { name = "onnx", specifier = ">=1.19.0" }, { name = "onnxscript", specifier = ">=0.7.0" }, - { name = "pandas-stubs" }, { name = "pyinstaller", specifier = ">=6.15.0" }, - { name = "types-toml" }, ] [[package]] @@ -328,7 +311,7 @@ name = "colorlog" version = "6.10.1" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321" } wheels = [ @@ -340,17 +323,17 @@ name = "contourpy" version = "1.3.2" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } resolution-markers = [ - "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", + "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", ] dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54" } wheels = [ @@ -417,62 +400,62 @@ name = "contourpy" version = "1.3.3" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } resolution-markers = [ - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", @@ -499,7 +482,7 @@ resolution-markers = [ "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", ] dependencies = [ - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880" } wheels = [ @@ -580,18 +563,6 @@ wheels = [ name = "cuda-bindings" version = "12.9.6" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -resolution-markers = [ - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version < '3.11' and platform_machine != 's390x'", - "python_full_version < '3.11' and platform_machine == 's390x'", -] dependencies = [ { name = "cuda-pathfinder", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, ] @@ -619,46 +590,6 @@ wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/4b/98/8e5363d00c959d4172b1d619a4f03af454bf9952636224f0ac0f5c35c067/cuda_bindings-12.9.6-cp314-cp314t-win_amd64.whl", hash = "sha256:7f0a08eba6e807d041bf6f2ba66d84db1ddf54787399dfac716497ef40fb5fc3" }, ] -[[package]] -name = "cuda-bindings" -version = "13.2.0" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -resolution-markers = [ - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version < '3.11' and platform_machine != 's390x'", - "python_full_version < '3.11' and platform_machine == 's390x'", -] -dependencies = [ - { name = "cuda-pathfinder", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, -] -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/1a/fe/7351d7e586a8b4c9f89731bfe4cf0148223e8f9903ff09571f78b3fb0682/cuda_bindings-13.2.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08b395f79cb89ce0cd8effff07c4a1e20101b873c256a1aeb286e8fd7bd0f556" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/aa/ef/184aa775e970fc089942cd9ec6302e6e44679d4c14549c6a7ea45bf7f798/cuda_bindings-13.2.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6f3682ec3c4769326aafc67c2ba669d97d688d0b7e63e659d36d2f8b72f32d6" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/ec/ea/81999d01375645f34596c76eb046b4b36d58cc6fe2bddb2410f8a7b7a827/cuda_bindings-13.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:845025438a1b9e20718b9fb42add3e0eb72e85458bcab3eeb80bfd8f0a9dab33" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/e0/a9/3a8241c6e19483ac1f1dcf5c10238205dcb8a6e9d0d4d4709240dff28ff4/cuda_bindings-13.2.0-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:721104c603f059780d287969be3d194a18d0cc3b713ed9049065a1107706759d" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/e9/94/2748597f47bb1600cd466b20cab4159f1530a3a33fe7f70fee199b3abb9e/cuda_bindings-13.2.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1eba9504ac70667dd48313395fe05157518fd6371b532790e96fbb31bbb5a5e1" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/29/5a/0ce1731c48bcd9f40996a4ef1abbf634f1a7fe4a15c5050b1e75ce3a7acf/cuda_bindings-13.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:debb51b211d246f8326f6b6e982506a5d0d9906672c91bc478b66addc7ecc60a" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/52/c8/b2589d68acf7e3d63e2be330b84bc25712e97ed799affbca7edd7eae25d6/cuda_bindings-13.2.0-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e865447abfb83d6a98ad5130ed3c70b1fc295ae3eeee39fd07b4ddb0671b6788" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/1f/92/f899f7bbb5617bb65ec52a6eac1e9a1447a86b916c4194f8a5001b8cde0c/cuda_bindings-13.2.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:46d8776a55d6d5da9dd6e9858fba2efcda2abe6743871dee47dd06eb8cb6d955" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/bb/a5/d7f01a415e134546248cef612adad8153c9f1eb10ec79505a7cd8294370b/cuda_bindings-13.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:45815daeb595bf3b405c52671a2542b1f8e9329f3b029494acbfcc74aeaa1f2d" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/df/93/eef988860a3ca985f82c4f3174fc0cdd94e07331ba9a92e8e064c260337f/cuda_bindings-13.2.0-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6629ca2df6f795b784752409bcaedbd22a7a651b74b56a165ebc0c9dcbd504d0" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/18/23/6db3aba46864aee357ab2415135b3fe3da7e9f1fa0221fa2a86a5968099c/cuda_bindings-13.2.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7dca0da053d3b4cc4869eff49c61c03f3c5dbaa0bcd712317a358d5b8f3f385d" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/c4/84/d3b6220b51cbc02ca14db7387e97445126b4ff5125aaa6c5dd7dcb75e679/cuda_bindings-13.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8cebe3ce4aeeca5af9c490e175f76c4b569bbf4a35a62294b777bc77bf7ac4d8" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/c0/87/87a014f045b77c6de5c8527b0757fe644417b184e5367db977236a141602/cuda_bindings-13.2.0-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a6464b30f46692d6c7f65d4a0e0450d81dd29de3afc1bb515653973d01c2cd6e" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/ee/5e/c0fe77a73aaefd3fff25ffaccaac69c5a63eafdf8b9a4c476626ef0ac703/cuda_bindings-13.2.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f4af9f3e1be603fa12d5ad6cfca7844c9d230befa9792b5abdf7dd79979c3626" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/e3/73/98bcb069778fe420226db75aff54b5dd6c3ecfd0912edabab723326e80b7/cuda_bindings-13.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:bd658bb5c0e55b7b3e5dd0ed509c6addb298c665db26a9bfba35e1e626000ba2" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/5f/58/ed2c3b39c8dd5f96aa7a4abef0d47a73932c7a988e30f5fa428f00ed0da1/cuda_bindings-13.2.0-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df850a1ff8ce1b3385257b08e47b70e959932f5f432d0a4e46a355962b4e4771" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/1f/01/0c941b112ceeb21439b05895eace78ca1aa2eaaf695c8521a068fd9b4c00/cuda_bindings-13.2.0-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8a16384c6494e5485f39314b0b4afb04bee48d49edb16d5d8593fd35bbd231b" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/52/49/4e01cc06447d39476e138d1b1adec8d35c0d04eccd2c8d69befc08cd66e8/cuda_bindings-13.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6ccf14e0c1def3b7200100aafff3a9f7e210ecb6e409329e92dcf6cd2c00d5c7" }, -] - [[package]] name = "cuda-pathfinder" version = "1.5.3" @@ -671,18 +602,6 @@ wheels = [ name = "cuda-toolkit" version = "12.8.1" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -resolution-markers = [ - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version < '3.11' and platform_machine != 's390x'", - "python_full_version < '3.11' and platform_machine == 's390x'", -] wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/d4/c8/7dce3a0b15b42a3b58e7d96eb22a687d3bf2c44e01d149a6874629cd9938/cuda_toolkit-12.8.1-py2.py3-none-any.whl", hash = "sha256:adc7906af4ecbf9a352f9dca5734eceb21daec281ccfcf5675e1d2f724fc2cba" }, ] @@ -722,61 +641,6 @@ nvtx = [ { name = "nvidia-nvtx-cu12", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, ] -[[package]] -name = "cuda-toolkit" -version = "13.0.2" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -resolution-markers = [ - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version < '3.11' and platform_machine != 's390x'", - "python_full_version < '3.11' and platform_machine == 's390x'", -] -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/57/b2/453099f5f3b698d7d0eab38916aac44c7f76229f451709e2eb9db6615dcd/cuda_toolkit-13.0.2-py2.py3-none-any.whl", hash = "sha256:b198824cf2f54003f50d64ada3a0f184b42ca0846c1c94192fa269ecd97a66eb" }, -] - -[package.optional-dependencies] -cublas = [ - { name = "nvidia-cublas", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, -] -cudart = [ - { name = "nvidia-cuda-runtime", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, -] -cufft = [ - { name = "nvidia-cufft", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, -] -cufile = [ - { name = "nvidia-cufile", marker = "sys_platform == 'linux'" }, -] -cupti = [ - { name = "nvidia-cuda-cupti", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, -] -curand = [ - { name = "nvidia-curand", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, -] -cusolver = [ - { name = "nvidia-cusolver", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, -] -cusparse = [ - { name = "nvidia-cusparse", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, -] -nvjitlink = [ - { name = "nvidia-nvjitlink", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, -] -nvrtc = [ - { name = "nvidia-cuda-nvrtc", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, -] -nvtx = [ - { name = "nvidia-nvtx", marker = "(python_full_version < '3.11' and sys_platform == 'win32') or sys_platform == 'linux'" }, -] - [[package]] name = "cycler" version = "0.12.1" @@ -1037,8 +901,8 @@ version = "5.10.2" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } dependencies = [ { name = "maaagentbinary" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "strenum" }, ] wheels = [ @@ -1055,7 +919,7 @@ name = "macholib" version = "1.16.4" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } dependencies = [ - { name = "altgraph", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu') or (python_full_version < '3.11' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu') or sys_platform == 'darwin' or (sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu') or (sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "altgraph", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu') or (python_full_version < '3.11' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu') or sys_platform == 'darwin' or (sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu') or (sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/10/2f/97589876ea967487978071c9042518d28b958d87b17dceb7cdc1d881f963/macholib-1.16.4.tar.gz", hash = "sha256:f408c93ab2e995cd2c46e34fe328b130404be143469e41bc366c807448979362" } wheels = [ @@ -1152,13 +1016,13 @@ name = "matplotlib" version = "3.10.9" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } dependencies = [ - { name = "contourpy", version = "1.3.2", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "contourpy", version = "1.3.3", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "contourpy", version = "1.3.2", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "contourpy", version = "1.3.3", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "cycler" }, { name = "fonttools" }, { name = "kiwisolver" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "packaging" }, { name = "pillow" }, { name = "pyparsing" }, @@ -1227,8 +1091,8 @@ name = "ml-dtypes" version = "0.5.4" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/0e/4a/c27b42ed9b1c7d13d9ba8b6905dece787d6259152f2309338aed29b2447b/ml_dtypes-0.5.4.tar.gz", hash = "sha256:8ab06a50fb9bf9666dd0fe5dfb4676fa2b0ac0f31ecff72a6c3af8e22c063453" } wheels = [ @@ -1282,14 +1146,12 @@ name = "networkx" version = "3.4.2" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } resolution-markers = [ - "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1" } wheels = [ @@ -1301,86 +1163,62 @@ name = "networkx" version = "3.6.1" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } resolution-markers = [ - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509" } wheels = [ @@ -1392,12 +1230,12 @@ name = "numpy" version = "2.2.6" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } resolution-markers = [ - "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", + "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", ] @@ -1464,62 +1302,62 @@ name = "numpy" version = "2.4.4" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } resolution-markers = [ - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", @@ -1620,16 +1458,6 @@ wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/04/74/f4c001f4714c3ad9ce037e18cf2b9c64871a84951eaa0baf683a9ca9301c/numpy-2.4.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:f2cf083b324a467e1ab358c105f6cad5ea950f50524668a80c486ff1db24e119" }, ] -[[package]] -name = "nvidia-cublas" -version = "13.1.0.3" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/e1/a5/fce49e2ae977e0ccc084e5adafceb4f0ac0c8333cb6863501618a7277f67/nvidia_cublas-13.1.0.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c86fc7f7ae36d7528288c5d88098edcb7b02c633d262e7ddbb86b0ad91be5df2" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/e7/44/423ac00af4dd95a5aeb27207e2c0d9b7118702149bf4704c3ddb55bb7429/nvidia_cublas-13.1.0.3-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:ee8722c1f0145ab246bccb9e452153b5e0515fd094c3678df50b2a0888b8b171" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/10/f5/f50bc3f5c2bb57ab8f5b4d78bc1146b57810d42cb8fcb28cbe2e14050376/nvidia_cublas-13.1.0.3-py3-none-win_amd64.whl", hash = "sha256:2a3b94a37def342471c59fad7856caee4926809a72dd5270155d6a31b5b277be" }, -] - [[package]] name = "nvidia-cublas-cu12" version = "12.8.4.1" @@ -1640,16 +1468,6 @@ wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/70/61/7d7b3c70186fb651d0fbd35b01dbfc8e755f69fd58f817f3d0f642df20c3/nvidia_cublas_cu12-12.8.4.1-py3-none-win_amd64.whl", hash = "sha256:47e9b82132fa8d2b4944e708049229601448aaad7e6f296f630f2d1a32de35af" }, ] -[[package]] -name = "nvidia-cuda-cupti" -version = "13.0.85" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/2a/2a/80353b103fc20ce05ef51e928daed4b6015db4aaa9162ed0997090fe2250/nvidia_cuda_cupti-13.0.85-py3-none-manylinux_2_25_aarch64.whl", hash = "sha256:796bd679890ee55fb14a94629b698b6db54bcfd833d391d5e94017dd9d7d3151" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/33/6d/737d164b4837a9bbd202f5ae3078975f0525a55730fe871d8ed4e3b952b0/nvidia_cuda_cupti-13.0.85-py3-none-manylinux_2_25_x86_64.whl", hash = "sha256:4eb01c08e859bf924d222250d2e8f8b8ff6d3db4721288cf35d14252a4d933c8" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/ad/df/b74b10025c1205695c5676373f2edd3e87a7202cc62ead0dfbc373b0f6ea/nvidia_cuda_cupti-13.0.85-py3-none-win_amd64.whl", hash = "sha256:683f58d301548deeefcb8f6fac1b8d907691b9d8b18eccab417f51e362102f00" }, -] - [[package]] name = "nvidia-cuda-cupti-cu12" version = "12.8.90" @@ -1660,16 +1478,6 @@ wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/41/bc/83f5426095d93694ae39fe1311431b5d5a9bb82e48bf0dd8e19be2765942/nvidia_cuda_cupti_cu12-12.8.90-py3-none-win_amd64.whl", hash = "sha256:bb479dcdf7e6d4f8b0b01b115260399bf34154a1a2e9fe11c85c517d87efd98e" }, ] -[[package]] -name = "nvidia-cuda-nvrtc" -version = "13.0.88" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/c3/68/483a78f5e8f31b08fb1bb671559968c0ca3a065ac7acabfc7cee55214fd6/nvidia_cuda_nvrtc-13.0.88-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:ad9b6d2ead2435f11cbb6868809d2adeeee302e9bb94bcf0539c7a40d80e8575" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/b7/dc/6bb80850e0b7edd6588d560758f17e0550893a1feaf436807d64d2da040f/nvidia_cuda_nvrtc-13.0.88-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d27f20a0ca67a4bb34268a5e951033496c5b74870b868bacd046b1b8e0c3267b" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/4a/af/345fedb9f4c76c84ab4fa445b36bd4048a4d9db60e6bc76b4f913ff4b852/nvidia_cuda_nvrtc-13.0.88-py3-none-win_amd64.whl", hash = "sha256:6bcd4e7f8e205cbe644f5a98f2f799bef9556fefc89dd786e79a16312ce49872" }, -] - [[package]] name = "nvidia-cuda-nvrtc-cu12" version = "12.8.93" @@ -1680,16 +1488,6 @@ wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/45/51/52a3d84baa2136cc8df15500ad731d74d3a1114d4c123e043cb608d4a32b/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-win_amd64.whl", hash = "sha256:7a4b6b2904850fe78e0bd179c4b655c404d4bb799ef03ddc60804247099ae909" }, ] -[[package]] -name = "nvidia-cuda-runtime" -version = "13.0.96" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/87/4f/17d7b9b8e285199c58ce28e31b5c5bbaa4d8271af06a89b6405258245de2/nvidia_cuda_runtime-13.0.96-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ef9bcbe90493a2b9d810e43d249adb3d02e98dd30200d86607d8d02687c43f55" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/2e/24/d1558f3b68b1d26e706813b1d10aa1d785e4698c425af8db8edc3dced472/nvidia_cuda_runtime-13.0.96-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7f82250d7782aa23b6cfe765ecc7db554bd3c2870c43f3d1821f1d18aebf0548" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/b7/94/6b867483bec07da24ffa32736c79fabb94ef3a7af4d787a9d4a974868576/nvidia_cuda_runtime-13.0.96-py3-none-win_amd64.whl", hash = "sha256:f79298c8a098cec150a597c8eba58ecdab96e3bdc4b9bc4f9983635031740492" }, -] - [[package]] name = "nvidia-cuda-runtime-cu12" version = "12.8.90" @@ -1713,32 +1511,6 @@ wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/a7/a5/48f07449fc9c6cc146dcafe6149fa5d69630137d2ec5b7d9e09f255fadd7/nvidia_cudnn_cu12-9.19.0.56-py3-none-win_amd64.whl", hash = "sha256:cec70596b9ce878fab83810c3f5a2e606d35f510e5fee579759e4cbc68a23750" }, ] -[[package]] -name = "nvidia-cudnn-cu13" -version = "9.19.0.56" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -dependencies = [ - { name = "nvidia-cublas", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, -] -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/f1/84/26025437c1e6b61a707442184fa0c03d083b661adf3a3eecfd6d21677740/nvidia_cudnn_cu13-9.19.0.56-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:6ed29ffaee1176c612daf442e4dd6cfeb6a0caa43ddcbeb59da94953030b1be4" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/a3/22/0b4b932655d17a6da1b92fa92ab12844b053bb2ac2475e179ba6f043da1e/nvidia_cudnn_cu13-9.19.0.56-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:d20e1734305e9d68889a96e3f35094d733ff1f83932ebe462753973e53a572bf" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/91/a2/f020386683ee9ab2c9a9f7f79290d9b0d07f7241de54dc746af2abd188d2/nvidia_cudnn_cu13-9.19.0.56-py3-none-win_amd64.whl", hash = "sha256:40d8c375005bcb01495f8edf375230b203a411a0c05fb6dc92a3781edcb23eac" }, -] - -[[package]] -name = "nvidia-cufft" -version = "12.0.0.61" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -dependencies = [ - { name = "nvidia-nvjitlink", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, -] -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/8b/ae/f417a75c0259e85c1d2f83ca4e960289a5f814ed0cea74d18c353d3e989d/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2708c852ef8cd89d1d2068bdbece0aa188813a0c934db3779b9b1faa8442e5f5" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/a8/2f/7b57e29836ea8714f81e9898409196f47d772d5ddedddf1592eadb8ab743/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6c44f692dce8fd5ffd3e3df134b6cdb9c2f72d99cf40b62c32dde45eea9ddad3" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/85/b2/f8af21a2ed1beed337a6a02c5a28aeb85441f4d578ec3d529543c775ea4b/nvidia_cufft-12.0.0.61-py3-none-win_amd64.whl", hash = "sha256:2abce5b39d2f5ae12730fb7e5db6696533e36c26e2d3e8fd1750bdd2853364eb" }, -] - [[package]] name = "nvidia-cufft-cu12" version = "11.3.3.83" @@ -1752,15 +1524,6 @@ wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/7d/ec/ce1629f1e478bb5ccd208986b5f9e0316a78538dd6ab1d0484f012f8e2a1/nvidia_cufft_cu12-11.3.3.83-py3-none-win_amd64.whl", hash = "sha256:7a64a98ef2a7c47f905aaf8931b69a3a43f27c55530c698bb2ed7c75c0b42cb7" }, ] -[[package]] -name = "nvidia-cufile" -version = "1.15.1.6" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/3f/70/4f193de89a48b71714e74602ee14d04e4019ad36a5a9f20c425776e72cd6/nvidia_cufile-1.15.1.6-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:08a3ecefae5a01c7f5117351c64f17c7c62efa5fffdbe24fc7d298da19cd0b44" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/ab/73/cc4a14c9813a8a0d509417cf5f4bdaba76e924d58beb9864f5a7baceefbf/nvidia_cufile-1.15.1.6-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:bdc0deedc61f548bddf7733bdc216456c2fdb101d020e1ab4b88d232d5e2f6d1" }, -] - [[package]] name = "nvidia-cufile-cu12" version = "1.13.1.3" @@ -1770,16 +1533,6 @@ wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/1e/f5/5607710447a6fe9fd9b3283956fceeee8a06cda1d2f56ce31371f595db2a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a" }, ] -[[package]] -name = "nvidia-curand" -version = "10.4.0.35" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/1e/72/7c2ae24fb6b63a32e6ae5d241cc65263ea18d08802aaae087d9f013335a2/nvidia_curand-10.4.0.35-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:133df5a7509c3e292aaa2b477afd0194f06ce4ea24d714d616ff36439cee349a" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/a5/9f/be0a41ca4a4917abf5cb9ae0daff1a6060cc5de950aec0396de9f3b52bc5/nvidia_curand-10.4.0.35-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:1aee33a5da6e1db083fe2b90082def8915f30f3248d5896bcec36a579d941bfc" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/99/27/72103153b1ffc00e09fdc40ac970235343dcd1ea8bd762e84d2d73219ffa/nvidia_curand-10.4.0.35-py3-none-win_amd64.whl", hash = "sha256:65b1710aa6961d326b411e314b374290904c5ddf41dc3f766ebc3f1d7d4ca69f" }, -] - [[package]] name = "nvidia-curand-cu12" version = "10.3.9.90" @@ -1790,21 +1543,6 @@ wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/b9/75/70c05b2f3ed5be3bb30b7102b6eb78e100da4bbf6944fd6725c012831cab/nvidia_curand_cu12-10.3.9.90-py3-none-win_amd64.whl", hash = "sha256:f149a8ca457277da854f89cf282d6ef43176861926c7ac85b2a0fbd237c587ec" }, ] -[[package]] -name = "nvidia-cusolver" -version = "12.0.4.66" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -dependencies = [ - { name = "nvidia-cublas", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, - { name = "nvidia-cusparse", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, - { name = "nvidia-nvjitlink", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, -] -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/c8/c3/b30c9e935fc01e3da443ec0116ed1b2a009bb867f5324d3f2d7e533e776b/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:02c2457eaa9e39de20f880f4bd8820e6a1cfb9f9a34f820eb12a155aa5bc92d2" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/5f/67/cba3777620cdacb99102da4042883709c41c709f4b6323c10781a9c3aa34/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:0a759da5dea5c0ea10fd307de75cdeb59e7ea4fcb8add0924859b944babf1112" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/99/ef/332a0101260ca78a1daef046bf0b06199e8ed4dac1d2aa698289c358169c/nvidia_cusolver-12.0.4.66-py3-none-win_amd64.whl", hash = "sha256:16515bd33a8e76bb54d024cfa068fa68d30e80fc34b9e1090813ea9362e0cb65" }, -] - [[package]] name = "nvidia-cusolver-cu12" version = "11.7.3.90" @@ -1820,19 +1558,6 @@ wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/13/c0/76ca8551b8a84146ffa189fec81c26d04adba4bc0dbe09cd6e6fd9b7de04/nvidia_cusolver_cu12-11.7.3.90-py3-none-win_amd64.whl", hash = "sha256:4a550db115fcabc4d495eb7d39ac8b58d4ab5d8e63274d3754df1c0ad6a22d34" }, ] -[[package]] -name = "nvidia-cusparse" -version = "12.6.3.3" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -dependencies = [ - { name = "nvidia-nvjitlink", marker = "(python_full_version < '3.11' and sys_platform == 'emscripten') or (python_full_version < '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" }, -] -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/f8/94/5c26f33738ae35276672f12615a64bd008ed5be6d1ebcb23579285d960a9/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:80bcc4662f23f1054ee334a15c72b8940402975e0eab63178fc7e670aa59472c" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/fa/18/623c77619c31d62efd55302939756966f3ecc8d724a14dab2b75f1508850/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b3c89c88d01ee0e477cb7f82ef60a11a4bcd57b6b87c33f789350b59759360b" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/02/b0/b043d6f3480f102f885cf87fc3ffd3edcb5e23b855025a50e2ef4d059185/nvidia_cusparse-12.6.3.3-py3-none-win_amd64.whl", hash = "sha256:cbcf42feb737bd7ec15b4c0a63e62351886bd3f975027b8815d7f720a2b5ea79" }, -] - [[package]] name = "nvidia-cusparse-cu12" version = "12.5.8.93" @@ -1856,16 +1581,6 @@ wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/2f/d8/a6b0d0d0c2435e9310f3e2bb0d9c9dd4c33daef86aa5f30b3681defd37ea/nvidia_cusparselt_cu12-0.7.1-py3-none-win_amd64.whl", hash = "sha256:f67fbb5831940ec829c9117b7f33807db9f9678dc2a617fbe781cac17b4e1075" }, ] -[[package]] -name = "nvidia-cusparselt-cu13" -version = "0.8.0" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/46/10/8dcd1175260706a2fc92a16a52e306b71d4c1ea0b0cc4a9484183399818a/nvidia_cusparselt_cu13-0.8.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:400c6ed1cf6780fc6efedd64ec9f1345871767e6a1a0a552a1ea0578117ea77c" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/fd/53/43b0d71f4e702fa9733f8b4571fdca50a8813f1e450b656c239beff12315/nvidia_cusparselt_cu13-0.8.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:25e30a8a7323935d4ad0340b95a0b69926eee755767e8e0b1cf8dd85b197d3fd" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/57/de/8f0578928b9b1246d7b1324db0528e6b9f9fb54496a49f40bf71f09f1a27/nvidia_cusparselt_cu13-0.8.0-py3-none-win_amd64.whl", hash = "sha256:e80212ed7b1afc97102fbb2b5c82487aa73f6a0edfa6d26c5a152593e520bb8f" }, -] - [[package]] name = "nvidia-nccl-cu12" version = "2.28.9" @@ -1875,25 +1590,6 @@ wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/4a/4e/44dbb46b3d1b0ec61afda8e84837870f2f9ace33c564317d59b70bc19d3e/nvidia_nccl_cu12-2.28.9-py3-none-manylinux_2_18_x86_64.whl", hash = "sha256:485776daa8447da5da39681af455aa3b2c2586ddcf4af8772495e7c532c7e5ab" }, ] -[[package]] -name = "nvidia-nccl-cu13" -version = "2.28.9" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/39/55/1920646a2e43ffd4fc958536b276197ed740e9e0c54105b4bb3521591fc7/nvidia_nccl_cu13-2.28.9-py3-none-manylinux_2_18_aarch64.whl", hash = "sha256:01c873ba1626b54caa12272ed228dc5b2781545e0ae8ba3f432a8ef1c6d78643" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/b0/b4/878fefaad5b2bcc6fcf8d474a25e3e3774bc5133e4b58adff4d0bca238bc/nvidia_nccl_cu13-2.28.9-py3-none-manylinux_2_18_x86_64.whl", hash = "sha256:e4553a30f34195f3fa1da02a6da3d6337d28f2003943aa0a3d247bbc25fefc42" }, -] - -[[package]] -name = "nvidia-nvjitlink" -version = "13.0.88" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/56/7a/123e033aaff487c77107195fa5a2b8686795ca537935a24efae476c41f05/nvidia_nvjitlink-13.0.88-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:13a74f429e23b921c1109976abefacc69835f2f433ebd323d3946e11d804e47b" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/ab/2c/93c5250e64df4f894f1cbb397c6fd71f79813f9fd79d7cd61de3f97b3c2d/nvidia_nvjitlink-13.0.88-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e931536ccc7d467a98ba1d8b89ff7fa7f1fa3b13f2b0069118cd7f47bff07d0c" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/e4/01/07530b0e37546231052e30234540289c42eaffa486f1a34a87fed340157b/nvidia_nvjitlink-13.0.88-py3-none-win_amd64.whl", hash = "sha256:634e96e3da9ef845ae744097a1f289238ecf946ce0b82e93cdce14b9782e682f" }, -] - [[package]] name = "nvidia-nvjitlink-cu12" version = "12.8.93" @@ -1913,25 +1609,6 @@ wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/b5/09/6ea3ea725f82e1e76684f0708bbedd871fc96da89945adeba65c3835a64c/nvidia_nvshmem_cu12-3.4.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:042f2500f24c021db8a06c5eec2539027d57460e1c1a762055a6554f72c369bd" }, ] -[[package]] -name = "nvidia-nvshmem-cu13" -version = "3.4.5" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/dc/0f/05cc9c720236dcd2db9c1ab97fff629e96821be2e63103569da0c9b72f19/nvidia_nvshmem_cu13-3.4.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dc2a197f38e5d0376ad52cd1a2a3617d3cdc150fd5966f4aee9bcebb1d68fe9" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/3c/35/a9bf80a609e74e3b000fef598933235c908fcefcef9026042b8e6dfde2a9/nvidia_nvshmem_cu13-3.4.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:290f0a2ee94c9f3687a02502f3b9299a9f9fe826e6d0287ee18482e78d495b80" }, -] - -[[package]] -name = "nvidia-nvtx" -version = "13.0.85" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/c2/f3/d86c845465a2723ad7e1e5c36dcd75ddb82898b3f53be47ebd429fb2fa5d/nvidia_nvtx-13.0.85-py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4936d1d6780fbe68db454f5e72a42ff64d1fd6397df9f363ae786930fd5c1cd4" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/a8/64/3708a90d1ebe202ffdeb7185f878a3c84d15c2b2c31858da2ce0583e2def/nvidia_nvtx-13.0.85-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb7780edb6b14107373c835bf8b72e7a178bac7367e23da7acb108f973f157a6" }, - { url = "https://mirrors.cloud.tencent.com/pypi/packages/d2/50/0e2220f8620a177de994211186ffc5bfa9f2ce1e1282797f8f90096f9f88/nvidia_nvtx-13.0.85-py3-none-win_amd64.whl", hash = "sha256:d66ea44254dd3c6eacc300047af6e1288d2269dd072b417e0adffbf479e18519" }, -] - [[package]] name = "nvidia-nvtx-cu12" version = "12.8.90" @@ -1961,8 +1638,8 @@ version = "1.21.0" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } dependencies = [ { name = "ml-dtypes" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "protobuf" }, { name = "typing-extensions" }, ] @@ -2003,8 +1680,8 @@ version = "0.2.1" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } dependencies = [ { name = "ml-dtypes" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "onnx" }, { name = "sympy" }, { name = "typing-extensions" }, @@ -2019,21 +1696,21 @@ name = "onnxruntime" version = "1.24.3" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } resolution-markers = [ - "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", + "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", ] dependencies = [ - { name = "flatbuffers", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "packaging", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "protobuf", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "sympy", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "flatbuffers", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "packaging", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "protobuf", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "sympy", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/15/41/3253db975a90c3ce1d475e2a230773a21cd7998537f0657947df6fb79861/onnxruntime-1.24.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3e6456801c66b095c5cd68e690ca25db970ea5202bd0c5b84a2c3ef7731c5a3c" }, @@ -2067,62 +1744,62 @@ name = "onnxruntime" version = "1.25.0" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } resolution-markers = [ - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", @@ -2149,10 +1826,10 @@ resolution-markers = [ "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", ] dependencies = [ - { name = "flatbuffers", marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "packaging", marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "protobuf", marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "flatbuffers", marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "packaging", marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "protobuf", marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/66/67/edb2cb6c4a38ebf539c3529c5449d68b8031f3006d8ee36574a6d45559b2/onnxruntime-1.25.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a71baa8e0e2f3417106e3a8b2183fd5741875b998041f1a2422a1d0240f302cb" }, @@ -2187,8 +1864,8 @@ version = "0.7.0" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } dependencies = [ { name = "ml-dtypes" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "onnx" }, { name = "onnx-ir" }, { name = "packaging" }, @@ -2204,8 +1881,8 @@ name = "opencv-python" version = "4.13.0.92" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/fc/6f/5a28fef4c4a382be06afe3938c64cc168223016fa520c5abaf37e8862aa5/opencv_python-4.13.0.92-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:caf60c071ec391ba51ed00a4a920f996d0b64e3e46068aac1f646b5de0326a19" }, @@ -2232,20 +1909,20 @@ name = "pandas" version = "2.3.3" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } resolution-markers = [ - "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", + "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", ] dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "python-dateutil", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "pytz", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "tzdata", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "python-dateutil", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "pytz", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "tzdata", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b" } wheels = [ @@ -2303,62 +1980,62 @@ name = "pandas" version = "3.0.2" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } resolution-markers = [ - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", @@ -2385,9 +2062,9 @@ resolution-markers = [ "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", ] dependencies = [ - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "python-dateutil", marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "tzdata", marker = "(python_full_version >= '3.11' and sys_platform == 'emscripten') or (python_full_version >= '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "python-dateutil", marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "tzdata", marker = "(python_full_version >= '3.11' and sys_platform == 'emscripten') or (python_full_version >= '3.11' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/da/99/b342345300f13440fe9fe385c3c481e2d9a595ee3bab4d3219247ac94e9a/pandas-3.0.2.tar.gz", hash = "sha256:f4753e73e34c8d83221ba58f232433fca2748be8b18dbca02d242ed153945043" } wheels = [ @@ -2440,123 +2117,6 @@ wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/cb/2b/f8434233fab2bd66a02ec014febe4e5adced20e2693e0e90a07d118ed30e/pandas-3.0.2-cp314-cp314t-win_arm64.whl", hash = "sha256:5371b72c2d4d415d08765f32d689217a43227484e81b2305b52076e328f6f482" }, ] -[[package]] -name = "pandas-stubs" -version = "2.3.3.260113" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -resolution-markers = [ - "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", -] -dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "types-pytz", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, -] -sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/92/5d/be23854a73fda69f1dbdda7bc10fbd6f930bd1fa87aaec389f00c901c1e8/pandas_stubs-2.3.3.260113.tar.gz", hash = "sha256:076e3724bcaa73de78932b012ec64b3010463d377fa63116f4e6850643d93800" } -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/d1/c6/df1fe324248424f77b89371116dab5243db7f052c32cc9fe7442ad9c5f75/pandas_stubs-2.3.3.260113-py3-none-any.whl", hash = "sha256:ec070b5c576e1badf12544ae50385872f0631fc35d99d00dc598c2954ec564d3" }, -] - -[[package]] -name = "pandas-stubs" -version = "3.0.0.260204" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -resolution-markers = [ - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", -] -dependencies = [ - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, -] -sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/27/1d/297ff2c7ea50a768a2247621d6451abb2a07c0e9be7ca6d36ebe371658e5/pandas_stubs-3.0.0.260204.tar.gz", hash = "sha256:bf9294b76352effcffa9cb85edf0bed1339a7ec0c30b8e1ac3d66b4228f1fbc3" } -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/7c/2f/f91e4eee21585ff548e83358332d5632ee49f6b2dcd96cb5dca4e0468951/pandas_stubs-3.0.0.260204-py3-none-any.whl", hash = "sha256:5ab9e4d55a6e2752e9720828564af40d48c4f709e6a2c69b743014a6fcb6c241" }, -] - [[package]] name = "pefile" version = "2024.8.26" @@ -2728,11 +2288,11 @@ version = "6.20.0" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } dependencies = [ { name = "altgraph" }, - { name = "macholib", marker = "sys_platform == 'darwin' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "macholib", marker = "sys_platform == 'darwin' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "packaging" }, - { name = "pefile", marker = "sys_platform == 'win32' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "pefile", marker = "sys_platform == 'win32' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "pyinstaller-hooks-contrib" }, - { name = "pywin32-ctypes", marker = "sys_platform == 'win32' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "pywin32-ctypes", marker = "sys_platform == 'win32' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "setuptools" }, ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/46/60/d03d52e6690d4e9caf333dcd14550cde634ce6c118b3bc8fa3112c3186fd/pyinstaller-6.20.0.tar.gz", hash = "sha256:95c5c7e03d5d61e9dfb8ef259c699cf492bb1041beb6dbe83696608cec07347a" } @@ -2956,8 +2516,8 @@ version = "3.8.1" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } dependencies = [ { name = "colorlog" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "omegaconf" }, { name = "opencv-python" }, { name = "pillow" }, @@ -2992,20 +2552,20 @@ name = "scikit-learn" version = "1.7.2" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } resolution-markers = [ - "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", + "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", ] dependencies = [ - { name = "joblib", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "scipy", version = "1.15.3", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "threadpoolctl", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "joblib", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "scipy", version = "1.15.3", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "threadpoolctl", marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda" } wheels = [ @@ -3046,62 +2606,62 @@ name = "scikit-learn" version = "1.8.0" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } resolution-markers = [ - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", @@ -3128,10 +2688,10 @@ resolution-markers = [ "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", ] dependencies = [ - { name = "joblib", marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "scipy", version = "1.17.1", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "threadpoolctl", marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "joblib", marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "scipy", version = "1.17.1", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "threadpoolctl", marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/0e/d4/40988bf3b8e34feec1d0e6a051446b1f66225f8529b9309becaeef62b6c4/scikit_learn-1.8.0.tar.gz", hash = "sha256:9bccbb3b40e3de10351f8f5068e105d0f4083b1a65fa07b6634fbc401a6287fd" } wheels = [ @@ -3178,17 +2738,17 @@ name = "scipy" version = "1.15.3" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } resolution-markers = [ - "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", + "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version < '3.11' and platform_machine != 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version < '3.11' and platform_machine == 's390x' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", ] dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf" } wheels = [ @@ -3244,62 +2804,62 @@ name = "scipy" version = "1.17.1" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } resolution-markers = [ - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128' and extra != 'extra-19-cannotmax-greenvine-cu130'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", @@ -3326,7 +2886,7 @@ resolution-markers = [ "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128'", ] dependencies = [ - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0" } wheels = [ @@ -3406,8 +2966,8 @@ name = "shapely" version = "2.1.2" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/4d/bc/0989043118a27cccb4e906a46b7565ce36ca7b57f5a18b78f4f1b0f72d9d/shapely-2.1.2.tar.gz", hash = "sha256:2ed4ecb28320a433db18a5bf029986aa8afcfd740745e78847e330d5d94922a9" } wheels = [ @@ -3523,20 +3083,24 @@ version = "2.11.0" source = { registry = "https://download.pytorch.org/whl/cpu" } resolution-markers = [ "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin'", "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin'", "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin'", "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin'", "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin'", ] dependencies = [ - { name = "filelock", marker = "platform_machine != 's390x' and sys_platform == 'darwin'" }, - { name = "fsspec", marker = "platform_machine != 's390x' and sys_platform == 'darwin'" }, - { name = "jinja2", marker = "platform_machine != 's390x' and sys_platform == 'darwin'" }, - { name = "networkx", version = "3.4.2", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version >= '3.11' and platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (python_full_version >= '3.11' and platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "networkx", version = "3.6.1", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version >= '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version < '3.11' and platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (python_full_version < '3.11' and platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (python_full_version < '3.11' and platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "setuptools", marker = "platform_machine != 's390x' and sys_platform == 'darwin'" }, - { name = "sympy", marker = "platform_machine != 's390x' and sys_platform == 'darwin'" }, - { name = "typing-extensions", marker = "platform_machine != 's390x' and sys_platform == 'darwin'" }, + { name = "filelock", marker = "(python_full_version >= '3.11' and sys_platform == 'darwin') or (platform_machine != 's390x' and sys_platform == 'darwin')" }, + { name = "fsspec", marker = "(python_full_version >= '3.11' and sys_platform == 'darwin') or (platform_machine != 's390x' and sys_platform == 'darwin')" }, + { name = "jinja2", marker = "(python_full_version >= '3.11' and sys_platform == 'darwin') or (platform_machine != 's390x' and sys_platform == 'darwin')" }, + { name = "networkx", version = "3.4.2", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version >= '3.11' and platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "networkx", version = "3.6.1", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version >= '3.11' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version < '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "setuptools", marker = "(python_full_version >= '3.11' and sys_platform == 'darwin') or (platform_machine != 's390x' and sys_platform == 'darwin')" }, + { name = "sympy", marker = "(python_full_version >= '3.11' and sys_platform == 'darwin') or (platform_machine != 's390x' and sys_platform == 'darwin')" }, + { name = "typing-extensions", marker = "(python_full_version >= '3.11' and sys_platform == 'darwin') or (platform_machine != 's390x' and sys_platform == 'darwin')" }, ] wheels = [ { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91209c7d8a2460b76e8ff5b28b7623da4ab1d27474b79e1de83e954871985afe", upload-time = "2026-03-23T15:16:50Z" }, @@ -3559,7 +3123,6 @@ resolution-markers = [ "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin'", "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32'", "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32'", "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32'", @@ -3578,22 +3141,19 @@ resolution-markers = [ "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin'", "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin'", "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin'", "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin'", ] dependencies = [ - { name = "filelock", marker = "platform_machine == 's390x' or sys_platform != 'darwin'" }, - { name = "fsspec", marker = "platform_machine == 's390x' or sys_platform != 'darwin'" }, - { name = "jinja2", marker = "platform_machine == 's390x' or sys_platform != 'darwin'" }, - { name = "networkx", version = "3.4.2", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version < '3.11' and platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version < '3.11' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version >= '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (python_full_version >= '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "networkx", version = "3.6.1", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version >= '3.11' and platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version >= '3.11' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version < '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (python_full_version < '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (python_full_version < '3.11' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "setuptools", marker = "platform_machine == 's390x' or sys_platform != 'darwin'" }, - { name = "sympy", marker = "platform_machine == 's390x' or sys_platform != 'darwin'" }, - { name = "typing-extensions", marker = "platform_machine == 's390x' or sys_platform != 'darwin'" }, + { name = "filelock", marker = "(python_full_version < '3.11' and platform_machine == 's390x') or sys_platform != 'darwin'" }, + { name = "fsspec", marker = "(python_full_version < '3.11' and platform_machine == 's390x') or sys_platform != 'darwin'" }, + { name = "jinja2", marker = "(python_full_version < '3.11' and platform_machine == 's390x') or sys_platform != 'darwin'" }, + { name = "networkx", version = "3.4.2", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version < '3.11' and platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version < '3.11' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version >= '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "networkx", version = "3.6.1", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version >= '3.11' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version < '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "setuptools", marker = "(python_full_version < '3.11' and platform_machine == 's390x') or sys_platform != 'darwin'" }, + { name = "sympy", marker = "(python_full_version < '3.11' and platform_machine == 's390x') or sys_platform != 'darwin'" }, + { name = "typing-extensions", marker = "(python_full_version < '3.11' and platform_machine == 's390x') or sys_platform != 'darwin'" }, ] wheels = [ { url = "https://download-r2.pytorch.org/whl/cpu/torch-2.11.0%2Bcpu-cp310-cp310-linux_s390x.whl", hash = "sha256:3d8a7789e61dbf11f8922672c43354614b9b0debd40899c0a94f1ad9e0bd6bd9", upload-time = "2026-04-27T21:55:13Z" }, @@ -3659,13 +3219,13 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine == 's390x'", ] dependencies = [ - { name = "cuda-bindings", version = "12.9.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "sys_platform == 'linux'" }, - { name = "cuda-toolkit", version = "12.8.1", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, extra = ["cublas", "cudart", "cufft", "cufile", "cupti", "curand", "cusolver", "cusparse", "nvjitlink", "nvrtc", "nvtx"], marker = "(sys_platform == 'linux' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "cuda-bindings", marker = "sys_platform == 'linux'" }, + { name = "cuda-toolkit", extra = ["cublas", "cudart", "cufft", "cufile", "cupti", "curand", "cusolver", "cusparse", "nvjitlink", "nvrtc", "nvtx"], marker = "(sys_platform == 'linux' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "filelock" }, { name = "fsspec" }, { name = "jinja2" }, - { name = "networkx", version = "3.4.2", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version < '3.11' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "networkx", version = "3.6.1", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version >= '3.11' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "networkx", version = "3.4.2", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version < '3.11' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "networkx", version = "3.6.1", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version >= '3.11' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "nvidia-cudnn-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-cusparselt-cu12", marker = "sys_platform == 'linux'" }, { name = "nvidia-nccl-cu12", marker = "sys_platform == 'linux'" }, @@ -3699,95 +3259,26 @@ wheels = [ { url = "https://download-r2.pytorch.org/whl/cu128/torch-2.11.0%2Bcu128-cp314-cp314t-win_amd64.whl", hash = "sha256:d86c125d720c2c368c53bd1a4ef062916d91fa965c10448c74c78b5d039faf2d", upload-time = "2026-04-27T18:01:14Z" }, ] -[[package]] -name = "torch" -version = "2.11.0+cu130" -source = { registry = "https://download.pytorch.org/whl/cu130" } -resolution-markers = [ - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version < '3.11' and platform_machine != 's390x'", - "python_full_version < '3.11' and platform_machine == 's390x'", -] -dependencies = [ - { name = "cuda-bindings", version = "13.2.0", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "sys_platform == 'linux'" }, - { name = "cuda-toolkit", version = "13.0.2", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, extra = ["cublas", "cudart", "cufft", "cufile", "cupti", "curand", "cusolver", "cusparse", "nvjitlink", "nvrtc", "nvtx"], marker = "(sys_platform == 'linux' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "filelock" }, - { name = "fsspec" }, - { name = "jinja2" }, - { name = "networkx", version = "3.4.2", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version < '3.11' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "networkx", version = "3.6.1", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version >= '3.11' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "nvidia-cudnn-cu13", marker = "sys_platform == 'linux'" }, - { name = "nvidia-cusparselt-cu13", marker = "sys_platform == 'linux'" }, - { name = "nvidia-nccl-cu13", marker = "sys_platform == 'linux'" }, - { name = "nvidia-nvshmem-cu13", marker = "sys_platform == 'linux'" }, - { name = "setuptools" }, - { name = "sympy" }, - { name = "triton", marker = "sys_platform == 'linux'" }, - { name = "typing-extensions" }, -] -wheels = [ - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:4af01fad0822353e766770ff2c7d6bdc2cbcc2ac7fcd6da93a9e3c6f3f932b21", upload-time = "2026-04-27T19:56:16Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:4c5be01584b7fee22d3c0d04062fd28026044acd07ffd0ee64cbd54b60e62d39", upload-time = "2026-04-27T19:56:40Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp310-cp310-win_amd64.whl", hash = "sha256:5b603a44f34816e18df254443a1fbfb4eef7d57128e5c7f6655f7fab45071f6e", upload-time = "2026-04-27T19:57:45Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:6304535e9e4cd1beeab449e407712602aa473a97e7b310dc5650ef50940bd94f", upload-time = "2026-04-27T19:58:56Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:225b22e0a4e36ea573d3a68796e6816a160616f67e8b8c55683a88bf7777f4cd", upload-time = "2026-04-27T19:59:21Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp311-cp311-win_amd64.whl", hash = "sha256:a1ff66c0ad21bf48c3187e84a08a6895d48e9bae435e27811b0b65f36bef4555", upload-time = "2026-04-27T20:00:28Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:252f237d417fac3ba59b1635815c1f035a8241f2af038f2c076ed430932d89f1", upload-time = "2026-04-27T20:01:46Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:96911323dcfcd42028c7e8edde7bdf25bb187753234e8775f0f3f112e86a22db", upload-time = "2026-04-27T20:02:14Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp312-cp312-win_amd64.whl", hash = "sha256:ef8beae16d781c3244ef28dc7bee6d8871c26bbde65d5bf66e902cb61972c4ab", upload-time = "2026-04-27T20:03:28Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c3d60f79666b9101e3914a2e5dec2e81eac834e13cae0bcf59e94dc1a465f756", upload-time = "2026-04-27T20:04:49Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:554461b76f21211927c776056bcb0b00fb42972364794b686d768ebb0b586366", upload-time = "2026-04-27T20:05:21Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313-win_amd64.whl", hash = "sha256:339801f2163698a53c7fb3c91883e7f44331d22c34d45acfbce4eff71f2332fa", upload-time = "2026-04-27T20:06:44Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:a33905bc3e093b25d2b019181cf834f7f7d4c562739e13dd36a798ecb2e411b0", upload-time = "2026-04-27T20:08:23Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:6fd10ed484eb695312ae829719888bb9f6c7f5e8503528e3e8ad1b98a45296c2", upload-time = "2026-04-27T20:08:56Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp313-cp313t-win_amd64.whl", hash = "sha256:21d2734fd02af45d19bb88c0ff2e86b238ce73f7bde6003ade7f1454ae299198", upload-time = "2026-04-27T20:10:20Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:efcdfe08ec2c9db28b50cc7329fed0c90bb74fa6fbce0f7eb12e20db2279a40f", upload-time = "2026-04-27T20:11:48Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:6ccc36928fd17c86011b46fb81bd2c85475f1fbf967dde758672d6a8d83a212a", upload-time = "2026-04-27T20:12:18Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp314-cp314-win_amd64.whl", hash = "sha256:d886f1c2f4406d7ad0c59f254ceb0a9c47a03e97a7c704b778a2066d752dde29", upload-time = "2026-04-27T20:13:41Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:bdb20f8b04e9fcaba2f354c3026667bebb74de8a92526b706aa735e2df334c24", upload-time = "2026-04-27T20:15:02Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:28f952cd4a927616ad9d77644a93237d1ca50bf30d0cf26962b9162d8a00ffa0", upload-time = "2026-04-27T20:15:30Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torch-2.11.0%2Bcu130-cp314-cp314t-win_amd64.whl", hash = "sha256:d0a857adc487f275bfc9e7cdc51d12940613ba18b6362da214e20e9e3871f817", upload-time = "2026-04-27T20:16:48Z" }, -] - [[package]] name = "torchvision" version = "0.26.0" source = { registry = "https://download.pytorch.org/whl/cpu" } resolution-markers = [ "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'darwin'", + "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin'", "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'darwin'", "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'darwin'", "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'darwin'", + "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin'", + "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin'", + "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin'", "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin'", ] dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version >= '3.11' and platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (python_full_version >= '3.11' and platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version >= '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version < '3.11' and platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (python_full_version < '3.11' and platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (python_full_version < '3.11' and platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "pillow", marker = "platform_machine != 's390x' and sys_platform == 'darwin'" }, - { name = "torch", version = "2.11.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "platform_machine != 's390x' and sys_platform == 'darwin'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version < '3.11' and platform_machine != 's390x' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version >= '3.11' and platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version >= '3.11' and sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version < '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "pillow", marker = "(python_full_version >= '3.11' and sys_platform == 'darwin') or (platform_machine != 's390x' and sys_platform == 'darwin')" }, + { name = "torch", version = "2.11.0", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(python_full_version >= '3.11' and sys_platform == 'darwin') or (platform_machine != 's390x' and sys_platform == 'darwin')" }, ] wheels = [ { url = "https://download-r2.pytorch.org/whl/cpu/torchvision-0.26.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a06d4772a8e13e772906ed736cc53ec6639e5e60554f8e5fa6ca165aabebc464", upload-time = "2026-03-23T15:36:09Z" }, @@ -3810,7 +3301,6 @@ resolution-markers = [ "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten'", "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'darwin'", "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32'", "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32'", "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32'", @@ -3829,18 +3319,15 @@ resolution-markers = [ "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'darwin' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'darwin'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'darwin'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'darwin'", "python_full_version < '3.11' and platform_machine != 's390x' and sys_platform != 'darwin'", "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform != 'darwin'", "python_full_version < '3.11' and platform_machine == 's390x' and sys_platform == 'darwin'", ] dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version < '3.11' and platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version < '3.11' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version >= '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (python_full_version >= '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version >= '3.11' and platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version >= '3.11' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version < '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (python_full_version < '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (python_full_version < '3.11' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra != 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "pillow", marker = "platform_machine == 's390x' or sys_platform != 'darwin'" }, - { name = "torch", version = "2.11.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "platform_machine == 's390x' or sys_platform != 'darwin'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version < '3.11' and platform_machine == 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version < '3.11' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version >= '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (platform_machine != 's390x' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version >= '3.11' and sys_platform != 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu') or (python_full_version < '3.11' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (sys_platform == 'darwin' and extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "pillow", marker = "(python_full_version < '3.11' and platform_machine == 's390x') or sys_platform != 'darwin'" }, + { name = "torch", version = "2.11.0+cpu", source = { registry = "https://download.pytorch.org/whl/cpu" }, marker = "(python_full_version < '3.11' and platform_machine == 's390x') or sys_platform != 'darwin'" }, ] wheels = [ { url = "https://download-r2.pytorch.org/whl/cpu/torchvision-0.26.0%2Bcpu-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:97df9a8595dce256d2e6dd16bbcd1c68dd00eec712e37d4b6ec7985453ddc2aa", upload-time = "2026-03-23T15:36:09Z" }, @@ -3899,8 +3386,8 @@ resolution-markers = [ "python_full_version < '3.11' and platform_machine == 's390x'", ] dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version < '3.11' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version >= '3.11' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version < '3.11' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version >= '3.11' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "pillow" }, { name = "torch", version = "2.11.0+cu128", source = { registry = "https://download.pytorch.org/whl/cu128" } }, ] @@ -3928,74 +3415,12 @@ wheels = [ { url = "https://download-r2.pytorch.org/whl/cu128/torchvision-0.26.0%2Bcu128-cp314-cp314t-win_amd64.whl", hash = "sha256:f160dc552a086244f7102c898f7be8ef46a41b36bce5ea80a4f2493cb30ca1fc", upload-time = "2026-04-09T23:21:41Z" }, ] -[[package]] -name = "torchvision" -version = "0.26.0+cu130" -source = { registry = "https://download.pytorch.org/whl/cu130" } -resolution-markers = [ - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'win32'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'win32'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform == 'emscripten'", - "python_full_version >= '3.14' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version >= '3.14' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'win32'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'win32'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'win32'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform == 'emscripten'", - "python_full_version == '3.13.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and platform_machine != 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.13.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.12.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version == '3.11.*' and platform_machine == 's390x' and sys_platform != 'emscripten' and sys_platform != 'win32'", - "python_full_version < '3.11' and platform_machine != 's390x'", - "python_full_version < '3.11' and platform_machine == 's390x'", -] -dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version < '3.11' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "(python_full_version >= '3.11' and extra != 'extra-19-cannotmax-greenvine-cpu' and extra != 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "pillow" }, - { name = "torch", version = "2.11.0+cu130", source = { registry = "https://download.pytorch.org/whl/cu130" } }, -] -wheels = [ - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:3094bed175eee817f9fc61d1c8bdecb1d807c25f49517fbfe60f15d24135fcde", upload-time = "2026-03-23T15:36:25Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:7d820708732d2467caf2ef16c3ad60c8ff402bd05bd246b108ee080f3fbfdc6e", upload-time = "2026-03-23T15:36:25Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp310-cp310-win_amd64.whl", hash = "sha256:a410cf52350ff4a5e0a71cedaf03bdec973c7a22421f36163d887a251acf51d7", upload-time = "2026-03-23T15:36:25Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:31f87cd00c09e071980d6a4ce218289a73302ad6a7ce0b3b62a74a4081fc339d", upload-time = "2026-03-23T15:36:25Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:3b53e3b611561e03ac261d06cb3f38782120ad9e0b4cd9f01549799097c713a6", upload-time = "2026-03-23T15:36:25Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp311-cp311-win_amd64.whl", hash = "sha256:d019b9d02433515d59ad403d8a6f521da7844c030d6c8003eeec39e15e59f9fa", upload-time = "2026-04-09T23:21:52Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e2b39db78be674ee4ce7e921f54b70e5c281594c9267d981c061684ed38df936", upload-time = "2026-03-23T15:36:26Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:0f030a9bd8ada1a31b7111ea1589c1ecb5fa0884fee700a203e731b4cf378a98", upload-time = "2026-03-23T15:36:26Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp312-cp312-win_amd64.whl", hash = "sha256:a3578f7c8e8a2724306c68c56873a1675fa7ce45471e18235c720a2ed242fe44", upload-time = "2026-04-09T23:21:53Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:3af2c699719cc0e2518bf317664200e5a987fb75a25b9b3bf3817a4796ddd64f", upload-time = "2026-03-23T15:36:26Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:441a98bed4fff1d54b8450499e377e1a605bec31f2ecb1a38a340f95dcc83897", upload-time = "2026-03-23T15:36:26Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313-win_amd64.whl", hash = "sha256:64de855465d6de60583e776889fad9412480f9f9e04fdd8d17ae96fa93864e9a", upload-time = "2026-04-09T23:21:54Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c3ac485da79552b4f579c525c826f7a63288b0d1cafc1201b16e1148bfdea69a", upload-time = "2026-03-23T15:36:26Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:110659ff38cd1d2ca0ac6e6a0f2c842fcb5fe739dfe65ff7456a12b2c4dce775", upload-time = "2026-03-23T15:36:26Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp313-cp313t-win_amd64.whl", hash = "sha256:a7e19c3ab5c6d8e3c9f8c6d427f6b8862dfb8227ea4a758ea7a709951daf2f0d", upload-time = "2026-04-09T23:21:55Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:13fe3dee74a9ee31b551b10a8b4113d9bc5212bb0572a07af88b34a5d25d9701", upload-time = "2026-03-23T15:36:26Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:8d6a83a639d14f7e84f6b838a17e26f9ce41cdbe3dfe0c29ef74b32eb398ba28", upload-time = "2026-03-23T15:36:26Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp314-cp314-win_amd64.whl", hash = "sha256:ab671ffe837aff470baad6af97133ea5a49f8ea2383832550e510a63caf711e4", upload-time = "2026-04-09T23:21:56Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:cd89effa98de436ec22ccbbd278cdadc0fdec8eb81a396150f50b321c2230866", upload-time = "2026-03-23T15:36:26Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:aacac4d990ac794f3abeca66cc26affb42fbeba9789e5c351183665bab4902d2", upload-time = "2026-03-23T15:36:26Z" }, - { url = "https://download-r2.pytorch.org/whl/cu130/torchvision-0.26.0%2Bcu130-cp314-cp314t-win_amd64.whl", hash = "sha256:23b9666084c72d07fc715001880b648e6a410796d1925c10f054f1ee034f5cc7", upload-time = "2026-04-09T23:21:57Z" }, -] - [[package]] name = "tqdm" version = "4.67.3" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "colorama", marker = "sys_platform == 'win32' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb" } wheels = [ @@ -4023,24 +3448,6 @@ wheels = [ { url = "https://mirrors.cloud.tencent.com/pypi/packages/f6/56/6113c23ff46c00aae423333eb58b3e60bdfe9179d542781955a5e1514cb3/triton-3.6.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:46bd1c1af4b6704e554cad2eeb3b0a6513a980d470ccfa63189737340c7746a7" }, ] -[[package]] -name = "types-pytz" -version = "2026.1.1.20260408" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/f7/b7/33f5a4f29b1f285b99ff79a607751a7996194cbb98705e331dab7a2daa28/types_pytz-2026.1.1.20260408.tar.gz", hash = "sha256:89b6a34b9198ea2a4b98a9d15cbca987053f52a105fd44f7ce3789cae4349408" } -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/ae/90/12c059e6bb330a22d9cc97daf027ac7fb7f50fbf518e4d88185b4d39120e/types_pytz-2026.1.1.20260408-py3-none-any.whl", hash = "sha256:c7e4dec76221fb7d0c97b91ad8561d689bebe39b6bcb7b728387e7ffd8cde788" }, -] - -[[package]] -name = "types-toml" -version = "0.10.8.20260408" -source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } -sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/71/9b/887564a51a84c96ba08b715570e546f0ea793df6372b736bfbc596ca5536/types_toml-0.10.8.20260408.tar.gz", hash = "sha256:6b30b031235565a12febb1388900b129f1adeabfcfa594da46d0372b2ac107ad" } -wheels = [ - { url = "https://mirrors.cloud.tencent.com/pypi/packages/56/f1/942d95ba026779bc6e3064f8b094216588dc3276cc328cf8e03a0541918d/types_toml-0.10.8.20260408-py3-none-any.whl", hash = "sha256:e958d4c660385e548705a298f17dc162baf44c8b6d6aff79aeefe75f4f77ac87" }, -] - [[package]] name = "typing-extensions" version = "4.15.0" @@ -4073,8 +3480,8 @@ name = "windows-capture" version = "2.0.0" source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" } dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, - { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128') or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu130') or (extra == 'extra-19-cannotmax-greenvine-cu128' and extra == 'extra-19-cannotmax-greenvine-cu130')" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version < '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, + { name = "numpy", version = "2.4.4", source = { registry = "https://mirrors.cloud.tencent.com/pypi/simple/" }, marker = "python_full_version >= '3.11' or (extra == 'extra-19-cannotmax-greenvine-cpu' and extra == 'extra-19-cannotmax-greenvine-cu128')" }, { name = "opencv-python" }, ] sdist = { url = "https://mirrors.cloud.tencent.com/pypi/packages/7e/60/1acdf4a4bb625bf04e94afde8bdb60a06997e644c6be7befe413dc5215ed/windows_capture-2.0.0.tar.gz", hash = "sha256:f1d587c182afa06c060e36ba2bd4f216a8ed03f320f51d7b6d5c8a2759469956" } diff --git a/src/models/val.py b/val.py similarity index 71% rename from src/models/val.py rename to val.py index f91a52f..2d83354 100644 --- a/src/models/val.py +++ b/val.py @@ -1,8 +1,7 @@ import torch import torch.nn as nn from torch.utils.data import DataLoader -from src.models.train import UnitAwareTransformer, ArknightsDataset - +from train import UnitAwareTransformer,ArknightsDataset def evaluate(model, data_loader, criterion, device): model.eval() @@ -17,16 +16,8 @@ def evaluate(model, data_loader, criterion, device): # 其余代码保持不变... # 检查输入值范围 - if ( - torch.isnan(ls).any() - or torch.isnan(lc).any() - or torch.isnan(rs).any() - or torch.isnan(rc).any() - or torch.isinf(ls).any() - or torch.isinf(lc).any() - or torch.isinf(rs).any() - or torch.isinf(rc).any() - ): + if torch.isnan(ls).any() or torch.isnan(lc).any() or torch.isnan(rs).any() or torch.isnan(rc).any() or \ + torch.isinf(ls).any() or torch.isinf(lc).any() or torch.isinf(rs).any() or torch.isinf(rc).any(): print("警告: 评估时输入数据包含NaN或Inf,跳过该批次") continue @@ -63,15 +54,14 @@ def evaluate(model, data_loader, criterion, device): return total_loss / max(1, len(data_loader)), 100 * correct / max(1, total) - def main(): config = { - "data_file": "arknights_clean.csv", - "batch_size": 256, - "max_feature_value": 200, # 限制特征最大值,防止极端值造成不稳定 + 'data_file': 'arknights_clean.csv', + 'batch_size': 256, + 'max_feature_value': 200 # 限制特征最大值,防止极端值造成不稳定 } # 设置设备 - device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') print(f"使用设备: {device}") # 检查CUDA可用性 @@ -85,41 +75,36 @@ def main(): torch.backends.cudnn.benchmark = False else: print("警告: 未检测到GPU,将在CPU上运行训练,这可能会很慢!") - + dataset = ArknightsDataset( - config["data_file"], - max_value=config["max_feature_value"], # 使用最大值限制 + config['data_file'], + max_value=config['max_feature_value'] # 使用最大值限制 ) - + # 修改这里 - 只有当数据在CPU上时才使用pin_memory val_loader = DataLoader( - dataset, - batch_size=config["batch_size"], + dataset, + batch_size=config['batch_size'], num_workers=0, - pin_memory=False, # 禁用pin_memory,或者根据你的数据集情况调整 + pin_memory=False # 禁用pin_memory,或者根据你的数据集情况调整 ) - + model = UnitAwareTransformer( num_units=34, # 更新为34个怪物 embed_dim=128, num_heads=8, - num_layers=4, # 注意:train.py中config['n_layers']=4 + num_layers=4 # 注意:train.py中config['n_layers']=4 ).to(device) # 加载模型权重 try: - model = torch.load( - "models/best_model_full.pth", - map_location=device, - weights_only=False, - ) + model = torch.load('models/best_model_full.pth', map_location=device, weights_only=False) except TypeError: # 如果旧版本 PyTorch 不认识 weights_only - model = torch.load("models/best_model_full.pth", map_location=device) + model = torch.load('models/best_model_full.pth', map_location=device) model.eval() criterion = nn.BCELoss() val_loss, val_acc = evaluate(model, val_loader, criterion, device) print(f"Val Loss: {val_loss:.4f} | Acc: {val_acc:.2f}%") - - + if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/src/game/winrt_capture.py b/winrt_capture.py similarity index 90% rename from src/game/winrt_capture.py rename to winrt_capture.py index 38ef03e..f69847d 100644 --- a/src/game/winrt_capture.py +++ b/winrt_capture.py @@ -11,7 +11,6 @@ - 运行时可调用 `recreate()` **切换捕获目标**(重新创建底层会话); - 通过锁保护 start/stop/recreate 的并发安全。 """ - from __future__ import annotations import threading import time @@ -23,11 +22,10 @@ import numpy as np from windows_capture import WindowsCapture, Frame, InternalCaptureControl -from PyQt6.QtWidgets import QVBoxLayout, QListWidget, QLineEdit, QDialog +from PyQt6.QtWidgets import (QVBoxLayout,QListWidget,QLineEdit,QDialog) logger = logging.getLogger(__name__) - class WinRTScreenCapture: """Windows.Graphics.Capture 适配器。 @@ -63,9 +61,7 @@ def __init__( # 控制状态 self._started = False - self._control: Optional[InternalCaptureControl] = ( - None # 保存 CaptureControl,用于停止 - ) + self._control: Optional[InternalCaptureControl] = None # 保存 CaptureControl,用于停止 # 保护 start/stop/recreate 的可重入锁 self._ctl_lock = threading.RLock() @@ -122,9 +118,7 @@ def start(self) -> None: cursor_capture=self._init_kwargs["cursor_capture"], draw_border=self._init_kwargs["draw_border"], secondary_window=None, - minimum_update_interval=self._init_kwargs[ - "minimum_update_interval" - ], + minimum_update_interval=self._init_kwargs["minimum_update_interval"], dirty_region=None, monitor_index=1, window_name=None, @@ -151,11 +145,7 @@ def stop(self) -> None: with self._lock: self._latest = None - def recreate( - self, - window_name: Optional[str] = None, - monitor_index: Optional[int] = None, - ) -> None: + def recreate(self, window_name: Optional[str] = None, monitor_index: Optional[int] = None) -> None: """运行时切换捕获目标并立即启动。 同步步骤:stop → 以新参数创建 → 重新绑定事件 → 启动。 @@ -166,9 +156,7 @@ def recreate( cursor_capture=self._init_kwargs["cursor_capture"], draw_border=self._init_kwargs["draw_border"], secondary_window=None, - minimum_update_interval=self._init_kwargs[ - "minimum_update_interval" - ], + minimum_update_interval=self._init_kwargs["minimum_update_interval"], dirty_region=None, monitor_index=monitor_index if (window_name is None) else None, window_name=window_name, @@ -206,9 +194,7 @@ def wait_first_frame(self, timeout_sec: float = 3.0) -> bool: time.sleep(0.01) return False - def snapshot( - self, bbox: Optional[tuple[int, int, int, int]] = None - ) -> np.ndarray: + def snapshot(self, bbox: Optional[tuple[int, int, int, int]] = None) -> np.ndarray: """返回最近一帧的 **BGR** 拷贝图像,可选裁剪到指定 bbox。 若尚未有首帧,将抛出 `RuntimeError`。 @@ -216,7 +202,7 @@ def snapshot( with self._lock: if self._latest is None: raise RuntimeError("WinRT capture 尚未产生首帧") - + frame = self._latest.copy() if bbox: x1, y1, x2, y2 = bbox @@ -228,11 +214,7 @@ def snapshot( return frame[y1:y2, x1:x2] return frame - def snapshot_once( - self, - bbox: Optional[tuple[int, int, int, int]] = None, - timeout_sec: float = 2.0, - ) -> np.ndarray: + def snapshot_once(self, bbox: Optional[tuple[int, int, int, int]] = None, timeout_sec: float = 2.0) -> np.ndarray: """返回最近一帧的 **BGR** 拷贝图像,可选裁剪到指定 bbox。 若当前未启动,则会临时启动捕获,获取一帧后立即停止。 @@ -241,7 +223,7 @@ def snapshot_once( was_started = self._started if not was_started: self.start() - + frame = None t0 = time.time() while time.time() - t0 < timeout_sec: @@ -250,8 +232,8 @@ def snapshot_once( frame = self._latest.copy() break time.sleep(0.01) - - if frame is None: # 超时 + + if frame is None: # 超时 if not was_started: self.stop() raise RuntimeError("WinRT capture 尚未产生首帧") @@ -269,11 +251,7 @@ def snapshot_once( self.stop() return frame - def set_capture_target( - self, - window_name: Optional[str] = None, - monitor_index: Optional[int] = None, - ) -> None: + def set_capture_target(self, window_name: Optional[str] = None, monitor_index: Optional[int] = None) -> None: """ 设置 WinRT 截屏目标(窗口标题或整屏),并启动捕获,等待首帧。 若初始化失败,将抛出异常。 @@ -281,15 +259,11 @@ def set_capture_target( with self._ctl_lock: if self._started: # 如果已经启动,则重建底层会话 - self.recreate( - window_name=window_name, monitor_index=monitor_index - ) + self.recreate(window_name=window_name, monitor_index=monitor_index) else: # 否则,更新初始化参数并启动 self._init_kwargs.update( - monitor_index=( - monitor_index if (window_name is None) else None - ), + monitor_index=monitor_index if (window_name is None) else None, window_name=window_name, ) self._cap = WindowsCapture(**self._init_kwargs) @@ -302,13 +276,10 @@ def set_capture_target( self.stop() raise RuntimeError("WinRT capture 尚未产生首帧") - def list_visible_window_titles() -> list[str]: """列出所有**可见**窗口的标题(去重并按字典序排序)。""" EnumWindows = ctypes.windll.user32.EnumWindows - EnumWindowsProc = ctypes.WINFUNCTYPE( - wintypes.BOOL, wintypes.HWND, wintypes.LPARAM - ) + EnumWindowsProc = ctypes.WINFUNCTYPE(wintypes.BOOL, wintypes.HWND, wintypes.LPARAM) IsWindowVisible = ctypes.windll.user32.IsWindowVisible GetWindowTextW = ctypes.windll.user32.GetWindowTextW GetWindowTextLengthW = ctypes.windll.user32.GetWindowTextLengthW @@ -331,7 +302,6 @@ def foreach(hwnd, lParam): logger.info(f"窗口列表:{titles}") return titles - # ------------------------- 截屏源选择对话框 ------------------------- class WindowPickerDialog(QDialog): """列出可见窗口标题,并内置“整屏(1/2/3)”选项。双击确定。""" diff --git a/iron_shark_launcher.bat "b/\343\200\220\350\204\232\346\234\254\343\200\221\351\223\201\351\262\250\351\261\274\345\220\257\345\212\250\357\274\201(\345\270\246PyTorch\347\211\210\346\234\254\351\200\211\346\213\251\347\211\210).bat" similarity index 62% rename from iron_shark_launcher.bat rename to "\343\200\220\350\204\232\346\234\254\343\200\221\351\223\201\351\262\250\351\261\274\345\220\257\345\212\250\357\274\201(\345\270\246PyTorch\347\211\210\346\234\254\351\200\211\346\213\251\347\211\210).bat" index b58d5b2..542044f 100644 --- a/iron_shark_launcher.bat +++ "b/\343\200\220\350\204\232\346\234\254\343\200\221\351\223\201\351\262\250\351\261\274\345\220\257\345\212\250\357\274\201(\345\270\246PyTorch\347\211\210\346\234\254\351\200\211\346\213\251\347\211\210).bat" @@ -1,81 +1,73 @@ -@echo off -chcp 65001 >nul -title CannotMax -echo 请按任意键启动CannotMax... -pause >nul - -set "current_dir=%cd%" - -:: 检查 uv 是否存在 -where uv >nul 2>nul -if %errorlevel% equ 0 goto run_main - -:: 安装 uv -echo 未检测到 uv,正在安装... -powershell -ExecutionPolicy Bypass -Command "irm https://gitee.com/wangnov/uv-custom/releases/download/latest/uv-installer-custom.ps1 | iex" - -call :refresh_path -:: 验证 uv 是否可用 -where uv >nul 2>nul -if %errorlevel% neq 0 ( - echo 安装 uv 后仍未找到,请检查安装路径 - pause - exit /b 1 -) -:: =================================== - -:run_main -cd /d "%current_dir%" - -:: ===== 选择推理环境选项询问 ===== -set "torch_choice=none" -echo. -echo 选择推理环境? (5秒后自动跳过) -echo C/c - Pytorch CPU版本 -echo D/d - Pytorch CUDA 12.8版本 -echo E/e - Pytorch CUDA 13.0版本 -echo N/n - 使用onnxruntime(默认) -echo ------------------------------------ - -:: 使用choice命令实现带超时的输入 -choice /c CDEN /t 5 /d N /n >nul -:: choice 的 errorlevel 对应顺序为: C=1, D=2, E=3, N=4 -if errorlevel 4 ( - set "torch_choice=none" -) else if errorlevel 3 ( - set "torch_choice=cu130" -) else if errorlevel 2 ( - set "torch_choice=cu128" -) else ( - set "torch_choice=cpu" -) - -:: 根据选择使用对应环境运行主程序 -if "%torch_choice%"=="cpu" ( - echo 使用Pytorch CPU版本... - uv sync --extra cpu -) else if "%torch_choice%"=="cu128" ( - echo 使用Pytorch CUDA 12.8版本... - uv sync --extra cu128 -) else if "%torch_choice%"=="cu130" ( - echo 使用Pytorch CUDA 13.0版本... - uv sync --extra cu130 -) else ( - echo 使用onnxruntime... - uv sync -) -echo. - -:: =================================== -uv run main.py - -echo 主程序已退出,感谢您的使用! -pause >nul -exit /b - -:: 刷新 PATH 的函数 -:refresh_path -for /f "skip=2 tokens=3*" %%a in ('reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path 2^>nul') do set "SYSTEM_PATH=%%a %%b" -for /f "skip=2 tokens=3*" %%a in ('reg query "HKCU\Environment" /v Path 2^>nul') do set "USER_PATH=%%a %%b" -set "PATH=%USER_PATH%;%SYSTEM_PATH%" +@echo off +chcp 65001 >nul +title CannotMax +echo 请按任意键启动CannotMax... +pause >nul + +set "current_dir=%cd%" + +:: 检查 uv 是否存在 +where uv >nul 2>nul +if %errorlevel% equ 0 goto run_main + +:: 安装 uv +echo 未检测到 uv,正在安装... +powershell -ExecutionPolicy Bypass -Command "irm https://gitee.com/wangnov/uv-custom/releases/download/latest/uv-installer-custom.ps1 | iex" + +call :refresh_path +:: 验证 uv 是否可用 +where uv >nul 2>nul +if %errorlevel% neq 0 ( + echo 安装 uv 后仍未找到,请检查安装路径 + pause + exit /b 1 +) +:: =================================== + +:run_main +cd /d "%current_dir%" + +:: ===== PyTorch安装选项询问 ===== +set "torch_choice=none" +echo. +echo 是否需要安装PyTorch? (5秒后自动跳过) +echo C/c - CPU版本 +echo G/g - CUDA版本 +echo N/n - 跳过安装 +echo ------------------------------------ + +:: 使用choice命令实现带超时的输入 +choice /c CGN /t 5 /d N /n >nul +if errorlevel 3 ( + set "torch_choice=none" +) else if errorlevel 2 ( + set "torch_choice=cuda" +) else if errorlevel 1 ( + set "torch_choice=cpu" +) + +:: 根据选择安装PyTorch +if "%torch_choice%"=="cpu" ( + echo 安装CPU版本的PyTorch... + uv add torch torchvision --extra cpu +) else if "%torch_choice%"=="cuda" ( + echo 安装CUDA版本的PyTorch... + uv add torch torchvision --extra cu128 +) else ( + echo 跳过PyTorch安装 +) +echo. + +:: =================================== +uv run main.py + +echo 主程序已退出,感谢您的使用! +pause >nul +exit /b + +:: 刷新 PATH 的函数 +:refresh_path +for /f "skip=2 tokens=3*" %%a in ('reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment" /v Path 2^>nul') do set "SYSTEM_PATH=%%a %%b" +for /f "skip=2 tokens=3*" %%a in ('reg query "HKCU\Environment" /v Path 2^>nul') do set "USER_PATH=%%a %%b" +set "PATH=%USER_PATH%;%SYSTEM_PATH%" exit /b \ No newline at end of file