Completed
Push — master ( a1420e...5c3586 )
by Tomáš
02:42
created

Game::setTeamScore()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 4

Importance

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