Open emersonthis opened 3 weeks ago
I also want to understand how the implementor is meant to associate the matches with one another and/or the overall tournament. For example, if the application has a page that shows the tournament bracket, how would the implementor know which match is in which round?
For concreteness, here is the rspec test I'm writing while figuring out this library...
RSpec.describe PcslDriver, type: :model do
let(:season) { create(:season) }
let!(:team1) { Team.create!(name: 'Team 1', season:) }
let!(:team2) { Team.create!(name: 'Team 2', season:) }
let!(:team3) { Team.create!(name: 'Team 3', season:) }
let!(:team4) { Team.create!(name: 'Team 4', season:) }
fit 'creates matches' do
driver = described_class.new season
rounds_count = TournamentSystem::RoundRobin.total_rounds(driver)
rounds_count.times do |i|
TournamentSystem::RoundRobin.generate driver, { round: i }
puts "Round #{i + 1}"
season.team_matches.each do |match|
puts "#{match.side_a.name} vs #{match.side_b.name}"
end
end
expect(season.team_matches.count).to eq(5)
end
end
This is the output I'm seeing:
Round 1
Team 1 vs Team 4
Team 2 vs Team 3
Round 2
Team 1 vs Team 4
Team 2 vs Team 3
Team 3 vs Team 1
Team 2 vs Team 4
Round 3
Team 1 vs Team 4
Team 2 vs Team 3
Team 3 vs Team 1
Team 2 vs Team 4
Team 1 vs Team 2
Team 3 vs Team 4
Is this close to how the generate
class is intended to be used?
Yes that's the intended use. generate
generates 1 round and it's up to you to keep track of any extra data (like which matches were generated in which round). The way I use it the list of matches is always empty ahead of calling generate
.
The way I use it the list of matches is always empty ahead of calling generate.
Can you elaborate on this a bit? If I want to generate the second round of a single elimination tournament, do I not need existing matches from the first round?
You only need them for the matches
method on the driver, you don't necessarily need to hook that up with the build_match
method. See for instance the TestDriver
in spec/support/test_driver.rb
, which has @matches
and @created_matches
(though do note that the driver isn't reused). But you don't need to follow that usage pattern; what you're already doing will work fine.
Thanks! I'll submit a PR with updates to the docs for this (and future) questions. Does that sound good? If so, I'll leave this open for now as a reminder and close it with the corresponding PR.
One more follow-up question about this...
I am trying to plan how to associate matches with a specific round of a tournament. If I run TournamentSystem::RoundRobin.generate myDriver
it creates the matches and returns nil
. I don't see anywhere that the round
option value is exposed to the drive. I'm envisioning a model structure in which Tournament has_many Round(s) and Round has_many Match(s). Is this architecture compatible with this library?
You'll need to put that into your driver yourself. You can use TournamentSystem::RoundRobin.guess_round myDriver
to determine the round from the existing matches.
Thanks! I'm studying guess_round
now... Are you suggesting something like this in the driver?
def build_match(home_team, away_team)
current_round = TournamentSystem::RoundRobin.guess_round self
@tournament.team_matches.create!(side_a: home_team, side_b: away_team, round: current_round)
end
(This ☝️ doesn't quite match the structure I described previously with a Round model. I simplified it for discussion purposes)
Thanks. I think I understand now. Citadel is initializing the driver with the round info in advance. So no need for guess_round
.
So if I follow this pattern, I think mine might look something like this...
my_driver = MyDriver.new
total_rounds_count = TournamentSystem::RoundRobin.total_rounds(my_driver)
total_rounds_count.times do |i|
round = Round.create!(number: i, ...)
my_driver.set_round_id round.id # build_match method will use this when creating a match
TournamentSystem::RoundRobin.generate my_driver, { round: i }
end
Is this making sense?
Yep, that looks good.
The docs explain how to generate a round of matches for a tournament. This seems straightforward for creating the first round of matches in a new tournament. For most formats (other than round robin) the subsequent rounds depend on who wins in the previous. I'm trying to understand how the additional rounds are meant to be created. Is it expected for the application to run
generate
repeatedly after each match is completed?