Passed
Push — master ( 795926...7012fc )
by Tomáš
11:11
created

Game::isPlayed()   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
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 2
ccs 2
cts 2
cp 1
crap 1
rs 10
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 100
	public function __construct(array $teams, Group $group) {
42 100
		$this->group = $group;
43 100
		$this->addTeam(...$teams);
44 99
	}
45
46
	/**
47
	 * Add teams to this game
48
	 *
49
	 * @param Team[] $teams
50
	 *
51
	 * @return $this
52
	 */
53 99
	public function addTeam(Team ...$teams) : Game {
54 99
		foreach ($teams as $team) {
55 99
			$this->teams[] = $team;
56 99
			$team->addGame($this);
57
58
			// Log games with this added teams to all teams added before
59 99
			foreach ($this->teams as $team2) {
60 99
				if ($team === $team2) {
61 99
					continue;
62
				}
63 99
				$team->addGameWith($team2, $this->group);
64 99
				$team2->addGameWith($team, $this->group);
65
			}
66
		}
67 99
		return $this;
68
	}
69
70
	/**
71
	 * Get the parent group object
72
	 *
73
	 * @return Group
74
	 */
75 99
	public function getGroup() : Group {
76 99
		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 24
	public function getTeamsIds() : array {
94 24
		return array_map(static function($a) {
95 24
			return $a->getId();
96 24
		}, $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
		$inGame = $this->group->getInGame();
125 75
		$i = 1;
126 75
		foreach ($results as $id => $score) {
127 75
			if (!is_numeric($score)) {
128 1
				throw new TypeError('Score passed to TournamentGenerator\Game::setResults() must be of the type numeric, '.gettype($score).' given');
129
			}
130 74
			$team = $this->getTeam($id);
131 74
			if (!isset($team)) {
132 1
				throw new Exception('Couldn\'t find team with id of "'.$id.'"');
133
			}
134 73
			$this->results[$team->getId()] = ['score' => $score];
135 73
			$team->addScore($score);
136
			switch ($inGame) {
137 73
				case 2:
138 63
					$this->setResults2($i, $score, $results, $team);
139 63
					break;
140 10
				case 3:
141 1
					$this->setResults3($i, $team);
142 1
					break;
143 9
				case 4:
144 9
					$this->setResults4($i, $team);
145 9
					break;
146
			}
147 73
			$team->groupResults[$this->group->getId()]['score'] += $score;
148 73
			$i++;
149
		}
150 73
		return $this;
151
	}
152
153
	/**
154
	 * Reset the game's results
155
	 *
156
	 * @post Scores are removed
157
	 * @post Team points are subtracted
158
	 *
159
	 * @return $this
160
	 * @throws Exception
161
	 */
162 75
	public function resetResults() : Game {
163 75
		foreach ($this->results as $teamId => $score) {
164 20
			$team = $this->getTeam($teamId);
165 20
			if (!isset($team)) {
166
				throw new Exception('Cannot find team with id: '.$teamId.' in game');
167
			}
168 20
			$team->groupResults[$this->group->getId()]['score'] -= $score['score'];
169 20
			$team->removeScore($score['score']);
170 20
			switch ($score['type']) {
171 20
				case 'win':
172 19
					$team->removeWin($this->group->getId());
173 19
					break;
174 20
				case 'draw':
175 1
					$team->removeDraw($this->group->getId());
176 1
					break;
177 19
				case 'loss':
178 19
					$team->removeLoss($this->group->getId());
179 19
					break;
180 2
				case 'second':
181 2
					$team->removeSecond($this->group->getId());
182 2
					break;
183 1
				case 'third':
184 1
					$team->removeThird($this->group->getId());
185 1
					break;
186
			}
187
		}
188 75
		$this->results = [];
189 75
		return $this;
190
	}
191
192
	/**
193
	 * Get team by ID
194
	 *
195
	 * @param string|int $id Team ID
196
	 *
197
	 * @return Team|null
198
	 */
199 76
	public function getTeam($id) : ?Team {
200 76
		$key = array_search($id, array_map(static function($a) {
201 76
			return $a->getId();
202 76
		}, $this->teams), true);
203 76
		return ($key !== false ? $this->teams[$key] : null);
204
	}
205
206
	/**
207
	 * Set results for 2 team game
208
	 *
209
	 * @param int   $teamPosition Team's position (first = 1, second = 2)
210
	 * @param int   $score        Team's score
211
	 * @param int[] $results      Results array (for draw checking)
212
	 * @param Team  $team         Team object
213
	 *
214
	 * @return $this
215
	 * @throws Exception
216
	 */
217 63
	protected function setResults2(int $teamPosition, int $score, array $results, Team $team) : Game {
218 63
		if (count(array_filter($results, static function($a) use ($score) {
219 63
				return $a === $score;
220 63
			})) > 1) {
221 13
			$this->drawIds[] = $team->getId();
222 13
			$team->addDraw($this->group->getId());
223 13
			$this->results[$team->getId()] += ['points' => $this->group->getDrawPoints(), 'type' => 'draw'];
224
		}
225 61
		elseif ($teamPosition === 1) {
226 61
			$this->winId = $team->getId();
227 61
			$team->addWin($this->group->getId());
228 61
			$this->results[$team->getId()] += ['points' => $this->group->getWinPoints(), 'type' => 'win'];
229
		}
230
		else {
231 61
			$this->lossId = $team->getId();
232 61
			$team->addLoss($this->group->getId());
233 61
			$this->results[$team->getId()] += ['points' => $this->group->getLostPoints(), 'type' => 'loss'];
234
		}
235 63
		return $this;
236
	}
237
238
	/**
239
	 * Set results for 3 team game
240
	 *
241
	 * @param int  $teamPosition Team's position (first = 1, second = 2, third = 3)
242
	 * @param Team $team         Team object
243
	 *
244
	 * @return $this
245
	 * @throws Exception
246
	 */
247 1
	protected function setResults3(int $teamPosition, Team $team) : Game {
248
		switch ($teamPosition) {
249 1
			case 1:
250 1
				$this->winId = $team->getId();
251 1
				$team->addWin($this->group->getId());
252 1
				$this->results[$team->getId()] += ['points' => $this->group->getWinPoints(), 'type' => 'win'];
253 1
				break;
254 1
			case 2:
255 1
				$this->secondId = $team->getId();
256 1
				$team->addSecond($this->group->getId());
257 1
				$this->results[$team->getId()] += ['points' => $this->group->getSecondPoints(), 'type' => 'second'];
258 1
				break;
259 1
			case 3:
260 1
				$this->lossId = $team->getId();
261 1
				$team->addLoss($this->group->getId());
262 1
				$this->results[$team->getId()] += ['points' => $this->group->getLostPoints(), 'type' => 'loss'];
263 1
				break;
264
		}
265 1
		return $this;
266
	}
267
268
	/**
269
	 * Set results for 4 team game
270
	 *
271
	 * @param int  $teamPosition Team's position (first = 1, second = 2, third = 3, fourth = 4)
272
	 * @param Team $team         Team object
273
	 *
274
	 * @return Game
275
	 * @throws Exception
276
	 */
277 9
	protected function setResults4(int $teamPosition, Team $team) : Game {
278
		switch ($teamPosition) {
279 9
			case 1:
280 9
				$this->winId = $team->getId();
281 9
				$team->addWin($this->group->getId());
282 9
				$this->results[$team->getId()] += ['points' => $this->group->getWinPoints(), 'type' => 'win'];
283 9
				break;
284 9
			case 2:
285 9
				$this->secondId = $team->getId();
286 9
				$team->addSecond($this->group->getId());
287 9
				$this->results[$team->getId()] += ['points' => $this->group->getSecondPoints(), 'type' => 'second'];
288 9
				break;
289 9
			case 3:
290 9
				$this->thirdId = $team->getId();
291 9
				$team->addThird($this->group->getId());
292 9
				$this->results[$team->getId()] += ['points' => $this->group->getThirdPoints(), 'type' => 'third'];
293 9
				break;
294 9
			case 4:
295 9
				$this->lossId = $team->getId();
296 9
				$team->addLoss($this->group->getId());
297 9
				$this->results[$team->getId()] += ['points' => $this->group->getLostPoints(), 'type' => 'loss'];
298 9
				break;
299
		}
300 9
		return $this;
301
	}
302
303
	/**
304
	 * Get the winning team's id
305
	 *
306
	 * @return int|string
307
	 */
308 2
	public function getWin() {
309 2
		return $this->winId;
310
	}
311
312
	/**
313
	 * Get the losing team's id
314
	 *
315
	 * @return int|string
316
	 */
317 2
	public function getLoss() {
318 2
		return $this->lossId;
319
	}
320
321
	/**
322
	 * Get the second team's id
323
	 *
324
	 * @return int|string
325
	 */
326 1
	public function getSecond() {
327 1
		return $this->secondId;
328
	}
329
330
	/**
331
	 * Get the third team's id
332
	 *
333
	 * @return int|string
334
	 */
335 1
	public function getThird() {
336 1
		return $this->thirdId;
337
	}
338
339
	/**
340
	 * Get the draws teams' id
341
	 *
342
	 * @return int[]|string[]
343
	 */
344 1
	public function getDraw() : array {
345 1
		return $this->drawIds;
346
	}
347
348
	/**
349
	 * Check if the game has been played
350
	 *
351
	 * @return bool
352
	 */
353 28
	public function isPlayed() : bool {
354 28
		return count($this->results) > 0;
355
	}
356
}
357