from flask import Blueprint, render_template, request, jsonify from web.services.web_service import WebService from web.services.stats_service import StatsService from web.services.feature_service import FeatureService import json bp = Blueprint('tactics', __name__, url_prefix='/tactics') @bp.route('/') def index(): return render_template('tactics/index.html') # API: Analyze Lineup @bp.route('/api/analyze', methods=['POST']) def api_analyze(): data = request.json steam_ids = data.get('steam_ids', []) if not steam_ids: return jsonify({'error': 'No players selected'}), 400 # 1. Get Basic Info & Stats players = StatsService.get_players_by_ids(steam_ids) player_data = [] total_rating = 0 total_kd = 0 total_adr = 0 count = 0 for p in players: p_dict = dict(p) # Fetch L3 features f = FeatureService.get_player_features(p_dict['steam_id_64']) stats = dict(f) if f else {} p_dict['stats'] = stats player_data.append(p_dict) if stats: total_rating += stats.get('basic_avg_rating', 0) or 0 total_kd += stats.get('basic_avg_kd', 0) or 0 total_adr += stats.get('basic_avg_adr', 0) or 0 count += 1 # 2. Shared Matches shared_matches = StatsService.get_shared_matches(steam_ids) # They are already dicts now with 'result_str' and 'is_win' # 3. Aggregates avg_stats = { 'rating': total_rating / count if count else 0, 'kd': total_kd / count if count else 0, 'adr': total_adr / count if count else 0 } # Calculate 8-Dimension Averages radar_keys = { 'score_aim': 'AIM', 'score_defense': 'DEFENSE', 'score_utility': 'UTILITY', 'score_clutch': 'CLUTCH', 'score_economy': 'ECONOMY', 'score_pace': 'PACE', 'score_pistol': 'PISTOL', 'score_stability': 'STABILITY' } radar_stats = {v: 0.0 for v in radar_keys.values()} if count > 0: for p in player_data: stats = p.get('stats', {}) for k, v in radar_keys.items(): radar_stats[v] += float(stats.get(k) or 0.0) for k in radar_stats: radar_stats[k] /= count # Calculate Chemistry # Formula: Base on shared matches and win rate # Max Score = 100 # 50% weight on match count (Cap at 50 matches = 50 pts) # 50% weight on win rate (100% WR = 50 pts) avg_shared_count = 0 avg_shared_winrate = 0 if shared_matches: avg_shared_count = len(shared_matches) wins = sum(1 for m in shared_matches if m['is_win']) avg_shared_winrate = wins / len(shared_matches) chem_match_score = min(50, avg_shared_count) # 1 point per match, max 50 chem_win_score = avg_shared_winrate * 50 chemistry_score = chem_match_score + chem_win_score # 4. Map Stats Calculation map_stats = {} # {map_name: {'count': 0, 'wins': 0}} total_shared_matches = len(shared_matches) for m in shared_matches: map_name = m['map_name'] if map_name not in map_stats: map_stats[map_name] = {'count': 0, 'wins': 0} map_stats[map_name]['count'] += 1 if m['is_win']: map_stats[map_name]['wins'] += 1 # Convert to list for frontend map_stats_list = [] for k, v in map_stats.items(): win_rate = (v['wins'] / v['count'] * 100) if v['count'] > 0 else 0 map_stats_list.append({ 'map_name': k, 'count': v['count'], 'wins': v['wins'], 'win_rate': win_rate }) # Sort by count desc map_stats_list.sort(key=lambda x: x['count'], reverse=True) return jsonify({ 'players': player_data, 'shared_matches': [dict(m) for m in shared_matches], 'avg_stats': avg_stats, 'radar_stats': radar_stats, 'chemistry_score': chemistry_score, 'map_stats': map_stats_list, 'total_shared_matches': total_shared_matches }) # API: Save Board @bp.route('/save_board', methods=['POST']) def save_board(): data = request.json title = data.get('title', 'Untitled Strategy') map_name = data.get('map_name', 'de_mirage') markers = data.get('markers') if not markers: return jsonify({'success': False, 'message': 'No markers to save'}) WebService.save_strategy_board(title, map_name, json.dumps(markers), 'Anonymous') return jsonify({'success': True, 'message': 'Board saved successfully'})