My attempts at exercism.org
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(php): tournament

cosmeak 662e47dd c5a95912

+379
+78
php/tournament/README.md
··· 1 + # Tournament 2 + 3 + Welcome to Tournament on Exercism's PHP Track. 4 + If you need help running the tests or submitting your code, check out `HELP.md`. 5 + 6 + ## Instructions 7 + 8 + Tally the results of a small football competition. 9 + 10 + Based on an input file containing which team played against which and what the 11 + outcome was, create a file with a table like this: 12 + 13 + ```text 14 + Team | MP | W | D | L | P 15 + Devastating Donkeys | 3 | 2 | 1 | 0 | 7 16 + Allegoric Alaskans | 3 | 2 | 0 | 1 | 6 17 + Blithering Badgers | 3 | 1 | 0 | 2 | 3 18 + Courageous Californians | 3 | 0 | 1 | 2 | 1 19 + ``` 20 + 21 + What do those abbreviations mean? 22 + 23 + - MP: Matches Played 24 + - W: Matches Won 25 + - D: Matches Drawn (Tied) 26 + - L: Matches Lost 27 + - P: Points 28 + 29 + A win earns a team 3 points. A draw earns 1. A loss earns 0. 30 + 31 + The outcome should be ordered by points, descending. In case of a tie, teams are ordered alphabetically. 32 + 33 + ## Input 34 + 35 + Your tallying program will receive input that looks like: 36 + 37 + ```text 38 + Allegoric Alaskans;Blithering Badgers;win 39 + Devastating Donkeys;Courageous Californians;draw 40 + Devastating Donkeys;Allegoric Alaskans;win 41 + Courageous Californians;Blithering Badgers;loss 42 + Blithering Badgers;Devastating Donkeys;loss 43 + Allegoric Alaskans;Courageous Californians;win 44 + ``` 45 + 46 + The result of the match refers to the first team listed. So this line: 47 + 48 + ```text 49 + Allegoric Alaskans;Blithering Badgers;win 50 + ``` 51 + 52 + means that the Allegoric Alaskans beat the Blithering Badgers. 53 + 54 + This line: 55 + 56 + ```text 57 + Courageous Californians;Blithering Badgers;loss 58 + ``` 59 + 60 + means that the Blithering Badgers beat the Courageous Californians. 61 + 62 + And this line: 63 + 64 + ```text 65 + Devastating Donkeys;Courageous Californians;draw 66 + ``` 67 + 68 + means that the Devastating Donkeys and Courageous Californians tied. 69 + 70 + ## Source 71 + 72 + ### Created by 73 + 74 + - @MichaelBunker 75 + 76 + ### Contributed to by 77 + 78 + - @dstockto
+122
php/tournament/Tournament.php
··· 1 + <?php 2 + 3 + declare(strict_types=1); 4 + 5 + class Tournament 6 + { 7 + private const HEADER = "Team | MP | W | D | L | P"; 8 + 9 + public function tally(string $input): string 10 + { 11 + if ($input === "") { 12 + return self::HEADER; 13 + } 14 + 15 + $teams = []; 16 + 17 + foreach ($this->parseInput($input) as [$team1, $team2, $result]) { 18 + $this->initTeam($teams, $team1); 19 + $this->initTeam($teams, $team2); 20 + 21 + $this->updateMatchesPlayed($teams, $team1, $team2); 22 + $this->updateMatchResult($teams, $team1, $team2, $result); 23 + } 24 + 25 + $this->sortTeams($teams); 26 + 27 + return $this->generateTable($teams); 28 + } 29 + 30 + private function parseInput(string $input): array 31 + { 32 + $rows = explode("\n", $input); 33 + $matches = []; 34 + 35 + foreach ($rows as $row) { 36 + if ($row === "") { 37 + continue; 38 + } 39 + 40 + $matches[] = explode(";", $row); 41 + } 42 + 43 + return $matches; 44 + } 45 + 46 + private function initTeam(array &$teams, string $team): void 47 + { 48 + if (!isset($teams[$team])) { 49 + $teams[$team] = [ 50 + "MP" => 0, 51 + "W" => 0, 52 + "D" => 0, 53 + "L" => 0, 54 + "P" => 0, 55 + ]; 56 + } 57 + } 58 + 59 + private function updateMatchesPlayed( 60 + array &$teams, 61 + string $team1, 62 + string $team2, 63 + ): void { 64 + $teams[$team1]["MP"]++; 65 + $teams[$team2]["MP"]++; 66 + } 67 + 68 + private function updateMatchResult( 69 + array &$teams, 70 + string $team1, 71 + string $team2, 72 + string $result, 73 + ): void { 74 + switch ($result) { 75 + case "win": 76 + $teams[$team1]["W"]++; 77 + $teams[$team2]["L"]++; 78 + $teams[$team1]["P"] += 3; 79 + break; 80 + 81 + case "loss": 82 + $teams[$team2]["W"]++; 83 + $teams[$team1]["L"]++; 84 + $teams[$team2]["P"] += 3; 85 + break; 86 + 87 + case "draw": 88 + $teams[$team1]["D"]++; 89 + $teams[$team2]["D"]++; 90 + $teams[$team1]["P"]++; 91 + $teams[$team2]["P"]++; 92 + break; 93 + } 94 + } 95 + 96 + private function sortTeams(array &$teams): void 97 + { 98 + uksort($teams, function ($teamA, $teamB) use ($teams) { 99 + return $teams[$teamB]["P"] <=> $teams[$teamA]["P"] ?: 100 + strcmp($teamA, $teamB); 101 + }); 102 + } 103 + 104 + private function generateTable(array $teams): string 105 + { 106 + $output = self::HEADER; 107 + 108 + foreach ($teams as $team => $stats) { 109 + $output .= sprintf( 110 + "\n%-31s| %2d | %2d | %2d | %2d | %2d", 111 + $team, 112 + $stats["MP"], 113 + $stats["W"], 114 + $stats["D"], 115 + $stats["L"], 116 + $stats["P"], 117 + ); 118 + } 119 + 120 + return $output; 121 + } 122 + }
+179
php/tournament/TournamentTest.php
··· 1 + <?php 2 + 3 + /* 4 + * By adding type hints and enabling strict type checking, code can become 5 + * easier to read, self-documenting and reduce the number of potential bugs. 6 + * By default, type declarations are non-strict, which means they will attempt 7 + * to change the original type to match the type specified by the 8 + * type-declaration. 9 + * 10 + * In other words, if you pass a string to a function requiring a float, 11 + * it will attempt to convert the string value to a float. 12 + * 13 + * To enable strict mode, a single declare directive must be placed at the top 14 + * of the file. 15 + * This means that the strictness of typing is configured on a per-file basis. 16 + * This directive not only affects the type declarations of parameters, but also 17 + * a function's return type. 18 + * 19 + * For more info review the Concept on strict type checking in the PHP track 20 + * <link>. 21 + * 22 + * To disable strict typing, comment out the directive below. 23 + */ 24 + 25 + declare(strict_types=1); 26 + 27 + use PHPUnit\Framework\TestCase; 28 + 29 + class TournamentTest extends TestCase 30 + { 31 + private Tournament $tournament; 32 + 33 + public static function setUpBeforeClass(): void 34 + { 35 + require_once 'Tournament.php'; 36 + } 37 + 38 + protected function setUp(): void 39 + { 40 + $this->tournament = new Tournament(); 41 + } 42 + 43 + public function testHeaderOnlyNoTeams(): void 44 + { 45 + $scores = ''; 46 + $expected = 'Team | MP | W | D | L | P'; 47 + $this->assertEquals($expected, $this->tournament->tally($scores)); 48 + } 49 + 50 + public function testWinIsThreePointsLossIsZeroPoints(): void 51 + { 52 + $scores = 'Allegoric Alaskans;Blithering Badgers;win'; 53 + $expected = 54 + "Team | MP | W | D | L | P\n" . 55 + "Allegoric Alaskans | 1 | 1 | 0 | 0 | 3\n" . 56 + "Blithering Badgers | 1 | 0 | 0 | 1 | 0"; 57 + $this->assertEquals($expected, $this->tournament->tally($scores)); 58 + } 59 + 60 + public function testWinCanAlsoBeExpressedAsALoss(): void 61 + { 62 + $scores = 'Blithering Badgers;Allegoric Alaskans;loss'; 63 + $expected = 64 + "Team | MP | W | D | L | P\n" . 65 + "Allegoric Alaskans | 1 | 1 | 0 | 0 | 3\n" . 66 + "Blithering Badgers | 1 | 0 | 0 | 1 | 0"; 67 + $this->assertEquals($expected, $this->tournament->tally($scores)); 68 + } 69 + 70 + public function testDifferentTeamsCanWin(): void 71 + { 72 + $scores = 'Blithering Badgers;Allegoric Alaskans;win'; 73 + $expected = 74 + "Team | MP | W | D | L | P\n" . 75 + "Blithering Badgers | 1 | 1 | 0 | 0 | 3\n" . 76 + "Allegoric Alaskans | 1 | 0 | 0 | 1 | 0"; 77 + $this->assertEquals($expected, $this->tournament->tally($scores)); 78 + } 79 + 80 + public function testADrawIsOnePointEach(): void 81 + { 82 + $scores = 'Allegoric Alaskans;Blithering Badgers;draw'; 83 + $expected = 84 + "Team | MP | W | D | L | P\n" . 85 + "Allegoric Alaskans | 1 | 0 | 1 | 0 | 1\n" . 86 + "Blithering Badgers | 1 | 0 | 1 | 0 | 1"; 87 + $this->assertEquals($expected, $this->tournament->tally($scores)); 88 + } 89 + 90 + public function testThereCanBeMultipleMatches(): void 91 + { 92 + $scores = 93 + "Allegoric Alaskans;Blithering Badgers;win\n" . 94 + "Allegoric Alaskans;Blithering Badgers;win"; 95 + $expected = 96 + "Team | MP | W | D | L | P\n" . 97 + "Allegoric Alaskans | 2 | 2 | 0 | 0 | 6\n" . 98 + "Blithering Badgers | 2 | 0 | 0 | 2 | 0"; 99 + $this->assertEquals($expected, $this->tournament->tally($scores)); 100 + } 101 + 102 + public function testThereCanBeMoreThanOneWinner(): void 103 + { 104 + $scores = 105 + "Allegoric Alaskans;Blithering Badgers;loss\n" . 106 + "Allegoric Alaskans;Blithering Badgers;win"; 107 + $expected = 108 + "Team | MP | W | D | L | P\n" . 109 + "Allegoric Alaskans | 2 | 1 | 0 | 1 | 3\n" . 110 + "Blithering Badgers | 2 | 1 | 0 | 1 | 3"; 111 + $this->assertEquals($expected, $this->tournament->tally($scores)); 112 + } 113 + 114 + public function testThereCanBeMoreThanTwoTeams(): void 115 + { 116 + $scores = 117 + "Allegoric Alaskans;Blithering Badgers;win\n" . 118 + "Blithering Badgers;Courageous Californians;win\n" . 119 + "Courageous Californians;Allegoric Alaskans;loss"; 120 + $expected = 121 + "Team | MP | W | D | L | P\n" . 122 + "Allegoric Alaskans | 2 | 2 | 0 | 0 | 6\n" . 123 + "Blithering Badgers | 2 | 1 | 0 | 1 | 3\n" . 124 + "Courageous Californians | 2 | 0 | 0 | 2 | 0"; 125 + $this->assertEquals($expected, $this->tournament->tally($scores)); 126 + } 127 + 128 + public function testStandardInput(): void 129 + { 130 + $scores = 131 + "Allegoric Alaskans;Blithering Badgers;win\n" . 132 + "Devastating Donkeys;Courageous Californians;draw\n" . 133 + "Devastating Donkeys;Allegoric Alaskans;win\n" . 134 + "Courageous Californians;Blithering Badgers;loss\n" . 135 + "Blithering Badgers;Devastating Donkeys;loss\n" . 136 + "Allegoric Alaskans;Courageous Californians;win"; 137 + $expected = 138 + "Team | MP | W | D | L | P\n" . 139 + "Devastating Donkeys | 3 | 2 | 1 | 0 | 7\n" . 140 + "Allegoric Alaskans | 3 | 2 | 0 | 1 | 6\n" . 141 + "Blithering Badgers | 3 | 1 | 0 | 2 | 3\n" . 142 + "Courageous Californians | 3 | 0 | 1 | 2 | 1"; 143 + $this->assertEquals($expected, $this->tournament->tally($scores)); 144 + } 145 + 146 + public function testIncompleteCompetitionWhereNotAllGamesPlayed(): void 147 + { 148 + $scores = 149 + "Allegoric Alaskans;Blithering Badgers;loss\n" . 150 + "Devastating Donkeys;Allegoric Alaskans;loss\n" . 151 + "Courageous Californians;Blithering Badgers;draw\n" . 152 + "Allegoric Alaskans;Courageous Californians;win"; 153 + $expected = 154 + "Team | MP | W | D | L | P\n" . 155 + "Allegoric Alaskans | 3 | 2 | 0 | 1 | 6\n" . 156 + "Blithering Badgers | 2 | 1 | 1 | 0 | 4\n" . 157 + "Courageous Californians | 2 | 0 | 1 | 1 | 1\n" . 158 + "Devastating Donkeys | 1 | 0 | 0 | 1 | 0"; 159 + $this->assertEquals($expected, $this->tournament->tally($scores)); 160 + } 161 + 162 + public function testTiesSortedAlphabetically(): void 163 + { 164 + $scores = 165 + "Courageous Californians;Devastating Donkeys;win\n" . 166 + "Allegoric Alaskans;Blithering Badgers;win\n" . 167 + "Devastating Donkeys;Allegoric Alaskans;loss\n" . 168 + "Courageous Californians;Blithering Badgers;win\n" . 169 + "Blithering Badgers;Devastating Donkeys;draw\n" . 170 + "Allegoric Alaskans;Courageous Californians;draw"; 171 + $expected = 172 + "Team | MP | W | D | L | P\n" . 173 + "Allegoric Alaskans | 3 | 2 | 1 | 0 | 7\n" . 174 + "Courageous Californians | 3 | 2 | 1 | 0 | 7\n" . 175 + "Blithering Badgers | 3 | 0 | 1 | 2 | 1\n" . 176 + "Devastating Donkeys | 3 | 0 | 1 | 2 | 1"; 177 + $this->assertEquals($expected, $this->tournament->tally($scores)); 178 + } 179 + }