Passed
Push — master ( 485366...592cb1 )
by Tomáš
01:40
created

Generator::two_twoGames()   B

Complexity

Conditions 8
Paths 24

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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