JavaScript单败淘汰赛制通用结构生成方案求助
通用单败淘汰赛结构生成方案(支持任意选手人数)
核心思路
单败淘汰赛每一轮需要选手两两配对对决,因此总参赛席位必须是2的幂次(2、4、8、16...)。对于非2幂次的选手人数,只需补充足够的bye(轮空)标记,将总席位凑到最近的、大于等于当前人数的2的幂次即可。轮空的选手无需参与本轮比赛,直接晋级下一轮。
实现代码
// 获取大于等于目标数的最小2的幂 function getNextPowerOfTwo(n) { if (n <= 1) return 1; let power = 1; while (power < n) { power *= 2; } return power; } // 生成单败淘汰赛结构 function generateSingleEliminationTournament(playerIDs) { const totalSlots = getNextPowerOfTwo(playerIDs.length); // 补充轮空标记,凑齐总参赛席位 const participants = [...playerIDs]; while (participants.length < totalSlots) { participants.push('bye'); } const tournament = { rounds: [] }; let currentRound = participants.map(id => ({ id })); // 逐轮生成对阵,直到决出冠军 while (currentRound.length > 1) { const nextRound = []; const roundMatches = []; // 两两配对生成本轮比赛 for (let i = 0; i < currentRound.length; i += 2) { const [p1, p2] = [currentRound[i], currentRound[i + 1]]; let winner; // 处理轮空情况:有轮空的一方直接晋级 if (p1.id === 'bye') { winner = p2; } else if (p2.id === 'bye') { winner = p1; } else { // 实际比赛前留空,后续可填充真实胜者ID winner = null; } roundMatches.push({ players: [p1, p2], winner: winner }); // 为下一轮准备参赛选手(轮空直接晋级,正常比赛暂占位) nextRound.push(winner || { id: null }); } tournament.rounds.push({ matches: roundMatches }); currentRound = nextRound; } // 最终剩余的选手即为冠军 tournament.champion = currentRound[0]; return tournament; }
使用示例
// 测试8人(2的幂次) const players8 = [6, 2, 1, 4, 7, 3, 8, 5]; console.log('8人淘汰赛结构:', generateSingleEliminationTournament(players8)); // 测试6人(需补2个轮空) const players6 = [1, 2, 3, 4, 5, 6]; console.log('6人淘汰赛结构:', generateSingleEliminationTournament(players6)); // 测试5人(需补3个轮空) const players5 = [1, 2, 3, 4, 5]; console.log('5人淘汰赛结构:', generateSingleEliminationTournament(players5));
可扩展优化点
- 随机配对:补充轮空后可打乱
participants数组,避免轮空集中在某一侧,让对阵更公平。 - 自定义轮空标识:将
'bye'替换为对象(如{ type: 'bye', label: '轮空' }),方便前端渲染展示。 - 结果更新支持:可扩展函数,支持传入已完成的比赛结果,自动推导后续轮次的晋级选手。
内容的提问来源于stack exchange,提问作者Juan Luis Moreno Calderón
相关产品推荐
相关产品推荐

