0

I am working on a tournament bracket with double elimination in Svelte. I keep having the issue of when two matchups have four teams when I update the score to select the winners, the matchup where the winners would face gets messed up. The team that was waiting for the other team gets set back to pending and the matchup that I just updated, gets put in the other team spot.

Visual of what is happening: https://imgur.com/a/Bzy2b5A

I believe it has something to do in updateBracket() but I'm not sure besides that. How do I stop this from happening when I input new scores?

Here are the types:

export type Bracket = {
    id: number;
    name: string;
    size: number;
    teams: BracketTeam[];
};

export type BracketTeam = {
    id: string;
    name: string;
    seed: number;
    bracket_id?: number;
};

export type BracketMatchup = {
    team1: { id: string; name: string; seed: number; score: number };
    team2: { id: string; name: string; seed: number; score: number };
};

export type BracketScores = { [round: string]: { matchups: BracketMatchup[] } };

Here is the code that I use for the page:

<script lang="ts">
    import { _showError } from '../../../+page';
    import type {
        Bracket,
        BracketMatchup,
        BracketScores,
        BracketTeam
    } from '../../../../stores/brackets';

    export let selectedBracket: Bracket;
    export let allMatchups: BracketScores = {};
    export let existingMatchups: BracketScores = {};

    $: createMatchups([...selectedBracket.teams]);
    // $: console.log(allMatchups);

    function createMatchups(teams: BracketTeam[], round = '0', losersBracket = false) {
        // Stop if less than 2 teams
        if (teams.length < 2) return;

        // Create bye team
        const bye = { id: 'bye', name: 'Bye', seed: 0 };

        if (round === '0') {
            // Make first round power of 2
            const needByes = Math.log2(teams.length) % 1 !== 0;

            if (needByes) {
                while (Math.log2(teams.length) % 1 !== 0) teams.push(bye);
            }

            // Shuffle teams by seed
            const numRounds = Math.log2(teams.length / 2);
            for (let i = 0; i < numRounds; i++) {
                let out = [];
                const splice = 2 ** i;

                while (teams.length > 0) {
                    out.push(...teams.splice(0, splice));
                    out.push(...teams.splice(-splice));
                }

                teams = out;
            }
        }

        // Create matchups
        const bracketKey = losersBracket ? `losers_${round}` : round;
        allMatchups[bracketKey] = { matchups: [] };

        // Add bye to teams if odd
        if (teams.length % 2 !== 0) teams.splice(1, 0, bye);

        // Pair teams
        for (let i = 0; i < teams.length; i += 2) {
            const existingMatchup = existingMatchups[bracketKey]?.matchups.find(
                (matchup) => matchup.team1.id === teams[i].id && matchup.team2.id === teams[i + 1].id
            );

            const team1 = { ...teams[i], score: existingMatchup ? existingMatchup.team1.score : 0 };
            const team2 = { ...teams[i + 1], score: existingMatchup ? existingMatchup.team2.score : 0 };

            allMatchups[bracketKey].matchups.push({ team1, team2 });
        }

        // Select winners for next round
        const pending = { id: 'pending', name: 'Pending', seed: 0 };

        let winners = allMatchups[bracketKey].matchups.map((matchup) => {
            const { team1, team2 } = matchup;

            if (team1.id === 'bye') return team2;
            if (team2.id === 'bye') return team1;

            if (team1.score > team2.score) return team1;
            if (team2.score > team1.score) return team2;

            return pending;
        });

        // Create next round
        if (round === '0') {
            // Select losers for losers bracket
            const losers = allMatchups[bracketKey].matchups.map((matchup) => {
                const { team1, team2 } = matchup;

                if (team1.id === 'bye') return bye;
                if (team2.id === 'bye') return bye;

                if (team1.score < team2.score) return team1;
                if (team2.score < team1.score) return team2;

                return pending;
            });

            // Create losers bracket
            createMatchups(losers, +round + 1 + '', true);
        } else if (losersBracket) createMatchups(winners, +round + 1 + '', true);

        createMatchups(winners, +round + 1 + '');
    }

    function updateBracket(round: string, matchup: BracketMatchup) {
        console.log(matchup);

        // Make sure scores are not negative
        if (matchup.team1.score < 0) matchup.team1.score = 0;
        if (matchup.team2.score < 0) matchup.team2.score = 0;

        // Ignore if pending or bye
        if (matchup.team1.id === 'pending' || matchup.team2.id === 'pending') return;
        if (matchup.team1.id === 'bye' || matchup.team2.id === 'bye') return;

        // Make sure round exists
        if (!existingMatchups[round]) existingMatchups[round] = { matchups: [] };

        // Make sure matchup exists add if not
        const matchupIdx = existingMatchups[round].matchups.findIndex(
            (matchup) => matchup.team1.id === matchup.team1.id && matchup.team2.id === matchup.team2.id
        );
        if (matchupIdx === -1) existingMatchups[round].matchups.push(matchup);
        else existingMatchups[round].matchups[matchupIdx] = matchup;

        createMatchups([...selectedBracket.teams], '0', round.includes('losers'));
    }
</script>

<div id="bracket">
    {#each Object.keys(allMatchups).sort((a, b) => {
        if (a.includes('losers') && !b.includes('losers')) return -1;
        else if (!a.includes('losers') && b.includes('losers')) return 1;
        else if (a.includes('losers') && b.includes('losers')) return b.localeCompare(a);
        else return a.localeCompare(b);
    }) as round}
        <div class="round">
            {#each allMatchups[round].matchups as matchup, i}
                <div class="matchup">
                    <div class="team">
                        <span>{matchup.team1.seed || ''}</span>
                        <p>{matchup.team1.name}</p>
                        <input
                            type="number"
                            min="0"
                            bind:value={matchup.team1.score}
                            on:input={() => updateBracket(round, matchup)}
                        />
                    </div>
                    <div class="team">
                        <span>{matchup.team2.seed || ''}</span>
                        <p>{matchup.team2.name}</p>
                        <input
                            type="number"
                            min="0"
                            bind:value={matchup.team2.score}
                            on:input={() => updateBracket(round, matchup)}
                        />
                    </div>
                </div>
            {/each}
        </div>
    {/each}
</div>

<style>
    #bracket {
        display: flex;
        flex-direction: row;
        justify-content: center;
        align-items: center;
        width: 100%;
        margin-top: 2rem;
    }

    .round {
        display: flex;
        flex-direction: column;
        justify-content: space-around;
        align-items: center;
        height: 100%;
    }

    .matchup {
        margin: 10px;
        border: 1px solid var(--color-theme-3);
        border-radius: 0.3rem;
        width: 200px;
    }

    .team {
        display: flex;
        flex-direction: row;
        justify-content: center;
        align-items: normal;
        background-color: var(--color-theme-1);
        margin: 0.5rem;
        padding: 0.3rem;
        border-radius: 0.5rem;
        font-size: 0.9rem;
    }

    .team p {
        margin: 0.5rem;
        padding-top: 0.3rem;
    }

    .team span {
        font-size: 0.7rem;
    }
</style>

Corrl
  • 6,206
  • 1
  • 10
  • 36
Maximus39
  • 21
  • 4

0 Answers0