FFA tourney with automatic tiebreakers between rounds
It is a pointless abstraction if you are modelling a game/sport in which match level ties cannot occur, but for when that's not true - or if you are providing a tiebreaking resolution outside an actual match - then this will provide the glue needed.
FFA, but watch for stages. What follows is a comprehensive stage-by-stage example.
All the constructor arguments are identical to FFA. This example will follow a three round tournament with 16 players in round one, 8 in round two, and 4 in round three. The top 2 from each match (match sizes always 4) will proceed to the next round, and we have additionally asked for an unambiguous top 2 from the final.
var FfaTb = require'ffa-tb';var trn = 16 sizes: 4 4 4 advancers: 2 2 limit: 2 ;
Each stage is scored in turn. First round is the quarter finals:
trninFFA; // truetrnmatchesid: s: 1 r: 1 m: 1 p: 1 5 12 16id: s: 1 r: 1 m: 2 p: 2 6 11 15id: s: 1 r: 1 m: 3 p: 3 7 10 14id: s: 1 r: 1 m: 4 p: 4 8 9 13trnmatchesforEachm =>trnscoremid midm === 3 ? 4331: 4321; // tie match 3;
This will complete the first stage, but not the entire tourney:
trnstageDone; // truetrnisDone; // false - two more ffa rounds to gotrncreateNextStage; // true - must createNextStage when stageDone && !isDone
Creating next stage will update state, and now we are in a tiebreaker round to resolve match 3:
trninTieBreaker; // truetrnmatches;id: s: 3 r: 1 m: 1 p: 7 10 // 2nd placers from match 3 must be resolvedtrnscoretrnmatches0id 01;trnstageDone && !trnisDone; // truetrncreateNextStage; // true - intermediate tiebreaker stage over
This made for a short stage (and typically tiebreakers are short), so we are now back to the FFA part, in round 2, the semifinals:
trninFFA; // truetrninFinal; // false - these are the semistrnmatches;id: s: 1 r: 1 m: 1 p: 1 3 6 10 // player 10 won tiebreakerid: s: 1 r: 1 m: 2 p: 2 4 5 8trnmatchesforEachm =>trnscoremid 4321; // score without ties;trnstageDone && !trnisDone; // truetrncreateNextStage; // true - advance to round 3
This round did not have any tiebreakers, so we skip any tiebreaker stages after round 2 and go straight to the final:
trninFFA && trninFinal; // true - in last round, and we're in FFAtrnmatchesid: s: 1 r: 1 m: 1 p: 1 2 3 4 // top seeds won their semistrnscoretrnmatches0id 1111; // complete tie in finaltrnstageDone && !trnisDone; // true - need to tiebreak final (limit set to 2)trncreateNextStage; // true
Because we had set
limit, we are now forced to replay the final in a tiebreaker:
trninTieBreaker && trninFinal; // true// matches is complete replay of final - full tietrnmatchesid: s: 1 r: 1 m: 1 p: 1 2 3 4trnscoretrnmatches0id 1110; // tie slightly lesstrnstageDone && !trnisDone; // true - need to tiebreak final bettertrncreateNextStage; // true
This goes on if things do not resolve, but we did at least knock out player 4:
trninTieBreaker && trninFinal; // truetrnmatches;id: s: 1 r: 1 m: 1 p: 1 2 3trnscoretrnmatches0id 110; // tied for 1st placetrnstageDone && trnisDone; // true - we don't need to break the top 2
This is actually sufficient. Note that we have a tie for 1st place, but we can pick out our top 2, which is all we asked of
limit. If you wanted the top 2, then split these two, you would really have an extra FFA round with 2 players and have
limit at 1.
At any rate, this example is over, let's lock it down so no one comes around later and messes with the final state:
See tiebreaker module. We will break the smallest cluster necessary to determine the top
n players where
n is the current advancers number or the
limit in the final round.
Since we have established that we can play matches with more than 2 players, tiebreakers are
simple, meaning they will make a single multiple player match which is a subset of the previous match. This is different from default behaviour in groupstage tiebreakers which actually require subgroups when there are multi-way ties.
In most cases, tiebreaker matches resolve most conflicts with modelling, and maps nicely onto the physical world. However, sometimes this is not true:
Suppose a match tied, but external factors (not present in the map score) actually decided who broke. For such a situation you have two options:
I.e. fill in the tiebreaker match with enough external information (pretend it was an actual match) to indicate to tournament who clearly won.
This way, since you never actually intend to play physical tiebreaker matches, you can just use FFA directly.
Both of these solutions are fine, and it comes to you how much data you want.
Football/soccer never really presents a physical tiebreaker match, but it certainly does tiebreak. Overtime rounds and penalty shootouts can all be viewed as individual tiebreaker matches, or you can just look at the grand total goal sum as the final score.
Whichever you want to use for a football tournament would depend on the information you want. Since the goals are pretty much perfectly the match score, you could easily just not use tiebreaker since the game itself has a way of resolving ties.
However, if you want a way to model the individual parts of the tiebreaking resolution, it could be useful (but note that this can more easily be done with metadata outside tournament structures).
Say you stick 10 players in a deatmatch server and want to take the pick the top 5. When the match is over, it is over. If there's a tie between 5th, 6th, and 7th, then extending the match would be unfair to the top 4 that clearly should proceed. In this case a tiebreaker match where these three players play another round of FFA is really the perfect fit.
Given the perfect fit of model and physical reality of the situation, this is were this module shines over plain
You could technically still choose not to model this inside the module, and present an amalgamated final score; i.e. if the scores were
[10,9,8,7,6,6,6,3,2,1] and the tie resolver
[3,2,1], you could just score the match as
[10,9,8,7,6,5,4,3,2,1] and gloss over the details.
Doing so would be a little silly though. This module can formalize manual tiebreaking processes, provide transparency, and can limit the time needed for organizers to work out this kind of stuff.
Install from npm:
$ npm install ffa-tb
MIT-Licensed. See LICENSE file for details.