tournament-js / tournament

A tournament base class for static tournament types
MIT License
64 stars 13 forks source link

Multi-Stage Tournaments #1

Closed clux closed 11 years ago

clux commented 11 years ago

I need a good way to plumb different tournament types together. I want to be able to create a, say, 32 player FFA elimination and forward the top 8 to a single elimination tournament (and auto create tiebreaker mini-groups when needed). Also, I may not necessarily want to finish the FFA elimination (but just stop when a top 8 has been determined if this is a good number to stop on).

trn.results() provides excellent statistics that should be sufficient figure out these things, but I can imagine it would get quite hairy if it's not been modeled properly.

The plumbing should work in a generic way between all the different tournament types that's serializable and deserializable into a wrapper type (or whatever works nicely).

clux commented 11 years ago

I've come to the conclusion that it should be handled outside to an extent, but we can prepare for how many to extract inside each tournament.

Each tournament type should implement a limit parameter that it should be able to distinguish. I.e. if you set limit to 6 in a groupstage, then the group stage must generate tiebreakers if necessary to determine the top 6 and account for this in the ::isDone() members.

This way, at the start, modification of tournaments can be put in place from the beginning. When the first stage is done, it's simply a matter of picking the top limit from ::results(). I may make another wrapper module to encapsulate this logic, but this is fundamentally simple stuff.

A few gotchas though;

clux commented 11 years ago

FFA tournaments can set a limit now. High level usage:

var ffa = new t.FFA(16, [4,4], [2], {limit: 4}); // final round is actually 2 semis, and instead of a final determine top 4

// ..
// score all matches

// when everything is done:
ffa.isDone(); // true

// can now pick top 4 
var winners = ffa.results().slice(0, ffa.limit);

// get their seed numbers so they can be mapped by your application to the actual participant list
var topSeedNums = winners.map(function(w) { return w.seed });

Note that deserialization needs to pass in the opitons object ({limit:4}) to fromJSON as a 2nd parameter as this is irrecoverable by the deserializer.

clux commented 11 years ago

Few pointers on this - there's not actually that desperately needs to be done:

clux commented 11 years ago

GroupStage now works fine with the new TieBreaker class.

Thus, no tournament type now desperately need it as the remaining KnockOut and Duel is nicely tuned to the end-stage tournament anyway. That said, implementing it for these may not be that hard (at least KnockOut will be easy).

clux commented 11 years ago

Tagging with the unimplemented ones.

clux commented 11 years ago

While limits is a great idea, I think staging needs a better idea than just doing that. TieBreaker does what you want for groupstage, but ideally there should be one class containing both.

Similarly, you should EASILY be able to make a class that contains to other tournaments and be able to turn those into a multi stage one. I have been experimenting in the groupstage repo locally by making a class containing both TieBreaker and GroupStage. This works by effectively freezing the GroupStage matches when the TieBreaker matches have been created.

There is ATM many things wrong with this approach:

So ideally, you need:

clux commented 11 years ago

An overridable Klass.from will be a receiver function in the future (you can send a finished tournament instance to it). Phasing out limits over better and more general tiebreaker support is the preferable approach, and it is my aim to implement this properly soon.

clux commented 11 years ago

This exists in 0.19.0 now. Works with most tournament types and is tested in trn.multi.test.js in this repo. GroupStage still needs TieBreaker, and this is broken at the moment, but the plan is to extend TieBreaker so we can use TieBreaker.from(groupStageInstance, limit);