Skip to content

Commit

Permalink
Résolution et tests unitaire du challenge MONSTERS_3 avec les Collect…
Browse files Browse the repository at this point in the history
…ions

4 objets créés :
- FoodType (enum)
- Monster
- MonstersLines
- MonstersLinesWC (Without Collection)

Tests unitaires réalisés avec Pest

+ readme
+ composer.json pour intégrer le package collections
  • Loading branch information
TainixCode committed Feb 8, 2024
1 parent 4d3cf99 commit 475cb81
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 2 deletions.
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -25,5 +25,7 @@ Corrigés des challenges, avec tests unitaires réalisés avec PHPUnit ou Pest P

[Design Pattern en PHP : Strategy](https://tainix.fr/code/POO-en-PHP-design-Pattern-Strategy).

[Utilisation des Collections sur des objets](https://tainix.fr/code/PHP-Utiliser-les-Collections-sur-des-objets).

### Autres
[Interface ou héritage avec méthode abstraite ?](https://tainix.fr/code/POO-interfaces-ou-methodes-abstraites).
12 changes: 12 additions & 0 deletions challenges/MONSTERS_3/FoodType.php
@@ -0,0 +1,12 @@
<?php
declare(strict_types=1);

namespace Challenges\MONSTERS_3;

enum FoodType: string
{
case FRUITS = 'F';
case GRASS = 'G';
case ROCK = 'R';
case WOOD = 'W';
}
23 changes: 23 additions & 0 deletions challenges/MONSTERS_3/Monster.php
@@ -0,0 +1,23 @@
<?php

namespace Challenges\MONSTERS_3;

class Monster
{
public function __construct(
public readonly string $name,
public readonly FoodType $foodType,
public readonly int $weight,
) {}

public static function createFromText(string $informations): Monster
{
$data = explode(':', $informations);

return new self(
name: $data[0],
foodType: FoodType::from($data[1]),
weight: (int) $data[2]
);
}
}
41 changes: 41 additions & 0 deletions challenges/MONSTERS_3/MonstersLines.php
@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);

namespace Challenges\MONSTERS_3;

class MonstersLines
{
/**
* @var Monster[]
*/
private array $monsters = [];

public function addMonsterFromText(string $informations): void
{
$this->monsters[] = Monster::createFromText($informations);
}

public function getMonstersFromFoodType(FoodType $foodType, int $number = 3): string
{
// Gestion du tri, par défaut, dans l'ordre croissant, décroissant pour ROCK et WOOD
$sort = 'sortBy';
if ($foodType === FoodType::ROCK || $foodType === FoodType::WOOD) {
$sort = 'sortByDesc';
}

return collect($this->monsters)
->filter(function(Monster $item) use ($foodType) {
return $item->foodType === $foodType;
})
->$sort('weight')
->slice(0, $number)
->implode('name', '-');
}

public function getAllFirstThree(): string
{
return collect(FoodType::cases())
->map( fn(FoodType $foodType) => $this->getMonstersFromFoodType($foodType, 3) )
->implode('-');
}
}
74 changes: 74 additions & 0 deletions challenges/MONSTERS_3/MonstersLinesWC.php
@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);

namespace Challenges\MONSTERS_3;

class MonstersLinesWC
{
/**
* @var Monster[]
*/
private array $monsters = [];

public function addMonsterFromText(string $informations): void
{
$this->monsters[] = Monster::createFromText($informations);
}

public function getMonstersFromFoodType(FoodType $foodType, int $nbMonsters = 3): string
{
// 1. Initialisation d'un tableau vide
$monsters = [];

// 2. Je filtre en selon le type de nourriture
foreach ($this->monsters as $monster) {
if ($monster->foodType === $foodType) {
$monsters[] = $monster;
}
}

// 3. Je trie dans un sens ou dans l'autre, selon le type de nourriture
// grâce à la fonction usort, en comparant les poids
if ($foodType === FoodType::FRUITS || $foodType === FoodType::GRASS) {
usort($monsters, function (Monster $m1, Monster $m2) {
return $m1->weight <=> $m2->weight;
});
} else {
// Sens inverse
usort($monsters, function (Monster $m1, Monster $m2) {
return $m2->weight <=> $m1->weight;
});
}

// 4. Je garde les N premiers monstres
$monsters = array_slice($monsters, 0, $nbMonsters);

// 5. J'extraie les noms des monstres
$names = array_column($monsters, 'name');

// 6. Je lie les noms avec un "-"
return implode('-', $names);
}

public function getAllFirstThree(): string
{
// 0. Je précise l'ordre attendu
$foodTypes = [
FoodType::FRUITS,
FoodType::GRASS,
FoodType::ROCK,
FoodType::WOOD
];

// 0. J'initialise un tableau vide en vue de mon implode final
$result = [];

// 1. Je parcours chaque type pour récupérer les 3 premiers monstres
foreach ($foodTypes as $foodType) {
$result[] = $this->getMonstersFromFoodType($foodType, 3);
}

// 2. Je lie les éléments avec un "-"
return implode('-', $result);
}
}
11 changes: 9 additions & 2 deletions composer.json
Expand Up @@ -5,7 +5,8 @@
"php": ">=7.4",
"pestphp/pest": "1.*",
"guzzlehttp/guzzle": "^7.0",
"vlucas/phpdotenv": "^5.4"
"vlucas/phpdotenv": "^5.4",
"illuminate/collections": "^10.43"
},
"require-dev": {
"phpstan/phpstan": "^1.4"
Expand All @@ -22,7 +23,13 @@
"autoload": {
"psr-4" : {
"Challenges\\" : "challenges/",
"Tainix\\" : "tainix/"
"Tainix\\" : "tainix/",
"Pest\\" : "pest/"
}
},
"config": {
"allow-plugins": {
"pestphp/pest-plugin": true
}
}
}
58 changes: 58 additions & 0 deletions pest/MONSTERS_3/MonsterLines_Test.php
@@ -0,0 +1,58 @@
<?php
declare(strict_types=1);

use Challenges\MONSTERS_3\FoodType;
use Challenges\MONSTERS_3\MonstersLines;
use Challenges\MONSTERS_3\MonstersLinesWC;

test('Tri des monstres FRUITS', function(string $className) {

$monsters = ['Drex29:F:16', 'Traz65:W:74', 'Blit86:R:27', 'Brux18:F:83', 'Cobi82:R:72', 'Brux61:F:56', 'Draz68:G:97'];

$monsterLine = new $className;

foreach ($monsters as $monsterInformations) {
$monsterLine->addMonsterFromText($monsterInformations);
}

expect($monsterLine->getMonstersFromFoodType(FoodType::FRUITS, 3))->toBe('Drex29-Brux61-Brux18');
})->with([
[MonstersLinesWC::class],
[MonstersLines::class]
]);


test('Tri des monstres ROCK', function(string $className) {

$monsters = ['Drex29:R:16', 'Traz65:W:74', 'Blit86:R:27', 'Brux18:F:83', 'Cobi82:R:72', 'Brux61:F:56', 'Draz68:G:97'];

$monsterLine = new $className;

foreach ($monsters as $monsterInformations) {
$monsterLine->addMonsterFromText($monsterInformations);
}

expect($monsterLine->getMonstersFromFoodType(FoodType::ROCK, 3))->toBe('Cobi82-Blit86-Drex29');
})->with([
[MonstersLinesWC::class],
[MonstersLines::class]
]);

test('Jeu de données complet', function (string $className) {

// Données issues de Tainix directement --------
$monsters = ['Zela56:W:49', 'Fluz56:W:40', 'Cobi12:R:63', 'Truz57:F:69', 'Chir23:F:18', 'Moxa15:R:33', 'Vrip15:W:55', 'Moxa72:W:54', 'Trex43:W:23', 'Spro49:R:75', 'Spro80:G:36', 'Brop35:W:60', 'Draz89:R:15', 'Flix26:F:97', 'Plor65:F:21', 'Fero70:G:51', 'Gloz30:R:59', 'Flix61:G:24', 'Vlaz59:R:90', 'Drin34:R:64', 'Chir96:R:99', 'Moxa73:W:50', 'Zorp31:F:74', 'Fluz86:W:12', 'Vlox73:G:34'];
$result = 'Chir23-Plor65-Truz57-Flix61-Vlox73-Spro80-Chir96-Vlaz59-Spro49-Brop35-Vrip15-Moxa72';
// ---------------------------------------------

$monsterLine = new $className;

foreach ($monsters as $monsterInformations) {
$monsterLine->addMonsterFromText($monsterInformations);
}

expect($monsterLine->getAllFirstThree())->toBe($result);
})->with([
[MonstersLinesWC::class],
[MonstersLines::class]
]);
16 changes: 16 additions & 0 deletions pest/MONSTERS_3/Monsters_3Test.php
@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);

use Challenges\MONSTERS_3\FoodType;
use Challenges\MONSTERS_3\Monster;

test('Parsing et création d\'un Monster', function() {

$informations = 'Luxo18:F:33';

$monster = Monster::createFromText($informations);

expect($monster->name)->toBe('Luxo18');
expect($monster->foodType)->toBe(FoodType::FRUITS);
expect($monster->weight)->toBe(33);
});

0 comments on commit 475cb81

Please sign in to comment.