Test Failed
Push — master ( 84ef8e...92b331 )
by Julien
08:45
created

assignFightersToBracket()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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