On commence par se passer des if/else et on termine avec des fonctions de callback.
// Données d'entrée
$input = 'PFCFFPC';
// Résultat attendu
$result = 'FCPCCFP';
$response = '';
$length = strlen($input);
for ($i = 0; $i < $length; $i++) {
$play = $input[$i];
if ($play === 'P') {
$counterPlay = 'F';
} elseif ($play === 'F') {
$counterPlay = 'C';
} else {
$counterPlay = 'P';
}
$response .= $counterPlay;
}
// Test de la solution trouvée
if ($response === $result) {
echo 'Challenge OK';
}
Il est important ici de bien effectuer le strlen avant le for. Sinon le strlen va s’effectuer à chaque itération.
Pour les prochains exemples, je ne reprendrais pas à chaque fois la déclaration de $input, $result, ni le test final.
$response = '';
$length = strlen($input);
for ($i = 0; $i < $length; $i++) {
if ($input[$i] === 'P') {
$response .= 'F';
} elseif ($input[$i] === 'F') {
$response .= 'C';
} elseif ($input[$i] === 'C') {
$response .= 'P';
} else {
// Erreur... encore un qui veut jouer Puit !
}
}
Je teste donc bien précisément le cas du « C » et je garde un dernier else pour une éventuelle erreur.
Je fais l’économie de mes variables $play et $counterPlay.
$response = '';
$length = strlen($input);
for ($i = 0; $i < $length; $i++) {
if ($input[$i] === 'P') {
$response .= 'F';
continue;
}
if ($input[$i] === 'F') {
$response .= 'C';
continue;
}
if ($input[$i] === 'C') {
$response .= 'P';
continue;
}
// Erreur... non, Puit ça n'existe pas !
}
Comme le continue va directement passer à l’itération suivante, plus besoin de else !
$response = '';
$length = strlen($input);
for ($i = 0; $i < $length; $i++) {
switch ($input[$i]) {
case 'P':
$response .= 'F';
break;
case 'F':
$response .= 'C';
break;
case 'C':
$response .= 'P';
break;
default:
// Erreur... il triche le coquin
break;
}
}
Le switch se prête très bien à ce genre de situation.
$response = '';
foreach (str_split($input) as $play) {
switch ($play) {
case 'P':
$response .= 'F';
break;
case 'F':
$response .= 'C';
break;
case 'C':
$response .= 'P';
break;
default:
// Erreur... Euh... Lézard ? Sérieux ?
break;
}
}
Le str_split peut être mis directement dans le foreach, pas nécessaire de créer une variable avant.
define('PIERRE', 'P');
define('FEUILLE', 'F');
define('CISEAUX', 'C');
$response = '';
foreach (str_split($input) as $play) {
switch ($play) {
case PIERRE:
$response .= FEUILLE;
break;
case FEUILLE:
$response .= CISEAUX;
break;
case CISEAUX:
$response .= PIERRE;
break;
default:
// Erreur... Euh... Le Lézard mange la Feuille ?
break;
}
}
On a un code qui se lit tout seul, et qui nous protège des fautes de frappe dans les chaînes de caractères.
$response = '';
$match = [
PIERRE => FEUILLE,
FEUILLE => CISEAUX,
CISEAUX => PIERRE
];
foreach (str_split($input) as $play) {
$response .= $match[$play];
}
D’un coup on économise quelques lignes ! Plus besoin de switch non plus.
$response = '';
foreach (str_split($input) as $play) {
$response .= counterPlay($play);
}
function counterPlay(string $play): string
{
$match = [
PIERRE => FEUILLE,
FEUILLE => CISEAUX,
CISEAUX => PIERRE
];
if (isset($match[$play])) {
return $match[$play];
}
// Erreur... Quoi ? Spock ? Qu'est ce qu'il vient faire là ?
}
Ma fonction est typée.
J’ai rajouté le test d’existence de la correspondance par rapport à la version précédente.
Variante de la fonction counterPlay avec l’instruction match (PHP 8) :
function counterPlay(string $play): string
{
return match($play) {
PIERRE => FEUILLE,
FEUILLE => CISEAUX,
CISEAUX => PIERRE,
default => ''
};
}
Toutes les infos sur match, qui permet de faire des choses bien + complexes et puissantes que l’exemple ci-dessus.
$plays = str_split($input);
$counterPlays = array_map('counterPlay', $plays);
$response = implode($counterPlays);
// ou en 1 ligne
$response = implode(array_map('counterPlay', str_split($input)));
Si la fonction implode est appelée avec un seul paramètre, qui est un tableau, alors la « glue » est « » (chaîne de caractère vide).
Si vous trouvez la version en 1 ligne complexe à lire, préférez une version en 2 ou 3 lignes, avec 1 ou 2 variables intermédiaires.
define('MATCH', [
PIERRE => FEUILLE,
FEUILLE => CISEAUX,
CISEAUX => PIERRE
]);
$response = array_reduce(
str_split($input),
'counterPlayReduce',
'' // Permet de définir $counterPlays à '' initialement
);
function counterPlayReduce(string $counterPlays, string $play): string
{
if (isset(MATCH[$play])) {
return $counterPlays . MATCH[$play];
}
// Erreur... Donc Spock mange le Lézard ?
}
Il est possible de mettre un tableau dans une constante.
Il faut que je définisse « initial » de array_reduce à « » sinon il prend null et ne respecte pas le typage de ma fonction.
Corrigés, challenges, actualités, veille technique... aucun spam.