diff --git a/build/coverage.serialized b/build/coverage.serialized index ddbef8a..a7c1961 100644 Binary files a/build/coverage.serialized and b/build/coverage.serialized differ diff --git a/build/coverage.xml b/build/coverage.xml index 319f03c..b5719d1 100644 --- a/build/coverage.xml +++ b/build/coverage.xml @@ -1,6 +1,6 @@ - - + + - - - - - - - + + + + + + + - - + + @@ -29,12 +29,12 @@ - - - + - + + @@ -81,9 +81,9 @@ - - - + + + @@ -92,15 +92,15 @@ - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + @@ -153,29 +153,29 @@ - - - - - - - - + + + + + + + + - - - - + + + + - - + + - - + + @@ -184,60 +184,60 @@ - - - + + + - - + + - - - - - + + + + + - - + + - - - - - - - - + count="195"/> + + + + + + + + - + count="195"/> + - - - - - + + + + + - + - - - - + + + + - - + + - - + + - + @@ -263,20 +263,20 @@ - - - - - - - - - - - + + + + + + + + + + + - - + + @@ -302,23 +302,23 @@ - - - - - - - + + + + + + + - + count="227"/> + - - - + count="205"/> + + + - + @@ -331,13 +331,13 @@ - - - + + + - - - + + + @@ -346,30 +346,30 @@ - - - - - + + + + + - - + + - + count="129"/> + - - - + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -778,25 +778,25 @@ - - - - - - - + + + + + + + - - + + - - - - - + + + + + - - + + @@ -818,41 +818,41 @@ - - - - - + + + + + - - - - - - + count="106"/> + + + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + @@ -902,15 +902,15 @@ - - + + - - + + - - + + @@ -921,164 +921,170 @@ - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - + + + + + + + + + - - - - + + + + - - - - + + + + - + - - + - - - - - + + + + - - - + + + - - - - - - - - + + + + + + + - - - - - - + + + + + + - - - - + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1288,8 +1294,8 @@ - - + + @@ -1297,13 +1303,13 @@ - - - - + + + + - - + + @@ -1311,57 +1317,57 @@ - - - - + + + + - - - - - - - - - + + + + + + + + + - - + + - - - - - - - - + count="51"/> + + + + + + + + - - - - - - - - - + count="51"/> + + + + + + + + + - - - + count="51"/> + + + @@ -1384,9 +1390,9 @@ - - + count="84"/> + + @@ -1460,27 +1466,27 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + - - - + + + - + @@ -1525,8 +1531,8 @@ - + @@ -1543,13 +1549,13 @@ - - - - - - - + + + + + + + - + @@ -1595,59 +1601,59 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - + + - - + + - - - - - - + count="69"/> + + + + + + @@ -1655,20 +1661,20 @@ - - + count="61"/> + + - - - - - + + + + + - - - + + + @@ -1685,16 +1691,16 @@ - - + + - - - - - - + count="183"/> + + + + + + + + + @@ -2075,6 +2085,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -2325,93 +2410,65 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - + + + + + + + @@ -2423,10 +2480,10 @@ - - - - + + + + @@ -2434,18 +2491,18 @@ - - - - - + + + + + - - - - - - + + + + + + @@ -2459,13 +2516,13 @@ - - - - - - - + + + + + + + @@ -2479,11 +2536,11 @@ - - + count="84"/> + + - + @@ -2492,9 +2549,9 @@ - - - + + + @@ -2509,23 +2566,23 @@ - - - - - - - - - - - - - - - - + count="257"/> + + + + + + + + + + + + + + + + @@ -2545,12 +2602,12 @@ - - - - - - + + + + + + @@ -2559,8 +2616,8 @@ - - + + - - - - - + + + + + @@ -2685,13 +2742,13 @@ - - + + - - - - + + + + @@ -2713,13 +2770,13 @@ - - + + - - - - + + + + @@ -2767,35 +2824,73 @@ - - + + - - - - - - + + + + + + - - - - - - - + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + count="183"/> + + + + - + count="192"/> + @@ -2850,8 +2945,8 @@ - - + + - - + count="170"/> + + - + count="193"/> + @@ -2881,14 +2976,14 @@ - - - - - - - - + + + + + + + + @@ -2907,11 +3002,11 @@ - - - - - + + + + + @@ -2920,24 +3015,24 @@ - - - - - - + + + + + + - - + + - - - - - - - - + + + + + + + + @@ -2953,23 +3048,23 @@ - - + + - - - - + + + + - - - - - - - + + + + + + + - + @@ -2978,22 +3073,22 @@ - - - + + + - - - - - + + + + + - + count="187"/> + - - + count="183"/> + + @@ -3005,8 +3100,8 @@ - + diff --git a/src/TournamentGenerator/BlankTeam.php b/src/TournamentGenerator/BlankTeam.php index c31fa1b..7479c1e 100644 --- a/src/TournamentGenerator/BlankTeam.php +++ b/src/TournamentGenerator/BlankTeam.php @@ -2,6 +2,8 @@ namespace TournamentGenerator; +use TournamentGenerator\Interfaces\ProgressionInterface; + /** * Blank / dummy team used for simulating the games * @@ -19,7 +21,7 @@ class BlankTeam extends Team /** @var Group A group that it was generated from during progression */ protected Group $from; /** @var Progression A progression object that generated this dummy team */ - protected Progression $progression; + protected ProgressionInterface $progression; /** * BlankTeam constructor. @@ -29,7 +31,7 @@ class BlankTeam extends Team * @param Group $from A group that the original team was playing in * @param Progression $progression A progression object that created this team */ - public function __construct(string $name, Team $original, Group $from, Progression $progression) { + public function __construct(string $name, Team $original, Group $from, ProgressionInterface $progression) { $this->groupResults = $original->groupResults; $this->from = $from; $this->progression = $progression; diff --git a/src/TournamentGenerator/Group.php b/src/TournamentGenerator/Group.php index c6f0f72..0e63ee4 100644 --- a/src/TournamentGenerator/Group.php +++ b/src/TournamentGenerator/Group.php @@ -6,6 +6,7 @@ use TournamentGenerator\Containers\GameContainer; use TournamentGenerator\Containers\HierarchyContainer; use TournamentGenerator\Containers\TeamContainer; +use TournamentGenerator\Interfaces\ProgressionInterface; use TournamentGenerator\Interfaces\WithGames; use TournamentGenerator\Interfaces\WithGeneratorSetters; use TournamentGenerator\Interfaces\WithSkipSetters; @@ -36,7 +37,7 @@ class Group extends HierarchyBase implements WithGeneratorSetters, WithSkipSette protected array $progressed = []; /** @var string Ordering parameter */ protected string $ordering = Constants::POINTS; - /** @var Progression[] List of progressions from this group */ + /** @var ProgressionInterface[] List of progressions from this group */ protected array $progressions = []; /** @var int Points acquired for winning */ protected int $winPoints = 3; @@ -58,20 +59,20 @@ class Group extends HierarchyBase implements WithGeneratorSetters, WithSkipSette /** - * Group constructor. - * - * @param string $name Group name - * @param int|string|null $id Group id - if omitted -> it is generated automatically as unique string - */ - public function __construct(string $name, int|string|null $id = null) { - $this->setName($name); - $this->generator = new Helpers\Generator($this); - /** @infection-ignore-all */ - $this->setId($id ?? uniqid('', false)); - $this->games = new GameContainer($this->id); - $this->teams = new TeamContainer($this->id); - $this->container = new HierarchyContainer($this->id); - } + * Group constructor. + * + * @param string $name Group name + * @param int|string|null $id Group id - if omitted -> it is generated automatically as unique string + */ + public function __construct(string $name, int|string|null $id = null) { + $this->setName($name); + $this->generator = new Helpers\Generator($this); + /** @infection-ignore-all */ + $this->setId($id ?? uniqid('', false)); + $this->games = new GameContainer($this->id); + $this->teams = new TeamContainer($this->id); + $this->container = new HierarchyContainer($this->id); + } /** * Add one or more teams into the object. @@ -81,7 +82,7 @@ public function __construct(string $name, int|string|null $id = null) { * @return $this * @throws Exception */ - public function addTeam(Team ...$teams) : Group { + public function addTeam(Team ...$teams): Group { foreach ($teams as $team) { $this->teams->insert($team); $team->addGroupResults($this); @@ -98,7 +99,7 @@ public function addTeam(Team ...$teams) : Group { * @return Team Newly created team * @throws Exception */ - public function team(string $name = '', $id = null) : Team { + public function team(string $name = '', $id = null): Team { $t = new Team($name, $id); $this->teams->insert($t); $t->addGroupResults($this); @@ -110,7 +111,7 @@ public function team(string $name = '', $id = null) : Team { * * @return $this */ - public function allowSkip() : Group { + public function allowSkip(): Group { $this->generator->allowSkip(); return $this; } @@ -120,7 +121,7 @@ public function allowSkip() : Group { * * @return $this */ - public function disallowSkip() : Group { + public function disallowSkip(): Group { $this->generator->disallowSkip(); return $this; } @@ -132,7 +133,7 @@ public function disallowSkip() : Group { * * @return $this */ - public function setSkip(bool $skip) : Group { + public function setSkip(bool $skip): Group { $this->generator->setSkip($skip); return $this; } @@ -142,7 +143,7 @@ public function setSkip(bool $skip) : Group { * * @return bool */ - public function getSkip() : bool { + public function getSkip(): bool { return $this->generator->getSkip(); } @@ -151,7 +152,7 @@ public function getSkip() : bool { * * @return int */ - public function getWinPoints() : int { + public function getWinPoints(): int { return $this->winPoints; } @@ -162,7 +163,7 @@ public function getWinPoints() : int { * * @return $this */ - public function setWinPoints(int $points) : Group { + public function setWinPoints(int $points): Group { $this->winPoints = $points; return $this; } @@ -172,7 +173,7 @@ public function setWinPoints(int $points) : Group { * * @return int */ - public function getDrawPoints() : int { + public function getDrawPoints(): int { return $this->drawPoints; } @@ -183,7 +184,7 @@ public function getDrawPoints() : int { * * @return $this */ - public function setDrawPoints(int $points) : Group { + public function setDrawPoints(int $points): Group { $this->drawPoints = $points; return $this; } @@ -193,7 +194,7 @@ public function setDrawPoints(int $points) : Group { * * @return int */ - public function getLostPoints() : int { + public function getLostPoints(): int { return $this->lostPoints; } @@ -204,7 +205,7 @@ public function getLostPoints() : int { * * @return $this */ - public function setLostPoints(int $points) : Group { + public function setLostPoints(int $points): Group { $this->lostPoints = $points; return $this; } @@ -214,7 +215,7 @@ public function setLostPoints(int $points) : Group { * * @return int */ - public function getSecondPoints() : int { + public function getSecondPoints(): int { return $this->secondPoints; } @@ -225,7 +226,7 @@ public function getSecondPoints() : int { * * @return $this */ - public function setSecondPoints(int $points) : Group { + public function setSecondPoints(int $points): Group { $this->secondPoints = $points; return $this; } @@ -235,7 +236,7 @@ public function setSecondPoints(int $points) : Group { * * @return int */ - public function getThirdPoints() : int { + public function getThirdPoints(): int { return $this->thirdPoints; } @@ -246,7 +247,7 @@ public function getThirdPoints() : int { * * @return $this */ - public function setThirdPoints(int $points) : Group { + public function setThirdPoints(int $points): Group { $this->thirdPoints = $points; return $this; } @@ -256,7 +257,7 @@ public function setThirdPoints(int $points) : Group { * * @return int */ - public function getProgressPoints() : int { + public function getProgressPoints(): int { return $this->progressPoints; } @@ -267,7 +268,7 @@ public function getProgressPoints() : int { * * @return Group */ - public function setProgressPoints(int $points) : Group { + public function setProgressPoints(int $points): Group { $this->progressPoints = $points; return $this; } @@ -283,7 +284,7 @@ public function setProgressPoints(int $points) : Group { * @return $this * @throws Exception */ - public function setMaxSize(int $size) : Group { + public function setMaxSize(int $size): Group { $this->generator->setMaxSize($size); return $this; } @@ -296,7 +297,7 @@ public function setMaxSize(int $size) : Group { * * @return int */ - public function getMaxSize() : int { + public function getMaxSize(): int { return $this->generator->getMaxSize(); } @@ -310,7 +311,7 @@ public function getMaxSize() : int { * @see Constants::GroupTypes * */ - public function setType(string $type = Constants::ROUND_ROBIN) : Group { + public function setType(string $type = Constants::ROUND_ROBIN): Group { $this->generator->setType($type); return $this; } @@ -322,7 +323,7 @@ public function setType(string $type = Constants::ROUND_ROBIN) : Group { * @see Constants::GroupTypes * */ - public function getType() : string { + public function getType(): string { return $this->generator->getType(); } @@ -331,7 +332,7 @@ public function getType() : string { * * @return int */ - public function getOrder() : int { + public function getOrder(): int { return $this->order; } @@ -342,7 +343,7 @@ public function getOrder() : int { * * @return $this */ - public function setOrder(int $order) : Group { + public function setOrder(int $order): Group { $this->order = $order; return $this; } @@ -352,7 +353,7 @@ public function setOrder(int $order) : Group { * * @return string */ - public function getOrdering() : string { + public function getOrdering(): string { return $this->ordering; } @@ -366,9 +367,9 @@ public function getOrdering() : string { * @see Constants::OrderingTypes * */ - public function setOrdering(string $ordering = Constants::POINTS) : Group { + public function setOrdering(string $ordering = Constants::POINTS): Group { if (!in_array($ordering, Constants::OrderingTypes, true)) { - throw new Exception('Unknown group ordering: '.$ordering); + throw new Exception('Unknown group ordering: ' . $ordering); } $this->ordering = $ordering; return $this; @@ -382,7 +383,7 @@ public function setOrdering(string $ordering = Constants::POINTS) : Group { * @return $this * @throws Exception */ - public function setInGame(int $inGame) : Group { + public function setInGame(int $inGame): Group { $this->generator->setInGame($inGame); return $this; } @@ -392,18 +393,18 @@ public function setInGame(int $inGame) : Group { * * @return int */ - public function getInGame() : int { + public function getInGame(): int { return $this->generator->getInGame(); } /** * Add a progression to this group * - * @param Progression $progression + * @param ProgressionInterface $progression * * @return $this */ - public function addProgression(Progression $progression) : Group { + public function addProgression(ProgressionInterface $progression): Group { $this->progressions[] = $progression; return $this; } @@ -421,12 +422,37 @@ public function addProgression(Progression $progression) : Group { * * @see https://www.php.net/manual/en/function.array-slice.php */ - public function progression(Group $to, int $offset = 0, int $len = null) : Progression { + public function progression(Group $to, int $offset = 0, int $len = null): Progression { $p = new Progression($this, $to, $offset, $len); $this->progressions[] = $p; return $p; } + /** + * Creates a new multi-progression INTO this group + * + * Progression uses a similar syntax to php's array_slice() function. + * + * @warning The logic is reversed from the Group::progression() method. This will create a progression INTO this group. + * + * @param Group[] $from + * @param int $offset First index + * @param int|null $len Maximum number of teams to progress + * @param int|null $totalCount + * @param int $totalStart + * + * @return MultiProgression + * + * @see https://www.php.net/manual/en/function.array-slice.php + */ + public function multiProgression(array $from, int $offset = 0, int $len = null, ?int $totalCount = null, int $totalStart = 0): MultiProgression { + $p = new MultiProgression($from, $this, $offset, $len, $totalCount, $totalStart); + foreach ($from as $group) { + $group->addProgression($p); + } + return $p; + } + /** * Progress all teams using already setup progression * @@ -438,7 +464,7 @@ public function progression(Group $to, int $offset = 0, int $len = null) : Progr * @return $this * @throws Exception */ - public function progress(bool $blank = false) : Group { + public function progress(bool $blank = false): Group { foreach ($this->progressions as $progression) { $progression->progress($blank); } @@ -452,8 +478,8 @@ public function progress(bool $blank = false) : Group { * * @return $this */ - public function addProgressed(Team ...$teams) : Group { - $this->progressed = array_merge($this->progressed, array_map(static function($a) { + public function addProgressed(Team ...$teams): Group { + $this->progressed = array_merge($this->progressed, array_map(static function ($a) { return $a->getId(); }, $teams)); return $this; @@ -466,7 +492,7 @@ public function addProgressed(Team ...$teams) : Group { * * @return bool */ - public function isProgressed(Team $team) : bool { + public function isProgressed(Team $team): bool { return in_array($team->getId(), $this->progressed, true); } @@ -476,7 +502,7 @@ public function isProgressed(Team $team) : bool { * @return array * @throws Exception */ - public function genGames() : array { + public function genGames(): array { return $this->generator->genGames(); } @@ -490,7 +516,7 @@ public function genGames() : array { * @return Game * @throws Exception */ - public function game(array $teams = []) : Game { + public function game(array $teams = []): Game { $g = new Game($teams, $this); $g->setId($this->games->getAutoIncrement()); $this->games->incrementId(); @@ -508,7 +534,7 @@ public function game(array $teams = []) : Game { * @return $this * @throws Exception */ - public function addGame(Game ...$games) : Group { + public function addGame(Game ...$games): Group { $this->games->insert(...$games); // Set the game id's foreach ($games as $game) { @@ -527,7 +553,7 @@ public function addGame(Game ...$games) : Group { * @return Game[] * @throws Exception */ - public function orderGames() : array { + public function orderGames(): array { if (count($this->games) < 5) { return $this->games->get(); } @@ -544,7 +570,7 @@ public function orderGames() : array { * @return Team[] * @throws Exception */ - public function simulate(array $filters = [], bool $reset = true) : array { + public function simulate(array $filters = [], bool $reset = true): array { return Helpers\Simulator::simulateGroup($this, $filters, $reset); } @@ -557,7 +583,7 @@ public function simulate(array $filters = [], bool $reset = true) : array { * @return $this * @throws Exception */ - public function resetGames() : Group { + public function resetGames(): Group { foreach ($this->getGames() as $game) { $game->resetResults(); } @@ -569,21 +595,21 @@ public function resetGames() : Group { * * @return bool */ - public function isPlayed() : bool { + public function isPlayed(): bool { if (count($this->games) === 0) { return false; } return count(array_filter($this->getGames(), static function ($a) { - return $a->isPlayed(); - })) === count($this->games); + return $a->isPlayed(); + })) === count($this->games); } /** * Get all progressions * - * @return Progression[] + * @return ProgressionInterface[] */ - public function getProgressions() : array { + public function getProgressions(): array { return $this->progressions; } @@ -592,7 +618,7 @@ public function getProgressions() : array { * @return array * @throws Exception */ - public function jsonSerialize() : array { + public function jsonSerialize(): array { return [ 'id' => $this->getId(), 'name' => $this->getName(), diff --git a/src/TournamentGenerator/Interfaces/ProgressionInterface.php b/src/TournamentGenerator/Interfaces/ProgressionInterface.php new file mode 100644 index 0000000..5729c28 --- /dev/null +++ b/src/TournamentGenerator/Interfaces/ProgressionInterface.php @@ -0,0 +1,47 @@ + + * @since 0.1 + */ +class MultiProgression implements ProgressionInterface +{ + use ProgressionTrait; + + /** @var Group[] What group to progress from */ + protected array $from; + protected ?int $totalCount = null; + private int $totalStart; + + /** + * Progression constructor. + * + * @param Group[] $from What groups to progress from + * @param Group $to What group to progress to + * @param int $start Offset to start picking teams + * @param int|null $len Maximum number of teams to progress from each $from groups + * @param int|null $totalCount Maximum total count to progress from the $from groups. + * If set, the final teams from each input group will be sorted only the first + * $totalCount will be progressed. + * @param int $totalStart Offset to start picking teams. The $totalCount must be set. + */ + public function __construct(array $from, Group $to, int $start = 0, ?int $len = null, ?int $totalCount = null, int $totalStart = 0) { + $this->from = $from; + $this->to = $to; + $this->start = $start; + $this->len = $len; + $this->totalCount = $totalCount; + $this->totalStart = $totalStart; + } + + /** + * Gets a description + * + * @return string + */ + public function __toString() { + return 'Team from ' . implode(', ', array_map(static fn(Group $group) => $group->getName(), $this->from)); + } + + + /** + * Progress the teams using set rules + * + * @param bool $blank If true -> do not move the real team objects, but create new dummy teams + * + * @return $this + * @throws Exception + */ + public function progress(bool $blank = false): static { + if ($this->progressed) { + return $this; + } + + $fromIds = []; + + /** @var Team[][] $teams */ + $teams = []; + foreach ($this->from as $key => $from) { + $fromIds[] = $from->getId(); + if ($blank) { + $teams[$key] = $from->isPlayed() ? + $from->sortTeams(null, $this->filters) : + $from->simulate($this->filters); + } + else { + $teams[$key] = $from->sortTeams(null, $this->filters); + } + } + + /** @var Team[][] $next */ + $next = []; + foreach ($teams as $key => $groupTeams) { + if ($this->start !== 0 || $this->len !== null) { + $next[$key] = array_splice($groupTeams, $this->start, ($this->len ?? count($groupTeams))); + } + else { + $next[$key] = $groupTeams; + } + } + + // Only $totalCount teams should progress from all groups + if ($this->totalCount !== null) { + $allTeams = array_merge(...$next); + usort($allTeams, static function (Team $a, Team $b) use ($fromIds) { + $aPoints = $a->sumPoints($fromIds); + $bPoints = $b->sumPoints($fromIds); + if ($aPoints === $bPoints) { + return $b->sumScore($fromIds) - $a->sumScore($fromIds); + } + return $bPoints - $aPoints; + }); + $allTeams = array_slice($allTeams, $this->totalStart, $this->totalCount); + foreach ($next as $key => $groupTeams) { + foreach ($groupTeams as $key2 => $team) { + if (!in_array($team, $allTeams, true)) { + unset($next[$key][$key2]); + } + } + } + } + + $i = 1; + foreach ($next as $key => $groupTeams) { + foreach ($groupTeams as $team) { + if ($blank) { + $this->to->addTeam(new BlankTeam($this . ' - ' . $i++, $team, $this->from[$key], $this)); + } + else { + $this->progressedTeams[] = $team; + $team->addPoints($this->points ?? $this->from[$key]->getProgressPoints()); + } + } + } + + foreach ($this->from as $key => $from) { + if (count($next[$key]) === 0) { + continue; + } + $from->addProgressed(...$next[$key]); + if (!$blank) { + $this->to->addTeam(...$next[$key]); + } + } + $this->progressed = true; + return $this; + } + + + /** + * @return Group[] + */ + public function getFrom(): array { + return $this->from; + } + + /** + * @return int|null + */ + public function getTotalCount(): ?int { + return $this->totalCount; + } + + /** + * @param int|null $totalCount + * + * @return $this + */ + public function setTotalCount(?int $totalCount): static { + $this->totalCount = $totalCount; + return $this; + } + + public function getTotalStart(): int { + return $this->totalStart; + } + + public function setTotalStart(int $totalStart): static { + $this->totalStart = $totalStart; + return $this; + } + +} diff --git a/src/TournamentGenerator/Progression.php b/src/TournamentGenerator/Progression.php index 57f1278..ab1e744 100644 --- a/src/TournamentGenerator/Progression.php +++ b/src/TournamentGenerator/Progression.php @@ -3,6 +3,8 @@ namespace TournamentGenerator; use Exception; +use TournamentGenerator\Interfaces\ProgressionInterface; +use TournamentGenerator\Traits\ProgressionTrait; /** * Progression is a class that takes care of moving teams between groups. @@ -14,40 +16,22 @@ * @author Tomáš Vojík * @since 0.1 */ -class Progression +class Progression implements ProgressionInterface { + use ProgressionTrait; /** @var Group What group to progress from */ protected Group $from; - /** @var Group What group to progress to */ - protected Group $to; - /** @var int Offset to start picking teams */ - protected int $start; - /** @var int|null Maximum number of teams to progress */ - protected ?int $len; - /** @var TeamFilter[] Filters to use */ - protected array $filters = []; - /** @var bool If the progression was already called */ - protected bool $progressed = false; - /** - * @var int|null Custom points for progression - * @package TournamentGenerator - */ - protected ?int $points = null; - - /** @var Team[] */ - protected array $progressedTeams = []; - - /** - * Progression constructor. - * - * @param Group $from What group to progress from - * @param Group $to What group to progress to - * @param int $start Offset to start picking teams - * @param int|null $len Maximum number of teams to progress - */ - public function __construct(Group $from, Group $to, int $start = 0, ?int $len = null) { + /** + * Progression constructor. + * + * @param Group $from What group to progress from + * @param Group $to What group to progress to + * @param int $start Offset to start picking teams + * @param int|null $len Maximum number of teams to progress + */ + public function __construct(Group $from, Group $to, int $start = 0, ?int $len = null) { $this->from = $from; $this->to = $to; $this->start = $start; @@ -60,21 +44,7 @@ public function __construct(Group $from, Group $to, int $start = 0, ?int $len = * @return string */ public function __toString() { - return 'Team from '.$this->from; - } - - /** - * Adds progression's filters - * - * @param TeamFilter[] $filters - * - * @return $this - */ - public function addFilter(TeamFilter ...$filters) : Progression { - foreach ($filters as $filter) { - $this->filters[] = $filter; - } - return $this; + return 'Team from ' . $this->from; } /** @@ -85,13 +55,15 @@ public function addFilter(TeamFilter ...$filters) : Progression { * @return $this * @throws Exception */ - public function progress(bool $blank = false) : Progression { + public function progress(bool $blank = false): static { if ($this->progressed) { return $this; } if ($blank) { - $teams = $this->from->isPlayed() ? $this->from->sortTeams(null, $this->filters) : $this->from->simulate($this->filters); + $teams = $this->from->isPlayed() ? $this->from->sortTeams(null, $this->filters) : $this->from->simulate( + $this->filters + ); } else { $teams = $this->from->sortTeams(null, $this->filters); @@ -108,11 +80,11 @@ public function progress(bool $blank = false) : Progression { foreach ($next as $team) { if ($blank) { - $this->to->addTeam(new BlankTeam($this.' - '.$i++, $team, $this->from, $this)); + $this->to->addTeam(new BlankTeam($this . ' - ' . $i++, $team, $this->from, $this)); } else { - $this->progressedTeams[] = $team; - $team->addPoints($this->points ?? $this->from->getProgressPoints()); + $this->progressedTeams[] = $team; + $team->addPoints($this->points ?? $this->from->getProgressPoints()); } } @@ -124,100 +96,11 @@ public function progress(bool $blank = false) : Progression { return $this; } - /** - * Reset progression - * - * @warning This does not remove the teams from the progressed groups! - * - * @return $this - */ - public function reset() : Progression { - $this->progressed = false; - return $this; - } - /** * @return Group */ - public function getFrom() : Group { + public function getFrom(): Group { return $this->from; } - /** - * @return Group - */ - public function getTo() : Group { - return $this->to; - } - - /** - * @return int - */ - public function getStart() : int { - return $this->start; - } - - /** - * @return int|null - */ - public function getLen() : ?int { - return $this->len; - } - - /** - * @return TeamFilter[] - */ - public function getFilters() : array { - return $this->filters; - } - - /** - * Sets progression's filters - * - * @param TeamFilter[] $filters - * - * @return $this - */ - public function setFilters(array $filters) : Progression { - $this->filters = $filters; - return $this; - } - - /** - * @return bool - */ - public function isProgressed(): bool { - return $this->progressed; - } - - /** - * @param bool $progressed - */ - public function setProgressed(bool $progressed): void { - $this->progressed = $progressed; - } - - /** - * @return int|null - */ - public function getPoints(): ?int { - return $this->points; - } - - /** - * @param int|null $points - * @return Progression - */ - public function setPoints(?int $points): Progression { - $this->points = $points; - return $this; - } - - /** - * @return array - */ - public function getProgressedTeams(): array { - return $this->progressedTeams; - } - } diff --git a/src/TournamentGenerator/Traits/ProgressionTrait.php b/src/TournamentGenerator/Traits/ProgressionTrait.php new file mode 100644 index 0000000..d65eb4f --- /dev/null +++ b/src/TournamentGenerator/Traits/ProgressionTrait.php @@ -0,0 +1,135 @@ +filters[] = $filter; + } + return $this; + } + + /** + * Reset progression + * + * @warning This does not remove the teams from the progressed groups! + * + * @return $this + */ + public function reset(): static { + $this->progressed = false; + return $this; + } + + /** + * @return Group + */ + public function getTo(): Group { + return $this->to; + } + + /** + * @return int + */ + public function getStart(): int { + return $this->start; + } + + /** + * @return int|null + */ + public function getLen(): ?int { + return $this->len; + } + + /** + * @return TeamFilter[] + */ + public function getFilters(): array { + return $this->filters; + } + + /** + * Sets progression's filters + * + * @param TeamFilter[] $filters + * + * @return $this + */ + public function setFilters(array $filters): static { + $this->filters = $filters; + return $this; + } + + /** + * @return bool + */ + public function isProgressed(): bool { + return $this->progressed; + } + + /** + * @param bool $progressed + */ + public function setProgressed(bool $progressed): void { + $this->progressed = $progressed; + } + + /** + * @return int|null + */ + public function getPoints(): ?int { + return $this->points; + } + + /** + * @param int|null $points + * + * @return $this + */ + public function setPoints(?int $points): static { + $this->points = $points; + return $this; + } + + /** + * @return array + */ + public function getProgressedTeams(): array { + return $this->progressedTeams; + } +} \ No newline at end of file diff --git a/tests/MultiProgressionTest.php b/tests/MultiProgressionTest.php new file mode 100644 index 0000000..5e5cb8b --- /dev/null +++ b/tests/MultiProgressionTest.php @@ -0,0 +1,122 @@ +isProgressed()); + $progression->setProgressed(true); + self::assertTrue($progression->isProgressed()); + } + + public function testProgressing(): void { + $tournament = new Tournament('Name of tournament 1'); + + for ($i = 1; $i <= 10; $i++) { + $tournament->team('Team ' . $i); + } + // Create a round and a final round + $round = $tournament->round("First's round's name"); + $final = $tournament->round("Final's round's name"); + + // Create 2 groups for the first round + $group1 = $round->group('Round 1')->setInGame(2); + $group2 = $round->group('Round 2')->setInGame(2); + + // Create a final group + $final_group = $final->group('Teams 1-4')->setInGame(2); + $second_group = $final->group('Teams 5-8')->setInGame(2); + + $tournament->splitTeams($round); + + $group1->progression($final_group, 0, 2); // PROGRESS 2 BEST WINNING TEAMS + $group2->progression($final_group, 0, 2); // PROGRESS 2 BEST WINNING TEAMS + $final_group->multiProgression([$group1, $group2], 2, 1, 1); // Progress the best of the third teams + $second_group->multiProgression([$group1, $group2], 2, 1, 1, 1); // Progress the worst of the third teams + $group1->progression($second_group, 3, 2); // Progress all other teams + $group2->progression($second_group, 3, 2); // Progress all other teams + + $round->genGames(); + $round->simulate(); + $round->progress(); + + self::assertCount(5, $final_group->getTeams()); + self::assertCount(5, $second_group->getTeams()); + + // Get third teams + $team1 = $group1->getTeams(true)[2]; + $team1Points = $team1->sumPoints([$group1->getId()]); + $team1Score = $team1->sumScore([$group1->getId()]); + $team2 = $group2->getTeams(true)[2]; + $team2Points = $team2->sumPoints([$group2->getId()]); + $team2Score = $team2->sumScore([$group2->getId()]); + + if ($team1Points > $team2Points) { + $betterTeam = $team1; + $worseTeam = $team2; + } + else { + if ($team1Points < $team2Points) { + $betterTeam = $team2; + $worseTeam = $team1; + } + else { + if ($team1Score > $team2Score) { + $betterTeam = $team1; + $worseTeam = $team2; + } + else { + $betterTeam = $team2; + $worseTeam = $team1; + } + } + } + + $this->assertContains($betterTeam->getId(), $final_group->getTeamContainer()->ids()->get()); + $this->assertContains($worseTeam->getId(), $second_group->getTeamContainer()->ids()->get()); + } + + public function testGetProgressedTeams(): void { + $tournament = new Tournament('Name of tournament 1'); + + // Create a round and a final round + $round = $tournament->round("First's round's name"); + $final = $tournament->round("Final's round's name"); + + // Create 1 group for the first round + $group1 = $round->group('Round 1')->setInGame(2); + $group2 = $round->group('Round 2')->setInGame(2); + + for ($i = 1; $i <= 6; $i++) { + $group1->team('Team ' . $i, $i); + } + + // Create a final group + $final_group = $final->group('Teams 1-2')->setInGame(2); + + $tournament->splitTeams($round); + + $progression = $final_group->multiProgression([$group1, $group2], 0, 2, 3); + + $round->genGames(); + $round->simulate(); + $round->progress(); + + self::assertCount(3, $final_group->getTeams()); + self::assertCount(3, $progression->getProgressedTeams()); + self::assertEquals($final_group->getTeams(), $progression->getProgressedTeams()); + } +} diff --git a/tests/ProgressionTest.php b/tests/ProgressionTest.php index c984965..46f1db8 100644 --- a/tests/ProgressionTest.php +++ b/tests/ProgressionTest.php @@ -49,6 +49,7 @@ public function check_progressing() : void { $group_1->progression($second_group, 2, 2); // PROGRESS 2 BEST WINNING TEAMS $group_2->progression($second_group, 2, 2); // PROGRESS 2 BEST WINNING TEAMS + $round->genGames(); $round->simulate(); $round->progress(); @@ -336,8 +337,8 @@ public function testGetProgressedTeams(): void { $progression = $group_1->progression($final_group, 0, 2); // PROGRESS 2 BEST WINNING TEAMS + $round->genGames(); $round->simulate(); - $round->progress(); self::assertCount(2, $final_group->getTeams());