Completed
Push — master ( 592cb1...c155af )
by Tomáš
02:46
created

Generator::r_rGames()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 15
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 13
nc 8
nop 1
dl 0
loc 15
rs 9.5222
c 1
b 0
f 0
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
				$games = $this->r_r3Games($teams, $games);
88
				break;
89
			case 4:
90
				$games = $this->r_r4Games($teams, $games);
91
				break;
92
		}
93
		return $games;
94
	}
95
	private function r_r3Games(array $teams, array &$games, \TournamentGenerator\Team $lockedTeam1 = null) {
96
		$teamsB = $teams;
97
		while (count($teamsB) >= 3) {
98
			$lockedTeam = array_shift($teamsB);
99
			$gamesTemp = Generator::circle_genGames2($teamsB, $this->group);
100
			foreach ($gamesTemp as $game) {
101
				if (isset($lockedTeam1)) $game->addTeam($lockedTeam1);
102
				$game->addTeam($lockedTeam);
103
			}
104
			$games = array_merge($games, $gamesTemp);
105
		}
106
		return $games;
107
	}
108
	private function r_r4Games(array $teams, array &$games) {
109
		$teamsB = $teams;
110
		$lockedTeam1 = array_shift($teamsB);
111
		while (count($teamsB) >= 4) {
112
			$this->r_r3Games($teamsB, $games, $lockedTeam1);
113
			$lockedTeam1 = array_shift($teamsB);
114
		}
115
		$games[] = new \TournamentGenerator\Game(array_merge([$lockedTeam1], $teamsB), $this->group);
116
		return $games;
117
	}
118
	private function two_twoGames(array $teams = []) {
119
		if (count($teams) === 0) $teams = $this->group->getTeams();
120
		$discard = [];
121
		shuffle($teams);
122
		$count = count($teams);
123
		while (count($teams) % $this->inGame !== 0) { $discard[] = array_shift($teams); }
124
125
		while (count($teams) > 0) {
126
			$tInGame = [];
127
			for ($i=0; $i < $this->inGame; $i++) { $tInGame[] = array_shift($teams); }
128
			$this->group->game($tInGame);
129
		}
130
131
		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
		return $this;
134
	}
135
	private function cond_splitGames(array $teams = []) {
136
		$games = [];
137
		if (count($teams) === 0) $teams = $this->group->getTeams();
138
139
		if (count($teams) > $this->maxSize) {
140
			$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
			foreach ($groups as $group) { $games[] = $this->r_rGames($group); }
142
			$g = 0;
143
			foreach ($games as $group) {	$g += count($group); }
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