Round   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 224
Duplicated Lines 0 %

Test Coverage

Coverage 91.03%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 71
dl 0
loc 224
ccs 71
cts 78
cp 0.9103
rs 10
c 1
b 0
f 0
wmc 29

13 Methods

Rating   Name   Duplication   Size   Complexity  
A jsonSerialize() 0 7 1
A progress() 0 5 2
A orderGroups() 0 6 1
A addGroup() 0 5 2
A __construct() 0 7 1
A group() 0 4 1
A getGroupsIds() 0 5 1
A simulate() 0 3 1
A splitTeams() 0 20 5
A splitTeamsEvenly() 0 21 6
A resetGames() 0 5 2
A isPlayed() 0 10 4
A genGames() 0 5 2
1
<?php
2
3
namespace TournamentGenerator;
4
5
use Exception;
6
use TournamentGenerator\Containers\GameContainer;
7
use TournamentGenerator\Containers\HierarchyContainer;
8
use TournamentGenerator\Containers\TeamContainer;
9
use TournamentGenerator\Helpers\Functions;
10
use TournamentGenerator\Interfaces\WithGames;
11
use TournamentGenerator\Interfaces\WithGroups;
12
use TournamentGenerator\Interfaces\WithSkipSetters;
13
use TournamentGenerator\Interfaces\WithTeams;
14
use TournamentGenerator\Interfaces\WithTeams as WithTeamsInterface;
15
use TournamentGenerator\Traits\WithGames as WithGamesTrait;
16
use TournamentGenerator\Traits\WithGroups as WithGroupsTrait;
17
use TournamentGenerator\Traits\WithSkipSetters as WithSkipSettersTrait;
18
use TournamentGenerator\Traits\WithTeams as WithTeamsTrait;
19
20
/**
21
 * Tournament round
22
 *
23
 * Round is a container for tournament groups. Groups in a round are played at the same time.
24
 * This modifies the generation of games - generate all games for each group and play them in alternating order (game 1 from group 1, game 1 from group 2, game 2 from group 1, ...).
25
 *
26
 * @package TournamentGenerator
27
 * @author  Tomáš Vojík <[email protected]>
28
 * @since   0.1
29
 */
30
class Round extends HierarchyBase implements WithSkipSetters, WithTeams, WithGroups, WithGames
31
{
32
	use WithTeamsTrait;
33
	use WithGroupsTrait;
34
	use WithSkipSettersTrait;
35
	use WithGamesTrait;
36
37
	/**
38
	 * Round constructor.
39
	 *
40
	 * @param string          $name Round name
41
	 * @param string|int|null $id   Round id - if omitted -> it is generated automatically as unique string
42
	 */
43 162
	public function __construct(string $name = '', $id = null) {
44 162
		$this->setName($name);
45
		/** @infection-ignore-all */
46 162
		$this->setId($id ?? uniqid('', false));
47 162
		$this->games = new GameContainer($this->id);
48 162
		$this->teams = new TeamContainer($this->id);
49 162
		$this->container = new HierarchyContainer($this->id);
50 162
	}
51
52
	/**
53
	 * Adds one or more group to round
54
	 *
55
	 * @param Group ...$groups
56
	 *
57
	 * @return $this
58
	 * @throws Exception
59
	 */
60 12
	public function addGroup(Group ...$groups) : Round {
61 12
		foreach ($groups as $group) {
62 12
			$this->insertIntoContainer($group);
63
		}
64 12
		return $this;
65
	}
66
67
	/**
68
	 * Creates a new group and adds it to round
69
	 *
70
	 * @param string          $name Group name
71
	 * @param string|int|null $id   Group id - if omitted -> it is generated automatically as unique string
72
	 *
73
	 * @return Group New group
74
	 * @throws Exception
75
	 */
76 150
	public function group(string $name, $id = null) : Group {
77 150
		$g = new Group($name, $id);
78 150
		$this->insertIntoContainer($g->setSkip($this->allowSkip));
79 150
		return $g;
80
	}
81
82
	/**
83
	 * Get all group ids
84
	 *
85
	 * @return string[]|int[] Array of ids
86
	 */
87 3
	public function getGroupsIds() : array {
88 3
		$groups = $this->orderGroups();
89 3
		return array_map(static function($a) {
90 3
			return $a->getId();
91 3
		}, $groups);
92
	}
93
94
	/**
95
	 * Sort groups by their order
96
	 *
97
	 * @return Group[] Sorted groups
98
	 */
99 4
	public function orderGroups() : array {
100 4
		$groups = $this->getGroups();
101 4
		usort($groups, static function($a, $b) {
102 4
			return $a->getOrder() - $b->getOrder();
103 4
		});
104 4
		return $groups;
105
	}
106
107
	/**
108
	 * Generate all games
109
	 *
110
	 * @return array
111
	 * @throws Exception
112
	 */
113 47
	public function genGames() : array {
114 47
		foreach ($this->getGroups() as $group) {
115 47
			$group->genGames();
116
		}
117 46
		return $this->getGames();
118
	}
119
120
	/**
121
	 * Check if all games in this round has been played
122
	 *
123
	 * @return bool
124
	 */
125 7
	public function isPlayed() : bool {
126 7
		if (count($this->games) === 0) {
127 5
			return false;
128
		}
129 5
		foreach ($this->getGroups() as $group) {
130 5
			if (!$group->isPlayed()) {
131 1
				return false;
132
			}
133
		}
134 5
		return true;
135
	}
136
137
	/**
138
	 * Split teams into its Groups
139
	 *
140
	 * @param Group[] $groups
141
	 *
142
	 * @return $this
143
	 * @throws Exception
144
	 * @noinspection CallableParameterUseCaseInTypeContextInspection
145
	 */
146 43
	public function splitTeams(Group ...$groups) : Round {
147 43
		if (count($groups) === 0) {
148 42
			$groups = $this->getGroups();
149
		}
150
151 43
		$teams = $this->getTeams(true, Constants::SEED);
152 43
		if ($this::isSeeded($teams)) {
153 2
			Functions::sortAlternate($teams);
154
		}
155
		else {
156 41
			shuffle($teams);
157
		}
158
159 43
		$split = ceil(count($teams) / count($groups));
160 43
		foreach ($groups as $where) {
161 43
			if (count($teams) > 0) {
162 43
				$where->addTeam(...array_splice($teams, 0, $split));
0 ignored issues
show
Bug introduced by
$split of type double is incompatible with the type integer|null expected by parameter $length of array_splice(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

162
				$where->addTeam(...array_splice($teams, 0, /** @scrutinizer ignore-type */ $split));
Loading history...
163
			}
164
		}
165 43
		return $this;
166
	}
167
168
	/**
169
	 * Split teams into its Groups
170
	 *
171
	 * @param Group ...$wheres
172
	 *
173
	 * @return \TournamentGenerator\Traits\WithTeams
174
	 * @throws Exception
175
	 * @noinspection CallableParameterUseCaseInTypeContextInspection
176
	 */
177 14
	public function splitTeamsEvenly(Group ...$wheres) : WithTeamsInterface {
178 14
		if (count($wheres) === 0) {
179 14
			$wheres = $this->getGroups();
180
		}
181
182 14
		$teams = $this->getTeams(true, Constants::SEED);
183 14
		if ($this::isSeeded($teams)) {
184
			Functions::sortAlternate($teams);
185
		}
186
		else {
187 14
			shuffle($teams);
188
		}
189
190 14
		while (count($teams) > 0) {
191 14
			foreach ($wheres as $where) {
192 14
				if (count($teams) > 0) {
193 14
					$where->addTeam(array_pop($teams));
194
				}
195
			}
196
		}
197 14
		return $this;
198
	}
199
200
	/**
201
	 * Progresses all teams from the round
202
	 *
203
	 * @param bool $blank If true -> creates dummy teams for (does not progress the real team objects) - used for simulation
204
	 *
205
	 * @return $this
206
	 * @throws Exception
207
	 */
208 46
	public function progress(bool $blank = false) : Round {
209 46
		foreach ($this->getGroups() as $group) {
210 46
			$group->progress($blank);
211
		}
212 46
		return $this;
213
	}
214
215
	/**
216
	 * Simulate all games in this round as they would be played for real
217
	 *
218
	 * @return $this
219
	 * @throws Exception
220
	 */
221 47
	public function simulate() : Round {
222 47
		Helpers\Simulator::simulateRound($this);
223 47
		return $this;
224
	}
225
226
	/**
227
	 * Reset all game results as if they were not played
228
	 *
229
	 * @post All games in this round are marked as "not played"
230
	 * @post All scores in this round are deleted
231
	 *
232
	 * @return $this
233
	 * @throws Exception
234
	 */
235 20
	public function resetGames() : Round {
236 20
		foreach ($this->getGroups() as $group) {
237 20
			$group->resetGames();
238
		}
239 20
		return $this;
240
	}
241
242
	/**
243
	 * @inheritDoc
244
	 * @return array
245
	 * @throws Exception
246
	 */
247
	public function jsonSerialize() : array {
248
		return [
249
			'id'     => $this->getId(),
250
			'name'   => $this->getName(),
251
			'games'  => $this->getGames(),
252
			'teams'  => $this->teams->ids(),
253
			'groups' => $this->queryGroups()->ids(),
254
		];
255
	}
256
}
257