Completed
Push — master ( c3f0f6...0c6e4d )
by Tomáš
02:30
created

GameSorter   A

Complexity

Total Complexity 37

Size/Duplication

Total Lines 244
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 37
eloc 84
c 0
b 0
f 0
dl 0
loc 244
ccs 93
cts 93
cp 1
rs 9.44

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 2 1
A orderCheckTeamsVal() 0 16 4
A cycle4() 0 11 3
A cycle3() 0 11 3
A cycle5() 0 11 3
B sort() 0 53 9
B moveCalculatedGames() 0 21 8
A cycle1() 0 11 3
A cycle2() 0 11 3
1
<?php
2
3
namespace TournamentGenerator\Helpers\Sorter;
4
5
use Exception;
6
use TournamentGenerator\Game;
7
use TournamentGenerator\Group;
8
9
/**
10
 * Tournament generator sorter for games
11
 *
12
 * WORKS BY COMPARING AVAILABLE GAMES BY THEIR TEAMS
13
 * TEAMS FROM LAST 3 GAMES
14
 * 1 = PLAYED ONLY 3RD GAME FROM END
15
 * 2 = PLAYED ONLY 2ND GAME FROM END
16
 * 3 = PLAYED 3RD AND 2ND GAME FROM END
17
 * 4 = PLAYED ONLY THE LAST GAME
18
 * 5 = PLAYED 3RD AND 1ST GAME FROM END
19
 * 6 = PLAYED 2ND ANS 1ST GAME FROM END
20
 * 7 = PLAYED ALL 3 LAST GAMES
21
 *
22
 * @author  Tomáš Vojík <[email protected]>
23
 *
24
 * @package TournamentGenerator\Helpers\Sorter
25
 * @since   0.3
26
 */
27
class GameSorter implements BaseSorter
28
{
29
30
	/** @var Group */
31
	private Group $group;
32
	/** @var Game[] */
33
	private array $games = [];
34
35
	/**
36
	 * Orders games from group
37
	 *
38
	 * @param Group $group
39
	 */
40 5
	public function __construct(Group $group) {
41 5
		$this->group = $group;
42 5
	}
43
44
	/**
45
	 * Orders games from group
46
	 *
47
	 * @param Game[] $data
48
	 *
49
	 * @return array
50
	 * @throws Exception
51
	 */
52 5
	public function sort(array $data) : array {
53
54 5
		if (count($data) < 5) {
55 1
			return $data;
56
		}
57
58 4
		$this->games = [];
59
60 4
		$teams = [];
61 4
		foreach ($this->group->getTeams() as $team) {
62 4
			$teams[$team->getId()] = 0;
63
		}
64
65 4
		$this->moveCalculatedGames(array_shift($data), $teams);
66
67 4
		while (count($data) > 0) {
68
			// CYCLE 1
69
			// TEAM WHICH DIDN'T PLAY IN LAST GAME (< 4)
70 4
			if ($this->cycle1($data, $teams)) {
71 4
				continue;
72
			}
73
74
			// CYCLE 2
75
			// NOT TEAM WHICH PLAYED IN LAST TWO GAMES (NOT 6 or 7)
76 4
			if ($this->cycle2($data, $teams)) {
77 4
				continue;
78
			}
79
80
			// CYCLE 3
81
			// NOT TEAM WHICH PLAYED IN LAST THREE GAMES (NOT 7)
82
			// TEAMS THAT DIDN'T PLAY IN LAST GAME WILL PLAY THIS GAME (< 4)
83 3
			if ($this->cycle3($data, $teams)) {
84 1
				continue;
85
			}
86
87
			// CYCLE 4
88
			// NOT TEAM WHICH PLAYED IN LAST THREE GAMES (NOT 7)
89 3
			if ($this->cycle4($data, $teams)) {
90 3
				continue;
91
			}
92
93
			// CYCLE 5
94
			// TEAMS THAT DIDN'T PLAY IN LAST GAME WILL PLAY THIS GAME (< 4)
95 2
			if ($this->cycle5($data, $teams)) {
96 2
				continue;
97
			}
98
99
			// CYCLE 6
100
			// FIRST AVAILABLE GAME
101 2
			$this->moveCalculatedGames(array_shift($data), $teams);
102
		}
103
104 4
		return $this->games;
105
	}
106
107
	/**
108
	 * Move teams that did not play in the last game (< 4)
109
	 *
110
	 * @param Game  $game
111
	 * @param array $teams
112
	 */
113 4
	private function moveCalculatedGames(Game $game, array &$teams) : void {
114
115 4
		$this->games[] = $game;
116
117 4
		foreach (end($this->games)->getTeamsIds() as $tid) {
118 4
			$teams[$tid] += 4;
119
		}
120
121 4
		if (count($this->games) > 1) {
122 4
			foreach (prev($this->games)->getTeamsIds() as $tid) {
123 4
				$teams[$tid] -= 2;
124
			}
125
		}
126 4
		if (count($this->games) > 2) {
127 4
			foreach (prev($this->games)->getTeamsIds() as $tid) {
128 4
				--$teams[$tid];
129
			}
130
		}
131 4
		if (count($this->games) > 3) {
132 4
			foreach (prev($this->games)->getTeamsIds() as $tid) {
133 4
				--$teams[$tid];
134
			}
135
		}
136
137 4
	}
138
139
	/**
140
	 * Teams that did not play in the last game (< 4)
141
	 *
142
	 * @param array $games
143
	 * @param array $teams
144
	 *
145
	 * @return bool
146
	 */
147 4
	private function cycle1(array &$games, array &$teams) : bool {
148 4
		$found = false;
149 4
		foreach ($games as $key => $game) {
150 4
			if ($this->orderCheckTeamsVal($game, $teams, [4, 5, 6, 7])) {
151 4
				$this->moveCalculatedGames($game, $teams);
152 4
				unset($games[$key]);
153 4
				$found = true;
154 4
				break;
155
			}
156
		}
157 4
		return $found;
158
	}
159
160
	/**
161
	 * Get first available game
162
	 *
163
	 * @param Game  $game
164
	 * @param array $teams
165
	 * @param array $checkVals
166
	 * @param array $required
167
	 *
168
	 * @return bool
169
	 */
170 4
	private function orderCheckTeamsVal(Game $game, array $teams, array $checkVals, array $required = []) : bool {
171
172 4
		$requiredTeams = array_filter($teams, static function($a) use ($required) {
173 4
			return in_array($a, $required, true);
174 4
		});
175
176 4
		foreach ($game->getTeamsIds() as $tid) {
177 4
			if (in_array($teams[$tid], $checkVals, true)) {
178 4
				return false;
179
			}
180 4
			if (isset($requiredTeams[$tid])) {
181 3
				unset($requiredTeams[$tid]);
182
			}
183
		}
184
185 4
		return !(count($requiredTeams) > 0);
186
187
	}
188
189
	/**
190
	 * Teams that did not play in the last two games (not 6 or 7)
191
	 *
192
	 * @param array $games
193
	 * @param array $teams
194
	 *
195
	 * @return bool
196
	 */
197 4
	private function cycle2(array &$games, array &$teams) : bool {
198 4
		$found = false;
199 4
		foreach ($games as $key => $game) {
200 4
			if ($this->orderCheckTeamsVal($game, $teams, [6, 7])) {
201 4
				$this->moveCalculatedGames($game, $teams);
202 4
				unset($games[$key]);
203 4
				$found = true;
204 4
				break;
205
			}
206
		}
207 4
		return $found;
208
	}
209
210
	/**
211
	 * Teams that did not play in the last three games (not 7) and teams that did not play in the last game (< 4)
212
	 *
213
	 * @param array $games
214
	 * @param array $teams
215
	 *
216
	 * @return bool
217
	 */
218 3
	private function cycle3(array &$games, array &$teams) : bool {
219 3
		$found = false;
220 3
		foreach ($games as $key => $game) {
221 3
			if ($this->orderCheckTeamsVal($game, $teams, [7], [1, 2, 3])) {
222 1
				$this->moveCalculatedGames($game, $teams);
223 1
				unset($games[$key]);
224 1
				$found = true;
225 1
				break;
226
			}
227
		}
228 3
		return $found;
229
	}
230
231
	/**
232
	 * Teams that did not play in the last three games (not 7)
233
	 *
234
	 * @param array $games
235
	 * @param array $teams
236
	 *
237
	 * @return bool
238
	 */
239 3
	private function cycle4(array &$games, array &$teams) : bool {
240 3
		$found = false;
241 3
		foreach ($games as $key => $game) {
242 3
			if ($this->orderCheckTeamsVal($game, $teams, [7])) {
243 3
				$this->moveCalculatedGames($game, $teams);
244 3
				unset($games[$key]);
245 3
				$found = true;
246 3
				break;
247
			}
248
		}
249 3
		return $found;
250
	}
251
252
	/**
253
	 * Teams that did not play in the last game will play this game (< 4)
254
	 *
255
	 * @param array $games
256
	 * @param array $teams
257
	 *
258
	 * @return bool
259
	 */
260 2
	private function cycle5(array &$games, array &$teams) : bool {
261 2
		$found = false;
262 2
		foreach ($games as $key => $game) {
263 2
			if ($this->orderCheckTeamsVal($game, $teams, [], [1, 2, 3])) {
264 2
				$this->moveCalculatedGames($game, $teams);
265 2
				unset($games[$key]);
266 2
				$found = true;
267 2
				break;
268
			}
269
		}
270 2
		return $found;
271
	}
272
273
}
274