Completed
Push — master ( dca578...2fbbce )
by Tomáš
09:39
created

Game::export()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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