Passed
Branch master (7949ab)
by Tomáš
02:07
created

Generator::r_rGames()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 15
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 13
nc 8
nop 1
dl 0
loc 15
ccs 14
cts 14
cp 1
crap 5
rs 9.5222
c 0
b 0
f 0
1
<?php
2
3
namespace TournamentGenerator\Utilis;
4
5
/**
6
 *
7
 */
8
class Generator implements \TournamentGenerator\WithGeneratorSetters, \TournamentGenerator\WithSkipSetters
9
{
10
11
	private $group = null;
12
	private $type = \TournamentGenerator\Constants::ROUND_ROBIN; // TYPE OF ROUND TO CREATE A LAYOUT
13
	private $inGame = 2; // NUMBER OF TEAMS IN ONE GAME - 2/3/4
14
	private $maxSize = 4; // MAX SIZE OF GROUP BEFORE SPLIT
15
	private $allowSkip = false; // IF IS NUMBER OF TEAMS LESS THAN $this->inGame THEN SKIP PLAYING THIS GROUP
16
17 127
	function __construct(\TournamentGenerator\Group $group) {
18 127
		$this->group = $group;
19 127
	}
20
21 1
	public function allowSkip(){
22 1
		$this->allowSkip = true;
23 1
		return $this;
24
	}
25 1
	public function disallowSkip(){
26 1
		$this->allowSkip = false;
27 1
		return $this;
28
	}
29 49
	public function setSkip(bool $skip) {
30 49
		$this->allowSkip = $skip;
31 49
		return $this;
32
	}
33 2
	public function getSkip() {
34 2
		return $this->allowSkip;
35
	}
36
37
38 39
	public function setType(/** @scrutinizer ignore-all */ string $type = \TournamentGenerator\Constants::ROUND_ROBIN) {
39 39
		if (in_array($type, \TournamentGenerator\Constants::GroupTypes)) $this->type = $type;
40 1
		else throw new \Exception('Unknown group type: '.$type);
41 39
		return $this;
42
	}
43 1
	public function getType() {
44 1
		return $this->type;
45
	}
46
47 51
	public function setInGame(int $inGame) {
48 51
		if ($inGame < 2 ||  $inGame > 4) throw new \Exception('Expected 2,3 or 4 as inGame '.$inGame.' given');
49 51
		$this->inGame = $inGame;
50 51
		return $this;
51
	}
52 74
	public function getInGame() {
53 74
		return $this->inGame;
54
	}
55
56 7
	public function setMaxSize(int $maxSize) {
57 7
		if ($maxSize < 2) throw new \Exception('Max group size has to be at least 2, '.$maxSize.' given');
58 7
		$this->maxSize = $maxSize;
59 7
		return $this;
60
	}
61 1
	public function getMaxSize() {
62 1
		return $this->maxSize;
63
	}
64
65 41
	public function genGames() {
66 41
		switch ($this->type) {
67
			case \TournamentGenerator\Constants::ROUND_ROBIN:
68 31
					$this->group->addGame($this->r_rGames());
69 31
				break;
70
			case \TournamentGenerator\Constants::ROUND_TWO:
71 9
					$this->two_twoGames();
72 8
				break;
73
			case \TournamentGenerator\Constants::ROUND_SPLIT:
74 5
				$this->cond_splitGames();
75 5
				break;
76
		}
77 40
		return $this->group->getGames();
78
	}
79 34
	private function r_rGames(array $teams = []) {
80 34
		$games = [];
81 34
		if (count($teams) === 0) $teams = $this->group->getTeams();
82 34
		switch ($this->inGame) {
83 34
			case 2:
84 29
				$games = Generator::circle_genGames2($teams, $this->group);
85 29
				break;
86 5
			case 3:
87 2
				$games = $this->r_r3Games($teams, $games);
88 2
				break;
89 3
			case 4:
90 3
				$games = $this->r_r4Games($teams, $games);
91 3
				break;
92
		}
93 34
		return $games;
94
	}
95 5
	private function r_r3Games(array $teams, array &$games, \TournamentGenerator\Team $lockedTeam1 = null) {
96 5
		$teamsB = $teams;
97 5
		while (count($teamsB) >= 3) {
98 5
			$lockedTeam = array_shift($teamsB);
99 5
			$gamesTemp = Generator::circle_genGames2($teamsB, $this->group);
100 5
			foreach ($gamesTemp as $game) {
101 5
				if (isset($lockedTeam1)) $game->addTeam($lockedTeam1);
102 5
				$game->addTeam($lockedTeam);
103
			}
104 5
			$games = array_merge($games, $gamesTemp);
105
		}
106 5
		return $games;
107
	}
108 3
	private function r_r4Games(array $teams, array &$games) {
109 3
		$teamsB = $teams;
110 3
		$lockedTeam1 = array_shift($teamsB);
111 3
		while (count($teamsB) >= 4) {
112 3
			$this->r_r3Games($teamsB, $games, $lockedTeam1);
113 3
			$lockedTeam1 = array_shift($teamsB);
114
		}
115 3
		$games[] = new \TournamentGenerator\Game(array_merge([$lockedTeam1], $teamsB), $this->group);
116 3
		return $games;
117
	}
118 9
	private function two_twoGames(array $teams = []) {
119 9
		if (count($teams) === 0) $teams = $this->group->getTeams();
120 9
		$discard = [];
121 9
		shuffle($teams);
122 9
		$count = count($teams);
123 9
		while (count($teams) % $this->inGame !== 0) { $discard[] = array_shift($teams); }
124
125 9
		while (count($teams) > 0) {
126 9
			$tInGame = [];
127 9
			for ($i=0; $i < $this->inGame; $i++) { $tInGame[] = array_shift($teams); }
128 9
			$this->group->game($tInGame);
129
		}
130
131 9
		if (count($discard) > 0 && !$this->allowSkip) throw new \Exception('Couldn\'t make games with all teams. Expected k*'.$this->inGame.' teams '.$count.' teams given - discarting '.count($discard).' teams ('.implode(', ', $discard).') in group '.$this->group.' - allow skip '.($this->allowSkip ? 'True' : 'False'));
132
133 8
		return $this;
134
	}
135 5
	private function cond_splitGames(array $teams = []) {
136 5
		$games = [];
137 5
		if (count($teams) === 0) $teams = $this->group->getTeams();
138
139 5
		if (count($teams) > $this->maxSize) {
140 4
			$groups = array_chunk($teams, /** @scrutinizer ignore-type */ ceil(count($teams)/ceil(count($teams)/$this->maxSize))); // SPLIT TEAMS INTO GROUP OF MAXIMUM SIZE OF $this->maxSize
141 4
			foreach ($groups as $group) { $games[] = $this->r_rGames($group); }
142 4
			$g = 0;
143 4
			foreach ($games as $group) {	$g += count($group); }
144 4
			while ($g > 0) {
145 4
				foreach ($games as $key => $group) {
146 4
					$this->group->addGame(array_shift($games[$key]));
147 4
					if (count($games[$key]) === 0) unset($games[$key]);
148 4
					$g--;
149
				}
150
			}
151 4
			return $this;
152
		}
153 1
		$this->group->addGame($this->r_rGames());
154
155 1
		return $this;
156
	}
157
158 22
	public function orderGames() {
159 22
		$sorter = new Sorter\Games($this->group);
160
161 22
		return $sorter->orderGames();
162
	}
163
164
	// GENERATES A ROBIN-ROBIN BRACKET
165 34
	public static function circle_genGames2(array $teams = [], \tournamentGenerator\Group $group) {
166 34
		$bracket = []; // ARRAY OF GAMES
167
168 34
		if (count($teams) % 2 != 0) $teams[] = \TournamentGenerator\Constants::DUMMY_TEAM; // IF NOT EVEN NUMBER OF TEAMS, ADD DUMMY
169
170 34
		shuffle($teams); // SHUFFLE TEAMS FOR MORE RANDOMNESS
171
172 34
		for ($i=0; $i < count($teams)-1; $i++) {
173 34
			$bracket = array_merge($bracket, Generator::circle_saveBracket($teams, $group)); // SAVE CURRENT ROUND
174
175 34
			$teams = Generator::circle_rotateBracket($teams); // ROTATE TEAMS IN BRACKET
176
		}
177
178 34
		return $bracket;
179
180
	}
181
	// CREATE GAMES FROM BRACKET
182 34
	public static function circle_saveBracket(array $teams, \tournamentGenerator\Group $group) {
183
184 34
		$bracket = [];
185
186 34
		for ($i=0; $i < count($teams)/2; $i++) { // GO THROUGH HALF OF THE TEAMS
187
188 34
			$home = $teams[$i];
189 34
			$reverse = array_reverse($teams);
190 34
			$away = $reverse[$i];
191
192 34
			if (($home == \TournamentGenerator\Constants::DUMMY_TEAM || $away == \TournamentGenerator\Constants::DUMMY_TEAM)) continue; // SKIP WHEN DUMMY_TEAM IS PRESENT
193
194 34
			$bracket[] = new \TournamentGenerator\Game([$home, $away], $group);
195
196
		}
197
198 34
		return $bracket;
199
200
	}
201
	// ROTATE TEAMS IN BRACKET
202 34
	public static function circle_rotateBracket(array $teams) {
203
204 34
		$first = array_shift($teams); // THE FIRST TEAM REMAINS FIRST
205 34
		$last = array_shift($teams); // THE SECOND TEAM MOVES TO LAST PLACE
206
207 34
		$teams = array_merge([$first], $teams, [$last]); // MERGE BACK TOGETHER
208
209 34
		return $teams;
210
211
	}
212
213
}
214