Skip to content

Instantly share code, notes, and snippets.

@jsvennevid
Last active November 21, 2018 15:11
Show Gist options
  • Save jsvennevid/8358e6a633feb3c022a4e0f3dff329d9 to your computer and use it in GitHub Desktop.
Save jsvennevid/8358e6a633feb3c022a4e0f3dff329d9 to your computer and use it in GitHub Desktop.
Algorithm to sort teams into matches appropriate for a bracketed tournament
class TournamentBracketGenerator {
static generate(teams) {
teams = teams.map((t,i) => [i,t]);
let curr = 2;
let matches = [[teams[0],teams[1]]];
do {
curr += curr;
matches = matches
.reduce((acc, curr) => acc.concat(curr))
.map(team => [team, teams[(curr-1)-team[0]]]);
} while (curr < teams.length);
return TournamentBracketGenerator.sort(matches)
.map(match => match.map(team => team && team[1]));
}
/* sort matches to improve spread (improve bracketing) */
static sort(matches) {
function splitsort(matches) {
if (matches.length < 2) {
return matches;
}
const middle = Math.ceil(matches.length / 2);
const low = matches.slice(0, middle);
const high = matches.slice(middle);
if ((low[0][0][0] & 1) && !(high[0][0][0] & 1)) {
return splitsort(high).concat(splitsort(low));
} else {
return splitsort(low).concat(splitsort(high));
}
}
return splitsort(matches);
}
/* collapse matches (where one or more teams are missing due to having lost) */
static collapse(matches) {
if (matches.length & 1) {
throw new Error("Uneven number of matches");
}
const output = [];
for (let offset = 0; offset < matches.length; offset += 2) {
let m1 = matches[offset].filter(team => team);
let m2 = matches[offset+1].filter(team => team);
if (m1.length > 1 || m2.length > 1) {
throw new Error("Too many teams in response");
}
output.push([m1[0],m2[0]]);
}
return output;
}
}
/*
function bracket(teams) {
const middle = Math.ceil(teams.length / 2);
const bottom = teams.slice(middle);
const top = teams.slice(0, middle).map((v,i) => [v,bottom.pop()]);
const matches = [];
let tick = false;
while (top.length > 1) {
if (!tick) {
matches.push(top.shift());
matches.push(top.pop());
} else {
const offset = Math.floor((top.length-1) / 2);
matches.push(top.splice(offset, 1)[0]);
matches.push(top.splice(offset, 1)[0]);
}
tick = !tick;
}
if (top.length > 0) {
matches.push(top.shift());
}
return matches;
}
*/
const team_count = Number(process.argv[2]);
const input = Array.apply(null, {length: team_count}).map(Number.call, Number).map(v => v+1);
let matches = TournamentBracketGenerator.generate(input);
while (matches.length > 1) {
console.log("matches:",matches);
const output = TournamentBracketGenerator.collapse(matches.map(match => {
if (Math.random() < 0.95) {
return [match[0],null];
} else {
return [null,match[1]];
}
}));
matches = output;
}
console.log("finale:", matches);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment