Test Failed
Push — master ( bdec7c...dc4278 )
by Julien
03:45
created

DirectEliminationTreeGen::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace Xoco70\KendoTournaments\TreeGen;
4
5
use Xoco70\KendoTournaments\Contracts\TreeGenerable;
6
7
class DirectEliminationTreeGen implements TreeGenerable
8
{
9
    private $names;
10
    private $brackets = array();
11
    private $noTeams;
12
    private $noRounds;
13
    private $playerWrapperHeight = 30;
14
    private $matchWrapperWidth = 150;
15
    private $roundSpacing = 40;
16
    private $matchSpacing = 42;
17
    private $borderWidth = 3;
18
19
    public function __construct($names)
20
    {
21
22
        $this->names = $names;
23
24
        $this->run();
25
26
    }
27
28
    public function run()
29
    {
30
31
        //If no names have been entered, then use numbers
32
33
        if ($this->names != '') {
34
            $teams = $this->names;
35
36
            //Make sure there's at least 2 teams
37
38
            if(count($teams) == 1){
39
                $teams[] = 'Team 2';
40
            }
41
42
            $this->noTeams = count($teams);
43
44
        }
45
46
47
        //Calculate the size of the first full round - for example if you have 5 teams, then the first full round will consist of 4 teams
48
        $minimumFirstRoundSize = pow(2, ceil(log($this->noTeams)/log(2)));
49
        $this->noRounds = log($minimumFirstRoundSize, 2);
50
        $noByesToAdd = $minimumFirstRoundSize - $this->noTeams;
51
52
        //Add the byes to the teams array
53
        for($i = 0; $i < $noByesToAdd; $i++){
54
            $teams[] = null;
0 ignored issues
show
Bug introduced by
The variable $teams does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
55
        }
56
57
        //Order the teams in a seeded order - this is required regardless of whether it is a seeded tournament or not, as it prevents BYEs playing eachother
58
        for($i = 0; $i < log($this->noTeams / 2, 2); $i++){
59
60
            $out = array();
61
62
            foreach($teams as $player){
63
                $splice = pow(2, $i);
64
                $out = array_merge($out, array_splice($teams, 0, $splice));
65
                $out = array_merge($out, array_splice($teams, -$splice));
66
            }
67
68
            $teams = $out;
69
70
        }
71
72
        //Randomise the draw if required - keep the position of the byes, but swap the players
73
74
//        if($this->type != 1){
0 ignored issues
show
Unused Code Comprehensibility introduced by
51% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
75
//
76
//            $randomTeams = array();
77
//            $shuffledTeams = array_filter($teams);
78
//            shuffle($shuffledTeams);
79
//
80
//            foreach($teams as $key => $team){
81
//                $randomTeams[$key] = is_null($team) ? null : array_pop($shuffledTeams);
82
//            }
83
//
84
//            $teams = $randomTeams;
85
//
86
//        }
87
88
        $roundNumber = 1;
89
90
        //Group 2 teams into a match
91
        $matches = array_chunk($teams, 2);
92
93
        //Only check for BYEs if there are more than 2 teams
94
        if($this->noTeams > 2){
95
96
            foreach($matches as $key => &$match){
97
98
                $matchNumber = $key + 1;
99
100
                //If both teams are present, then that means they haven't had a BYE to the next round, so they must play in the first round
101
                if($match[0] && $match[1]){
102
103
                    //Add the match to the first round
104
                    $this->brackets[$roundNumber][$matchNumber] = $match;
105
106
                    //Set the match to null as the result of the above match hasn't yet been determined
107
                    $match = null;
108
109
                }else{
110
111
                    //If only the first or second player exists, then replace the multidimensional array with the existing player
112
                    $match = $match[0] ? $match[0] : $match[1];
113
114
                }
115
116
            }
117
118
            //Now all of the blank spaces except the ones awaiting first round results have gone, group the single dimension array into a multiple dimensional array, so opponents share the same parent array
119
            $matches = array_chunk($matches, 2);
120
121
        }
122
123
        //If there's already a match in the match array, then that means the next round is round 2, so increase the round number
124
        if(count($this->brackets)) $roundNumber++;
125
126
        //Create the first full round of teams, some may be blank if waiting on the results of a previous round
127
        for($i = 0; $i < count($matches); $i++){
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
128
            $this->brackets[$roundNumber][$i+1] = $matches[$i];
129
        }
130
131
        //Create the result of the empty rows for this tournament
132
133
        for($roundNumber += 1; $roundNumber <= $this->noRounds; $roundNumber++){
134
            for($matchNumber = 1; $matchNumber <= ($minimumFirstRoundSize/pow(2, $roundNumber)); $matchNumber++){
135
                $this->brackets[$roundNumber][$matchNumber] = array(null, null);
136
            }
137
        }
138
139
        $this->assignPositions();
140
141
    }
142
143
    private function assignPositions()
144
    {
145
146
        //Variables required for figuring outing the height of the vertical connectors
147
148
        $matchSpacingMultiplier = 0.5;
149
        $playerWrapperHeightMultiplier = 1;
150
151
        foreach($this->brackets as $roundNumber => &$round){
152
153
            foreach($round as $matchNumber => &$match){
154
155
                //Give teams a nicer index
156
157
                $match['playerA'] = $match[0];
158
                $match['playerB'] = $match[1];
159
160
                unset($match[0]);
161
                unset($match[1]);
162
163
                //Figure out the bracket positions
164
165
                $match['matchWrapperTop'] = (((2 * $matchNumber) - 1) * (pow(2, ($roundNumber) - 1)) - 1) * (($this->matchSpacing / 2) + $this->playerWrapperHeight);
166
                $match['matchWrapperLeft'] = ($roundNumber - 1) * ($this->matchWrapperWidth + $this->roundSpacing - 1);
167
                $match['vConnectorLeft'] = floor($match['matchWrapperLeft'] + $this->matchWrapperWidth + ($this->roundSpacing / 2) - ($this->borderWidth / 2));
168
                $match['vConnectorHeight'] = ($matchSpacingMultiplier * $this->matchSpacing) + ($playerWrapperHeightMultiplier * $this->playerWrapperHeight) + $this->borderWidth;
169
                $match['vConnectorTop'] = $match['hConnectorTop'] = $match['matchWrapperTop'] + $this->playerWrapperHeight;
170
                $match['hConnectorLeft'] = ($match['vConnectorLeft'] - ($this->roundSpacing / 2)) + 2;
171
                $match['hConnector2Left'] = $match['matchWrapperLeft'] + $this->matchWrapperWidth + ($this->roundSpacing / 2);
172
173
                //Adjust the positions depending on the match number
174
175
                if(!($matchNumber % 2)){
176
                    $match['hConnector2Top'] = $match['vConnectorTop'] -= ($match['vConnectorHeight'] - $this->borderWidth);
177
                }else{
178
                    $match['hConnector2Top'] = $match['vConnectorTop'] + ($match['vConnectorHeight'] - $this->borderWidth);
179
                }
180
181
            }
182
183
            //Update the spacing variables
184
185
            $matchSpacingMultiplier *= 2;
186
            $playerWrapperHeightMultiplier *= 2;
187
188
        }
189
190
    }
191
192
    public function printBrackets()
193
    {
194
195
        $this->printRoundTitles();
196
197
        echo '<div id="brackets-wrapper">';
198
199
        foreach($this->brackets as $roundNumber => $round) {
200
201
            foreach($round as $matchNumber => $match) {
202
203
                echo '<div class="match-wrapper" style="top: '.$match['matchWrapperTop'].'px; left: '.$match['matchWrapperLeft'].'px; width: '.$this->matchWrapperWidth.'px;">
204
                        <input type="text" class="score">'
205
                    .$this->getPlayerList($match['playerA']).
206
                    '<div class="match-divider">
207
                        </div>
208
                        <input type="text" class="score">'
209
                    .$this->getPlayerList($match['playerB']).
210
                    '</div>';
211
212
                if ($roundNumber != $this->noRounds) {
213
214
                    echo '<div class="vertical-connector" style="top: '.$match['vConnectorTop'].'px; left: '.$match['vConnectorLeft'].'px; height: '.$match['vConnectorHeight'].'px;"></div>
215
                          <div class="horizontal-connector" style="top: '.$match['hConnectorTop'].'px; left: '.$match['hConnectorLeft'].'px;"></div>
216
                          <div class="horizontal-connector" style="top: '.$match['hConnector2Top'].'px; left: '.$match['hConnector2Left'].'px;"></div>';
217
218
                }
219
220
            }
221
222
        }
223
224
        echo '</div>';
225
226
    }
227
228
    private function printRoundTitles(){
229
230
        if($this->noTeams == 2){
231
232
            $roundTitles = array('Final');
233
234
        }elseif($this->noTeams <= 4){
235
236
            $roundTitles = array('Semi-Finals', 'Final');
237
238
        }elseif($this->noTeams <= 8){
239
240
            $roundTitles = array('Quarter-Finals', 'Semi-Finals', 'Final');
241
242
        }else{
243
244
            $roundTitles = array('Quarter-Finals', 'Semi-Finals', 'Final');
245
            $noRounds = ceil(log($this->noTeams, 2));
246
            $noTeamsInFirstRound = pow(2, ceil(log($this->noTeams)/log(2)));
247
            $tempRounds = array();
248
249
            //The minus 3 is to ignore the final, semi final and quarter final rounds
250
251
            for($i = 0; $i < $noRounds - 3; $i++){
252
                $tempRounds[] = 'Last '.$noTeamsInFirstRound;
253
                $noTeamsInFirstRound /= 2;
254
            }
255
256
            $roundTitles = array_merge($tempRounds, $roundTitles);
257
258
        }
259
260
        echo '<div id="round-titles-wrapper">';
261
262
        foreach($roundTitles as $key => $roundTitle) {
263
264
            $left = $key * ($this->matchWrapperWidth + $this->roundSpacing - 1);
265
266
            echo '<div class="round-title" style="left: '.$left.'px;">' . $roundTitle . '</div>';
267
268
        }
269
270
        echo '</div>';
271
272
    }
273
274
    private function getPlayerList($selected)
275
    {
276
277
        $html = '<select>
278
                <option'.($selected == '' ? ' selected' : '').'></option>';
279
280
        foreach(array_merge($this->brackets[1], $this->brackets[2]) as $bracket){
281
282 View Code Duplication
            if($bracket['playerA'] != ''){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
283
                $html .= '<option'.($selected == $bracket['playerA'] ? ' selected' : '').'>'.$bracket['playerA'].'</option>';
284
            }
285
286 View Code Duplication
            if($bracket['playerB'] != ''){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
287
                $html .= '<option'.($selected == $bracket['playerB'] ? ' selected' : '').'>'.$bracket['playerB'].'</option>';
288
            }
289
290
        }
291
292
        $html .= '</select>';
293
294
        return $html;
295
296
    }
297
}
298