Test Failed
Push — master ( 943f49...1c4bf0 )
by Tomáš
09:55
created

Game::jsonSerialize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 2
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace TournamentGenerator;
4
5
use Exception;
6
use JsonSerializable;
7
use TournamentGenerator\Export\ExporterInterface;
8
use TournamentGenerator\Export\Single\GameExporter;
9
use TournamentGenerator\Interfaces\Exportable;
10
use TournamentGenerator\Interfaces\WithId;
11
use TypeError;
12
13
/**
14
 * Class Game
15
 *
16
 * @package TournamentGenerator
17
 * @author  Tomáš Vojík <[email protected]>
18
 * @since   0.1
19
 */
20
class Game implements WithId, Exportable, JsonSerializable
21
{
22
23
	/** @var int Autoincrement game id */
24
	protected int $id;
25
	/** @var Team[] Teams playing this game */
26
	protected array $teams;
27
	/** @var array[] List of scores - [teamId => [score => value, type => win|loss|draw|second|third]] pairs */
28
	protected array $results = [];
29
	/** @var Group Group that the game belongs to */
30
	protected Group $group;
31
	/** @var int|string Id of the winning team */
32
	protected $winId;
33
	/** @var int|string Id of the losing team */
34
	protected $lossId;
35
	/** @var int|string Id of the second team */
36
	private $secondId;
37
	/** @var int|string Id of the third team */
38
	private $thirdId;
39
	/** @var int[]|string[] Ids of the teams that have drawn */
40
	private array $drawIds = [];
41
42
	/**
43
	 * Game constructor.
44
	 *
45
	 * @param Team[] $teams Teams that play in this game
46
	 * @param Group  $group Group that this game belongs to
47 207
	 */
48 207
	public function __construct(array $teams, Group $group) {
49 207
		$this->group = $group;
50 206
		$this->addTeam(...$teams);
51
	}
52
53
	/**
54
	 * Add teams to this game
55
	 *
56
	 * @param Team[] $teams
57
	 *
58
	 * @return $this
59 206
	 */
60 206
	public function addTeam(Team ...$teams) : Game {
61 206
		foreach ($teams as $team) {
62 206
			$this->teams[] = $team;
63
			$team->addGame($this);
64
65 206
			// Log games with this added teams to all teams added before
66 206
			foreach ($this->teams as $team2) {
67 206
				if ($team === $team2) {
68
					continue;
69 206
				}
70 206
				$team->addGameWith($team2, $this->group);
71
				$team2->addGameWith($team, $this->group);
72
			}
73 206
		}
74
		return $this;
75
	}
76
77
	/**
78
	 * Get the parent group object
79
	 *
80
	 * @return Group
81 206
	 */
82 206
	public function getGroup() : Group {
83
		return $this->group;
84
	}
85
86
	/**
87
	 * Get all teams from the game
88
	 *
89
	 * @return Team[]
90 33
	 */
91 33
	public function getTeams() : array {
92
		return $this->teams;
93
	}
94
95
	/**
96
	 * Get all team ids from this game
97
	 *
98
	 * @return string[]|int[]
99 32
	 */
100 32
	public function getTeamsIds() : array {
101 32
		return array_map(static function($a) {
102 32
			return $a->getId();
103
		}, $this->teams);
104
	}
105
106
	/**
107
	 * Get results
108
	 *
109
	 * @return array[]
110 26
	 */
111 26
	public function getResults() : array {
112 26
		ksort($this->results);
113
		return $this->results;
114
	}
115
116
	/**
117
	 * Set the game's results
118
	 *
119
	 * Results is an array of [teamId => teamScore] key-value pairs.
120
	 *
121
	 * @param int[] $results array of [teamId => teamScore] key-value pairs
122
	 *
123
	 * @return $this
124
	 * @throws Exception
125 82
	 */
126 82
	public function setResults(array $results = []) : Game {
127 82
		if (count($this->results) === 0) {
128
			$this->resetResults();
129 82
		}
130 82
		arsort($results);
131 82
		$i = 1;
132 82
		foreach ($results as $id => $score) {
133 1
			if (!is_numeric($score)) {
134
				throw new TypeError('Score passed to TournamentGenerator\Game::setResults() must be of the type numeric, '.gettype($score).' given');
135 81
			}
136 81
			$team = $this->getTeam($id);
137 1
			if (!isset($team)) {
138
				throw new Exception('Couldn\'t find team with id of "'.$id.'"');
139 80
			}
140 80
			$this->setTeamScore($i, $team, $results, $score);
141
			$i++;
142 80
		}
143
		return $this;
144
	}
145
146
	/**
147
	 * Reset the game's results
148
	 *
149
	 * @post Scores are removed
150
	 * @post Team points are subtracted
151
	 *
152
	 * @return $this
153
	 * @throws Exception
154 82
	 */
155 82
	public function resetResults() : Game {
156 20
		foreach ($this->results as $teamId => $score) {
157
			$this->resetTeamScore($teamId, $score);
158 82
		}
159 82
		$this->results = [];
160
		return $this;
161
	}
162
163
	/**
164
	 * Resets a score for a team
165
	 *
166
	 * @param string|int $teamId
167
	 * @param array      $score
168
	 *
169
	 * @throws Exception
170
	 * @noinspection NullPointerExceptionInspection
171 20
	 */
172 20
	protected function resetTeamScore($teamId, array $score) : void {
173 20
		$team = $this->getTeam($teamId);
174 20
		$team->groupResults[$this->group->getId()]['score'] -= $score['score'];
175 20
		$team->removeScore($score['score']);
176 20
		switch ($score['type']) {
177 19
			case 'win':
178 19
				$team->removeWin($this->group->getId());
179 20
				break;
180 1
			case 'draw':
181 1
				$team->removeDraw($this->group->getId());
182 19
				break;
183 19
			case 'loss':
184 19
				$team->removeLoss($this->group->getId());
185 2
				break;
186 2
			case 'second':
187 2
				$team->removeSecond($this->group->getId());
188 1
				break;
189 1
			case 'third':
190 1
				$team->removeThird($this->group->getId());
191
				break;
192 20
		}
193
	}
194
195
	/**
196
	 * Get team by ID
197
	 *
198
	 * @param string|int $id Team ID
199
	 *
200
	 * @return Team|null
201 83
	 */
202 83
	public function getTeam($id) : ?Team {
203 83
		$key = array_search($id, array_map(static function($a) {
204 83
			return $a->getId();
205 83
		}, $this->teams),   true);
206
		return ($key !== false ? $this->teams[$key] : null);
207
	}
208
209
	/**
210
	 * Set a score for a team
211
	 *
212
	 * @param int   $position Team's position
213
	 * @param Team  $team
214
	 * @param int[] $results  The whole results set
215
	 * @param int   $score    Team's score
216
	 *
217
	 * @throws Exception
218 80
	 */
219 80
	protected function setTeamScore(int $position, Team $team, array $results, int $score) : void {
220 80
		$this->results[$team->getId()] = ['score' => $score];
221 80
		$team->addScore($score);
222 80
		switch ($this->group->getInGame()) {
223 70
			case 2:
224 70
				$this->setResults2($position, $score, $results, $team);
225 10
				break;
226 1
			case 3:
227 1
				$this->setResults3($position, $team);
228 9
				break;
229 9
			case 4:
230 9
				$this->setResults4($position, $team);
231
				break;
232 80
		}
233 80
		$team->groupResults[$this->group->getId()]['score'] += $score;
234
	}
235
236
	/**
237
	 * Set results for 2 team game
238
	 *
239
	 * @param int   $teamPosition Team's position (first = 1, second = 2)
240
	 * @param int   $score        Team's score
241
	 * @param int[] $results      Results array (for draw checking)
242
	 * @param Team  $team         Team object
243
	 *
244
	 * @return $this
245
	 * @throws Exception
246 70
	 */
247 70
	protected function setResults2(int $teamPosition, int $score, array $results, Team $team) : Game {
248 70
		if (count(array_filter($results, static function($a) use ($score) {
249 70
				return $a === $score;
250 15
			})) > 1) {
251 15
			$this->drawIds[] = $team->getId();
252 15
			$team->addDraw($this->group->getId());
253
			$this->results[$team->getId()] += ['points' => $this->group->getDrawPoints(), 'type' => 'draw'];
254 68
		}
255 68
		elseif ($teamPosition === 1) {
256 68
			$this->winId = $team->getId();
257 68
			$team->addWin($this->group->getId());
258
			$this->results[$team->getId()] += ['points' => $this->group->getWinPoints(), 'type' => 'win'];
259
		}
260 68
		else {
261 68
			$this->lossId = $team->getId();
262 68
			$team->addLoss($this->group->getId());
263
			$this->results[$team->getId()] += ['points' => $this->group->getLostPoints(), 'type' => 'loss'];
264 70
		}
265
		return $this;
266
	}
267
268
	/**
269
	 * Set results for 3 team game
270
	 *
271
	 * @param int  $teamPosition Team's position (first = 1, second = 2, third = 3)
272
	 * @param Team $team         Team object
273
	 *
274
	 * @return $this
275
	 * @throws Exception
276 1
	 */
277
	protected function setResults3(int $teamPosition, Team $team) : Game {
278 1
		switch ($teamPosition) {
279 1
			case 1:
280 1
				$this->winId = $team->getId();
281 1
				$team->addWin($this->group->getId());
282 1
				$this->results[$team->getId()] += ['points' => $this->group->getWinPoints(), 'type' => 'win'];
283 1
				break;
284 1
			case 2:
285 1
				$this->secondId = $team->getId();
286 1
				$team->addSecond($this->group->getId());
287 1
				$this->results[$team->getId()] += ['points' => $this->group->getSecondPoints(), 'type' => 'second'];
288 1
				break;
289 1
			case 3:
290 1
				$this->lossId = $team->getId();
291 1
				$team->addLoss($this->group->getId());
292 1
				$this->results[$team->getId()] += ['points' => $this->group->getLostPoints(), 'type' => 'loss'];
293
				break;
294 1
		}
295
		return $this;
296
	}
297
298
	/**
299
	 * Set results for 4 team game
300
	 *
301
	 * @param int  $teamPosition Team's position (first = 1, second = 2, third = 3, fourth = 4)
302
	 * @param Team $team         Team object
303
	 *
304
	 * @return Game
305
	 * @throws Exception
306 9
	 */
307
	protected function setResults4(int $teamPosition, Team $team) : Game {
308 9
		switch ($teamPosition) {
309 9
			case 1:
310 9
				$this->winId = $team->getId();
311 9
				$team->addWin($this->group->getId());
312 9
				$this->results[$team->getId()] += ['points' => $this->group->getWinPoints(), 'type' => 'win'];
313 9
				break;
314 9
			case 2:
315 9
				$this->secondId = $team->getId();
316 9
				$team->addSecond($this->group->getId());
317 9
				$this->results[$team->getId()] += ['points' => $this->group->getSecondPoints(), 'type' => 'second'];
318 9
				break;
319 9
			case 3:
320 9
				$this->thirdId = $team->getId();
321 9
				$team->addThird($this->group->getId());
322 9
				$this->results[$team->getId()] += ['points' => $this->group->getThirdPoints(), 'type' => 'third'];
323 9
				break;
324 9
			case 4:
325 9
				$this->lossId = $team->getId();
326 9
				$team->addLoss($this->group->getId());
327 9
				$this->results[$team->getId()] += ['points' => $this->group->getLostPoints(), 'type' => 'loss'];
328
				break;
329 9
		}
330
		return $this;
331
	}
332
333
	/**
334
	 * Get the winning team's id
335
	 *
336
	 * @return int|string
337 2
	 */
338 2
	public function getWin() {
339
		return $this->winId;
340
	}
341
342
	/**
343
	 * Get the losing team's id
344
	 *
345
	 * @return int|string
346 2
	 */
347 2
	public function getLoss() {
348
		return $this->lossId;
349
	}
350
351
	/**
352
	 * Get the second team's id
353
	 *
354
	 * @return int|string
355 1
	 */
356 1
	public function getSecond() {
357
		return $this->secondId;
358
	}
359
360
	/**
361
	 * Get the third team's id
362
	 *
363
	 * @return int|string
364 1
	 */
365 1
	public function getThird() {
366
		return $this->thirdId;
367
	}
368
369
	/**
370
	 * Get the draws teams' id
371
	 *
372
	 * @return int[]|string[]
373 1
	 */
374 1
	public function getDraw() : array {
375
		return $this->drawIds;
376
	}
377
378
	/**
379
	 * Check if the game has been played
380
	 *
381
	 * @return bool
382 36
	 */
383 36
	public function isPlayed() : bool {
384
		return count($this->results) > 0;
385
	}
386
387
	/**
388
	 * @return int
389
	 * @since 0.5
390 107
	 */
391 107
	public function getId() : int {
392
		return $this->id;
393
	}
394
395
	/**
396
	 * @param int $id
397
	 *
398
	 * @return Game
399
	 * @since 0.5
400 189
	 */
401 189
	public function setId($id) : Game {
402 1
		if (!is_int($id)) {
0 ignored issues
show
introduced by
The condition is_int($id) is always true.
Loading history...
403
			throw new TypeError('Game\'s ID needs to be an integer.');
404 189
		}
405 189
		$this->id = $id;
406
		return $this;
407
	}
408
409
	/**
410
	 * @inheritDoc
411
	 * @return array
412
	 */
413 4
	public function jsonSerialize() : array {
414 4
		return $this->export()->get();
415
	}
416
417
	/**
418
	 * Prepares an export query for the object
419
	 *
420
	 * @return ExporterInterface Exporter for this class
421
	 */
422
	public function export() : ExporterInterface {
423
		return GameExporter::start($this);
424
	}
425
}
426