GameSorter::cycle4()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
eloc 8
c 0
b 0
f 0
dl 0
loc 11
ccs 9
cts 9
cp 1
rs 10
cc 3
nc 3
nop 2
crap 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
	protected Group $group;
32
	/** @var Game[] */
33
	protected 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
	 * @pre  The autoincrement must be reset on the group's container
50
	 * @post All games will have reset ids in the new order
51
	 *
52
	 * @return array
53
	 * @throws Exception
54
	 */
55 5
	public function sort(array $data) : array {
56
57 5
		if (count($data) < 5) {
58 1
			return $data;
59
		}
60
61 4
		$this->games = [];
62
63 4
		$teams = [];
64 4
		foreach ($this->group->getTeams() as $team) {
65 4
			$teams[$team->getId()] = 0;
66
		}
67
68 4
		$this->moveCalculatedGames(array_shift($data), $teams);
69
70 4
		while (count($data) > 0) {
71
			// CYCLE 1
72
			// TEAM WHICH DIDN'T PLAY IN LAST GAME (< 4)
73 4
			if ($this->cycle1($data, $teams)) {
74 4
				continue;
75
			}
76
77
			// CYCLE 2
78
			// NOT TEAM WHICH PLAYED IN LAST TWO GAMES (NOT 6 or 7)
79 4
			if ($this->cycle2($data, $teams)) {
80 4
				continue;
81
			}
82
83
			// CYCLE 3
84
			// NOT TEAM WHICH PLAYED IN LAST THREE GAMES (NOT 7)
85
			// TEAMS THAT DIDN'T PLAY IN LAST GAME WILL PLAY THIS GAME (< 4)
86 2
			if ($this->cycle3($data, $teams)) {
87 1
				continue;
88
			}
89
90
			// CYCLE 4
91
			// NOT TEAM WHICH PLAYED IN LAST THREE GAMES (NOT 7)
92 2
			if ($this->cycle4($data, $teams)) {
93 2
				continue;
94
			}
95
96
			// CYCLE 5
97
			// TEAMS THAT DIDN'T PLAY IN LAST GAME WILL PLAY THIS GAME (< 4)
98 2
			if ($this->cycle5($data, $teams)) {
99 2
				continue;
100
			}
101
102
			// CYCLE 6
103
			// FIRST AVAILABLE GAME
104 2
			$this->moveCalculatedGames(array_shift($data), $teams);
105
		}
106
107 4
		$this->resetGameIds();
108
109 4
		return $this->games;
110
	}
111
112
	/**
113
	 * Move teams that did not play in the last game (< 4)
114
	 *
115
	 * @param Game  $game
116
	 * @param array $teams
117
	 */
118 4
	protected function moveCalculatedGames(Game $game, array &$teams) : void {
119
120 4
		$this->games[] = $game;
121
122 4
		foreach (end($this->games)->getTeamsIds() as $tid) {
123 4
			$teams[$tid] += 4;
124
		}
125
126 4
		if (count($this->games) > 1) {
127 4
			foreach (prev($this->games)->getTeamsIds() as $tid) {
128 4
				$teams[$tid] -= 2;
129
			}
130
		}
131 4
		if (count($this->games) > 2) {
132 4
			foreach (prev($this->games)->getTeamsIds() as $tid) {
133 4
				--$teams[$tid];
134
			}
135
		}
136 4
		if (count($this->games) > 3) {
137 4
			foreach (prev($this->games)->getTeamsIds() as $tid) {
138 4
				--$teams[$tid];
139
			}
140
		}
141
142 4
	}
143
144
	/**
145
	 * Teams that did not play in the last game (< 4)
146
	 *
147
	 * @param array $games
148
	 * @param array $teams
149
	 *
150
	 * @return bool
151
	 */
152 4
	protected function cycle1(array &$games, array &$teams) : bool {
153 4
		$found = false;
154 4
		foreach ($games as $key => $game) {
155 4
			if ($this->orderCheckTeamsVal($game, $teams, [4, 5, 6, 7])) {
156 4
				$this->moveCalculatedGames($game, $teams);
157 4
				unset($games[$key]);
158 4
				$found = true;
159 4
				break;
160
			}
161
		}
162 4
		return $found;
163
	}
164
165
	/**
166
	 * Get first available game
167
	 *
168
	 * @param Game  $game
169
	 * @param array $teams
170
	 * @param array $checkVals
171
	 * @param array $required
172
	 *
173
	 * @return bool
174
	 */
175 4
	protected function orderCheckTeamsVal(Game $game, array $teams, array $checkVals, array $required = []) : bool {
176
177 4
		$requiredTeams = array_filter($teams, static function($a) use ($required) {
178 4
			return in_array($a, $required, true);
179 4
		});
180
181 4
		foreach ($game->getTeamsIds() as $tid) {
182 4
			if (in_array($teams[$tid], $checkVals, true)) {
183 4
				return false;
184
			}
185 4
			if (isset($requiredTeams[$tid])) {
186 2
				unset($requiredTeams[$tid]);
187
			}
188
		}
189
190 4
		return !(count($requiredTeams) > 0);
191
192
	}
193
194
	/**
195
	 * Teams that did not play in the last two games (not 6 or 7)
196
	 *
197
	 * @param array $games
198
	 * @param array $teams
199
	 *
200
	 * @return bool
201
	 */
202 4
	protected function cycle2(array &$games, array &$teams) : bool {
203 4
		$found = false;
204 4
		foreach ($games as $key => $game) {
205 4
			if ($this->orderCheckTeamsVal($game, $teams, [6, 7])) {
206 4
				$this->moveCalculatedGames($game, $teams);
207 4
				unset($games[$key]);
208 4
				$found = true;
209 4
				break;
210
			}
211
		}
212 4
		return $found;
213
	}
214
215
	/**
216
	 * Teams that did not play in the last three games (not 7) and teams that did not play in the last game (< 4)
217
	 *
218
	 * @param array $games
219
	 * @param array $teams
220
	 *
221
	 * @return bool
222
	 */
223 2
	protected function cycle3(array &$games, array &$teams) : bool {
224 2
		$found = false;
225 2
		foreach ($games as $key => $game) {
226 2
			if ($this->orderCheckTeamsVal($game, $teams, [7], [1, 2, 3])) {
227 1
				$this->moveCalculatedGames($game, $teams);
228 1
				unset($games[$key]);
229 1
				$found = true;
230 1
				break;
231
			}
232
		}
233 2
		return $found;
234
	}
235
236
	/**
237
	 * Teams that did not play in the last three games (not 7)
238
	 *
239
	 * @param array $games
240
	 * @param array $teams
241
	 *
242
	 * @return bool
243
	 */
244 2
	protected function cycle4(array &$games, array &$teams) : bool {
245 2
		$found = false;
246 2
		foreach ($games as $key => $game) {
247 2
			if ($this->orderCheckTeamsVal($game, $teams, [7])) {
248 2
				$this->moveCalculatedGames($game, $teams);
249 2
				unset($games[$key]);
250 2
				$found = true;
251 2
				break;
252
			}
253
		}
254 2
		return $found;
255
	}
256
257
	/**
258
	 * Teams that did not play in the last game will play this game (< 4)
259
	 *
260
	 * @param array $games
261
	 * @param array $teams
262
	 *
263
	 * @return bool
264
	 */
265 2
	protected function cycle5(array &$games, array &$teams) : bool {
266 2
		$found = false;
267 2
		foreach ($games as $key => $game) {
268 2
			if ($this->orderCheckTeamsVal($game, $teams, [], [1, 2, 3])) {
269 2
				$this->moveCalculatedGames($game, $teams);
270 2
				unset($games[$key]);
271 2
				$found = true;
272 2
				break;
273
			}
274
		}
275 2
		return $found;
276
	}
277
278
	/**
279
	 * Resets the game ids
280
	 *
281
	 * @pre   The autoincrement must be reset on the group's container
282
	 * @post  All games will have reset ids in the new order
283
	 *
284
	 * @since 0.5
285
	 */
286 4
	protected function resetGameIds() : void {
287 4
		$container = $this->group->getGameContainer();
288 4
		foreach ($this->games as $game) {
289 4
			$game->setId($container->getAutoIncrement());
290
			/** @noinspection DisconnectedForeachInstructionInspection */
291 4
			$container->incrementId();
292
		}
293 4
	}
294
295
}
296