Completed
Push — master ( 5d9f44...4b85e8 )
by Tomáš
03:31
created

DoubleElimination::generateWinSide()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 10
nc 2
nop 8
dl 0
loc 12
rs 9.9332
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace TournamentGenerator\Preset;
4
5
/**
6
 *
7
 */
8
class DoubleElimination extends \TournamentGenerator\Tournament
9
{
10
11
	public function generate() {
12
		$this->allowSkip();
13
14
		$countTeams = count($this->getTeams());
15
16
		if ($countTeams < 3) throw new \Exception('Double elimination is possible for minimum of 3 teams - '.$countTeams.' teams given.');
17
18
19
		// CALCULATE BYES
20
		$nextPow = 0;
21
		$byes = $this->calcByes($countTeams, $nextPow);
22
23
		$startRound = $this->round('Start round');
24
25
		$roundsNum = log($nextPow, 2)*2;
26
27
		$startGroups = ($countTeams+$byes)/2;
28
29
		$previousGroups = [];
30
		$previousLosingGroups = [];
31
		$groupIds = [];
32
		$allGroups = [];
33
34
		for ($i=1; $i <= $startGroups; $i++) {
35
			$g = $startRound->group('Start group - '.$i)->setInGame(2)->setType(\TournamentGenerator\Constants::ROUND_TWO);
36
			$allGroups[] = $g;
37
			$groupIds[] = $g->id;
38
			$previousGroups[] = $g;
39
		}
40
41
		// SPLIT TEAMS EVENLY
42
		$this->splitTeams();
43
44
		for ($r=2; $r <= $roundsNum-1; $r++) {
45
			$groups = [];
46
			$losingGroups = [];
47
			$round = $this->round('Round '.$r);
48
49
			// GENERATE GROUPS AND PROGRESSIONS
50
51
			// GENERATING LOSING AND WINNING SIDE
52
			$lastLosingGroup = $this->generateLosingSide($r, $round, $allGroups, $previousLosingGroups, $previousGroups, $losingGroups);
53
			$this->generateWinSide($r, $byes, $countTeams, $round, $allGroups, $groups, $lastWinningGroup, $previousGroups);
54
55
			$previousGroups = $groups;
56
			$previousLosingGroups = $losingGroups;
57
		}
58
59
		// LAST ROUND
60
		$round = $this->round('Round '.$roundsNum.' - Finale');
61
		$groupFinal = $round->group('Round '.$r.' - finale')->setInGame(2)->setType(\TournamentGenerator\Constants::ROUND_TWO)->setOrder(1);
62
		$allGroups[] = $groupFinal;
63
		$lastLosingGroup->progression($groupFinal, 0, 1);
64
		$lastWinningGroup->progression($groupFinal, 0, 1);
65
66
		// REPEAT GROUP IF LOSING TEAM WON
67
		$group = $round->group('Round '.$r.' - finale (2)')->setInGame(2)->setType(\TournamentGenerator\Constants::ROUND_TWO)->setOrder(1);
68
		$twoLoss = new \TournamentGenerator\TeamFilter('losses', '=', 1, $allGroups);
69
		$groupFinal->progression($group, 0, 2)->addFilter($twoLoss);
70
71
		return $this;
72
73
	}
74
75
	private function calcByes(int $countTeams, int &$nextPow) {
76
		$byes = 0;
77
		$nextPow = $countTeams;
78
		if ( !\TournamentGenerator\isPowerOf2($countTeams) ) {
79
			$nextPow = bindec(str_pad(1, strlen(decbin($countTeams))+1, 0, STR_PAD_RIGHT));
80
			$byes = $nextPow-$countTeams;
81
		}
82
		return $byes;
83
	}
84
	private function generateWinSide(int &$r, int &$byes, int &$countTeams, \TournamentGenerator\Round &$round, array &$allGroups, array &$groups, \TournamentGenerator\Group &$lastWinningGroup = null, array &$previousGroups = []) {
85
		$order = 1;
86
		for ($g=1; $g <= (($countTeams+$byes)/pow(2, $r)); $g++) {
87
			$group = $round->group('Round '.$r.' - win '.$g)->setInGame(2)->setType(\TournamentGenerator\Constants::ROUND_TWO)->setOrder($order);
88
			$allGroups[] = $group;
89
			$order += 2;
90
			$groups[] = $group;
91
			$lastWinningGroup = $group; // KEEP THE LAST GROUP FOR FINALE
92
			$previousGroups[2*($g-1)]->progression($group, 0, 1); // PROGRESS FROM GROUP BEFORE
93
			$previousGroups[(2*($g-1))+1]->progression($group, 0, 1); // PROGREESS FROM GROUP BEFORE
94
		}
95
		return $this;
96
	}
97
	private function generateLosingSide(int &$r, \TournamentGenerator\Round &$round, array &$allGroups, array &$previousLosingGroups = [], array &$previousGroups = [], array &$losingGroups = []) {
98
		$losingGroupTeamsCount = count($previousLosingGroups)+count($previousGroups);
99
		$order = 2;
100
		if (\TournamentGenerator\isPowerOf2($losingGroupTeamsCount)) { // IF THE NUMBER OF TEAMS IS A POWER OF 2, GENERATE GROUPS WITHOUT BYES
101
			for ($g=1; $g <= $losingGroupTeamsCount/2; $g++) {
102
				$group = $round->group('Round '.$r.' - loss '.$g)->setInGame(2)->setType(\TournamentGenerator\Constants::ROUND_TWO)->setOrder($order);
103
				$allGroups[] = $group;
104
				$order += 2;
105
				$losingGroups[] = $group;
106
				$lastLosingGroup = $group; // KEEP THE LAST GROUP FOR FINALE
107
				if ($r === 2) { // FIRST LOSING ROUND
108
					$previousGroups[2*($g-1)]->progression($group, 1, 1); // PROGRESS FROM STARTING GROUP
109
					$previousGroups[(2*($g-1))+1]->progression($group, 1, 1); // PROGREESS FROM STARTING GROUP
110
				}
111
				elseif ($losingGroupTeamsCount >= 2) {
112
					$previousLosingGroups[$g-1]->progression($group, 0, 1); // PROGRESS FROM LOSING GROUP BEFORE
113
					if (isset(array_reverse($previousGroups)[$g-1])) array_reverse($previousGroups)[$g-1]->progression($group, 1, 1); // PROGREESS FROM WINNING GROUP BEFORE
114
					else $previousLosingGroups[$g]->progression($group, 0, 1); // PROGRESS OTHER TEAM FROM LOSING GROUP BEEFORE
115
				}
116
			}
117
		}
118
		else { // IF THE NUMBER OF TEAMS IS NOT A POWER OF 2, GENERATE GROUPS WITH BYES
119
			// LOOK FOR THE CLOSEST LOWER POWER OF 2
120
			$losingByes = $losingGroupTeamsCount-bindec(str_pad(1, strlen(decbin($losingGroupTeamsCount)), 0, STR_PAD_RIGHT));
121
			$n = (floor(count($previousLosingGroups)/2)+$losingByes);
122
			$byesGroupsNums = [];
123
			$byesProgressed = 0;
124
			for ($i=0; $i < $losingByes; $i++) {
125
				$byesGroupsNums[] = $n-($i*2);
126
			}
127
			$lastGroup = 0;
128
			for ($g=1; $g <= ((count($previousLosingGroups)/2)+$losingByes); $g++) {
129
				$group = $round->group('Round '.$r.' - loss '.$g)->setInGame(2)->setType(\TournamentGenerator\Constants::ROUND_TWO)->setOrder($order);
130
				$allGroups[] = $group;
131
				$order += 2;
132
				$losingGroups[] = $group;
133
				$lastLosingGroup = $group; // KEEP THE LAST GROUP FOR FINALE
134
				if (in_array($g, $byesGroupsNums) && isset($previousGroups[$byesProgressed])) { // EMPTY GROUP FROM BYE
135
					$previousGroups[$byesProgressed]->progression($group, 1, 1); // PROGRESS FROM WINNING GROUP BEFORE
136
					$byesProgressed++;
137
				}
138
				else {
139
					$previousLosingGroups[$lastGroup]->progression($group, 0, 1); // PROGRESS FROM LOSING GROUP BEFORE
140
					if (isset($previousLosingGroups[$lastGroup + 1])) $previousLosingGroups[$lastGroup + 1]->progression($group, 0, 1); // PROGREESS FROM LOSING GROUP BEFORE
141
					$lastGroup += 2;
142
				}
143
			}
144
		}
145
		return $lastLosingGroup;
146
	}
147
148
}
149