### Thread: Building an automated tournament bracket chart

1. No Profile Picture
Super Moderator
Devshed Beginner (1000 - 1499 posts)

Join Date
Jun 2009
Location
Hartford, WI
Posts
1,399
Rep Power
24

#### Building an automated tournament bracket chart

Well, I am currently storing all data in a multi-dimensional array just fine.
\$array[index]['assoc']
'assoc' can be: 'round', 'white', 'black', or 'result'

Total rounds is fetched from the tournament_info table, and calculates # of players per column.
If 6 rounds, this is calculated for \$match_count: (7th column/round is simply just the "winner")
array(7) { [0]=> int(64) [1]=> int(32) [2]=> int(16) [3]=> int(8) [4]=> int(4) [5]=> int(2) [6]=> int(1) }

If someone can even help create an empty table from this info, I may be able to figure out the data insertion. I am thinking of using the calculated numbers from both directions. 0-6 will define total rows, and 6-0 will define rowspan. The part that I can't figure out is the fact that I'm not seeing a consistency in any step to simply increment something or such.

Example:
16-player tournament
array(5) { [0]=> int(16) [1]=> int(8) [2]=> int(4) [3]=> int(2) [4]=> int(1) }
The column count per row would be as follows, due to previous rowspans:
5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1

Is there a way I could maybe build this column count into an array to use as a reference in a loop? I just can't think how to make my script calculate those columns->row numbers that I manually counted in the 16-player example.

If it helps at all, my current code so far:
PHP Code:
``` <?php   error_reporting(E_ALL);   ini_set('display_errors', TRUE);   ini_set('display_startup_errors', TRUE);   include('./inc/db.inc');   function build_bracket(\$tid) {     global \$link;     \$i = 0;     \$rows = NULL;     \$round_count = \$link->prepare('SELECT rounds FROM zulutest_chess_tournaments WHERE id = ?;');     \$round_count->bind_param('i', \$tid);     \$round_count->execute();     \$round_count->bind_result(\$rounds);     \$round_count->fetch();     \$round_count->close();     \$fetch_matches = \$link->prepare('SELECT round, white, black, result FROM zulutest_chess_rounds WHERE tournament = ?;');     \$fetch_matches->bind_param('i', \$tid);     \$fetch_matches->execute();     \$fetch_matches->bind_result(\$round, \$white, \$black, \$result);     while(\$fetch_matches->fetch()) {       \$matches[\$i]['round'] = \$round;       \$matches[\$i]['white'] = \$white;       \$matches[\$i]['black'] = \$black;       \$matches[\$i]['result'] = count(explode('-', \$result)) == 1 ? array('*', '*') : explode('-', \$result);       \$i++;     }     \$fetch_matches->close();     \$i = 0;     while(\$i <= \$rounds) {       \$match_count[\$i] = 2 ** (\$rounds - \$i);       \$i++;     }     var_dump(\$match_count);     foreach(\$matches AS \$data) {       \$rows .= '      <TR><TD style="padding-top: 5px;">White: ' . \$data['white'] . "</TD></TR>\n";       \$rows .= '      <TR><TD style="padding-bottom: 5px;">Black: ' . \$data['black'] . "</TD></TR>\n";     }     return \$rows;   } ?><!DOCTYPE html> <HTML>   <HEAD>     <TITLE>Bracket Page</TITLE>   </HEAD>   <BODY>     <TABLE> <?php echo build_bracket(571); ?>     </TABLE>   </BODY> </HTML> ```
Thank you very much for any assistance!
Last edited by Triple_Nothing; February 19th, 2017 at 09:26 AM.
2. No Profile Picture
Contributing User
Devshed Specialist (4000 - 4499 posts)

Join Date
Jul 2003
Posts
4,238
Rep Power
601
Perhaps an array is the wrong approach. I'm not sure I completely understand how you want the pairings but perhaps thinking about an OOP object for each pairing and bracket might work.
3. No Profile Picture
Super Moderator
Devshed Beginner (1000 - 1499 posts)

Join Date
Jun 2009
Location
Hartford, WI
Posts
1,399
Rep Power
24
From my understanding, the client is to provide a file that will define everything to the database. As far as order and such, I am told everything will be in proper order that I could just SELECT * for each round, and that list will be in valid order as to the winners of the previous rounds.

If tables could be built column by column instead of row by row, this would be so easy... ^_^
4. No Profile Picture
Contributing User
Devshed Specialist (4000 - 4499 posts)

Join Date
Jul 2003
Posts
4,238
Rep Power
601
Would array_flip help? Then building the array by row would work, I think.
5. No Profile Picture
Super Moderator
Devshed Beginner (1000 - 1499 posts)

Join Date
Jun 2009
Location
Hartford, WI
Posts
1,399
Rep Power
24
Well, my reference of the 0-6 and 6-0 is no problem. It's more my lack of math or such to generate the array(5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1)

If I can create such an array, a loop would simply add that many columns per cycle. I do kinda see a pattern in that array, but am not sure how to get a script to dynamically create this outcome.
6. No Profile Picture
Contributing User
Devshed Specialist (4000 - 4499 posts)

Join Date
Jul 2003
Posts
4,238
Rep Power
601
I guess I don't really understand what you are asking. To me a tournament bracket means pairings and your "pattern" is not that. There really is no pattern to your array.
7. No Profile Picture
Super Moderator
Devshed Beginner (1000 - 1499 posts)

Join Date
Jun 2009
Location
Hartford, WI
Posts
1,399
Rep Power
24
Example for 16 initial teams:
Code:
```<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang='en'>
<meta http-equiv='Content-Type' content='text/html; charset=ISO-8859-1'>
<title>Page Title</title>
<!-- link rel='stylesheet' href='style.css' type='text/css' -->
<style type="text/css">
<!--
table {
border-collapse: collapse;
border: none;
font: small arial, helvetica, sans-serif;
}
td {
vertical-align: middle;
width: 10em;
margin: 0;
}
td p {
border-bottom: solid 1px black;
margin: 0;
}
-->
</style>
<body>
<table summary="Tournament Bracket">
<tr>
<td><p>1. team name</p></td>
<td rowspan="2"><p>team name</p></td>
<td rowspan="4"><p>team name</p></td>
<td rowspan="8"><p>team name</p></td>
<td rowspan="16"><p>team name</p></td>
</tr>
<tr>
<td><p>16. team name</p></td>
</tr>
<tr>
<td><p>8. team name</p></td>
<td rowspan="2"><p>team name</p></td>
</tr>
<tr>
<td><p>9. team name</p></td>
</tr>
<tr>
<td><p>5. team name</p></td>
<td rowspan="2"><p>team name</p></td>
<td rowspan="4"><p>team name</p></td>
</tr>
<tr>
<td><p>12. team name</p></td>
</tr>
<tr>
<td><p>4. team name</p></td>
<td rowspan="2"><p>team name</p></td>
</tr>
<tr>
<td><p>13. team name</p></td>
</tr>
<tr>
<td><p>6. team name</p></td>
<td rowspan="2"><p>team name</p></td>
<td rowspan="4"><p>team name</p></td>
<td rowspan="8"><p>team name</p></td>
</tr>
<tr>
<td><p>11. team name</p></td>
</tr>
<tr>
<td><p>3. team name</p></td>
<td rowspan="2"><p>team name</p></td>
</tr>
<tr>
<td><p>14. team name</p></td>
</tr>
<tr>
<td><p>7. team name</p></td>
<td rowspan="2"><p>team name</p></td>
<td rowspan="4"><p>team name</p></td>
</tr>
<tr>
<td><p>10. team name</p></td>
</tr>
<tr>
<td><p>2. team name</p></td>
<td rowspan="2"><p>team name</p></td>
</tr>
<tr>
<td><p>15. team name</p></td>
</tr>
</table>
</body>
</html>```
(Example code from: creating tournament brackets?)

Maybe to offer a better visual from the example, maybe define a border for all sides, instead of just the few currently defined.

The "pattern" I am trying to generate would be to define how many cells/columns are in that row. The very first will have the most, define all columns and initial rowspans. The 2nd row will only consist of 1 cell/column since the previous row for column 2+ spans 2+ rows. The 3rd row will be the 1st cell/column AND the 2nd, defining rowspan as 2 for the 2nd column, which puts us back at only 1 cell/column for the next row...
Last edited by Triple_Nothing; February 21st, 2017 at 09:18 AM.
8. No Profile Picture
Contributing User
Devshed Specialist (4000 - 4499 posts)

Join Date
Jul 2003
Posts
4,238
Rep Power
601
That is what I expected it to look like but that does not match what your array contains. The calculations for the number of rows are easy. For first column the rows are total teams/2. The 2nd is total teams/4 and the 3rd is total teams/8, etc. In other words the denominator will be 2 raised to the power of the column number. You will need to determine how to handle the case where there is an odd number of teams. Probably create a team named 'Bye' and pair it with the top seed.
Last edited by gw1500se; February 21st, 2017 at 02:10 PM.
9. No Profile Picture
Super Moderator
Devshed Beginner (1000 - 1499 posts)

Join Date
Jun 2009
Location
Hartford, WI
Posts
1,399
Rep Power
24
Ya, the overall row count for a column is easy. That's rows for columns. I need to figure out columns for rows.

Like, if you look at the 16-team example horizontally, 1 row at a time, and count the cells STARTING in that 1 row, that's where the following array would come into place.
array(5, 1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1)

Each step of that array tells how many cells start in that row. Then the 0-6/6-0 will be used within that loop's process to define rowspan and such.

Row 1 defines 5 cells.
Row 2 defines 1 cell since remaining 4 are claimed via prior rowspans.
Row 3 defines 2 cells, 1st/2nd column, w/ a rowspan of 2 on 2nd column.
Row 3 defines 1 cell since previous row claimed 2nd column due to rowspan, and 1st row's rowspan's are still claiming the rest.
...

I know every other will only define 1 cell, since 1st column defines 2 cells per match, then the 2nd column will be rowspan'ed 2 for the winner.

Only the 1st row will define the last column, since its rowspan claims all, and the rowspan for the prior column will be defined in 1st row, and half-way through, which is where that "4" is in the example array.

EDIT:
I just edited the border definitions to offer a better visual to hopefully help my explanations...
Code:
```<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang='en'>
<meta http-equiv='Content-Type' content='text/html; charset=ISO-8859-1'>
<title>Page Title</title>
<!-- link rel='stylesheet' href='style.css' type='text/css' -->
<style type="text/css">
<!--
table {
font: small arial, helvetica, sans-serif;
}
td {
border: solid 1px black;
vertical-align: middle;
width: 10em;
margin: 0;
}
td p {
margin: 0;
}
-->
</style>
<body>
<table summary="Tournament Bracket">
<tr>
<td><p>5 columns defined</p></td>
<td rowspan="2"><p>team name</p></td>
<td rowspan="4"><p>team name</p></td>
<td rowspan="8"><p>team name</p></td>
<td rowspan="16"><p>team name</p></td>
</tr>
<tr>
<td><p>1 column defined</p></td>
</tr>
<tr>
<td><p>2 columns defined</p></td>
<td rowspan="2"><p>team name</p></td>
</tr>
<tr>
<td><p>1 column defined</p></td>
</tr>
<tr>
<td><p>3 columns defined</p></td>
<td rowspan="2"><p>team name</p></td>
<td rowspan="4"><p>team name</p></td>
</tr>
<tr>
<td><p>1 column defined</p></td>
</tr>
<tr>
<td><p>2 columns defined</p></td>
<td rowspan="2"><p>team name</p></td>
</tr>
<tr>
<td><p>1 column defined</p></td>
</tr>
<tr>
<td><p>4 columns defined</p></td>
<td rowspan="2"><p>team name</p></td>
<td rowspan="4"><p>team name</p></td>
<td rowspan="8"><p>team name</p></td>
</tr>
<tr>
<td><p>1 column defined</p></td>
</tr>
<tr>
<td><p>2 columns defined</p></td>
<td rowspan="2"><p>team name</p></td>
</tr>
<tr>
<td><p>1 column defined</p></td>
</tr>
<tr>
<td><p>3 columns defined</p></td>
<td rowspan="2"><p>team name</p></td>
<td rowspan="4"><p>team name</p></td>
</tr>
<tr>
<td><p>1 column defined</p></td>
</tr>
<tr>
<td><p>2 columns defined</p></td>
<td rowspan="2"><p>team name</p></td>
</tr>
<tr>
<td><p>1 column defined</p></td>
</tr>
</table>
</body>
</html>```
Edit2: I edited the wording in the first column to explain/match the values in the array.
Last edited by Triple_Nothing; February 22nd, 2017 at 07:12 AM.
10. No Profile Picture
Contributing User
Devshed Specialist (4000 - 4499 posts)

Join Date
Jul 2003
Posts
4,238
Rep Power
601
I think the array itself is what is over complicating the problem. If the query returns the correct pairings, it is not clear why you create that particular array. Once you have the total number of teams you can create the array using the pairings in column order then generate the table easily from that. The first array is the initial pairings, the 2nd inner array is the winner bracket spanning 2
rows the 3rd inner array is the quarter finals spanning 4 rows, etc.

array(array(array(1,16),array(2,15),array(3,14),...),array(array(winner,winner),...)...)
11. No Profile Picture
Super Moderator
Devshed Beginner (1000 - 1499 posts)

Join Date
Jun 2009
Location
Hartford, WI
Posts
1,399
Rep Power
24
I think you might just be thinking in a vertical manner, which is easy to figure out. The problem is tables are build horizontally. I finally figured out a basic loop to create the desired array. I mentioned even building an empty table may be enough for me since the tournaments being posted may only be part way through, but he still wants the remaining blank chart to show, which I would then have no count for via database info.

(Updated)
You can view the following code live at: Building an automated tournament bracket chart
PHP Code:
``` <?php   function create_rowspan(\$players) {     for(\$i = 0, \$rs = 1; \$rs <= \$players; \$i++, \$rs = \$rs * 2) {       \$rowspan[\$i] = \$rs;     }     return \$rowspan;   }   function create_col_array(\$players) {     \$col_init = array(NULL);     for(\$c = 1; \$c < \$players; \$c = \$c * 2) {       for(\$i = 0; \$i < \$players; \$i = \$i + \$c) {         \$col_init[\$i] = !isset(\$col_init[\$i]) ? 1 : \$col_init[\$i] + 1;       }     }     \$col_init[0]++;     return \$col_init;   } ?><!DOCTYPE HTML> <HTML>   <HEAD>     <TITLE>Building an automated tournament bracket chart</TITLE>   </HEAD>   <BODY>     function create_col_array(16) :<BR /><PRE><?php print_r(create_col_array(16)); ?></PRE>     function create_rowspan(16) :<BR /><PRE><?php print_r(create_rowspan(16)); ?></PRE>     Rounds: count(create_rowspan(16)) - 1 : <?php echo count(create_rowspan(16)) - 1; ?><BR />(sqrt() was also another consideration, esp. if Bye's come into play)   </BODY> </HTML> ```
The inner for() simply does the "Add 1 to.." or "Set 1 if not-set..." which the outter starts the increment 1 by 1, setting the initial, then doubling the index steps each time through, spacing the "Add 1" out correctly.

Edit: Optional side question... I am allowed to use ++ for \$col_init[0]++, but MUST use + 1 instead in the following... Why?
PHP Code:
``` \$col_init[\$i] = !isset(\$col_init[\$i]) ? 1 : \$col_init[\$i] + 1;  ```
Last edited by Triple_Nothing; February 22nd, 2017 at 09:40 AM.
12. No Profile Picture
Contributing User
Devshed Specialist (4000 - 4499 posts)

Join Date
Jul 2003
Posts
4,238
Rep Power
601
The point is that once the array is built vertically, you can generate the table from it horizontally.

As for the side question, dunno. It will take someone more familiar with the internals of PHP than me to answer that. I would have thought that should work.
13. No Profile Picture
Super Moderator
Devshed Beginner (1000 - 1499 posts)

Join Date
Jun 2009
Location
Hartford, WI
Posts
1,399
Rep Power
24
Just for an example in relation to your vertical array, could you build such using just perhaps the index # as the team/player name and generate me a chart in that manner?

My mind is only seeing building the table row by row, which would work horizontally, and not technically build it round-by-round(vertically).

Final outcome...

Overall script: (Live at: Building an automated tournament bracket chart)
PHP Code:
``` <?php   function create_rowspan(\$players) {     for(\$i = 0, \$rs = 1; \$rs <= \$players; \$i++, \$rs = \$rs * 2) {       \$rowspan[\$i] = \$rs;     }     return \$rowspan;   }   function create_col_array(\$players) {     \$col_init = array(NULL);     for(\$c = 1; \$c < \$players; \$c = \$c * 2) {       for(\$i = 0; \$i < \$players; \$i = \$i + \$c) {         \$col_init[\$i] = !isset(\$col_init[\$i]) ? 1 : \$col_init[\$i] + 1;       }     }     \$col_init[0]++;     return \$col_init;   }   function build_chart(\$players) {     \$col_to_define = create_col_array(\$players);     \$rowspan = create_rowspan(\$players);     \$i = 0;     \$rows = array(NULL);     foreach(\$col_to_define AS \$col_count) {       \$rows[\$i] = '      <TR>';       for(\$col = 1; \$col <= \$col_count; \$col++) {         \$rows[\$i] .= '<TD rowspan="' . \$rowspan[\$col - 1] . '">Round ' . \$col . ' - Rowspan ' . \$rowspan[\$col - 1] . '</TD>';       }       \$rows[\$i] .= "</TR>\n";       \$i++;     }     return \$rows;   } ?><!DOCTYPE HTML> <HTML>   <HEAD>     <TITLE>Building an automated tournament bracket chart</TITLE>     <STYLE type="text/css">td { border: solid 1px black; width: 200px; }</STYLE>   </HEAD>   <BODY>     function create_col_array(16) :<BR /><PRE><?php print_r(create_col_array(16)); ?></PRE>     function create_rowspan(16) :<BR /><PRE><?php print_r(create_rowspan(16)); ?></PRE>     <TABLE> <?php foreach(build_chart(16) AS \$row) echo \$row; ?>     </TABLE>   </BODY> </HTML> ```
The basic functions needed:
PHP Code:
``` function create_rowspan(\$players) {   for(\$i = 0, \$rs = 1; \$rs <= \$players; \$i++, \$rs = \$rs * 2) {     \$rowspan[\$i] = \$rs;   }   return \$rowspan; } function create_col_array(\$players) {   \$col_init = array(NULL);   for(\$c = 1; \$c < \$players; \$c = \$c * 2) {     for(\$i = 0; \$i < \$players; \$i = \$i + \$c) {       \$col_init[\$i] = !isset(\$col_init[\$i]) ? 1 : \$col_init[\$i] + 1;     }   }   \$col_init[0]++;   return \$col_init; } function build_chart(\$players) {   \$col_to_define = create_col_array(\$players);   \$rowspan = create_rowspan(\$players);   \$i = 0;   \$rows = array(NULL);   foreach(\$col_to_define AS \$col_count) {     \$rows[\$i] = '      <TR>';     for(\$col = 1; \$col <= \$col_count; \$col++) {       \$rows[\$i] .= '<TD rowspan="' . \$rowspan[\$col - 1] . '">Round ' . \$col . ' - Rowspan ' . \$rowspan[\$col - 1] . '</TD>';     }     \$rows[\$i] .= "</TR>\n";     \$i++;   }   return \$rows; }  ```
Usage: (16 = example player count)
PHP Code:
```     <TABLE> <?php foreach(build_chart(16) AS \$row) echo \$row; ?>     </TABLE> ```
Last edited by Triple_Nothing; February 22nd, 2017 at 11:54 AM.
14. No Profile Picture
Contributing User
Devshed Specialist (4000 - 4499 posts)

Join Date
Jul 2003
Posts
4,238
Rep Power
601
I won't have time today but I'll see what I can come up with when I get a chance, if you don't solve it in the meantime.
15. No Profile Picture
Super Moderator
Devshed Beginner (1000 - 1499 posts)

Join Date
Jun 2009
Location
Hartford, WI
Posts
1,399
Rep Power
24
That final post/example actually builds the whole thing. The only thing to be added is the DB info which would just be referenced/inserted during the loop that currently builds that cell and enters the example's text.

I guess one other thing that may come into play, but I've no clue how it's really going to exist in the first place, is the tournament "Bye's" for non-squared counts. Many do it the initial round, some don't. So, once I get word on details to that, that will be the next thing to figure in.