Package Exports
- groupstage
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (groupstage) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
GroupStage
[
](https://david-dm.org/clux/groupstage
Stability: 3 - StableOverview
GroupStage is a simple and customizable way to add a preliminary stage to a tournament. A group stage is designed to pick out the best players by first splitting them up in fair groups of requested size, then round robin schedule each group.
They are advantageous compared to eliminations because they guarantee exactly groupSize-1 matches per player. A Duel tournament, by contrast, only guarantees at least one or two matches (latter in double elimination mode), whereas a full round robin scheduled league forces everyone to battle everyone, and no final matches are played.
By combining a group stage with a later elimination round, the best players get picked out for an exciting finale.
Construction
Specify the number of players and the group size.
// 16 players in groups of 4
var gs1 = new GroupStage(16, 4);
// 9 players in groups of 3
var gs2 = new GroupStage(9, 3);The GroupStage.invalid(numPlayers, groupSize) will tell you whether the constructor arguments produce a valid tournament. Read its entry in the tournament commonalities doc for info on this.
Match ids
Like all tournament types, matches have an id object that contains three values all in {1, 2, ...}:
{
s: Number, // the group number
r: Number, // the round number
m: Number // the match number
}Finding matches
All the normal Base class helper methods exist on a GroupStage instance.
Some notable examples follow:
var group1 = gs.findMatches({ s: 1 });
var group2round1 = gs.findMatches({ s: 2, r: 1 });
var upcomingForSeed1 = gs.upcoming(1);
var matchesForSeed1 = gs.matchesFor(1);Scoring matches
Call gs.score(id, [player0Score, player1Score]) as for every match played.
The gs.unscorable(id, scoreArray) will tell you whether the score is valid. Read the entry in the tournament commonalities doc.
NB: Few restrictions
Unlike any other tournament, GroupStages allow for individual match ties. The results are simply tallied up by points (configurable) at the end. If match ties is not possible/ideal, just check for it externally:
var score = function (id, score) {
// assumes you have guarded on `gs.unscorable` earlier
if (score[0] !== score[1]) {
// filtering out the ties - but should probably present an error reason
gs.score(id, score);
}
};Special methods
groupFor(seedNumber) :: [Match]
Get all the matches in the group that a given player is in.
Special helpers
If you are requiring the tournament under the full entry point (i.e. var t = require('tournament')) then the meaty algorithms behind splitting up a list of seeds into fair groups and round robin scheduling for a group of size n are exposed for your experimental needs:
t.groups(numPlayers, groupSize) :: [Groups]
t.groups(15, 5); // 15 players in groups of 5
[ [ 1, 4, 7, 12, 15 ],
[ 2, 5, 8, 11, 14 ],
[ 3, 6, 9, 10, 13 ] ]t.robin(numPlayers) :: [Rounds]
t.robin(4); // 4 player round robin pairups
[ [ [ 1, 4 ], [ 2, 3 ] ], // round 1
[ [ 1, 3 ], [ 4, 2 ] ], // round 2
[ [ 1, 2 ], [ 3, 4 ] ] ] // round 3Caveats
End results
Acting on end results in a group stage is sometimes problematic. Ties are allowed, and complex, unexpected results can cause multi-way ties (it is possible for an entire group to tie), and results() even if ties have been disallowed. We cannot sensibly compensate for that without additional input:
Results config
Unlike any other tournament GroupStage can compute results in a variable manner. An options object can be passed to gs.results(opts) that will use any of the following:
{
winPoints: Number, // Number of points awarded per win - default 3
tiePoints: Number, // Number of points awarded per tie - default 1
mapsBreak: Boolean, // Look at the sum of map scores in case of ties - default false
}Tiebreaking
But in some cases, even this is insufficient. For this you need to forward the gs.results() to a TieBreaker tournament. This tournament can also be used as a test of whether or not tiebreaking is needed.
Seeding and groups
Like for most other tournaments, seeding is important. The initial player partitioning into groups is done in such a way so that there is a variety of differently skilled players:
- If the number of players is divisible by the number of groups (ideal condition), then the sum of the seeds in each group differ by at most the number of groups.
t.groups(15, 5); // 15 players in groups of 5
[ [ 1, 4, 7, 12, 15 ],
[ 2, 5, 8, 11, 14 ],
[ 3, 6, 9, 10, 13 ] ]- If additionally, every group size is even, then the sum of seeds in each group is identical.
These conditions make standard group arrangements like 16 players in groups of 4 perfectly fair, provided the seeding is perfect.
> t.groups(16, 4)
[ [ 1, 5, 12, 16 ],
[ 2, 6, 11, 15 ],
[ 3, 7, 10, 14 ],
[ 4, 8, 9, 13 ] ]This model ensures that unusual results are directly caused by upsets (a presumed bad player beats a higher ranked one), not the fact that the top 4 players was in one group, causing lower ranked players to advance from the group stage without merit.
License
MIT-Licensed. See LICENSE file for details.