Last active
November 21, 2018 15:11
-
-
Save jsvennevid/8358e6a633feb3c022a4e0f3dff329d9 to your computer and use it in GitHub Desktop.
Algorithm to sort teams into matches appropriate for a bracketed tournament
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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