5

I'm running through a great old brain fart currently and am stuck dynamically selecting the next "round match" that the winners of the below rounds will advance to:

generated ladder


The ladder above is dynamically generated, and what I'd like to do is figure out the next match ID. I've got this as a POC currently, but it isn't sustainable if a competition ladder were to run up to 64/more:

$ar = [
 1 => [
     ['id' => 1,'name' => 'round1, pair 1'],
     ['id' => 2,'name' => 'round1, pair 2'],
     ['id' => 3,'name' => 'round1, pair 3'],
     ['id' => 4,'name' => 'round1, pair 4'],
 ],
 2 => [
     ['id' => 5,'name' => 'round2, pair 1'],
     ['id' => 6,'name' => 'round2, pair 2'],
 ]
];

$cases = [0, 0, 1, 1, 2, 2];

foreach($ar as $i => $round) {

    foreach($round as $_i => $r) {
        echo $r['name'] . " & NEXT_MATCH_ID::> " . $ar[($i + 1)][$cases[$_i]]['id'] . "<br /> ";
    }
}

Is there a more simplified way of achieving what the above without hard-coded variables ($cases) for example.

Essentially the amount of "matches/pairs" are being halved as a ladder would be: 4 -> 2 -> 1.

The above generates the correct ID's but it isn't expandable or dynamic;

round1, pair 1 & NEXT_MATCH_ID::> 5
round1, pair 2 & NEXT_MATCH_ID::> 5
round1, pair 3 & NEXT_MATCH_ID::> 6
round1, pair 4 & NEXT_MATCH_ID::> 6
round2, pair 1 & NEXT_MATCH_ID::> ...
round2, pair 2 & NEXT_MATCH_ID::> ...
//......etc etc...

Demo/ Example of the above code if required.


Notes

  • There is no limit on "players/team" matches and this can be exponential, 4, 6, 8, 10, 12, 14, 16, 18....32, 34...64...etc.
  • This will never happen/apply to the last round (Grand Final - 1 match) as there is no further round to advance to. (easily limited by if($i == count($rounds)) {.... do not continue...).
  • There is a possibility of multiple matches being run simultaneously, so the "next round ID" could not be lastId + 1.
Darren
  • 13,050
  • 4
  • 41
  • 79
  • 1
    Next match id can be calculated from round's last id and current pair index: `$nextId = $roundLastId + 1 + (int) floor($pairIndex/2);`. Btw. Number of pairs need to be (filled up to) the power of 2 (2,4,8,16...). – shudder Feb 15 '17 at 12:55
  • @shudder That'd almost be correct! but there could be multiple matches running with various different ID's as the "next round ID", hence the POC I went through :P – Darren Feb 15 '17 at 23:52
  • In this case you can't figure out next match id with algorithm, because it's not deterministic. You need to solve it on data level first. Having `next_match` field inside pair, using common ladder/round id (so you could calculate match id within same ladder/round) or if you're not dealing with relational database then going directly into tree structure might also work. – shudder Feb 16 '17 at 01:04

1 Answers1

1

Just math

Keep in mind, that every round contains pow(2, Rounds - Round + 1) of teams and pow(2, Rounds - Round) of matches. Just sum it as a geometric progression.

Number of matches taken before round $round is a geometric progression 2^(rounds-1) + 2^(rounds-2) + ... 2^(rounds - round + 1) with a=2^(rounds-1), r=1/2, n=round-1. Its sum is 2^(rounds) - 2^(rounds+1-round).

So match id and next match id are just functions of three arguments: pairnum, round, rounds. I moved its calculations into functions getMatchId and getNextId.

Example

<?php
// just matchesInPreviousRounds + parnum
function getMatchId($pairnum, $round, $rounds) {
    // matchesInPreviousRounds - is a sum of a geometric progression  
    // 2^(rounds-1) + 2^(rounds-2) + ... 2^(rounds - round + 1) 
    // with a=2^(rounds-1), r=1/2, n = round-1
    // its sum is 2^(rounds) - 2^(rounds+1-round)
    $inPreviousRounds = $round > 1 ?  (pow(2, $rounds) - pow(2, $rounds + 1 - $round)) : 0;

    $id = $inPreviousRounds + $pairnum;

    return (int)$id;
}

// next id is last id of a round + half a pairnum.
function getNextId($pairnum, $round, $rounds) {
    if($round === $rounds) {
        return false;
    }

    $matchesInThisAndPreviousRounds = pow(2, $rounds) - pow(2, $rounds - $round);

    $nextid = $matchesInThisAndPreviousRounds + ceil($pairnum / 2);

    return (int)$nextid;
}

$divide = 64; // for 1/64 at the start
$power = round(log($divide) / log(2)); // get 6 for 64
$rounds = (int) $power + 1;


for($round = 1; $round <= $rounds; $round++) {
    // every round contains 2^($rounds - $round + 1) of teams 
    // and has 2^($rounds - $round) of matches
    $teamsLeft = pow(2, $rounds - $round + 1);
    $pairsLeft = pow(2, $rounds - $round);


    for($pairnum = 1; $pairnum <= $pairsLeft; $pairnum++) {
        $id = getMatchId($pairnum, $round, $rounds);
        $nextid = getNextId($pairnum, $round, $rounds);

        echo "Round $round, pair $pairnum, id $id ";
        echo "winner goes to " . $nextid ? $nextid : "A BAR" . "\n";
    }
}

Its results

Round 1, pair 1, id 1, winner goes to 65
Round 1, pair 2, id 2, winner goes to 65
...
Round 1, pair 62, id 62, winner goes to 95
Round 1, pair 63, id 63, winner goes to 96
Round 1, pair 64, id 64, winner goes to 96
Round 2, pair 1, id 65, winner goes to 97
Round 2, pair 2, id 66, winner goes to 97
...
Round 2, pair 29, id 93, winner goes to 111
Round 2, pair 30, id 94, winner goes to 111
Round 2, pair 31, id 95, winner goes to 112
Round 2, pair 32, id 96, winner goes to 112
Round 3, pair 1, id 97, winner goes to 113
Round 3, pair 2, id 98, winner goes to 113
...
Round 3, pair 13, id 109, winner goes to 119
Round 3, pair 14, id 110, winner goes to 119
Round 3, pair 15, id 111, winner goes to 120
Round 3, pair 16, id 112, winner goes to 120
Round 4, pair 1, id 113, winner goes to 121
Round 4, pair 2, id 114, winner goes to 121
...
Round 4, pair 7, id 119, winner goes to 124
Round 4, pair 8, id 120, winner goes to 124
Round 5, pair 1, id 121, winner goes to 125
Round 5, pair 2, id 122, winner goes to 125
Round 5, pair 3, id 123, winner goes to 126
Round 5, pair 4, id 124, winner goes to 126
Round 6, pair 1, id 125, winner goes to 127
Round 6, pair 2, id 126, winner goes to 127
Round 7, pair 1, id 127, winner goes to A BAR
shukshin.ivan
  • 11,075
  • 4
  • 53
  • 69