Drarig29 / brackets-manager.js

A simple library to manage tournament brackets (round-robin, single elimination, double elimination).
https://drarig29.github.io/brackets-docs
MIT License
245 stars 38 forks source link

BYE first 2 seed #210

Closed fluidpb closed 1 month ago

fluidpb commented 2 months ago

I'm trying to setup a single elimination bracket where seed 1-2 have a bye. This is my data:

const seeding = [
  {
    id: '8213a86b-b1fe-4649-8688-93252ab674e7',
    name: 'Gowtham Mulpuri / Duncan Hawvermale',
    tournament_id: 'a6d240d4-b8e7-4beb-ac7c-ff849ed76bf7'
          },
  null,
  {
    id: 'cdcffdd0-9387-4a2e-92c8-07598e66481d',
    name: 'Brian Kerr / Austin Bricker',
    tournament_id: 'a6d240d4-b8e7-4beb-ac7c-ff849ed76bf7'
          },  
  null,
  {
    id: '3e143b1c-1265-4a6e-b388-4995c832c435',
    name: 'Joseph Zero / Ty Robbins',
    tournament_id: 'a6d240d4-b8e7-4beb-ac7c-ff849ed76bf7'
  },
  {
    id: 'b2e1de8d-30db-4f00-be4a-ef6b64a8b177',
    name: 'Bryan Everhart / Gowtham Mulpuri',
    tournament_id: 'a6d240d4-b8e7-4beb-ac7c-ff849ed76bf7'
  },
  {
    id: 'd80fe8fb-5ce2-4bcc-a2da-e7289bf8ce1c',
    name: 'Garrett Goh / Filomeno Gonzalez',
    tournament_id: 'a6d240d4-b8e7-4beb-ac7c-ff849ed76bf7'
  },
  {
    id: '7f2b3b1a-2def-40ff-9606-3dbd92f455cb',
    name: 'Hao Nguyen / Jeron Paraiso',
    tournament_id: 'a6d240d4-b8e7-4beb-ac7c-ff849ed76bf7'
  }
]

await manager.create.stage({
    name: 'Elimination',
    tournamentId: bracket.id,
    type: 'single_elimination',
    settings: {
        balanceByes: true,
        grandFinal: 'none'
   },
   seeding,
});

Screenshot 2024-07-11 at 2 35 51 PM

For some reason, seed 1 and 3 are getting bye instead. How do I resolve this?

Drarig29 commented 2 months ago

Did you try without balanceByes?

fluidpb commented 2 months ago

I ended up with a different approach altogether. Found a script that generate seeding with null if it's not a power of 2:

const changeIntoBye = (seed: number, participantsCount: number) => {
  return seed <= participantsCount ?  seed : null;
}

const generateSeeding = (participants: any[]) => {
  const participantsCount = participants.length,
    rounds = Math.ceil(Math.log(participantsCount) / Math.log(2)),
    bracketSize = Math.pow(2, rounds);

  if (participantsCount < 2) {
    return [];
  }

  let matches: any = [[1,2]];

  for (let round: number = 1; round < rounds; round++) {
    let roundMatches = [],
      sum = Math.pow(2, round + 1) + 1;

    for (let i: number = 0; i < matches.length; i++) {
      let home = changeIntoBye(matches[i][0], participantsCount),
        away = changeIntoBye(sum - matches[i][0], participantsCount);
      roundMatches.push([home, away]);
      home = changeIntoBye(sum - matches[i][1], participantsCount);
      away = changeIntoBye(matches[i][1], participantsCount);
      roundMatches.push([home, away]);
    }
    matches = roundMatches;   

  }   

  return matches;    
}

This will generate something like this [ 1, null ], [ 5, 4 ], [ 3, 6 ], [ null, 2 ]. I don't think brackets-manager supports non power of 2 participant list so this is a workaround.

Lastly,

const seeding = generateSeeding(participants);
const newParticipants: any[] = [];
const seedOrder: any[] = [];
seeding.forEach((seed: any) => {
  seedOrder.push(seed[0], seed[1]);
});

seedOrder.forEach((seed: number | null) => {
  if (seed === null) {      
    newParticipants.push(null);
  }
  else {            
    newParticipants.push(participants[seed - 1])
  }
});

await manager.create.stage({
  name: 'Elimination',
  tournamentId: bracket.id,
  type: 'single_elimination',
  settings: {
    grandFinal: 'none',            
    seedOrdering: ['natural']
  },
  seeding: newParticipants
});

Let me know if this is ok. I've tested several different ways and it worked nicely.

fluidpb commented 2 months ago

FYI, this is the software in action. https://app.fluidpb.com/tournaments/bracket/dd3df6a1-d9b2-47a9-b25e-fefa2d4072ca/playoff. We had to modify the viewer and a few other things to work with Pickleball.

Drarig29 commented 1 month ago

Cool! I like the app you made! I'll close the issue since you managed to find a custom way 👍