Double Limit Tournament Schedule

I am trying to create some logic for creating a tournament schedule with two exceptions .

Here is an example of the command console:

rd1 quarter    semi    finals
A───┐
  0 β”œβ”€β”€β”€β”€β”€β”€β”€A┐
Bβ”€β”€β”€β”˜        β”‚
           4 β”œβ”€β”€β”€β”€β”€β”€β”€β”€A┐
C───┐        β”‚         β”‚
  1 β”œβ”€β”€β”€β”€β”€β”€β”€Cβ”˜         β”‚
Dβ”€β”€β”€β”˜                  β”‚
                    10 β”œβ”€β”€β”€β”€β”€β”€A┐
E───┐                  β”‚       β”‚
  2 β”œβ”€β”€β”€β”€β”€β”€β”€E┐         β”‚       β”‚
Fβ”€β”€β”€β”˜        β”‚         β”‚       β”‚
           5 β”œβ”€β”€β”€β”€β”€β”€β”€β”€Eβ”˜       β”‚
G───┐        β”‚              13 β”œβ”€β”€β”€= Champ
  3 β”œβ”€β”€β”€β”€β”€β”€β”€Gβ”˜                 β”‚
Hβ”€β”€β”€β”˜                          β”‚
                    E────┐     β”‚
         C───┐           β”‚     β”‚
    B───┐  8 β”œβ”€β”€β”€β”€C┐  12 β”œβ”€β”€β”€β”€Eβ”˜
      6 β”œBβ”€β”€β”€β”˜     β”‚     β”‚
    Dβ”€β”€β”€β”˜       11 β”œCβ”€β”€β”€β”€β”˜
         G───┐     β”‚
    F───┐  9 β”œβ”€β”€β”€β”€Gβ”˜
      7 β”œFβ”€β”€β”€β”˜
    Hβ”€β”€β”€β”˜

The numbers represent the indices in the match array, which is the desired output. For example, index 0 will represent team 1 compared to team 8 (using the seed system), index 4 will represent index 0 winner versus index 1 winner.

The losers crane is filled from the losing bracket of the winner, where index 6 is the loser of index 0 against the loser of index 1, and index 8 is the loser of index 4 against the winner of index 6.

, , , , . 0 A B, 4 0 (A) 1 (C). 6 0 (B) 1 (D), 8 4 (C) 6 (B)

, , . 2- . , 8 , , .

// round one
for( $i = 0; $i < log( count( $competitors ), 2 ); $i++ )
{
    $seeded = array( );
    foreach( $competitors as $competitor )
    {
        $splice = pow( 2, $i );

        $seeded = array_merge( $seeded, array_splice( $competitors, 0, $splice ) );
        $seeded = array_merge( $seeded, array_splice( $competitors, -$splice ) );
    }
    $competitors = $seeded;
}

$events = array_chunk( $seeded, 2 );

// quarter finals
for( $i = 0; $i < count( $competitors ) / 2; $i++ )
{
    array_push( $events, array(
        array( 'from_event_index' => $i, 'from_event_rank' => 1 ), // rank 1 = winner
        array( 'from_event_index' => ++$i, 'from_event_rank' => 1 )
    ) );
}

$round_matchups = array( );
for( $i = 0; $i < count( $competitors ) / 2; $i++ )
{
    array_push( $round_matchups, array(
        array( 'from_event_index' => $i, 'from_event_rank' => 2 ), // rank 2 = loser
        array( 'from_event_index' => ++$i, 'from_event_rank' => 2 )
    ) );
}
$events = array_merge( $events, $round_matchups );

for( $i = 0; $i < count( $round_matchups ); $i++ )
{
    array_push( $events, array(
        array( 'from_event_index' => $i + count( $competitors ) / 2, 'from_event_rank' => 2 ),
        array( 'from_event_index' => $i + count( $competitors ) / 2 + count( $competitors ) / 2 / 2, 'from_event_rank' => 1 )
    ) );
}

// semi finals
for( $i = 0; $i < count( $competitors ) / 2 / 2; $i++ )
{
    array_push( $events, array(
        array( 'from_event_index' => $i + count( $competitors ) / 2, 'from_event_rank' => 1 ),
        array( 'from_event_index' => ++$i + count( $competitors ) / 2, 'from_event_rank' => 1 )
    ) );
}

$round_matchups = array( );
for( $i = 0; $i < count( $competitors ) / 2 / 2; $i++ )
{
    array_push( $round_matchups, array(
        array( 'from_event_index' => $i + count( $competitors ), 'from_event_rank' => 1 ),
        array( 'from_event_index' => ++$i + count( $competitors ), 'from_event_rank' => 1 )
    ) );
}
$events = array_merge( $events, $round_matchups );

for( $i = 0; $i < count( $round_matchups ); $i++ )
{
    array_push( $events, array(
        array( 'from_event_index' => $i + count( $competitors ) + count( $competitors ) / 2 - 2, 'from_event_rank' => 2 ),
        array( 'from_event_index' => $i + count( $competitors ) + count( $competitors ) / 2 - 1, 'from_event_rank' => 1 )
    ) );
}

// finals
for( $i = 0; $i < count( $competitors ) / 2 / 2 / 2; $i++ )
{
    array_push( $events, array(
        array( 'from_event_index' => $i + count( $competitors ) / 2 * 3 - 2, 'from_event_rank' => 1 ),
        array( 'from_event_index' => ++$i + count( $competitors ) / 2 * 3 - 1, 'from_event_rank' => 1 )
    ) );
}

:

$events = array(14) {
  [0]=>
  array(2) {
    [0]=>
    array(4) {
      ["team"]=>int(1)
    }
    [1]=>
    array(4) {
      ["team"]=>int(8)
    }
  }
  [1]=>
  array(2) {
    [0]=>
    array(4) {
      ["team"]=>int(4)
    }
    [1]=>
    array(4) {
      ["team"]=>int(5)
    }
  }
  [2]=>
  array(2) {
    [0]=>
    array(4) {
      ["team"]=>int(2)
    }
    [1]=>
    array(4) {
      ["team"]=>int(7)
    }
  }
  [3]=>
  array(2) {
    [0]=>
    array(4) {
      ["team"]=>int(3)
    }
    [1]=>
    array(4) {
      ["team"]=>int(6)
    }
  }
  [4]=>
  array(2) {
    [0]=>
    array(2) {
      ["from_event_index"]=>int(0)
      ["from_event_rank"]=>int(1)
    }
    [1]=>
    array(2) {
      ["from_event_index"]=>int(1)
      ["from_event_rank"]=>int(1)
    }
  }
  [5]=>
  array(2) {
    [0]=>
    array(2) {
      ["from_event_index"]=>int(2)
      ["from_event_rank"]=>int(1)
    }
    [1]=>
    array(2) {
      ["from_event_index"]=>int(3)
      ["from_event_rank"]=>int(1)
    }
  }
  [6]=>
  array(2) {
    [0]=>
    array(2) {
      ["from_event_index"]=>int(0)
      ["from_event_rank"]=>int(2)
    }
    [1]=>
    array(2) {
      ["from_event_index"]=>int(1)
      ["from_event_rank"]=>int(2)
    }
  }
  [7]=>
  array(2) {
    [0]=>
    array(2) {
      ["from_event_index"]=>int(2)
      ["from_event_rank"]=>int(2)
    }
    [1]=>
    array(2) {
      ["from_event_index"]=>int(3)
      ["from_event_rank"]=>int(2)
    }
  }
  [8]=>
  array(2) {
    [0]=>
    array(2) {
      ["from_event_index"]=>int(4)
      ["from_event_rank"]=>int(2)
    }
    [1]=>
    array(2) {
      ["from_event_index"]=>int(6)
      ["from_event_rank"]=>int(1)
    }
  }
  [9]=>
  array(2) {
    [0]=>
    array(2) {
      ["from_event_index"]=>int(5)
      ["from_event_rank"]=>int(2)
    }
    [1]=>
    array(2) {
      ["from_event_index"]=>int(7)
      ["from_event_rank"]=>int(1)
    }
  }
  [10]=>
  array(2) {
    [0]=>
    array(2) {
      ["from_event_index"]=>int(4)
      ["from_event_rank"]=>int(1)
    }
    [1]=>
    array(2) {
      ["from_event_index"]=>int(5)
      ["from_event_rank"]=>int(1)
    }
  }
  [11]=>
  array(2) {
    [0]=>
    array(2) {
      ["from_event_index"]=>int(8)
      ["from_event_rank"]=>int(1)
    }
    [1]=>
    array(2) {
      ["from_event_index"]=>int(9)
      ["from_event_rank"]=>int(1)
    }
  }
  [12]=>
  array(2) {
    [0]=>
    array(2) {
      ["from_event_index"]=>int(10)
      ["from_event_rank"]=>int(2)
    }
    [1]=>
    array(2) {
      ["from_event_index"]=>int(11)
      ["from_event_rank"]=>int(1)
    }
  }
  [13]=>
  array(2) {
    [0]=>
    array(2) {
      ["from_event_index"]=>int(10)
      ["from_event_rank"]=>int(1)
    }
    [1]=>
    array(2) {
      ["from_event_index"]=>int(12)
      ["from_event_rank"]=>int(1)
    }
  }
}

, , 4 , 16 2 ^ n-? , "" - , 0+ , , , , .

+4
3

, --, 16- 32- . , , . , .

$rounds = log( count( $competitors ), 2 ) + 1;

// round one
for( $i = 0; $i < log( count( $competitors ), 2 ); $i++ )
{
    $seeded = array( );
    foreach( $competitors as $competitor )
    {
        $splice = pow( 2, $i );

        $seeded = array_merge( $seeded, array_splice( $competitors, 0, $splice ) );
        $seeded = array_merge( $seeded, array_splice( $competitors, -$splice ) );
    }
    $competitors = $seeded;
}

$events = array_chunk( $seeded, 2 );

if( $rounds > 2 )
{
    $round_index = count( $events );

    // second round
    for( $i = 0; $i < count( $competitors ) / 2; $i++ )
    {
        array_push( $events, array(
            array( 'from_event_index' => $i, 'from_event_rank' => 1 ), // rank 1 = winner
            array( 'from_event_index' => ++$i, 'from_event_rank' => 1 )
        ) );
    }

    $round_matchups = array( );
    for( $i = 0; $i < count( $competitors ) / 2; $i++ )
    {
        array_push( $round_matchups, array(
            array( 'from_event_index' => $i, 'from_event_rank' => 2 ), // rank 2 = loser
            array( 'from_event_index' => ++$i, 'from_event_rank' => 2 )
        ) );
    }
    $events = array_merge( $events, $round_matchups );

    for( $i = 0; $i < count( $round_matchups ); $i++ )
    {
        array_push( $events, array(
            array( 'from_event_index' => $i + count( $competitors ) / 2, 'from_event_rank' => 2 ),
            array( 'from_event_index' => $i + count( $competitors ) / 2 + count( $competitors ) / 2 / 2, 'from_event_rank' => 1 )
        ) );
    }
}

if( $rounds > 3 )
{
    // subsequent rounds
    for( $i = 0; $i < $rounds - 3; $i++ )
    {
        $round_events = pow( 2, $rounds - 3 - $i );
        $total_events = count( $events );

        for( $j = 0; $j < $round_events; $j++ )
        {
            array_push( $events, array(
                array( 'from_event_index' => $j + $round_index, 'from_event_rank' => 1 ),
                array( 'from_event_index' => ++$j + $round_index, 'from_event_rank' => 1 )
            ) );
        }

        for( $j = 0; $j < $round_events; $j++ )
        {
            array_push( $events, array(
                array( 'from_event_index' => $j + $round_index + $round_events * 2, 'from_event_rank' => 1 ),
                array( 'from_event_index' => ++$j + $round_index + $round_events * 2, 'from_event_rank' => 1 )
            ) );
        }

        for( $j = 0; $j < $round_events / 2; $j++ )
        {
            array_push( $events, array(
                array( 'from_event_index' => $j + $total_events, 'from_event_rank' => 2 ),
                array( 'from_event_index' => $j + $total_events + $round_events / 2, 'from_event_rank' => 1 )
            ) );
        }

        $round_index = $total_events;
    }

}

if( $rounds > 1 )
{
    // finals
    array_push( $events, array(
        array( 'from_event_index' => count( $events ) - 3, 'from_event_rank' => 1 ),
        array( 'from_event_index' => count( $events ) - 1, 'from_event_rank' => 1 )
     ) );
}

32 ( 2) 64 , . .

+4

. , . , . : ?.

+2

Thank you for sharing this solution with us. I translated your algorithm into C #. maybe someone could use this:

using System;
using System.Collections.Generic;
using System.Linq;
using TmBackend.Entities;

namespace TmBackend.Services
{
    partial class TournamentRepository
    {
        private void GenerateDoubleEliminationMatches(Tournament tournament)
        {
            var roundsCount = Convert.ToInt32(Math.Log(tournament.Teams.Count, 2)) + 1;

            var rand = new Random();
            var shuffledTeams = tournament.Teams.OrderBy(t => rand.Next()).ToArray();

            // Round 0
            var rounds = new List<TournamentRound>
            {
                new TournamentRound
                {
                    Matches = new List<TournamentMatch>(),
                    Order = 1.0,
                    Type = TournamentRoundType.Winnerbracket,
                }
            };

            for (var i = 0; i < shuffledTeams.Length; i += 2)
            {
                rounds[0].Matches.Add(new TournamentMatch
                {
                    MatchIndex = rounds[0].Matches.Count,
                    Scores = new List<TournamentMatchScore>
                    {
                        new TournamentMatchScore
                        {
                            TournamentTeamId = shuffledTeams[i].Id
                        },
                        new TournamentMatchScore
                        {
                            TournamentTeamId = shuffledTeams[i + 1].Id
                        },
                    },
                });
            }

            var matchIndex = rounds[0].Matches.Count();
            if (roundsCount > 2)
            {
                // second round
                var winnerRound = new TournamentRound
                {
                    Matches = new List<TournamentMatch>(),
                    Order = 2,
                    Type = TournamentRoundType.Winnerbracket
                };
                rounds.Add(winnerRound);
                var loserRound = new TournamentRound
                {
                    Matches = new List<TournamentMatch>(),
                    Order = 2,
                    Type = TournamentRoundType.Loserbracket
                };
                rounds.Add(loserRound);
                var loserRound2 = new TournamentRound
                {
                    Matches = new List<TournamentMatch>(),
                    Order = 2.5,
                    Type = TournamentRoundType.Loserbracket
                };
                rounds.Add(loserRound2);

                // winner bracket
                for (var i = 0; i < shuffledTeams.Length / 2; i++)
                {
                    var m = new TournamentMatch
                    {
                        MatchIndex = matchIndex++,
                        Scores = new List<TournamentMatchScore>
                        {
                            new TournamentMatchScore
                            {
                                PreviousMatchIndex = i,
                                PreviousMatchRank = MatchRank.Winner
                            },
                            new TournamentMatchScore
                            {
                                PreviousMatchIndex = ++i,
                                PreviousMatchRank = MatchRank.Winner
                            },
                        }
                    };
                    winnerRound.Matches.Add(m);
                }

                // loser bracket 2.0
                for (var i = 0; i < shuffledTeams.Length / 2; i++)
                {
                    var m = new TournamentMatch
                    {
                        MatchIndex = matchIndex++,
                        Scores = new List<TournamentMatchScore>
                        {
                            new TournamentMatchScore
                            {
                                PreviousMatchIndex = i,
                                PreviousMatchRank = MatchRank.Loser
                            },
                            new TournamentMatchScore
                            {
                                PreviousMatchIndex = ++i,
                                PreviousMatchRank = MatchRank.Loser
                            }
                        }
                    };
                    loserRound.Matches.Add(m);
                }

                // loser bracket 2.5
                var loserRoundCount = loserRound.Matches.Count;
                for (var i = 0; i < loserRoundCount; i++)
                {
                    var m = new TournamentMatch
                    {
                        MatchIndex = matchIndex++,
                        Scores = new List<TournamentMatchScore>
                        {
                            new TournamentMatchScore
                            {
                                PreviousMatchIndex = i + shuffledTeams.Length / 2,
                                PreviousMatchRank = MatchRank.Loser
                            },
                            new TournamentMatchScore
                            {
                                PreviousMatchIndex = i + shuffledTeams.Length / 2 + shuffledTeams.Length / 2 / 2,
                                PreviousMatchRank = MatchRank.Winner
                            }
                        }
                    };
                    loserRound2.Matches.Add(m);
                }
            }


            if (roundsCount > 3)
            {
                // subsequent rounds
                for (var i = 0; i < roundsCount - 3; i++)
                {
                    var matchesCountRound = (int) Math.Pow(2, roundsCount - 3 - i);
                    var matchesCountTotalBefore = rounds.Take(rounds.Count - 3).Sum(r => r.Matches.Count);
                    var matchesCountTotal = rounds.Sum(r => r.Matches.Count);

                    var winnerRound = new TournamentRound
                    {
                        Matches = new List<TournamentMatch>(),
                        Order = 3 + i,
                        Type = TournamentRoundType.Winnerbracket
                    };
                    rounds.Add(winnerRound);
                    var loserRound = new TournamentRound
                    {
                        Matches = new List<TournamentMatch>(),
                        Order = 3 + i,
                        Type = TournamentRoundType.Loserbracket
                    };
                    rounds.Add(loserRound);
                    var loserRound2 = new TournamentRound
                    {
                        Matches = new List<TournamentMatch>(),
                        Order = 3.5 + i,
                        Type = TournamentRoundType.Loserbracket
                    };
                    rounds.Add(loserRound2);

                    // winner bracket
                    for (var j = 0; j < matchesCountRound; j++)
                    {
                        var m = new TournamentMatch
                        {
                            MatchIndex = matchIndex++,
                            Scores = new List<TournamentMatchScore>
                            {
                                new TournamentMatchScore
                                {
                                    PreviousMatchIndex = j + matchesCountTotalBefore,
                                    PreviousMatchRank = MatchRank.Winner
                                },
                                new TournamentMatchScore
                                {
                                    PreviousMatchIndex = ++j + matchesCountTotalBefore,
                                    PreviousMatchRank = MatchRank.Winner
                                },
                            }
                        };
                        winnerRound.Matches.Add(m);
                    }

                    // loser bracket X.0
                    for (var j = 0; j < matchesCountRound; j++)
                    {
                        var m = new TournamentMatch
                        {
                            MatchIndex = matchIndex++,
                            Scores = new List<TournamentMatchScore>
                            {
                                new TournamentMatchScore
                                {
                                    PreviousMatchIndex = j + matchesCountTotalBefore + matchesCountRound * 2,
                                    PreviousMatchRank = MatchRank.Winner
                                },
                                new TournamentMatchScore
                                {
                                    PreviousMatchIndex = ++j + matchesCountTotalBefore + matchesCountRound * 2,
                                    PreviousMatchRank = MatchRank.Winner
                                },
                            }
                        };
                        loserRound.Matches.Add(m);
                    }

                    // loser bracket X.5
                    for (var j = 0; j < matchesCountRound / 2; j++)
                    {
                        var m = new TournamentMatch
                        {
                            MatchIndex = matchIndex++,
                            Scores = new List<TournamentMatchScore>
                            {
                                new TournamentMatchScore
                                {
                                    PreviousMatchIndex = j + matchesCountTotal,
                                    PreviousMatchRank = MatchRank.Loser
                                },
                                new TournamentMatchScore
                                {
                                    PreviousMatchIndex = j + matchesCountTotal + matchesCountRound / 2,
                                    PreviousMatchRank = MatchRank.Winner
                                },
                            }
                        };
                        loserRound.Matches.Add(m);
                    }
                }
            }

            // finals
            if (roundsCount > 1)
            {
                var winnerRound = new TournamentRound
                {
                    Matches = new List<TournamentMatch>(),
                    Order = rounds.Count / 3 + 2,
                    Type = TournamentRoundType.Final
                };
                rounds.Add(winnerRound);

                var m = new TournamentMatch
                {
                    MatchIndex = matchIndex,
                    Scores = new List<TournamentMatchScore>
                    {
                        new TournamentMatchScore
                        {
                            PreviousMatchIndex = matchIndex - 3,
                            PreviousMatchRank = MatchRank.Winner
                        },
                        new TournamentMatchScore
                        {
                            PreviousMatchIndex = matchIndex - 1,
                            PreviousMatchRank = MatchRank.Winner
                        },
                    }
                };
                winnerRound.Matches.Add(m);
            }

            tournament.Rounds = rounds;
        }
    }
}
0
source

All Articles