TP CSS et PHP : un jeu de mémoire Les objectifs pédagogiques de ce TP portent sur : l apprentissage du css, la gestion (contrôle) de la navigation (gestion de l état), l utilisation des sessions, la mise en pratique de génération de CSS en php Le cas d étude de ce TP est de faire un jeu. Il s agit de mémoriser une grille contenant des chiffres, puis, une fois la grille masquée, de désigner, dans un ordre aléatoire, les chiffres les uns après les autres. L utilisateur voit donc une grille, de 9 cases, 3x3. Il lance alors le jeu : la grille est masquée (à la place des chiffres, il y a des?). Dans cette grille une case est mise en valeur. L utilisateur doit indiquer quel chiffre est, selon lui, contenu dans la casé. Pour cela, les chiffres sont disponibles sur une ligne au-dessus de la grille. L utilisateur doit donc cliquer sur un de ces chiffres pour répondre. Ce TP est découpé en 3 grandes phases, découpées en sous problèmes pour une construction progressive du jeu : 1. La première phase porte sur le CSS, pour la mise en forme des pages, en considérant des grilles de 9 cases (3x3), en faisant bien apparaitre dans vos règles les nombres 9 et 3 (et en utilisant la fonction «calc» de CSS) 2. La deuxième phase porte sur le php pour gérer le jeu, en considérant des grilles de 9 cases (3x3) 3. La troisième partie porte sur l adaptation à des grilles de 4, 9, 16, 25, etc. cases. Une quatrième phase optionnelle est possible pour les plus avancés. Les phases 1 et 2 peuvent se faire séquentiellement ou en parallèle : - Si vous faites la phase 1 en entier, vous êtes dans une démarche de planification globale : vous faites d abord les maquettes (en html / css) des pages, puis en faisant la phase 2 vous réalisez la dynamique du jeu - Si vous faites les phases 1 et 2 simultanément, en étant guidé par le déroulement de la phase 2 et les liens entre les questions des deux phases, vous êtes dans une démarche itérative, plus proche des processus actuels de développement. Les images (check, question, question-grayscale) sont disponibles de l archive : http://deptinfo.unice.fr/~renevier/progwebserveur/tps/07.%20jeu%20m%c3%a9moire/img.zip. Phase I. le CSS Cette partie permet de préparer le rendu des pages qui seront générées en php. Ce travail peut se faire sur des pages statiques, sans que le jeu ne soit réalisé. Vous pouvez aussi faire ce travail de CSS au fur et à mesure de votre progression lors de la phase 2. 1 / 9
I.a. Faire une ligne Cette partie correspond à la mise en forme liée au paragraphe II.e. La Figure 1 illustre les différents états de la ligne de numéros : 1. La première correspond au cas des numéros pas encore placés dans la grille. La ligne est constituée de liens (<a>) contenus dans une barre de navigation (<nav>). Cette barre sera placée dans l entête de la page (<header> sous <body>). La mise en forme se fait grâce à une flex box horizontale. Pour chaque lien, la largeur est fixée via la flex-basis. La largeur totale (width + épaisseurs des traits + padding) doit Figure 1. La ligne des numéros faire 3rem. Chaque lien a une ombre diffuse, des coins arrondis et ont leur contenu centré verticalement et honrizontalement (en utilisant une fois encore un «display : flex ;»). Chaque lien a une marge gauche de 1rem. 2. Pour chaque numéros disponibles, lors de leur survol par la souris, une mise en valeur est réalisée par un grossissement (une transformation par mise à l échelle). 3. Les numéros déjà placés dans la grille ne sont plus des liens, mais des «<span>» de classe «disabled». Par transformation ils sont inclinés (une combinaison de skewy et de rotatey à partir du coin en haut à gauche). Ils ont aussi une image de fond, check.png, que vous devrez centrer. Le contenu (le numéro) est également centré verticallement et honrizontalement. Leur marge à gauche est également de 1rem, sauf s il sont précédés d une autre span de même classe, au quel cas ils ont une marge gauche de 0.1rem. 4. La dernière ligne illustre le rendu quand tous les numéros ont été placé sur la grille. Elle est donc constituée uniquement de «<span>» de classe «disabled». I.b. Faire une grille Cette partie correspond à la mise en forme liée au paragraphe II.c. La grille est une «<section>» comportant les numéros, des «<span>». La section et les spans seront des carrés. Pour mettre en forme la grille, vous utiliserez une flex box (verticale ou horizontale) dont les éléments contenus auront comme longueur (incluant les marges internes et épaisseur des bords) de côté 1/ nombre_de_case du côté de la grille. Cette longueur de côté inclut les pixels des bords. Un des côtés sera fixé par «flex-basis» et l autre par la largeur (en cas de flex box vertical) ou par la hauteur (en cas de flex box horizontal). Par exemple, la Figure 2 illustre les cas pour des grilles 2x2 et 3x3. Dans le cas de d une grille 2x2, chaque case fait la moitié (1/2) de la longueur d un côté de la grille. Dans le cas d une grille 3x3 c est 1/3. Faites le CSS pour le cas 3x3, en faisant bien apparaitre dans vos règles les nombres 9 et 3. 2 / 9
Figure 2. Grilles «verticales» 2x2 et 3x3 Gérez également les arrondis spécifiques : 1 ère case (arrondi en haut à gauche), dernière case (arrondi en bas à droite), et les cases n nombre_de_case et nombre_de_case + 1 nombre_de_case dont les arrondis seront, pour une flex box verticale, respectivement en bas à gauche et en haut à droite. Ces deux derniers arrondis sont inversés en cas de flex box horizontal. Dans le cas d une grille 3x3, ce sont donc les cases 3 et 7. Le contenu de chaque case est centré verticalement et horizontalement et il y a une ombre diffuse (et arrondie) autour de la grille. I.c. Faire les pages (statiques : début, 1 ère question, en cours de jeu, la grille est finie) Il s agit de finaliser les maquettes par rapport à ce qui a été décrit dans les questions précédentes. Il y a tout d abord l écran qui montre la grille à mémoriser. Elle est illustrée par la Figure 3. Elle introduit un titre «<h1>» qui changera à chaque page. Il y a aussi une zone flottante (une <section> ou un <aside>) sur le côté avec deux liens. Cette boite sera présente sur toutes les pages, son contenu sera adapté. Le lien recommencer à zéro permettra dans tous les cas de revenir à cette page. Cette partie correspond à la mise en forme liée au paragraphe II.b. Il y a ensuite l écran qui correspond à la page du jeu lors de la première question : l utilisateur arrive sur cette page en cliquant sur le lien «Commencer le jeu». Tous les chiffres sont disponibles (aucun n est placé dans la grille), la grille est masquée et une case est mise en valeur. La grille est alors faite de span vide et la case mise en valeur correspond à un span de classe «tofind». Cette page est illustrée par la Figure 4. Cette partie correspond à la mise en forme liée aux paragraphes II.c. et II.f. Figure 3. Page d'accueil Figure 4. Page du jeu lors de la première question 3 / 9
Au fur et à mesure que l utilisateur retrouve les numéros cachés dans les cases, la grille se remplit. C est illustré par la Figure 5. Les cases retrouvées doivent apparaitre avec un «check». Ceci se fait pour les cases non vides avec une image de fond placée aux ¾ de la largeur de la case et à la ½ de la hauteur de la case. Cette partie correspond à la mise en forme liée aux paragraphes II.f. et II.g. La dernière apparence que revêtit la page du jeu est illustrée par la Figure 6, quand la partie est terminée. Le nombre de coup pour retrouver la grille est indiqué. Le titre a une nouvelle fois changé. Le lien «recommencer» lance une nouvelle partie (retour à l écran initial). Cette partie correspond à la mise en forme liée aux paragraphes II.h. et II.i. Figure 6. La partie est terminée Figure 5. Page pendant le jeu Phase II. le Php Cette partie correspond au développement du code php pour mettre en place la gestion du jeu : savoir dans quelle étape du jeu le joueur est. Il faut aussi générer la grille à mémoriser, puis afficher la grille à retrouver en indiquant quelle case il faut retrouver. L utilisateur doit pouvoir répondre. Finalement, il faudra gérer la fin de la partie. La Figure 7 illustre cet enchainement. Tout au long de cette phase, pensez-également à mettre à jour le titre et la zone de côté. 4 / 9
Figure 7. Les états du jeu II.a. Gérer la remise à zéro (pratique pour la suite) La première étape est de gérer la remise à zéro de la session, pour pouvoir essayer plus facilement votre jeu, en remettant tout à zéro. La fonction suivante doit être utilisée : /** destruction de la session **/ function detruiresession() { // il faut detruire la session : copier coller de php.net... // La session est deja initialisee // Detruit toutes les variables de session $_SESSION = array(); // Si vous voulez detruire completement la session, effacez egalement // le cookie de session. // cela detruira la session et pas seulement les donnees de session! if (isset($_cookie[session_name()])) { setcookie(session_name(), '', time()-42000, '/'); } // Finalement, on detruit la session. session_destroy(); } // on termine par la redirection header("location: index.php"); II.b. Début la gestion des pages (navigation, session) Mettez en place la gestion de la navigation, même partiellement (car la fin de la partie n est pas facilement gérable à ce stade) pour pouvoir passer d une page à une autre, en suivant la navigation indiquée sur la Figure 7. 5 / 9
Pour structurer votre code, votre page sera toujours dans le fichier index.php. Celui-ci fera «un include» de la page en cours. Le fichier php «montrer.inc» correspond aux états «intinial» et «début de partie». Le fichier «question.inc» correspondront aux états «en jeu» et «jeu fini». En fonction de l état d avancement du jeu, mémorisé dans une variable de session $_SESSION["etat"], qui est une chaine de caractère, votre page index fera donc l include du fichier correspondant. Sans oublier de gérer la remise à zéro. Les événements (flèches noires sur la Figure 7. Les états du jeu) sont pour la plus part consécutif à une action de l utilisateur. Il n y a que le passage à «jeu fini» qui est automatique (après avoir donné la dernière réponse). Ces actions sont en fait des clics sur des liens. Ces liens doivent alors comporter un paramètre?action qui pourra valoir : «abandon» pour une remise à zéro, «commencer» pour passer à l état «en question», «recommencer» pour passer de l état «jeu fini» à «début de partie». II.c. session) Générer une grille à trouver (et la mémoriser dans la Il s agit ici de compléter le fichier «monter.inc». Il faut donc générer une grille, si elle n existe pas, la mémoriser dans $_SESSION["grille_resultat"]. Cette variable de session est un tableau dont la taille est le nombre de case (par exemple 9) et qui contient dans un ordre aléatoire les numéros à retrouver. Voici les fonctions qui peuvent vous aider. Un appel à la fonction rand(0, 8) renverra un nombre compris entre 0 et 8, 0 et 8 étant des valeurs possibles. La fonction unset($tab[5]) peut permettre de détruire la case d indice 5 du tableau $tab. $source = array_values($source); permet de réindexer (donc d enlever des trous dans la numérotation) d un tableau. Puis il faut générer le html correspondant (titre, la grille, la zone de côté). II.d. Générer une grille vide (visuellement pleine de «?») et désigner une case à trouver Il s agit de compléter le fichier «question.inc», mais aussi de compléter «montrer.inc». Le fichier «question.inc» doit montrer la grille en cours, en représentant les numéros qui n ont pas encore été découvert par un?, en mettant une case en valeur pour désigner laquelle doit être découverte et en affichant les numéros déjà retrouvées (voir la Figure 6). Il faut donc mémoriser dans une variable de session $_SESSION["grille_reponses"] les cases qui ont été découvertes ou non. Il s agit d un tableau qui indique pour chaque case si elle a été trouvé : $_SESSION["grille_reponses"][0] vaut false si la première case n a pas encore été retrouvée. Elle vaudra la valeur du numéro (par exemple 1 sur la Figure 2) quand elle aura été retrouvée. Pour générer la grille, si $_SESSION["grille_reponses"][$i] est faux, alors il faut générer un span vide (sans texte), le «?» étant une image (voir le paragraphe I.c. ). Si $_SESSION["grille_reponses"][$i] n est pas faux, et vaut donc un numéro, il faut générer un span non vide, contenant le numéro correspondant. 6 / 9
Il faut aussi compléter «montrer.inc» pour initialiser $_SESSION["grille_reponses"] (chaque case vaut false). Il faut aussi désigner une case à trouver. Cette case est à mémoriser dans $_SESSION["question_courante"]. Ce sera une des cases non encore trouvées. La fonction rand peut aussi être utile ici. La case correspondante devra être affichée par une span de classe «tofind». La question courante changera quand elle sera trouvée (c.f. II.g. ), mais en attendant, si une question courante a été choisie, il ne faut pas en redésigner une si elle n a pas été trouvée : ( isset($_session["question_courante"]) && (! $_SESSION["grille_reponses"][$_SESSION["question_courante"]]) ) II.e. Générer une ligne de numéro pour répondre Quand l utilisateur commence à retrouver les numéros, tous les numéros sont disponibles. Il faut donc générer les liens (qui permettent d identifier), qui pointe donc index.php mais avec un paramètre?case= la valeur du numéro proposé. Les numéros disponibles doivent être mémoriser dans une variqble de session $_SESSION["reponses_utilisees"] qui est un tableau indiquant pour chaque numéro s il a été utilisé ou non (false ou true). $_SESSION["reponses_utilisees"] contient donc des valeurs (de 1 à 9) et non pas des indices. Il faut initialiser ce tableau dans «montrer.inc» et générer la ligne de lien dans «question.inc». A ce stade, vous devriez voir une page semblable à la Figure 4. II.f. Gérer les réponses fausses Il s agit de mettre en place, au début du fichier «question.inc», le traitement de la réponse proposée. Elle est dans $_GET["case"]. Il s agit de vérifier si c est bien une réponse attendu, c est-à-dire en la convertissant en nombre (avec la fonction intval) et en vérifiant que la valeur est possible : comprise entre 1 et le nombre de case (par exemple 9). S il y a une question en cours, alors il faudra vérifier si la réponse proposée correspond à la réponse attendue (qui est dans $_SESSION["grille_resultat"] à l indice $_SESSION["question_courante"]). Si tout cela est faux, alors c est une réponse fausse, il ne faut alors rien faire : la question reste la même. II.g. Gérer les réponses justes (case remplie et validée, numéro non cliquable) Dans le cas où les tests de vérification sont tous passés avec succès, alors c est la bonne réponse. Il faut alors mettre à jour les variables de session $_SESSION["grille_reponses"] et $_SESSION["reponses_utilisees"]. Vous pouvez aussi détruire $_SESSION["question_courante"]. 7 / 9
Si tout fonctionne bien, le numéro devient grisé (c est un span et non plus un lien) dans la ligne de numéro. La case correspondante dans la grille est visible. Une autre case (non trouvée) est mise en valeur (c est la question suivante). II.h. Gérer la fin de partie Finalement, il ne reste plus qu à gérer la fin de la partie pour passer de l état «en jeu» à l état «jeu fini». Ce passage se fait lors de la vérification de la réponse soumise. Si elle est juste (c.f. ci-dessus) et si toutes les cases ont été retrouvées (on le sait en parcourant le tableau $_SESSION["reponses_utilisees"] où toutes les valeurs doivent être à true). Dans ce cas, on peut passer à l état «jeu fini». Du coup, il ne faut pas chercher de nouvelle question (il n y en a plus). Recommencer un jeu, cela veut dire ré-initialiser certaines variables de session (toutes celles utilisées jusqu à présent). II.i. Compter le nombre d essai Il vous reste à déterminer en combien d essai la grille a été retrouvée. Plus ce nombre est proche du nombre de case (ici 9), moins l utilisateur s est trompé et on peut estimer qu il a alors une bonne mémoire. Incrémenter aux moments opportuns une variable de session $_SESSION["nb_coups"] pour compter ce nombre de coup. Afficher le résultat lorsque l état est «jeu fini». Gérer aussi la (ré)initialisation de cette variable. Phase III. Adaptation à la taille de la grille A plusieurs endroit dans le CSS, vous devez avoir des expressions (calc) ou des sélecteurs (nth-child) qui dépendent du nombre de case (soit de 9 soit de 3, sa racine carrée). Identifiez tout cela, retirez du CSS et générez ce code CSS (que vous pouvez inclure dans une balise <style> dans la page). Cette génération doit dépendre d un paramètre : le nombre de case. Du coup, votre code Php doit se référencer à cette variable (ou constante) et cela doit vous permettre de changer le nombre de cases facilement, tant au niveau du php que du css. Phase IV. Pour aller plus loin Vous pouvez compter le nombre de partie faite, le nombre total de coup joué, le nombre de coup le plus petit pour une partie et le nombre de coup le plus grand pour une partie. Voici un dernier challenge : au lieu de placer des chiffres dans la grille, placer des mots comme parmi une liste de mot, voir l exemple ci-après. Une des difficultés est qu il n y a plus de correspondance entre les valeurs (le contenu des cases) et les indices. Pensez à encoder les paramètres des liens, sinon les caractères comme «'» poseront problème. Adaptez le code php mais aussi le css. 8 / 9
// source de la liste des couleurs : // http://fr.wikipedia.org/wiki/liste_de_noms_de_couleur $COULEURS = array("rouge", "orange", "jaune", "vert", "bleu", "indigo", "violet", "blanc", "noir", "Abricot", "Absinthe", "Acajou", "Aiguemarine", "Albâtre", "Amande", "Amarante", "Ambre jaune", "Ambre rouge", "Améthyste", "Anthracite", "Ardoise", "Argent", "Argile", "Asperge", "Aubergine", "Aurore", "Avocat", "Azur", "Azur brume", "Azur clair", "Azurin", "Banane", "Beige", "Beige clair", "Beurre", "Beurre frais", "Bis", "Bisque", "Bistre", "Blanc cassé", "Blanc de lait", "Blanc lunaire", "Bleu acier", "Bleu barbeau ou bleuet", "Bleu canard", "Bleu charrette", "Bleu ciel", "Bleu céleste", "Bleu de minuit", "Bleu des mers du sud", "Bleu dragée", "Bleu fumée", "Bleu givré", "Bleu guède", "Bleu Majorelle", "Bleu nuit", "Bleu outremer", "Bleu paon", "Bleu Persan", "Bleu pétrole", "Bleu roi", "Bleu turquin", "Bleu électrique", "Blond", "Blond vénitien", "Blé", "Bordeaux", "Bourgogne", "Bouton d'or", "Brique", "Bronze", "Brou de noix", "Brun", "Brun clair", "Bureau", "Caca d'oie", "Cacao", "Café", "Café au lait", "Cannelle", "Capucine", "Caramel", "Carotte", "Cerise", "Cerise Hollywood", "Cerise profonde", "Cerise rose", "Chair", "Chamois", "Chartreuse", "Chaudron", "Chocolat", "Châtaigne", "Châtain", "Citron", "Citrouille", "Colombin", "Coquelicot", "Coquille d'œuf", "Corail", "Cramoisi", "Crème", "Cuisse de nymphe", "Cuisse de nymphe émue", "Cuivre", "Cyan", "Cæruléum", "Denim", "Fauve", "Feu", "Feuille morte", "Flave", "Fraise", "Fraise écrasée", "Framboise", "Framboise rose", "Fuchsia", "Glauque", "Glycine", "Grenadine", "Grenat", "Gris", "Gris acier", "Gris de lin", "Gris fer", "Gris perle", "Groseille", "Grège", "Héliotrope", "Incarnadin", "Incarnat", "Indigo chaud", "Indigo du web", "Indigo électrique", "Ivoire", "Jais", "Jaune bouton d or", "Jaune canari", "Jaune chartreuse", "Jaune d'or", "Jaune impérial", "Jaune mimosa", "Kaki", "Lapis-lazuli", "Lavande", "Lie de vin", "Lilas", "Lin", "Magenta", "Magenta foncé, primaire en synthèse soustractive", "Magenta fuchsia", "Malachite", "Mandarine", "Marine", "Marron", "Mastic", "Maïs", "Melon", "Menthe", "Menthe à l'eau", "Mordoré", "Moutarde", "Nacarat", "Nankin", "Neige", "Noir d'encre", "Noir de jais", "Noisette", "Olive", "Opale", "Or", "Orange brûlé", "Orchidée", "Orpin de Perse", "Paille", "Parme", "Pervenche", "Pistache", "Poil de chameau", "Ponceau", "Prasin", "Prune", "Puce", "Queue-de-renard", "Rose", "Rose bonbon", "Rose dragée", "Rose du web", "Rose Mountbatten", "Rose Persan vif", "Rose razzle dazzle", "Rose ultra", "Rose vif", "Rouge cardinal", "Rouge cerise", "Rouge feu", "Rouge sang", "Rouge tomette", "Rouge-orangé", "Rouille", "Roux", "Rubis", "Sable", "Safran", "Safre", "Sang de bœuf", "Sanguine", "Saphir", "Sarcelle", "Saumon", "Saumon rose", "Soufre", "Souris", "Sépia", "Tabac", "Tangerine", "Taupe", "Tomate", "Topaze", "Tourterelle", "Turquoise", "Vanille", "Vermeil", "Vermillon", "Vert anis", "Vert bouteille", "Vert chartreuse", "Vert céladon", "Vert d'eau", "Vert gazon", "Vert impérial", "Vert kaki", "Vert lichen", "Vert lime", "Vert militaire", "Vert mousse", "Vert mélèze", "Vert opaline", "Vert perroquet", "Vert pin", "Vert poireau", "Vert pomme", "Vert prairie", "Vert printemps", "Vert sapin", "Vert sauge", "Vert tilleul", "Vert épinard", "Violet d'évêque", "Violine", "Zinzolin", "Ébène", "Écarlate", "Écru", "Émeraude", "Étain"); 9 / 9