feat(tournaments): add partnership tracking and tournament management
Implement comprehensive partnership tracking system and tournament management features including round-robin, single/double elimination, and Swiss system pairings. Changes: - Add partnership_games and partnership_stats tables - Implement PartnershipTracker service for recording partnership data - Add tournament generator with multiple formats - Create tournament management actions and views - Add acceptance tests for partnership tracking - Fix PartnershipTracker to use single snapshot per player per match - Fix round-robin test to query by round_number instead of hardcoded ID Note: All 8 acceptance tests now passing
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module EuchreCamp
|
||||
module Actions
|
||||
module Admin
|
||||
module Tournaments
|
||||
class Schedule < EuchreCamp::Action
|
||||
include Deps[
|
||||
events_repo: 'repositories.events',
|
||||
teams_repo: 'repositories.teams',
|
||||
rounds_repo: 'repositories.tournament_rounds',
|
||||
matchups_repo: 'repositories.bracket_matchups'
|
||||
]
|
||||
|
||||
def handle(request, response)
|
||||
tournament_id = request.params[:id]
|
||||
tournament = events_repo.by_id(tournament_id)
|
||||
teams = teams_repo.by_event(tournament_id)
|
||||
|
||||
if teams.empty?
|
||||
response.flash[:error] = "No teams to schedule. Add teams first."
|
||||
response.redirect_to("/admin/tournaments/#{tournament_id}")
|
||||
return
|
||||
end
|
||||
|
||||
# Generate matchups based on format
|
||||
teams_data = teams.map { |t| { id: t[:id], seed: t[:id] } }
|
||||
format = tournament[:format]
|
||||
|
||||
begin
|
||||
case format
|
||||
when 'round_robin'
|
||||
rounds = EuchreCamp::Services::TournamentGenerator.round_robin(teams_data)
|
||||
create_round_robin_schedule(tournament_id, rounds)
|
||||
when 'single_elim'
|
||||
bracket = EuchreCamp::Services::TournamentGenerator.single_elimination(teams_data)
|
||||
create_single_elim_schedule(tournament_id, bracket, teams)
|
||||
when 'swiss'
|
||||
# For Swiss, create first round
|
||||
rounds = EuchreCamp::Services::TournamentGenerator.swiss(teams_data, 1)
|
||||
create_swiss_schedule(tournament_id, rounds, 1)
|
||||
else
|
||||
response.flash[:error] = "Format '#{format}' not yet implemented"
|
||||
response.redirect_to("/admin/tournaments/#{tournament_id}")
|
||||
return
|
||||
end
|
||||
|
||||
# Update tournament status
|
||||
events_repo.update(tournament_id, status: 'active')
|
||||
|
||||
response.flash[:message] = "Schedule generated successfully"
|
||||
response.redirect_to("/admin/tournaments/#{tournament_id}")
|
||||
rescue StandardError => e
|
||||
response.flash[:error] = "Failed to generate schedule: #{e.message}"
|
||||
response.redirect_to("/admin/tournaments/#{tournament_id}")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_round_robin_schedule(tournament_id, rounds)
|
||||
rounds.each do |round_data|
|
||||
round = rounds_repo.create(
|
||||
event_id: tournament_id,
|
||||
round_number: round_data[:round_number],
|
||||
status: round_data[:round_number] == 1 ? 'active' : 'pending'
|
||||
)
|
||||
|
||||
round_data[:matchups].each_with_index do |matchup, index|
|
||||
matchups_repo.create(
|
||||
event_id: tournament_id,
|
||||
round_id: round[:id],
|
||||
team_1_id: matchup[:team_1_id],
|
||||
team_2_id: matchup[:team_2_id],
|
||||
bracket_position: index + 1
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_single_elim_schedule(tournament_id, bracket, teams)
|
||||
# Create first round
|
||||
round = rounds_repo.create(
|
||||
event_id: tournament_id,
|
||||
round_number: 1,
|
||||
status: 'active'
|
||||
)
|
||||
|
||||
bracket[:first_round_matchups].each do |matchup|
|
||||
# Skip if team is nil (BYE)
|
||||
next if matchup[:team_1_id].nil? && matchup[:team_2_id].nil?
|
||||
|
||||
matchups_repo.create(
|
||||
event_id: tournament_id,
|
||||
round_id: round[:id],
|
||||
team_1_id: matchup[:team_1_id],
|
||||
team_2_id: matchup[:team_2_id],
|
||||
bracket_position: matchup[:bracket_position]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def create_swiss_schedule(tournament_id, rounds, round_number)
|
||||
round = rounds_repo.create(
|
||||
event_id: tournament_id,
|
||||
round_number: round_number,
|
||||
status: 'active'
|
||||
)
|
||||
|
||||
rounds.each do |round_data|
|
||||
round_data[:matchups].each_with_index do |matchup, index|
|
||||
matchups_repo.create(
|
||||
event_id: tournament_id,
|
||||
round_id: round[:id],
|
||||
team_1_id: matchup[:team_1_id],
|
||||
team_2_id: matchup[:team_2_id],
|
||||
bracket_position: index + 1
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user