Un bon exercice pour mettre en pratique les principes de la POO.
La plupart des challenges de Tainix peuvent être réalisés en créant un seul programme. Créer des classes n’est pas obligatoire. Mais Tainix, c’est aussi l’occasion de s’entrainer ! Illustration ici avec un challenge débutant que l’on va résoudre en différents objets en PHP.
$reponse = '';
$ennemisDetails = [];
foreach ($ennemis as $ennemi) {
[$position, $pv] = sscanf($ennemi, 'x:%d pv:%d');
$ennemisDetails[$position] = $pv;
}
ksort($ennemisDetails);
$batmobile = 0;
foreach ($ennemisDetails as $position => $pv) {
$nbDeplacements = ($position - $batmobile);
$reponsereponse .= str_repeat('D', $nbDeplacements);
$batmobile = $position;
$nbFire = ceil($pv / 10);
$reponse .= str_repeat('F', $nbFire);
}
Explications
On commence par parcourir les ennemis pour extraire les données importantes.
On utilise la fonction sscanf, qui permet d’extraire les données selon leur format. Là on définit, qu’il y a « x: » puis un nombre (%d), puis » pv: », puis un autre nombre (%d). Et on utilise une double attribution pour renseigner à la fois $position et $pv.
On crée donc un nouveau tableau, indexé par la position.
La fonction ksort, qui fonctionne par référence, me permet de trier selon les cles (keys) du tableau.
La batmobile démarre en position 0.
Je parcours à nouveau chaque ennemi.
Le nombre de déplacement vers la Droite correspond à la différence entre la position de l’ennemi et la position courante de la batmobile. Puis elle avance.
Le nombre de coup de F correspond à l’arrondi supérieur des points de vie de l’ennemi divisés par 10.
J’utilise la fonction str_repeat pour répéter mes caractères D ou F.
final class Enemy
{
private int $position;
private int $pv;
public function __construct(string $informations)
{
[$this->position, $this->pv] = sscanf($informations, 'x:%d pv:%d');
}
public function getPosition(): int
{
return $this->position;
}
public function getPv(): int
{
return $this->pv;
}
}
final class Enemies
{
private array $enemies;
public function __construct(array $informations)
{
foreach ($informations as $enemy) {
$this->enemies[] = new Enemy($enemy);
}
usort($this->enemies, [$this, 'sortEnemis']);
}
public function sortEnemis(Enemy $e1, Enemy $e2): int
{
return ($e1->getPosition() < $e2->getPosition()) ? -1 : 1;
}
public function getEnemies(): array
{
return $this->enemies;
}
}
final class Batmobile
{
private const INSTRUCTION_MOVE = 'D';
private const INSTRUCTION_FIRE = 'F';
private const POWER_FIRE = 10;
private $position = 0;
public function getInstructionsToMove(int $position): string
{
$distance = $position - $this->position;
$this->move($distance);
return str_repeat(
self::INSTRUCTION_MOVE,
$distance
);
}
private function move(int $distance): void
{
$this->position += $distance;
}
public function getInstructionsToFire(int $pv): string
{
return str_repeat(
self::INSTRUCTION_FIRE,
ceil($pv / self::POWER_FIRE)
);
}
}
Explications
Je crée 3 classes.
La classe Enemy traite les informations via sscanf lors de la construction.
La classe Enemies regroupe tous les Enemy. Elle utilise usort avec la méthode dédiée sortEnemis, qui permet de créer une méthode de tri spécifique. Ici je vais donc pouvoir trier mes ennemis selon leur attribut position.
La classe Batmobile a quelques constantes liées à l’énoncé du challenge. Elle a ensuite 2 méthodes publiques « getInstructions… » qui vont retourner les instructions permettant de déplacer ou de faire feu. La position courante de la batmobile est mise à jour via la méthode privée move.
$reponse = '';
$batmobile = new Batmobile;
$enemies = new Enemies($data['ennemis']);
foreach ($enemies->getEnemies() as $enemy) {
$reponse .= $batmobile->getInstructionsToMove($enemy->getPosition());
$reponse .= $batmobile->getInstructionsToFire($enemy->getPv());
}
echo $reponse;
D’autres techniques de parsing en PHP
D’autres challenges Débutant qui se prêtent bien à la programmation orientée objet :
Corrigés, challenges, actualités, veille technique... aucun spam.