Game::getWin()   A
last analyzed

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
	 */
48 227
	public function __construct(array $teams, Group $group) {
49 227
		$this->group = $group;
50 227
		$this->addTeam(...$teams);
51 226
	}
52
53
	/**
54
	 * Add teams to this game
55
	 *
56
	 * @param Team[] $teams
57
	 *
58
	 * @return $this
59
	 */
60 226
	public function addTeam(Team ...$teams) : Game {
61 226
		foreach ($teams as $team) {
62 226
			$this->teams[] = $team;
63 226
			$team->addGame($this);
64
65
			// Log games with this added teams to all teams added before
66 226
			foreach ($this->teams as $team2) {
67 226
				if ($team === $team2) {
68 226
					continue;
69
				}
70 226
				$team->addGameWith($team2, $this->group);
71 226
				$team2->addGameWith($team, $this->group);
72
			}
73
		}
74 226
		return $this;
75
	}
76
77
	/**
78
	 * Get the parent group object
79
	 *
80
	 * @return Group
81
	 */
82 226
	public function getGroup() : Group {
83 226
		return $this->group;
84
	}
85
86
	/**
87
	 * Get all teams from the game
88
	 *
89
	 * @return Team[]
90
	 */
91 53
	public function getTeams() : array {
92 53
		return $this->teams;
93
	}
94
95
	/**
96
	 * Get all team ids from this game
97
	 *
98
	 * @return string[]|int[]
99
	 */
100 32
	public function getTeamsIds() : array {
101 32
		return array_map(static function($a) {
102 32
			return $a->getId();
103 32
		}, $this->teams);
104
	}
105
106
	/**
107
	 * Get results
108
	 *
109
	 * @return array[]
110
	 */
111 26
	public function getResults() : array {
112 26
		ksort($this->results);
113 26
		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
	 */
126 102
	public function setResults(array $results = []) : Game {
127 102
		if (count($this->results) === 0) {
128 102
			$this->resetResults();
129
		}
130 102
		arsort($results);
131 102
		$i = 1;
132 102
		foreach ($results as $id => $score) {
133 102
			if (!is_numeric($score)) {
134 1
				throw new TypeError('Score passed to TournamentGenerator\Game::setResults() must be of the type numeric, '.gettype($score).' given');
135
			}
136 101
			$team = $this->getTeam($id);
137 101
			if (!isset($team)) {
138 1
				throw new Exception('Couldn\'t find team with id of "'.$id.'"');
139
			}
140 100
			$this->setTeamScore($i, $team, $results, $score);
141 100
			$i++;
142
		}
143 100
		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
	 */
155 102
	public function resetResults() : Game {
156 102
		foreach ($this->results as $teamId => $score) {
157 26
			$this->resetTeamScore($teamId, $score);
158
		}
159 102
		$this->results = [];
160 102
		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
	 */
172 26
	protected function resetTeamScore($teamId, array $score) : void {
173 26
		$team = $this->getTeam($teamId);
174 26
		$team->groupResults[$this->group->getId()]['score'] -= $score['score'];
175 26
		$team->removeScore($score['score']);
176 26
		switch ($score['type']) {
177 26
			case 'win':
178 25
				$team->removeWin($this->group->getId());
179 25
				break;
180 26
			case 'draw':
181 1
				$team->removeDraw($this->group->getId());
182 1
				break;
183 25
			case 'loss':
184 25
				$team->removeLoss($this->group->getId());
185 25
				break;
186 2
			case 'second':
187 2
				$team->removeSecond($this->group->getId());
188 2
				break;
189 1
			case 'third':
190 1
				$team->removeThird($this->group->getId());
191 1
				break;
192
		}
193 26
	}
194
195
	/**
196
	 * Get team by ID
197
	 *
198
	 * @param string|int $id Team ID
199
	 *
200
	 * @return Team|null
201
	 */
202 103
	public function getTeam($id) : ?Team {
203 103
		$key = array_search($id, array_map(static function($a) {
204 103
			return $a->getId();
205 103
		}, $this->teams),   true);
206 103
		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
	 */
219 100
	protected function setTeamScore(int $position, Team $team, array $results, int $score) : void {
220 100
		$this->results[$team->getId()] = ['score' => $score];
221 100
		$team->addScore($score);
222 100
		switch ($this->group->getInGame()) {
223 100
			case 2:
224 90
				$this->setResults2($position, $score, $results, $team);
225 90
				break;
226 10
			case 3:
227 1
				$this->setResults3($position, $team);
228 1
				break;
229 9
			case 4:
230 9
				$this->setResults4($position, $team);
231 9
				break;
232
		}
233 100
		$team->groupResults[$this->group->getId()]['score'] += $score;
234 100
	}
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
	 */
247 90
	protected function setResults2(int $teamPosition, int $score, array $results, Team $team) : Game {
248 90
		if (count(array_filter($results, static function($a) use ($score) {
249 90
				return $a === $score;
250 90
			})) > 1) {
251 15
			$this->drawIds[] = $team->getId();
252 15
			$team->addDraw($this->group->getId());
253 15
			$this->results[$team->getId()] += ['points' => $this->group->getDrawPoints(), 'type' => 'draw'];
254
		}
255 88
		elseif ($teamPosition === 1) {
256 88
			$this->winId = $team->getId();
257 88
			$team->addWin($this->group->getId());
258 88
			$this->results[$team->getId()] += ['points' => $this->group->getWinPoints(), 'type' => 'win'];
259
		}
260
		else {
261 88
			$this->lossId = $team->getId();
262 88
			$team->addLoss($this->group->getId());
263 88
			$this->results[$team->getId()] += ['points' => $this->group->getLostPoints(), 'type' => 'loss'];
264
		}
265 90
		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
	 */
277 1
	protected function setResults3(int $teamPosition, Team $team) : Game {
278
		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 1
				break;
294
		}
295 1
		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
	 */
307 9
	protected function setResults4(int $teamPosition, Team $team) : Game {
308
		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 9
				break;
329
		}
330 9
		return $this;
331
	}
332
333
	/**
334
	 * Get the winning team's id
335
	 *
336
	 * @return int|string
337
	 */
338 16
	public function getWin() {
339 16
		return $this->winId;
340
	}
341
342
	/**
343
	 * Get the losing team's id
344
	 *
345
	 * @return int|string
346
	 */
347 2
	public function getLoss() {
348 2
		return $this->lossId;
349
	}
350
351
	/**
352
	 * Get the second team's id
353
	 *
354
	 * @return int|string
355
	 */
356 1
	public function getSecond() {
357 1
		return $this->secondId;
358
	}
359
360
	/**
361
	 * Get the third team's id
362
	 *
363
	 * @return int|string
364
	 */
365 1
	public function getThird() {
366 1
		return $this->thirdId;
367
	}
368
369
	/**
370
	 * Get the draws teams' id
371
	 *
372
	 * @return int[]|string[]
373
	 */
374 15
	public function getDraw() : array {
375 15
		return $this->drawIds;
376
	}
377
378
	/**
379
	 * Check if the game has been played
380
	 *
381
	 * @return bool
382
	 */
383 56
	public function isPlayed() : bool {
384 56
		return count($this->results) > 0;
385
	}
386
387
	/**
388
	 * @return int
389
	 * @since 0.5
390
	 */
391 107
	public function getId() : int {
392 107
		return $this->id;
393
	}
394
395
	/**
396
	 * @param int $id
397
	 *
398
	 * @return Game
399
	 * @since 0.5
400
	 */
401 209
	public function setId($id) : Game {
402 209
		if (!is_int($id)) {
0 ignored issues
show
introduced by
The condition is_int($id) is always true.
Loading history...
403 1
			throw new TypeError('Game\'s ID needs to be an integer.');
404
		}
405 209
		$this->id = $id;
406 209
		return $this;
407
	}
408
409
	/**
410
	 * @inheritDoc
411
	 * @return array
412
	 */
413
	public function jsonSerialize() : array {
414
		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 4
	public function export() : ExporterInterface {
423 4
		return GameExporter::start($this);
424
	}
425
}
426