File Coverage

blib/lib/HTML/TableBracket.pm
Criterion Covered Total %
statement 6 201 2.9
branch 0 50 0.0
condition 0 12 0.0
subroutine 2 8 25.0
pod 0 6 0.0
total 8 277 2.8


line stmt bran cond sub pod time code
1             package HTML::TableBracket;
2              
3             $HTML::TableBracket::VERSION = '0.11';
4              
5 1     1   6451 use strict;
  1         2  
  1         46  
6 1     1   903 use POSIX qw(ceil floor);
  1         6924  
  1         9  
7              
8             =head1 NAME
9              
10             HTML::TableBracket - Tournament Table Bracket Generator
11              
12             =head1 SYNOPSIS
13              
14             use HTML::TableBracket;
15              
16             # Create the Bracket, list of names in seeded order
17             $temp=HTML::TableBracket->new("Jeek", "Tom", "Dick", "Harry",
18             "Larry", "Curly", "Moe");
19              
20             # Process the matches (TEAM1 => SCORE1, TEAM2 => SCORE2)
21             $temp->match(Larry => 10, Harry => 20);
22             $temp->match(Jeek => 10, Harry => 20);
23             $temp->match(Dick => 20, Curly => 21);
24             $temp->match(Moe => 10, Tom => 20);
25              
26             # For matches that don't have a score, such as chess matches,
27             # Use the round method. (WINNER,LOSER)
28             $temp->round("Tom","Curly");
29              
30             # Display the table in HTML format
31             print $temp->as_html;
32              
33             # Display the table in XHTML format
34             print $temp->as_xhtml;
35              
36             # Display the table in .dot format (name of graph as argument)
37             print $temp->as_directed_graph_source("Tournament");
38              
39             # Display the table as a directed graph (name of graph as argument)
40             print $temp->as_directed_graph("Tournament")->as_png;
41              
42              
43             =head1 DESCRIPTION
44              
45             This module generates a tournament bracket drawing for standard
46             single-elimination-style matchups.
47              
48             =cut
49              
50             #my (%element, $lastelement, @person, $numofpeople);
51              
52             sub new {
53 0     0 0   my $class = shift;
54 0           my (%element, $lastelement, @person, $j);
55 0           my $numofpeople = 0;
56              
57 0           foreach my $name (@_) {
58 0           $person[++$numofpeople] = "$numofpeople $name";
59             }
60              
61 0           for ($j = 2; $j < 2 * (2 ** ceil(log($numofpeople) / log(2))); $j++) {
62 0           $element{$j} = 0;
63             }
64              
65 0           my $row = 0;
66 0           $element{1} = 1;
67              
68 0           for ($j = 2; $j <= $numofpeople;) {
69 0           my $maxrankincurrentrow = 0;
70 0           my $maxrankaddress = 0;
71              
72 0           for (my $k = (2 ** $row) / 2; $k < (2 ** $row); $k++) {
73 0 0         $k = 1 if ($k < 1);
74              
75 0 0         if ($element{$k}>$maxrankincurrentrow) {
76 0           $maxrankincurrentrow=$element{$k}; $maxrankaddress=$k;
  0            
77             }
78             }
79              
80 0 0         if ($maxrankincurrentrow == 0) {
81 0           $row++;
82             } else {
83 0 0         if (($maxrankaddress / 2) == (ceil($maxrankaddress / 2))) {
84 0 0         if (($maxrankaddress / 4) != (floor($maxrankaddress / 4))) {
85 0           $element{$maxrankaddress * 2} = $maxrankincurrentrow;
86 0           $element{($maxrankaddress * 2) + 1} = $j;
87             } else {
88 0 0         if ($maxrankaddress == 2) {
89 0           $element{4} = $j;
90 0           $element{5} = $maxrankincurrentrow;
91             } else {
92 0           $element{$maxrankaddress * 2} = $maxrankincurrentrow;
93 0           $element{($maxrankaddress * 2) + 1} = $j;
94             }
95             }
96             } else {
97 0 0         if (($maxrankaddress / 4) == (floor($maxrankaddress / 4))) {
98 0           $element{$maxrankaddress * 2} = $maxrankincurrentrow;
99 0           $element{($maxrankaddress * 2) + 1} = $j;
100             } else {
101 0           $element{$maxrankaddress * 2} = $j;
102 0           $element{($maxrankaddress * 2) + 1} = $maxrankincurrentrow;
103             }
104             }
105              
106 0           $element{$maxrankaddress} = -1;
107 0           $j++;
108             }
109             }
110              
111 0           return bless({
112             ELEMENT => \%element,
113             NUMOFPEOPLE => $numofpeople,
114             LASTELEMENT => $numofpeople,
115             PERSON => \@person,
116             }, $class);
117             }
118              
119             sub match {
120 0     0 0   my ($self, $teamname1, $score1, $teamname2, $score2) = @_;
121 0           my (%element, $lastelement, @person, $numofpeople);
122 0           my ($team1, $team2, $x) = (0, 0, 0);
123              
124 0           $numofpeople = $self->{NUMOFPEOPLE};
125 0           @person = @{$self->{PERSON}};
  0            
126 0           %element = %{$self->{ELEMENT}};
  0            
127 0           $lastelement = $self->{LASTELEMENT};
128              
129 0           while ($team1 == 0) {
130 0           $_ = $person[++$x];
131 0 0 0       $team1 = $x if (/\d+ (.*)/ and ($1 eq $teamname1));
132 0 0         die "Invalid Team 1" if ($team1 > $lastelement);
133             }
134              
135 0           $x = 0;
136              
137 0           while ($team2 == 0) {
138 0           $_ = $person[++$x];
139 0 0 0       $team2 = $x if (/\d+ (.*)/ and ($1 eq $teamname2));
140 0 0         die "Invalid Team 2" if ($team2 > $lastelement);
141             }
142              
143 0           my $i = 2;
144              
145 0           while ($team2 != $element{(0 - (2 * (($i % 2)- .5)) + $i)}) {
146 0           $i++ while ($element{$i} != $team1);
147             }
148              
149 0 0         if ($score1 > $score2) {
150 0           $element{floor($i / 2)} = $team1;
151 0           $person[$lastelement + 1] = "";
152 0           $x++;
153 0           $person[$lastelement + 2] = "";
154 0           $person[++$lastelement] .= "$person[$team1] ($score1)";
155 0           $element{$i} = $lastelement;
156 0           $person[++$lastelement] .= "$person[$team2] ($score2)";
157             } else {
158 0           $element{floor($i / 2)} = $team2;
159 0           $person[$lastelement + 1] ="";
160 0           $person[$lastelement + 2] ="";
161 0           $person[++$lastelement] .= "$person[$team1] ($score1)";
162 0           $element{$i} = $lastelement;
163 0           $person[++$lastelement] .= "$person[$team2] ($score2)";
164             }
165              
166 0           $element{(0 - (2 * (($i % 2) - .5)) + $i)} = $lastelement;
167              
168 0           @{$self}{qw/ELEMENT LASTELEMENT PERSON NUMOFPEOPLE/}
  0            
169             = (\%element, $lastelement, \@person, $numofpeople);
170              
171 0           return $self;
172             }
173              
174             sub round {
175 0     0 0   my ($self, $teamname1, $teamname2) = @_;
176 0           my (%element, $lastelement, @person, $numofpeople);
177 0           my ($team1, $team2, $x) = (0, 0, 0);
178              
179 0           $numofpeople = $self->{NUMOFPEOPLE};
180 0           @person = @{$self->{PERSON}};
  0            
181 0           %element = %{$self->{ELEMENT}};
  0            
182 0           $lastelement = $self->{LASTELEMENT};
183              
184 0           while ($team1 == 0) {
185 0           $_ = $person[++$x];
186 0 0 0       $team1 = $x if (/\d+ (.*)/ and ($1 eq $teamname1));
187 0 0         die "Invalid Team 1" if ($team1 > $lastelement);
188             }
189              
190 0           $x = 0;
191              
192 0           while ($team2 == 0) {
193 0           $_ = $person[++$x];
194 0 0 0       $team2 = $x if (/\d+ (.*)/ and ($1 eq $teamname2));
195 0 0         die "Invalid Team 2" if ($team2 > $lastelement);
196             }
197              
198 0           my $i = 2;
199 0           while ($team2 != $element{(0 - (2 * (($i % 2) - .5)) + $i)}) {
200 0           $i++ while ($element{$i} != $team1);
201             }
202              
203 0           $element{floor($i / 2)} = $team1;
204 0           $person[$lastelement + 1] = "";
205 0           $x++;
206 0           $person[$lastelement + 2] = "";
207 0           $person[++$lastelement] .= "$person[$team1] ";
208 0           $element{$i} = $lastelement;
209 0           $person[++$lastelement] .= "$person[$team2]";
210              
211 0           $element{(0 - (2 * (($i % 2) - .5)) + $i)} = $lastelement;
212              
213 0           @{$self}{qw/ELEMENT LASTELEMENT PERSON NUMOFPEOPLE/}
  0            
214             = (\%element, $lastelement, \@person, $numofpeople);
215              
216 0           return $self;
217             }
218              
219             sub as_html {
220 0     0 0   my $self = shift; my $output = "";
  0            
221 0           my (%element, $lastelement, @person, $numofpeople);
222              
223 0           $numofpeople = $self->{NUMOFPEOPLE};
224 0           @person = @{$self->{PERSON}};
  0            
225 0           %element = %{$self->{ELEMENT}};
  0            
226 0           $lastelement = $self->{LASTELEMENT};
227              
228 0           my $firstentry = 2 ** ceil(log($numofpeople) / log(2));
229 0           my $width = floor(100 / (log($firstentry) + 3));
230              
231 0           $output .= "\n"; \n"; \n"; \n"; \n"; \n";
232              
233 0           for (my $i = $firstentry; $i <= (2 * $firstentry - 1); $i++) {
234 0           $output .= "
235              
236 0           my $j = $i;
237 0           my $x = 1.5 * (2 ** ceil(log($i + 1) / log(2))) - $j - 1;
238 0           my $k = 1;
239              
240 0           while ($j == floor($j)) {
241 0           $x=(1.5 * (2 ** (ceil(log($j + 1) / log(2))))) - $j - 1;
242              
243 0 0         if ($element{$x} < 0) {
    0          
244 0           $output .= "  
245             } elsif ($element{$x} == 0) {
246 0           $output .= "  
247             } else {
248 0           $output .= " $person[$element{$x}]
249             }
250              
251 0           $j /= 2; $k *= 2;
  0            
252             }
253              
254 0           $output .= "
255             }
256              
257 0           $output .= "
\n";
258             }
259              
260             sub as_xhtml {
261 0     0 0   my $self = shift; my $output = "";
  0            
262              
263 0           my (%element, $lastelement, @person, $numofpeople);
264 0           $numofpeople = $self->{NUMOFPEOPLE};
265 0           @person = @{$self->{PERSON}};
  0            
266 0           %element = %{$self->{ELEMENT}};
  0            
267 0           $lastelement = $self->{LASTELEMENT};
268              
269 0           my $firstentry = 2 ** ceil(log($numofpeople) / log(2));
270 0           my $width = floor(100 / (log($firstentry) + 3));
271              
272 0           $output .= "\n \n"; \n"; \n"; \n"; \n"; \n"; \n
273              
274 0           for (my $i = $firstentry; $i <= (2 * $firstentry - 1); $i++) {
275 0           $output .= "
276              
277 0           my $j = $i;
278 0           my $x = 1.5 * (2 ** ceil(log($i + 1) / log(2))) - $j - 1;
279 0           my $k = 1;
280              
281 0           while ($j == floor($j)) {
282 0           $x=(1.5 * (2 ** (ceil(log($j + 1) / log(2))))) - $j - 1;
283              
284 0 0         if ($element{$x} < 0) {
    0          
285 0           $output .= "  
286             } elsif ($element{$x} == 0) {
287 0           $output .= "  
288             } else {
289 0           $output .= " $person[$element{$x}]
290             }
291              
292 0           $j /= 2; $k *= 2;
  0            
293             }
294              
295 0           $output .= "
296             }
297              
298 0           $output .= "
\n";
299 0           $output =~ s!!!isg;
300              
301 0           return $output;
302             }
303              
304             sub as_directed_graph_source {
305 0     0 0   my $self = shift; my $output = ""; my $reverse="";
  0            
  0            
306 0           my $name = shift;
307 0           my (%element, $lastelement, @person, $numofpeople);
308 0           my $i = 0; my $current="";
  0            
309              
310 0           $numofpeople = $self->{NUMOFPEOPLE};
311 0           @person = @{$self->{PERSON}};
  0            
312 0           %element = %{$self->{ELEMENT}};
  0            
313 0           $lastelement = $self->{LASTELEMENT};
314              
315 0           my $firstentry = 2 ** ceil(log($numofpeople) / log(2));
316 0           for ($i = 1; $i < (2 * $firstentry - 1); $i++) {
317 0 0         if ($element{$i} > 0) {
    0          
318 0           $current=$person[$element{$i}];
319 0           $output = " $i [label=\"$current\"];\n". $output;
320             } elsif ($i < $firstentry) {
321 0           $output = " $i [label=\" \"];\n" . $output;
322             }
323              
324 0           my $j = 0; my $k = 0;
  0            
325              
326 0 0         if ($i > 1) {
327 0 0         if ($i < $firstentry) {
    0          
328 0           $j = floor($i / 2);
329 0           $reverse = " $i -> $j;\n" . $reverse;
330             } elsif ($element{$i} > 0) {
331 0           $j = floor($i / 2);
332 0           $reverse = " $i -> $j;\n" . $reverse;
333             }
334             }
335             }
336              
337 0           $output = "digraph $name {\n rankdir=LR;\n" . $output;
338 0           $output .= $reverse . "}\n";
339 0           $output =~ s!!!isg;
340 0           $output =~ s! ! !isg;
341              
342 0           return $output;
343             }
344              
345             #sub as_directed_graph {
346             # my $self = shift;
347             # my $name = shift;
348             # my (%element, $lastelement, @person, $numofpeople);
349             # my $i = 0; my $current = "";
350             #
351             # eval "use GraphViz; 1" or die "You need to install GraphViz.pm to use this function"
352             # my $g = GraphViz->new(directed => 1, rankdir => 1);
353             #
354             # $numofpeople = $self->{NUMOFPEOPLE};
355             # @person = @{$self->{PERSON}};
356             # %element = %{$self->{ELEMENT}};
357             # $lastelement = $self->{LASTELEMENT};
358             #
359             # my $firstentry = 2 ** ceil(log($numofpeople) / log(2));
360             # for ($i = (2 * $firstentry); $i > 0; $i--) {
361             # if ($element{$i} > 0) {
362             # $current = $person[$element{$i}];
363             # $current =~ s!!!isg;
364             # $current =~ s! ! !isg;
365             # $g->add_node($i, label => $current);
366             # } elsif ($i<$firstentry) {
367             # $g->add_node($i, label => ' ');
368             # }
369             #
370             # my $j = 0;
371             #
372             # if ($i > 1) {
373             # if ($i < $firstentry) {
374             # $j = floor($i / 2);
375             # $g->add_edge($i, $j);
376             # } elsif ($element{$i} > 0) {
377             # $j = floor($i / 2);
378             # $g->add_edge($i, $j);
379             # }
380             # }
381             # }
382             #
383             # return $g;
384             #}
385              
386             1;
387              
388             =head1 ACKNOWLEDGEMENTS
389              
390             Thanks to Fletch and autrijus of the I<#perl that doesn't officially exist>
391             for interface suggestions.
392              
393             More thanks to autrijus for setting up the original distribution.
394              
395             Yet more thanks to autrijus for his continuing assistance in polishing th
396             code.
397              
398             =head1 BUGS
399              
400             The as_directed_graph function is commented out until I can find a way
401             to only load it if the user has GraphViz installed.
402              
403             =head1 AUTHORS
404              
405             T. J. Eckman Ejeek@jeek.netE.
406              
407             =head1 COPYRIGHT
408              
409             Copyright 2001 by T. J. Eckman Ejeek@jeek.netE.
410              
411             This program is free software; you can redistribute it and/or
412             modify it under the same terms as Perl itself.
413              
414             See L
415              
416             =cut