added new tournament mode.

This commit is contained in:
2025-08-10 10:31:15 +02:00
parent 5c7f255a02
commit 054c81e78e
6 changed files with 1826 additions and 629 deletions
+75 -26
View File
@@ -299,7 +299,17 @@ def create_results_structure(tournament_data):
return None
tournament_type = tournament_data.get('tournament_type', '20_targets')
num_targets = 40 if tournament_type == '40_targets' else 20
# Determine target count and shots per target
if tournament_type == '40_targets':
num_targets = 40
shots_per_target = 2
elif tournament_type == '4_targets':
num_targets = 4
shots_per_target = 5
else: # 20_targets (default)
num_targets = 20
shots_per_target = 2
results = {
'tournament_id': tournament_data.get('created_at', datetime.now().isoformat()),
@@ -320,9 +330,18 @@ def create_results_structure(tournament_data):
for player in all_players:
player_id = str(player['id'])
# Create target structure based on tournament type
targets = {}
for i in range(1, num_targets + 1):
target = {}
for j in range(1, shots_per_target + 1):
target[f'shot{j}'] = None
targets[str(i)] = target
results['participants'][player_id] = {
'name': player['name'],
'targets': {str(i): {'shot1': None, 'shot2': None} for i in range(1, num_targets + 1)},
'targets': targets,
'total_score': 0,
'completed': False
}
@@ -333,19 +352,17 @@ def calculate_total_score(targets):
"""Calculate total score from targets, treating None as 0"""
total = 0
for target in targets.values():
shot1 = target.get('shot1')
shot2 = target.get('shot2')
total += (shot1 if shot1 is not None else 0)
total += (shot2 if shot2 is not None else 0)
for shot_key, shot_value in target.items():
if shot_key.startswith('shot') and shot_value is not None:
total += shot_value
return total
def is_participant_completed(targets):
"""Check if a participant has completed all targets (all shots entered, including 0s)"""
for target in targets.values():
shot1 = target.get('shot1')
shot2 = target.get('shot2')
if shot1 is None or shot2 is None:
return False
for shot_key, shot_value in target.items():
if shot_key.startswith('shot') and shot_value is None:
return False
return True
def calculate_league_final_scores(league_data):
@@ -749,6 +766,8 @@ def get_all_players_from_archives():
return players_list
# Add these routes after the existing routes in app.py
# Add this to your app.py file to integrate the modern archive system
@@ -875,15 +894,17 @@ def api_get_archive_stats():
'leagues': [1, 1, 2, 1, 2, 1]
}
# Calculate tournament type distribution
type_distribution = {'20_targets': 0, '40_targets': 0}
# Calculate tournament type distribution - now includes 4_targets
type_distribution = {'20_targets': 0, '40_targets': 0, '4_targets': 0}
for tournament in tournaments:
tournament_type = tournament.get('tournament_type', '20_targets')
type_distribution[tournament_type] += 1
if tournament_type in type_distribution:
type_distribution[tournament_type] += 1
for league in leagues:
league_type = league.get('tournament_type', '20_targets')
type_distribution[league_type] += 1
if league_type in type_distribution:
type_distribution[league_type] += 1
stats = {
'overview': {
@@ -894,15 +915,14 @@ def api_get_archive_stats():
},
'activity_data': activity_data,
'type_distribution': {
'labels': ['20 Targets', '40 Targets'],
'data': [type_distribution['20_targets'], type_distribution['40_targets']]
'labels': ['20 Targets', '40 Targets', '4 Targets'],
'data': [type_distribution['20_targets'], type_distribution['40_targets'], type_distribution['4_targets']]
}
}
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"""
@@ -1629,10 +1649,9 @@ def start_league():
try:
data = request.get_json()
tournament_type = data.get('tournament_type', '20_targets')
if tournament_type not in ['20_targets', '40_targets']:
if tournament_type not in ['20_targets', '40_targets', '4_targets']:
return jsonify({'status': 'error', 'message': 'Invalid tournament type'}), 400
players_data = load_players()
enabled_players = [p for p in players_data['players'] if p['enabled']]
@@ -1741,7 +1760,7 @@ def start_tournament():
data = request.get_json() or {}
tournament_type = data.get('tournament_type', '20_targets')
if tournament_type not in ['20_targets', '40_targets']:
if tournament_type not in ['20_targets', '40_targets', '4_targets']:
return jsonify({'status': 'error', 'message': 'Invalid tournament type'}), 400
players_data = load_players()
@@ -1869,6 +1888,13 @@ def finish_tournament():
results['tournament_finished'] = True
results['finished_at'] = datetime.now().isoformat()
# Define total shots per participant for each tournament type
total_shots_per_participant = {
'20_targets': 40, # 20 targets × 2 shots
'40_targets': 80, # 40 targets × 2 shots
'4_targets': 20 # 4 targets × 5 shots
}
league_finished = False # Track if league finished
# Update league state if this is a league tournament
@@ -1901,13 +1927,21 @@ def finish_tournament():
'joker': True
})
# Calculate total shots correctly for any tournament type
tournament_type = results.get('tournament_type', '20_targets')
shots_per_participant = total_shots_per_participant.get(tournament_type, 40)
total_shots_fired = len(results['participants']) * shots_per_participant
# Add to completed tournaments
league_state['completed_tournaments'].append({
'tournament_number': tournament_number,
'tournament_type': tournament_type,
'finished_at': datetime.now().isoformat(),
'results_summary': {
'participants': len(results['participants']),
'total_shots': len(results['participants']) * (40 if results.get('tournament_type') == '40_targets' else 20) * 2
'shots_per_participant': shots_per_participant,
'total_shots': total_shots_fired,
'format_description': get_tournament_format_description(tournament_type)
}
})
@@ -1920,7 +1954,7 @@ def finish_tournament():
calculate_league_final_scores(league_state)
league_finished = True
print("League finished!")
print(f"League finished! Final tournament was {tournament_type} format.")
save_league_state(league_state)
@@ -1928,9 +1962,11 @@ def finish_tournament():
archive_success = False
if not league_state: # Only archive standalone tournaments
archive_success = archive_tournament(tournament_state, results)
print(f"Standalone tournament archived: {archive_success}")
tournament_type = results.get('tournament_type', '20_targets')
print(f"Standalone {tournament_type} tournament archived: {archive_success}")
else:
print("League tournament - not archiving individual tournament")
tournament_type = results.get('tournament_type', '20_targets')
print(f"League {tournament_type} tournament - not archiving individual tournament")
# Archive the league if it just finished
league_archive_success = False
@@ -1952,7 +1988,9 @@ def finish_tournament():
'status': 'success',
'results': results,
'archived': archive_success,
'league_archived': league_archive_success if league_finished else None
'league_archived': league_archive_success if league_finished else None,
'tournament_type': results.get('tournament_type', '20_targets'),
'tournament_format': get_tournament_format_description(results.get('tournament_type', '20_targets'))
}
if league_state:
@@ -1967,6 +2005,15 @@ def finish_tournament():
print(f"Error finishing tournament: {e}")
return jsonify({'status': 'error', 'message': str(e)}), 400
def get_tournament_format_description(tournament_type):
"""Get human-readable description of tournament format"""
format_descriptions = {
'20_targets': '20 Targets (2 shots each)',
'40_targets': '40 Targets (2 shots each)',
'4_targets': '4 Targets (5 shots each)'
}
return format_descriptions.get(tournament_type, '20 Targets (2 shots each)')
@app.route('/api/results', methods=['GET'])
def get_results():
"""API endpoint to get current results"""
@@ -2115,5 +2162,7 @@ def get_camera_titles():
except Exception as e:
return jsonify({'status': 'error', 'message': str(e)}), 400
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)