Completed
Push — master ( 05fdcf...5c98a0 )
by Julien
02:38
created

CreateDirectEliminationTree::build()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 31
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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