2

I've looked through several other posts similar to this but can't find anything that suits what I'm looking for...

I've managed to hard code an 8 team tournament brackets table but I really want a way for the table to be drawn up using for/if statements based on the number of teams that are inputted.

Here's the code for hard coding the table using colspans and rowspans to create the blank spaces (and before you say use CSS instead of tables, I don't know CSS that well but am confident with tables):

<table border='1' cellspacing='1' cellpadding='1'>
<tr><td colspan='2' width='120'><b>Round 1</b></td></td><td colspan='2' width='120'><b>Round 2</b></td></td><td colspan='2' width='120'><b>Final</b></td><td width='120'><b>Winner</b></td></tr>
<tr><td colspan='2'>&nbsp;</td><td colspan='2' rowspan='2'></td><td colspan='2' rowspan='4'></td><td rowspan='8'></td></tr>
<tr><td>Group 1</td><td width='20'></td></tr>
<tr><td align='center'>Score 1</td><td></td><td>Round 1 Winner</td><td width='20'></td></tr>
<tr><td>Group 2</td><td></td><td rowspan='3' align='center'>Score 5</td><td></td></tr>
<tr><td colspan='2'></td><td></td><td>Round 2 Winner</td><td width='20'></td></tr>
<tr><td>Group 3</td><td></td><td></td><td rowspan='7' align='center'>Score 7</td><td></td></tr>
<tr><td align='center'>Score 2</td><td></td><td>Round 1 Winner<td></td><td></td></tr>
<tr><td>Group 4</td><td></td><td colspan='2' rowspan='3'></td><td></td></tr>
<tr><td colspan='2'></td><td></td><td>Champion</td></tr>
<tr><td>Group 5</td><td></td><td></td><td rowspan='8'></td></tr>
<tr><td align='center'>Score 3</td><td></td><td>Round 1 Winner</td><td></td><td></td></tr>
<tr><td>Group 6</td><td></td><td rowspan='3' align='center'>Score 6</td><td></td><td></td></tr>
<tr><td colspan='2'></td><td></td><td>Round 2 Winner</td><td></td></tr>
<tr><td>Group 7</td><td></td><td></td><td colspan='2' rowspan='3'></td></tr>
<tr><td align='center'>Score 4</td><td></td><td>Round 1 Winner</td><td></td></tr>
<tr><td>Group 8</td><td></td><td colspan='2'></td></tr>
</table>

This is what it produces:

Image1

And here's my attempt so far to create the above using for and if statements, I've got to the point where it lists the team names in the first column but I can't work out what I need to do from this point...

<?php
echo "<table border='1' cellspacing='1' cellpadding='1'>";
$num_teams = 8;
$nRounds = floor(log($num_teams,2));
$max_rows = $num_teams*2;
for ($row = 0; $row <= $max_rows; $row++)
{
    echo "<tr>";
    if ($row == 0)
    {
        for ($i = 1; $i <= $nRounds+1; $i++)
        {
            if($i < $nRounds)
            {
                echo "<td width='120'><b>Round ".$i."</b></td>";
                echo "<td width='20'></td>";
            }
            elseif($i == $nRounds)
            {
                echo "<td width='120'><b>Final</b></td>";
                echo "<td width='20'></td>";
            }
            else
            {
                echo "<td width='120'><b>Winner</b></td>";
            }
        }       
    }
    elseif($row == 1)
    {
        $rowwhitespace = ($nRounds*2)+1;
        echo "<td colspan='".$rowwhitespace."'>&nbsp;</td>";
    }
    else
    {
        $rowwhitespace = ($nRounds*2);
        for ($i = 1; $i <= $num_teams; $i++)
        {
            if($i == $row/2)
            {
                echo "<td>Group ".$i."</td>";
                echo "<td colspan='".$rowwhitespace."'></td>";
            }
        }
    }
    echo "</tr>";
}
echo "</table>";
?>

And here's what that looks like:

Image2

Ultimately the team names, scores and winners will be pulled from a DB so will need to incorporate that once I can get the structure laid out correctly.

I'd also like this to be scalable to 64 teams and to automatically draw the table based on that many teams without using manually hard code tables as this will takes ages to create tables for 16,32 and 64 teams. Coupled with considering double elimination for up to 64 teams which will make manually coding this a massive job!

Any pointers or assistance with this would be massively appreciated!

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
pmgrace
  • 121
  • 1
  • 2
  • 9

2 Answers2

5

EDIT:

Alright I decided to tackle this problem a little before 2AM in the morning. Took roughly half an hour to debug. I know I don't have more spanning but I don't want to spend anymore time trying to do that as it's more tweaking of the mathematical formulas to get those correctly. Screenshots follow. Let me know if you need explanation on anything.

<?php

function is_player($round, $row, $team) {
    return $row == pow(2, $round-1) + 1 + pow(2, $round)*($team - 1);
}

$num_teams = 16;
$total_rounds = floor(log($num_teams, 2)) + 1;
$max_rows = $num_teams*2;
$team_array = array();
$unpaired_array = array();
$score_array = array();

for ($round = 1; $round <= $total_rounds; $round++) {
    $team_array[$round] = 1;
    $unpaired_array[$round] = False;
    $score_array[$round] = False;
}


echo "<table border=\"1\" cellspacing=\"1\" cellpadding=\"1\">\n";
echo "\t<tr>\n";

for ($round = 1; $round <= $total_rounds; $round++) {

    echo "\t\t<td colspan=\"2\"><strong>Round $round</strong></td>\n";

}

echo "\t</tr>\n";

for ($row = 1; $row <= $max_rows; $row++) {

    echo "\t<tr>\n";

    for ($round = 1; $round <= $total_rounds; $round++) {
        $score_size = pow(2, $round)-1;
        if (is_player($round, $row, $team_array[$round])) {
            $unpaired_array[$round] = !$unpaired_array[$round];
            echo "\t\t<td>Team</td>\n";
            echo "\t\t<td width=\"20\">&nbsp;</td>\n";
            $team_array[$round]++;
            $score_array[$round] = False;
        } else {
            if ($unpaired_array[$round] && $round != $total_rounds) {
                if (!$score_array[$round]) {
                    echo "\t\t<td rowspan=\"$score_size\">Score</td>\n";
                    echo "\t\t<td rowspan=\"$score_size\" width=\"20\">$round</td>\n";
                    $score_array[$round] = !$score_array[$round];
                }
            } else {
                echo "\t\t<td colspan=\"2\">&nbsp;</td>\n";
            }
        }

    }

    echo "\t</tr>\n";

}

echo "</table>\n";

?>

8 Teams

16 Teams

Cheers


Original: I don't have time to write up a script but mathematically speaking it should work to follow some sort of pattern. If you assume the teams are always a power of 2 (so you can always have a champion) and 4 rows in the beginning to start off the first round so you have

1| Empty Row
2| Team 1
3|    Score
4| Team 2

Then we can mathematically make the following:

Let $round be the round number and $row be the row number and $team be the team number in the round (will explain in a bit).

Teams are printed on $row = [2^($round-1) + 1] + [2^($round)]*$team to understand this formula you'll need to draw it out, but basically because the teams are powers of 2 and you use 4 rows (power of 2) to represent each "game" in the first round, we can continuously split things down and mathematically solve for the row # where teams are printed. So the formula states that for team numbered $team in round $round will be listed in row $row The number of teams is always divided by 2 since half the teams are eliminated. Total number of rounds is just base 2 log of total teams as you've done in your code. Next scores are posted in between ever pair of teams so that isn't too bad to determine.

The biggest issue of course is the fact that you need to print a table which requires going by row rather than column when printing it out. The best way is to have a target formula and you test whether the row and column you are at satisfies the equation which just requires a simple function to test (as you go across generating the total number of columns which you know since you know how many rounds).

I hope this helps lead you to the goal that I am trying to setup. I will try to make something later if I get the time. Cheers.

richardhsu
  • 878
  • 5
  • 13
  • what do the square brackets do in that equation for $row? – pmgrace Jun 08 '12 at 19:38
  • Sorry I wrote it more like an equation, in a code language, I guess it'd mess things up but it was just to emphasize the different parts logically. Really you can just have () sorry for any confusion it created. – richardhsu Jun 08 '12 at 19:39
  • Ok, using that formula (replacing the square brackets with normal parenthesis) does not give the correct row numbers, EG: If Round = 1 and Team = 1, the row number comes back as 4 when it should be 2. Assuming that the row starts as zero and then a gap row. – pmgrace Jun 08 '12 at 19:40
  • Oh yeah, erp sorry about that, I was offsetting things quickly it should be $row = (2^($round-1) + 1) + (2^($round))*($team - 1) – richardhsu Jun 08 '12 at 19:43
  • ok, thats great, this now works perfectly to output the correct row across all rounds for where the team name should be output to, including the winner. Just need to develop this in to drawing the table out now. – pmgrace Jun 08 '12 at 19:48
  • I edited it this morning. Don't know if it notifies but hopefully you'll see it :) As it has some code that generates a table :D – richardhsu Jun 09 '12 at 19:52
  • Excellent, I'll have a play around with this... the editing didn't notify but your comment did. The rowspans are fine as they are anyway, the key spanning was in between the team names of each match. The plan would be to use an image to show the progression from each match to the winner of that match, so where you have a cell next to each team name and also a number in a cell, they will have some images in them, something that would look like an } symbol. I'm impressed you put this together so fast it's taken me days of looking at to try and figure out some sort of equation that would do it. – pmgrace Jun 09 '12 at 21:49
  • Well I'm glad to help you get to your goals for your project. Cheers :) – richardhsu Jun 10 '12 at 00:06
  • thanks for your help on this richardhsu, I've tweaked a couple of area's to fit exactly how I want it and got the images added and it looks perfect now. Now to work on getting the team names and scores etc added to this table layout! – pmgrace Jun 10 '12 at 15:03
  • No problem and again glad it helped you :) Good luck with the rest of your project :D – richardhsu Jun 11 '12 at 17:51
1

the fastest and easiest way is, save your manually coded html into some kind of template file. Let say, tournament-table.html.

Next, change every instance of what would be dynamic data in saved template file into template tags, eg:

  • Group 1 => {#group1-name}
  • Group 2 => {#group2-name}
  • Score 1 => {#score1-name}
  • Champion => {#champion-name}

Your template would look something like this:

<tr><td>{#group1-name}</td><td width='20'></td></tr>
<tr><td align='center'>{#score1-name}</td><td></td><td>{#round1-winner}</td><td width='20'></td></tr>

Next, to fill in the data, you will just have to load template into variable and do string replacements into it:

  • To load data, you do something like this:

    $raw_template = file_get_contents('/path/to/your/template/tournament-table.html');
    
  • Fill in the needed data into variables:

    //do the needed queries
    //after that, fill variable with query and processes result
    $group1_name = "Group 1";
    $group2_name = "Group 2";
    $Score1_name = "Score 1";
    
  • Next step is perform string replacement:

    $raw_template = str_replace('{#group1-name}', $group1_name, $raw_template, 1);
    
  • Finally, echo the result:

    echo $raw_template;
    
ariefbayu
  • 21,849
  • 12
  • 71
  • 92
  • Interesting method, would mean having to manually create tables for larger number of teams but still a possibility. – pmgrace Jun 08 '12 at 16:52