Print function correction + player analysis fix and player stats fix

This commit is contained in:
bl3kunja-FW
2025-08-10 18:22:22 +02:00
parent 054c81e78e
commit 33758e7340
7 changed files with 1678 additions and 383 deletions
+502 -51
View File
@@ -638,14 +638,9 @@ def analyze_player_performance(player_id, archives_data):
if score < player_stats['worst_tournament_score']:
player_stats['worst_tournament_score'] = score
# Count shots fired
targets = participant.get('targets', {})
shots_in_tournament = 0
for target in targets.values():
if target.get('shot1') is not None:
shots_in_tournament += 1
if target.get('shot2') is not None:
shots_in_tournament += 1
# Count shots fired - NOW WITH PROPER COUNTING FOR ALL FORMATS
tournament_type = archive.get('tournament_type', '20_targets')
shots_in_tournament = count_shots_in_tournament(participant, tournament_type)
player_stats['total_shots_fired'] += shots_in_tournament
@@ -655,7 +650,7 @@ def analyze_player_performance(player_id, archives_data):
'score': score,
'tournament_type': archive['tournament_type'],
'completed': completed,
'shots_fired': shots_in_tournament
'shots_fired': shots_in_tournament # NOW CORRECTLY CALCULATED
})
except Exception as e:
print(f"Error analyzing tournament archive: {e}")
@@ -923,48 +918,7 @@ def api_get_archive_stats():
return jsonify({'status': 'success', 'stats': stats})
except Exception as e:
return jsonify({'status': 'error', 'message': str(e)}), 500
@app.route('/api/archive/player/<int:player_id>/performance', methods=['GET'])
def api_get_player_performance(player_id):
"""API endpoint to get player performance data for charts"""
try:
archives_data = {
'tournaments': get_archived_tournaments(),
'leagues': get_archived_leagues()
}
player_stats = analyze_player_performance(player_id, archives_data)
# Prepare chart data
performance_data = {
'trend': {
'labels': [f'T{i+1}' for i in range(len(player_stats['tournament_scores']))],
'data': player_stats['tournament_scores']
},
'distribution': {
'labels': ['0-50', '51-60', '61-70', '71-80', '81-90', '91-100'],
'data': [0, 0, 0, 0, 0, 0]
}
}
# Calculate score distribution
for score in player_stats['tournament_scores']:
if score <= 50:
performance_data['distribution']['data'][0] += 1
elif score <= 60:
performance_data['distribution']['data'][1] += 1
elif score <= 70:
performance_data['distribution']['data'][2] += 1
elif score <= 80:
performance_data['distribution']['data'][3] += 1
elif score <= 90:
performance_data['distribution']['data'][4] += 1
else:
performance_data['distribution']['data'][5] += 1
return jsonify({'status': 'success', 'performance': performance_data})
except Exception as e:
return jsonify({'status': 'error', 'message': str(e)}), 500
@app.route('/api/archive/players/with-stats', methods=['GET'])
def api_get_players_with_stats():
"""API endpoint to get all players with their basic stats"""
@@ -2162,7 +2116,504 @@ def get_camera_titles():
except Exception as e:
return jsonify({'status': 'error', 'message': str(e)}), 400
@app.route('/api/archive/player/<int:player_id>/shot-accuracy')
def get_player_shot_accuracy(player_id):
"""
Get aggregated shot accuracy data for a player from tournament archive files
"""
try:
# Get player name from JSON file instead of database
players_data = load_players()
player = None
for p in players_data['players']:
if p['id'] == player_id:
player = p
break
if not player:
return jsonify({
'status': 'error',
'message': f'Player with ID {player_id} not found'
}), 404
player_name = player['name']
# Initialize shot counts by tournament type
shot_accuracy = {
'40 Targets': defaultdict(int),
'20 Targets': defaultdict(int),
'4 Targets': defaultdict(int)
}
# Path to tournament archives
tournament_archives_path = 'tournament_archives'
# Check if directory exists
if not os.path.exists(tournament_archives_path):
return jsonify({
'status': 'error',
'message': f'Tournament archives directory not found: {tournament_archives_path}'
}), 404
# Find all tournament archive files
archive_files = glob.glob(f"{tournament_archives_path}/tournament_*.json")
if not archive_files:
return jsonify({
'status': 'success',
'data': {},
'player_name': player_name,
'message': 'No tournament archive files found'
})
# Process each tournament archive file
for file_path in archive_files:
try:
with open(file_path, 'r') as f:
tournament_data = json.load(f)
# Check if this tournament has our player
participants = tournament_data.get('results', {}).get('participants', {})
# Find player by ID or name
player_data = None
for participant_id, participant_info in participants.items():
if (str(participant_id) == str(player_id) or
participant_info.get('name') == player_name):
player_data = participant_info
break
if not player_data or not player_data.get('completed'):
continue
# Determine tournament type
tournament_type = determine_tournament_type_from_archive(tournament_data)
# Extract individual shots - NOW WITH PROPER SHOT COUNTING FOR ALL FORMATS
shots = extract_shots_from_player_data(player_data, tournament_type)
# Debug print to verify shot counts
print(f"Player {player_name}, Tournament type: {tournament_type}, Total shots extracted: {len(shots)}")
# Count shots by value
for shot_value in shots:
if shot_value == 10:
shot_accuracy[tournament_type]['tens'] += 1
elif shot_value == 9:
shot_accuracy[tournament_type]['nines'] += 1
elif shot_value == 8:
shot_accuracy[tournament_type]['eights'] += 1
elif shot_value == 7:
shot_accuracy[tournament_type]['sevens'] += 1
elif shot_value == 6:
shot_accuracy[tournament_type]['sixes'] += 1
elif shot_value == 5:
shot_accuracy[tournament_type]['fives'] += 1
elif shot_value == 4:
shot_accuracy[tournament_type]['fours'] += 1
elif shot_value == 3:
shot_accuracy[tournament_type]['threes'] += 1
elif shot_value == 2:
shot_accuracy[tournament_type]['twos'] += 1
elif shot_value == 1:
shot_accuracy[tournament_type]['ones'] += 1
elif shot_value == 0:
shot_accuracy[tournament_type]['zeros'] += 1
except Exception as e:
print(f"Error processing tournament file {file_path}: {e}")
continue
# Convert defaultdict to regular dict for JSON serialization
result = {}
for tournament_type, counts in shot_accuracy.items():
if any(counts.values()): # Only include types with data
result[tournament_type] = dict(counts)
return jsonify({
'status': 'success',
'data': result,
'player_name': player_name,
'files_processed': len(archive_files)
})
except Exception as e:
import traceback
return jsonify({
'status': 'error',
'message': str(e),
'traceback': traceback.format_exc()
}), 500
@app.route('/api/archive/tournament/<tournament_id>/shots')
def get_tournament_shots(tournament_id):
"""
Get individual shot data for a specific tournament from archive
"""
try:
# Tournament ID might be a database ID or the tournament filename/timestamp
tournament_archives_path = 'tournament_archives'
# Try to find tournament file by various methods
tournament_file = None
# Method 1: Direct filename match
potential_files = [
f"{tournament_archives_path}/tournament_{tournament_id}.json",
f"{tournament_archives_path}/{tournament_id}.json"
]
for file_path in potential_files:
if os.path.exists(file_path):
tournament_file = file_path
break
# Method 2: Search through all tournament files for matching ID
if not tournament_file:
archive_files = glob.glob(f"{tournament_archives_path}/tournament_*.json")
for file_path in archive_files:
try:
with open(file_path, 'r') as f:
data = json.load(f)
# Check if tournament ID matches
tournament_data = data.get('tournament', {})
results_data = data.get('results', {})
if (tournament_data.get('created_at') == tournament_id or
results_data.get('tournament_id') == tournament_id or
str(tournament_id) in file_path):
tournament_file = file_path
break
except:
continue
if not tournament_file:
return jsonify({
'status': 'error',
'message': 'Tournament archive file not found'
}), 404
# Load tournament data
with open(tournament_file, 'r') as f:
tournament_data = json.load(f)
# Extract all players' shots
participants = tournament_data.get('results', {}).get('participants', {})
all_shots_data = {}
for participant_id, participant_info in participants.items():
if participant_info.get('completed'):
shots = extract_shots_from_player_data(participant_info)
all_shots_data[participant_info.get('name')] = shots
return jsonify({
'status': 'success',
'tournament_data': {
'tournament_type': determine_tournament_type_from_archive(tournament_data),
'participants': len(participants),
'file_path': tournament_file
},
'shots_by_player': all_shots_data
})
except Exception as e:
return jsonify({
'status': 'error',
'message': str(e)
}), 500
def extract_shots_from_player_data(player_data, tournament_type=None):
"""
Extract individual shot values from player data in your archive format
Now properly handles all tournament formats:
- 4 targets: 5 shots each (shot1-shot5) = 20 total shots
- 20 targets: 2 shots each (shot1-shot2) = 40 total shots
- 40 targets: 2 shots each (shot1-shot2) = 80 total shots
"""
shots = []
targets = player_data.get('targets', {})
if not targets:
return shots
# Sort targets by number to maintain order
target_numbers = sorted([int(k) for k in targets.keys() if k.isdigit()])
# Determine shots per target based on tournament format
if tournament_type and '4' in str(tournament_type):
shots_per_target = 5 # 4 targets format: 5 shots each
else:
# Auto-detect if tournament_type not provided
num_targets = len(target_numbers)
if num_targets <= 6: # Likely 4 targets format (4 targets + maybe some extras)
shots_per_target = 5
else: # 20 or 40 targets format
shots_per_target = 2
for target_num in target_numbers:
target_data = targets[str(target_num)]
# Extract shots for this target
for shot_num in range(1, shots_per_target + 1):
shot_key = f'shot{shot_num}'
shot_value = target_data.get(shot_key)
if shot_value is not None:
shots.append(int(shot_value))
return shots
def count_shots_in_tournament(participant_data, tournament_type=None):
"""
Count total shots fired by a participant in a tournament
Now properly handles all tournament formats:
- 4 targets: 5 shots each = 20 total shots
- 20 targets: 2 shots each = 40 total shots
- 40 targets: 2 shots each = 80 total shots
"""
targets = participant_data.get('targets', {})
shots_count = 0
if not targets:
return shots_count
# Determine shots per target based on tournament format
if tournament_type and '4' in str(tournament_type):
max_shots_per_target = 5 # 4 targets format: 5 shots each
else:
# Auto-detect if tournament_type not provided
target_count = len([k for k in targets.keys() if k.isdigit()])
if target_count <= 6: # Likely 4 targets format
max_shots_per_target = 5
else: # 20 or 40 targets format
max_shots_per_target = 2
for target in targets.values():
for shot_num in range(1, max_shots_per_target + 1):
shot_key = f'shot{shot_num}'
if target.get(shot_key) is not None:
shots_count += 1
return shots_count
def determine_tournament_type_from_archive(tournament_data):
"""
Determine tournament type from your archive data structure
"""
# First check the tournament_type field
tournament_info = tournament_data.get('tournament', {})
results_info = tournament_data.get('results', {})
tournament_type = (tournament_info.get('tournament_type') or
results_info.get('tournament_type'))
if tournament_type:
if '40' in tournament_type:
return '40 Targets'
elif '20' in tournament_type:
return '20 Targets'
elif '4' in tournament_type:
return '4 Targets'
# Fallback: count targets from first completed player
participants = results_info.get('participants', {})
for participant_info in participants.values():
if participant_info.get('completed'):
targets = participant_info.get('targets', {})
target_count = len([k for k in targets.keys() if k.isdigit()])
if target_count >= 30: # 40 targets
return '40 Targets'
elif target_count >= 10: # 20 targets
return '20 Targets'
elif target_count <= 6: # 4 targets (changed from <= 8 to <= 6)
return '4 Targets'
break
# Default fallback
return '20 Targets'
@app.route('/api/debug/player/<int:player_id>')
def debug_player_info(player_id):
"""
Debug endpoint to check player info and archive structure
"""
try:
# Check player exists
players_data = load_players()
player = None
for p in players_data['players']:
if p['id'] == player_id:
player = p
break
# Check archive directory
tournament_archives_path = 'tournament_archives'
archive_exists = os.path.exists(tournament_archives_path)
archive_files = []
if archive_exists:
archive_files = glob.glob(f"{tournament_archives_path}/tournament_*.json")
# Check current working directory
cwd = os.getcwd()
# List contents of current directory
current_dir_contents = os.listdir('.')
return jsonify({
'status': 'success',
'player_found': player is not None,
'player_info': player,
'current_working_directory': cwd,
'current_dir_contents': current_dir_contents,
'archive_directory_exists': archive_exists,
'archive_directory_path': tournament_archives_path,
'archive_files_found': len(archive_files),
'archive_files': [os.path.basename(f) for f in archive_files[:5]] # First 5 files
})
except Exception as e:
import traceback
return jsonify({
'status': 'error',
'message': str(e),
'traceback': traceback.format_exc()
}), 500
# Debug endpoint to see raw tournament data
@app.route('/api/archive/tournament-file/<path:filename>')
def get_tournament_file_debug(filename):
"""
Debug endpoint to see raw tournament file data
"""
try:
tournament_archives_path = 'tournament_archives'
file_path = os.path.join(tournament_archives_path, filename)
if not os.path.exists(file_path):
return jsonify({
'status': 'error',
'message': 'File not found'
}), 404
with open(file_path, 'r') as f:
data = json.load(f)
return jsonify({
'status': 'success',
'file_path': file_path,
'data': data
})
except Exception as e:
return jsonify({
'status': 'error',
'message': str(e)
}), 500
@app.route('/api/archive/tournament-leaders', methods=['GET'])
def api_get_tournament_leaders():
"""API endpoint to get overall tournament leaders by tournament type"""
try:
tournaments = get_archived_tournaments()
# Group data by tournament type
tournament_types = {
'20_targets': {
'name': '20 Targets',
'description': '20 Targets (2 shots each)',
'best_score': {'player_name': None, 'score': 0},
'most_tens': {'player_name': None, 'tens': 0},
'total_tournaments': 0
},
'40_targets': {
'name': '40 Targets',
'description': '40 Targets (2 shots each)',
'best_score': {'player_name': None, 'score': 0},
'most_tens': {'player_name': None, 'tens': 0},
'total_tournaments': 0
},
'4_targets': {
'name': '4 Targets',
'description': '4 Targets (5 shots each)',
'best_score': {'player_name': None, 'score': 0},
'most_tens': {'player_name': None, 'tens': 0},
'total_tournaments': 0
}
}
for tournament in tournaments:
try:
data = load_archive_file(tournament['filepath'])
if not data:
continue
results = data.get('results', {})
participants = results.get('participants', {})
tournament_type = tournament.get('tournament_type', '20_targets')
if tournament_type not in tournament_types or not participants:
continue
tournament_types[tournament_type]['total_tournaments'] += 1
for player_id, participant in participants.items():
if not participant.get('completed'):
continue
player_name = participant.get('name', f'Player {player_id}')
# Check best score for this tournament type
score = participant.get('total_score', 0)
if score > tournament_types[tournament_type]['best_score']['score']:
tournament_types[tournament_type]['best_score'] = {
'player_name': player_name,
'score': score
}
# Count 10s for this player in this tournament
targets = participant.get('targets', {})
tens_count = 0
for target in targets.values():
if target.get('shot1') == 10:
tens_count += 1
if target.get('shot2') == 10:
tens_count += 1
# For 4_targets format, check additional shots
for shot_num in range(3, 6): # shot3, shot4, shot5
if target.get(f'shot{shot_num}') == 10:
tens_count += 1
if tens_count > tournament_types[tournament_type]['most_tens']['tens']:
tournament_types[tournament_type]['most_tens'] = {
'player_name': player_name,
'tens': tens_count
}
except Exception as e:
print(f"Error processing tournament {tournament.get('filepath', 'unknown')}: {e}")
continue
# Convert to list format, only include types with data
tournament_leaders = []
for type_key, type_data in tournament_types.items():
if type_data['total_tournaments'] > 0 and type_data['best_score']['player_name']:
tournament_leaders.append({
'id': type_key,
'name': type_data['name'],
'description': type_data['description'],
'total_tournaments': type_data['total_tournaments'],
'best_score': type_data['best_score'],
'most_tens': type_data['most_tens']
})
return jsonify({'status': 'success', 'tournament_types': tournament_leaders})
except Exception as e:
return jsonify({'status': 'error', 'message': str(e)}), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)