Passed
Branch bigRefactor (c260a1)
by Julien
34:53
created

CreateDirectEliminationTree::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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