jquery-bracket icon indicating copy to clipboard operation
jquery-bracket copied to clipboard

Double-elimination major semi-final inconsistent loser sources

Open kpagcha opened this issue 8 years ago • 9 comments
trafficstars

I realized there is a bug when choosing what Winner Bracket Losers are sources for the Loser Bracket Major semi-finals.

Notice the major SF loser sources in this 8-team bracket:

8-team

Major SF1 second team is the WB SF2 loser. Major SF2 second team is the WB SF1 loser.

Notice now the major SF loser sources in a 10-team bracket:

10-team

Major SF1 second team is the WB SF1 loser. Major SF2 second team is the WB SF2 loser.

At first I thought this was a power-of-two bracket vs non-power-of-two bracket scenario, but no, because look at this 6-team bracket where the teams are picked just like the 8-team bracket does.

6-team

There is a discrepancy when choosing which SF loser goes to which major SF, and it is impossible to figure out when the plugin is going to apply one way to do it or the other, which makes it really hard to work with the plugin. Quick fix?

kpagcha avatar Dec 26 '16 10:12 kpagcha

Hi,

Is this different from the second half of this comment https://github.com/teijo/jquery-bracket/issues/92#issuecomment-265576063? Starting from:

So what's the "correct" way to do it?

teijo avatar Dec 26 '16 12:12 teijo

I think the issue you describe comes from the bracket being populated from beginning to end instead of looking from finals, then semi-finals, etc. Every time the bracket size increases, the number of rounds switches between even and odd, leading to the loser bracket seeding switching every [second] time.

Changing this in backwards compatible manner would require some kind of flag the user would need to give to indicate different algorithm.

I think in loserMatchSources https://github.com/teijo/jquery-bracket/blob/d3b8ca8ee20d036d547b51679c9d2e7dfd358639/src/jquery.bracket.ts#L456 you would need to consider the r (being round number) to go from roundCount - r to r instead of from r to roundCount when deciding to reverse the flow.

teijo avatar Dec 26 '16 12:12 teijo

Yes this is a completely different matter.

In that comment I was asking about what method was being applied in the double-elimination brackets when selecting WB losers which are sent to the LB, and what order was being applied. Then you said that every second round (this is called a major stage), losers are selected in a reverse order. Great, gotcha.

Then this is what I am always going to expect. The issue here is that in only some cases, this does not stand true and teams are not seeded in the reverse order but in the normal order. The issue is that this is an inconsistency. Once the rules are defined, one should expect always the same output, and not an inconsistent result.

So yeah, I think this is then a bug, teams should be seeded always as the rule says, and not differently and unexpectedly. edit: I think this should be flagged as bug rather than enhancement because it "breaks the contract".

kpagcha avatar Dec 26 '16 12:12 kpagcha

Every time the bracket size increases, the number of rounds switches between even and odd

I don't think so. The loser bracket will also have an even number of rounds because the number of rounds by its very nature is even: n_rounds_LB = (n_rounds_WB - 1) * 2. It is multiplied by 2, so it will always be an even number.

kpagcha avatar Dec 26 '16 12:12 kpagcha

It is multiplied by 2, so it will always be an even number.

Every second round in LB is between LB teams and every second is between LB team and a seeded team from WB. These seeded matches switch order every second time.

If you look at the first picture, the first seeded rounds (ignoring the very first round) in LB, reading from top to bottom, go from high to low (teams 7 and 3). Now compare that to the second picture with more teams. First seeded rounds in LB go also from high to low (teams 10, 8, 6, 3). If you look at the second seeded rounds in the big picture, the seeded rounds are reversed, from low to high (teams 5 and 9).

Considering that in small picture, there are 2 seeded rounds, the LB final will have only 1 reversal, meaning that reading back from the finals, the "seeded semifinal" (teams 6 and 3), is high to low. In big picture, there are 3 seeded rounds with 2 reversals, leading the "seeded semifinal" (teams 5 and 9), to be low to high.

Since small one has even number of seeded rounds, reading from right to left (final to semifinal), the order looks different than with odd numbers in big picture.

This would be where I"d start looking at first.

teijo avatar Dec 26 '16 13:12 teijo

So yeah, I think this is then a bug, teams should be seeded always as the rule says, and not differently and unexpectedly.

I definitely agree, if it doesn't behave consistently it's a bug. Unclear documentation and unintuitive behaviour are different issues.

teijo avatar Dec 26 '16 13:12 teijo

I will try fixing it then. Unfortunately I don't know TypeScript so I cannot make changes directly to the repo. So I will try directly with the JS dist.

kpagcha avatar Dec 26 '16 14:12 kpagcha

There shouldn't be any TypeScript specific changes I think.

Just make sure you have node installed, then run npm install in project root. After that running grunt will create a new file to dist based on your modifictions in src (or running npm start will start doing that automatically when changes in src/ are spotted).

Update your git clone first! I just had to update the dependencies as Grunt and SASS had somehow broken.

teijo avatar Dec 26 '16 15:12 teijo

I thought I managed to fix it passing roundCount to loserMatchSources and changing this

const winnerMatch = (r % 2 === 0) ? (matchCount - m - 1) : m;

to this

const winnerMatch = ((roundCount - r) % 2 === 0) ? (matchCount - m - 1) : m;

However, I realized this affected now the previous major round so it wasn't reversed when it should be.

I am having trouble in figuring out how to tell when a match belongs to a minor or to a major stage when we are in the loserMatchSources function. I thought n meant that since in the loop above it's called subRounds but apparently its value is 0 for the first pass (1st round minor stage) and then always 1 no matter what stage we're in.

Edit: how about this other condition?

const winnerMatch = (r % 2 === 0 || (roundCount - r) % 2 === 0) ? (matchCount - m - 1) : m;

I'm afraid to break something else though.

kpagcha avatar Dec 27 '16 10:12 kpagcha