Test Failed
Push — master ( 051cab...019850 )
by Julien
04:18
created

DirectEliminationTreeGen::getNewFighter()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
3
namespace Xoco70\KendoTournaments\TreeGen;
4
5
use Xoco70\KendoTournaments\Contracts\TreeGenerable;
6
use Xoco70\KendoTournaments\Models\Competitor;
7
use Xoco70\KendoTournaments\Models\Team;
8
9
class DirectEliminationTreeGen implements TreeGenerable
10
{
11
    public $names;
12
    public $brackets = [];
13
    public $championship;
14
    public $noTeams;
15
    public $noRounds;
16
    public $playerWrapperHeight = 30;
17
    public $matchWrapperWidth = 150;
18
    public $roundSpacing = 40;
19
    public $matchSpacing = 42;
20
    public $borderWidth = 3;
21
22
    public function __construct($names, $championship)
0 ignored issues
show
Unused Code introduced by
The parameter $championship is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
23
    {
24
25
        $this->names = $names;
26
        $this->run();
27
28
    }
29
30
    public function run()
31
    {
32
        $teams = [];
33
        //If no names have been entered, then use numbers
34
35
        if ($this->names != '') {
36
            $teams = $this->names;
37
            $this->noTeams = count($teams);
38
        }
39
40
41
        //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
42
        $minimumFirstRoundSize = pow(2, ceil(log($this->noTeams) / log(2)));
43
        $this->noRounds = log($minimumFirstRoundSize, 2);
44
        $noByesToAdd = $minimumFirstRoundSize - $this->noTeams;
45
46
        //Add the byes to the teams array
47
        for ($i = 0; $i < $noByesToAdd; $i++) {
48
            $teams[] = null;
49
        }
50
51
52
        //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
53
//        $teams = $this->orderTeamsInSeededOrder($teams);
54
55
        $roundNumber = 1;
56
57
        //Group 2 teams into a match
58
        $matches = array_chunk($teams, 2);
59
60
        //If there's already a match in the match array, then that means the next round is round 2, so increase the round number
61
        if (count($this->brackets)) $roundNumber++;
62
63
        $countMatches = count($matches);
64
        //Create the first full round of teams, some may be blank if waiting on the results of a previous round
65
        for ($i = 0; $i < $countMatches; $i++) {
66
            $this->brackets[$roundNumber][$i + 1] = $matches[$i];
67
        }
68
69
        //Create the result of the empty rows for this tournament
70
71
        for ($roundNumber += 1; $roundNumber <= $this->noRounds; $roundNumber++) {
72
            for ($matchNumber = 1; $matchNumber <= ($minimumFirstRoundSize / pow(2, $roundNumber)); $matchNumber++) {
73
                $this->brackets[$roundNumber][$matchNumber] = [$this->getNewFighter(), $this->getNewFighter()];
74
            }
75
        }
76
        $this->assignPositions();
77
    }
78
79
    private function assignPositions()
80
    {
81
82
        //Variables required for figuring outing the height of the vertical connectors
83
84
        $matchSpacingMultiplier = 0.5;
85
        $playerWrapperHeightMultiplier = 1;
86
87
        foreach ($this->brackets as $roundNumber => &$round) {
88
89
            foreach ($round as $matchNumber => &$match) {
90
91
                //Give teams a nicer index
92
93
                $match['playerA'] = $match[0];
94
                $match['playerB'] = $match[1];
95
96
                unset($match[0]);
97
                unset($match[1]);
98
99
                //Figure out the bracket positions
100
101
                $match['matchWrapperTop'] = (((2 * $matchNumber) - 1) * (pow(2, ($roundNumber) - 1)) - 1) * (($this->matchSpacing / 2) + $this->playerWrapperHeight);
102
                $match['matchWrapperLeft'] = ($roundNumber - 1) * ($this->matchWrapperWidth + $this->roundSpacing - 1);
103
                $match['vConnectorLeft'] = floor($match['matchWrapperLeft'] + $this->matchWrapperWidth + ($this->roundSpacing / 2) - ($this->borderWidth / 2));
104
                $match['vConnectorHeight'] = ($matchSpacingMultiplier * $this->matchSpacing) + ($playerWrapperHeightMultiplier * $this->playerWrapperHeight) + $this->borderWidth;
105
                $match['vConnectorTop'] = $match['hConnectorTop'] = $match['matchWrapperTop'] + $this->playerWrapperHeight;
106
                $match['hConnectorLeft'] = ($match['vConnectorLeft'] - ($this->roundSpacing / 2)) + 2;
107
                $match['hConnector2Left'] = $match['matchWrapperLeft'] + $this->matchWrapperWidth + ($this->roundSpacing / 2);
108
109
                //Adjust the positions depending on the match number
110
111
                if (!($matchNumber % 2)) {
112
                    $match['hConnector2Top'] = $match['vConnectorTop'] -= ($match['vConnectorHeight'] - $this->borderWidth);
113
                } else {
114
                    $match['hConnector2Top'] = $match['vConnectorTop'] + ($match['vConnectorHeight'] - $this->borderWidth);
115
                }
116
117
            }
118
119
            //Update the spacing variables
120
121
            $matchSpacingMultiplier *= 2;
122
            $playerWrapperHeightMultiplier *= 2;
123
124
        }
125
126
    }
127
128
    public function printBrackets()
129
    {
130
131
        $this->printRoundTitles();
132
133
        echo '<div id="brackets-wrapper">';
134
135
        foreach ($this->brackets as $roundNumber => $round) {
136
137
            foreach ($round as $matchNumber => $match) {
138
139
                echo '<div class="match-wrapper" style="top: ' . $match['matchWrapperTop'] . 'px; left: ' . $match['matchWrapperLeft'] . 'px; width: ' . $this->matchWrapperWidth . 'px;">
140
                        <input type="text" class="score">'
141
                    . $this->getPlayerList($match['playerA']) .
142
                    '<div class="match-divider">
143
                        </div>
144
                        <input type="text" class="score">'
145
                    . $this->getPlayerList($match['playerB']) .
146
                    '</div>';
147
148
                if ($roundNumber != $this->noRounds) {
149
150
                    echo '<div class="vertical-connector" style="top: ' . $match['vConnectorTop'] . 'px; left: ' . $match['vConnectorLeft'] . 'px; height: ' . $match['vConnectorHeight'] . 'px;"></div>
151
                          <div class="horizontal-connector" style="top: ' . $match['hConnectorTop'] . 'px; left: ' . $match['hConnectorLeft'] . 'px;"></div>
152
                          <div class="horizontal-connector" style="top: ' . $match['hConnector2Top'] . 'px; left: ' . $match['hConnector2Left'] . 'px;"></div>';
153
154
                }
155
156
            }
157
158
        }
159
160
        echo '</div>';
161
162
    }
163
164
    /**
165
     * Print Round Titles
166
     */
167
    public function printRoundTitles()
168
    {
169
170
        if ($this->noTeams == 2) {
171
172
            $roundTitles = array('Final');
173
174
        } elseif ($this->noTeams <= 4) {
175
176
            $roundTitles = array('Semi-Finals', 'Final');
177
178
        } elseif ($this->noTeams <= 8) {
179
180
            $roundTitles = array('Quarter-Finals', 'Semi-Finals', 'Final');
181
182
        } else {
183
184
            $roundTitles = array('Quarter-Finals', 'Semi-Finals', 'Final');
185
            $noRounds = ceil(log($this->noTeams, 2));
186
            $noTeamsInFirstRound = pow(2, ceil(log($this->noTeams) / log(2)));
187
            $tempRounds = array();
188
189
            //The minus 3 is to ignore the final, semi final and quarter final rounds
190
191
            for ($i = 0; $i < $noRounds - 3; $i++) {
192
                $tempRounds[] = 'Last ' . $noTeamsInFirstRound;
193
                $noTeamsInFirstRound /= 2;
194
            }
195
196
            $roundTitles = array_merge($tempRounds, $roundTitles);
197
198
        }
199
200
        echo '<div id="round-titles-wrapper">';
201
202
        foreach ($roundTitles as $key => $roundTitle) {
203
204
            $left = $key * ($this->matchWrapperWidth + $this->roundSpacing - 1);
205
206
            echo '<div class="round-title" style="left: ' . $left . 'px;">' . $roundTitle . '</div>';
207
208
        }
209
210
        echo '</div>';
211
212
    }
213
214
    /**
215
     * @param $selected
216
     * @return string
217
     */
218
    public function getPlayerList($selected)
219
    {
220
221
        $html = '<select>
222
                <option' . ($selected == '' ? ' selected' : '') . '></option>';
223
        foreach (array_merge($this->brackets[1]) as $bracket) { // Bug Fix 24-02-2017 , $this->brackets[2]
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% 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...
224 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...
225
                $html .= '<option' . ($selected == $bracket['playerA'] ? ' selected' : '') . '>' . $bracket['playerA'] . '</option>';
226
            }
227
228 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...
229
                $html .= '<option' . ($selected == $bracket['playerB'] ? ' selected' : '') . '>' . $bracket['playerB'] . '</option>';
230
            }
231
        }
232
233
        $html .= '</select>';
234
235
        return $html;
236
237
    }
238
239
    /**
240
     * @param $teams
241
     * @return array
242
     */
243
    private function orderTeamsInSeededOrder($teams): array
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
244
    {
245
        $logNoTeam = log($this->noTeams / 2, 2);
246
247
        for ($i = 0; $i < $logNoTeam; $i++) {
248
249
            $out = [];
250
251
            foreach ($teams as $player) {
252
                $splice = pow(2, $i);
253
                $out = array_merge($out, array_splice($teams, 0, $splice));
254
                $out = array_merge($out, array_splice($teams, -$splice));
255
            }
256
257
            $teams = $out;
258
259
        }
260
        return $teams;
261
    }
262
263
    public function getNewFighter()
264
    {
265
        if ($this->championship->category->isTeam()) {
266
            return new Team;
267
        }
268
        return new Competitor;
269
    }
270
}
271