Completed
Push — master ( 5c3586...68bdab )
by Tomáš
02:53
created

Game::setId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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