Dessiner le Labyrinthe
Objectif
L'objectif de cette séance est de comprendre et d'appliquer les structures de données pour dessiner le labyrinthe de notre jeu Pacman.

Nous allons apprendre :
- à représenter le labyrinthe sous forme de tableau (array) en JavaScript,
 - et à afficher le tableau du labyrinthe à l'écran avec Expo.
 
Notions théoriques
Pour représenter notre labyrinthe, nous allons utiliser un tableau à 2 dimensions.
Chaque élément du tableau correspondra à une case du labyrinthe : un mur ou un chemin.
Les tableaux en Javascript
Les tableaux en JavaScript sont des collections ordonnées de valeurs qui peuvent être de différents types.
Les tableaux en JavaScript :
- sont flexibles,
 - peuvent changer de taille dynamiquement,
 - et offrent des méthodes pour effectuer des opérations telles que l'itération et la transformation des éléments.
 
Exemple d'un tableau simple :
let fruits = ["pomme", "banane", "cerise"];
Exemple d'un tableau de tableaux (aussi appelé tableau multidimensionnel) :
let grille = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];
En JavaScript, un tableau à 2 dimensions peut être vu comme un tableau de tableaux.
Voici un exemple de représentation d'un petit labyrinthe :
const labyrinthe = [
  [1, 1, 1, 1, 1],
  [1, 0, 0, 0, 1],
  [1, 0, 1, 0, 1],
  [1, 0, 1, 0, 1],
  [1, 1, 1, 1, 1]
];
- Dans ce tableau, 
1représente un mur et0un chemin. - Ce tableau représente un labyrinthe avec un contour de murs et un chemin à l'intérieur.
 
let ou const
En JavaScript, let et const sont des mots-clés utilisés pour déclarer des variables.
letpermet de déclarer des variables dont la valeur peut changer,- tandis que 
constest utilisé pour des variables dont la valeur ne peut pas changer. 
Exemple pratique
Pour transformer notre tableau en un véritable labyrinthe visuel,
nous pouvons utiliser le composant View de React Native.
- 
Voici un exemple de fonction pour dessiner une case :
function Case(props) {
const estMur = props.estMur;
const styleCase = {
width: 40,
height: 40,
backgroundColor: estMur ? 'black' : 'blue',
};
return <View style={styleCase} />;
}Explications des lignes de la fonction
Case.- 
Déclaration de la fonction :
Case(props)déclare une fonction qui prend un objetpropsen paramètre.propsest un objet standard en React qui permet de passer des données et des configurations aux composants. - 
Extraction de la propriété
estMur: La ligneconst estMur = props.estMur;extrait la propriétéestMurde l'objetprops. Cette propriété est utilisée pour déterminer si la case à dessiner est un mur ou non. - 
Définition du style de la case : La constante
styleCaseest un objet qui définit les styles CSS pour le composantViewqui sera retourné. Les styles définissent la largeur et la hauteur de la case (widthetheightsont tous deux de 40 pixels). La couleur de fond (backgroundColor) est conditionnelle : siestMurest vrai (c'est-à-dire si la case représente un mur), la couleur de fond sera noire ('black'), sinon elle sera bleue ('blue'). - 
Rendu du composant : La fonction retourne un élément
Viewavec le style appliqué via l'attributstyle. En React Native,Viewest un composant conteneur qui peut être utilisé pour envelopper d'autres composants. Il est similaire à unediven HTML. 
En résumé, la fonction
Caseretourne une case de 40 pixels de côté qui sera soit noire si elle représente un mur, soit bleue sinon. - 
 - 
Voici un exemple de fonction pour dessiner toutes les cases, en faisant appel à la fonction Case() pour chaque case du labyrinthe :
function Labyrinthe(props) {
const labyrinthe = props.labyrinthe;
return (
<View style={{ flexDirection: 'column' }}>
{labyrinthe.map(function(ligne, indexLigne) {
return (
<View key={indexLigne} style={{ flexDirection: 'row' }}>
{ligne.map(function(caseLabyrinthe, indexColonne) {
return (
<Case
key={indexColonne}
estMur={caseLabyrinthe === 1}
/>
);
})}
</View>
);
})}
</View>
);
}Explications des lignes de la fonction
Labyrinthe.La fonction
Labyrintheprend un seul argument,props, qui est un objet contenant toutes les propriétés (props) passées au composantLabyrinthelorsqu'il est utilisé dans un autre composant.Voici une explication détaillée de ce que fait chaque partie du code :
- 
Extraction de
labyrinthedepuisprops: La première ligne à l'intérieur de la fonction extrait la propriétélabyrinthede l'objetprops. Cette propriétélabyrintheest supposée être un tableau à deux dimensions représentant le labyrinthe, où chaque sous-tableau représente une ligne du labyrinthe. - 
Rendu du composant
Viewracine: Le composant retourne un élémentViewde React Native, qui est l'équivalent d'unedivdans le web. Cet élémentViewest configuré pour disposer ses enfants en colonne avec le styleflexDirection: 'column'. - 
Itération sur les lignes du labyrinthe: À l'intérieur de cet élément
View, le code itère sur chaque ligne du labyrinthe en utilisant la méthodemap. Pour chaque ligne, une fonction est appelée qui prend la ligne actuelle et son index (indexLigne) en tant qu'arguments. - 
Rendu des lignes du labyrinthe: Pour chaque ligne, un autre élément
Viewest retourné, qui représente une ligne du labyrinthe. Cet élémentViewest configuré pour disposer ses enfants en ligne avec le styleflexDirection: 'row'. La clé (key) est utilisée pour aider React à identifier quels éléments ont changé, ont été ajoutés ou sont restés les mêmes lors des mises à jour de la liste. - 
Itération sur les cases de chaque ligne: À l'intérieur de chaque ligne, une autre itération est faite sur chaque case de cette ligne avec la méthode
map. Pour chaque case, une fonction est appelée qui prend la valeur de la case (caseLabyrinthe) et l'index de la colonne (indexColonne) en tant qu'arguments. - 
Rendu des cases individuelles: Pour chaque case de la ligne, le composant
Caseest retourné. Ce composant est probablement un autre composant personnalisé qui sait comment dessiner une case individuelle du labyrinthe. Il reçoit une propestMurqui est un booléen déterminé par la conditioncaseLabyrinthe === 1. Cela suggère que dans le tableaulabyrinthe, une valeur de1représente un mur et toute autre valeur représente un espace vide. Lekeyest également utilisé ici pour les mêmes raisons d'optimisation des performances. 
En résumé, la fonction
Labyrintheprend un tableau à deux dimensions représentant un labyrinthe et le transforme en une représentation visuelle à l'aide de composants React Native. Chaque ligne est rendue comme une série deViewen ligne, et chaque case est rendue par le composantCase, qui change d'apparence en fonction de savoir si elle est un mur ou un espace vide. - 
 
Dans ce code, nous définissons 2 fonctions :
Casepour dessiner une case individuelle,- et 
Labyrinthepour dessiner le labyrinthe entier en utilisantCase. 
Elements de code à connaître
Array.map(): Cette méthode crée un nouveau tableau avec les résultats de l'appel d'une fonction fournie sur chaque élément du tableau appelant.React Native Views: LesViewsont des conteneurs qui supportent le style et le layout. Ils sont l'équivalent desdiven HTML.
Test de mémorisation/compréhension
TP : Dessiner le labyrinthe
Votre mission
Votre mission consiste à dessiner un labyrinthe (avec des chemins et des murs).
Etapes
Voici un exemple de code qui permet dessiner un labyrinthe :
- 
Créez un nouveau fichier
GenererationLabyrinthe.jsà la racine de votre projet (à côté deApp.js).// GenererationLabyrinthe.js - 
Ajoutez la fonction
genererLabyrinthe(rows, cols)dans le fichierGenererationLabyrinthe.js:function genererLabyrinthe(rows, cols) {
const labyrinthe = [
...
];
return labyrinthe;
} - 
Ajoutez le tableau
labyrinthefourni ci-dessous, dans votre fichierGenererationLabyrinthe.js, pour représenter le labyrinthe de base :const labyrinthe = [
[1, 1, 1, 1, 1, 1, 1, 1, 1], // Mur supérieur
[1, 0, 0, 0, 0, 0, 0, 0, 1], // Chemin horizontal
[1, 0, 1, 1, 1, 1, 1, 0, 1], // 2 passages sur la ligne 3
[1, 0, 0, 0, 0, 0, 0, 0, 1], // Chemin horizontal
[1, 1, 1, 1, 0, 1, 1, 1, 1], // 1 passage sur la ligne 5
[1, 0, 0, 0, 0, 0, 0, 0, 1], // Chemin horizontal
[1, 1, 1, 0, 1, 1, 1, 0, 1], // 2 passages sur la ligne 7
[1, 0, 0, 0, 0, 0, 0, 0, 1], // Chemin horizontal
[1, 1, 1, 1, 1, 1, 1, 1, 1] // Mur inférieur
];- Dans ce tableau, 
1représente un mur et0un chemin. - Ce tableau représente un labyrinthe avec un contour de murs et un chemin à l'intérieur.
 
 - Dans ce tableau, 
 - 
Ajoutez l'export de la fonction
genererLabyrintheà la fin du fichierGenererationLabyrinthe.js:export default genererLabyrinthe; - 
Importez le composant
genererLabyrinthe, dans votreApp.js, pour accéder au tableaulabyrinthe:import genererLabyrinthe from './GenererationLabyrinthe'; 
- 
Créez un nouveau fichier
Labyrinthe.jsà la racine de votre projet (à côté deApp.js).// Labyrinthe.js
import React from 'react';
import { View } from 'react-native';
const tailleCase = 40;
function Case(props) {
...
}
function Labyrinthe(props) {
...
} - 
Implémentez la fonction
Casepour afficher une case du labyrinthe....
function Case(props) {
const estMur = props.estMur;
const styleCase = {
width: tailleCase,
height: tailleCase,
backgroundColor: estMur ? 'black' : 'blue',
};
return <View style={styleCase} />;
} - 
Implémentez la fonction
Labyrinthepour afficher toutes les cases du labyrinthe....
function Labyrinthe(props) {
const labyrinthe = props.labyrinthe;
return (
<View style={{ flexDirection: 'column' }}>
{labyrinthe.map(function(ligne, indexLigne) {
return (
<View key={indexLigne} style={{ flexDirection: 'row' }}>
{ligne.map(function(caseLabyrinthe, indexColonne) {
return (
<Case
key={indexColonne}
estMur={caseLabyrinthe === 1}
/>
);
})}
</View>
);
})}
</View>
);
} - 
Ajoutez l'export de la fonction
Labyrintheà la fin du fichierLabyrinthe.js:export default Labyrinthe; - 
Effacez la ligne d'import de la Barre de statut, inutile, dans le fichier
App.js.Voici la ligne inutile, à effacer :
import { StatusBar } from 'expo-status-bar'; - 
Importez le composant
Labyrinthe, dans votreApp.js, pour rendre la fonctionLabyrintheaccessible dans l'application :import Labyrinthe from './Labyrinthe'; - 
Créez une variable (constante)
labyrinthepour stocker le tableau du labyrinthe dans le programme principalApp.js.import Labyrinthe from './Labyrinthe';
const labyrinthe = genererLabyrinthe(11, 11);
export default function App() { 
- 
Effacez les lignes inutiles dans le composant
Viewdu fichierApp.js.Voici les 2 lignes inutiles, à effacer :
<Text>Open up App.js to start working on your app!</Text>
<StatusBar style="auto" /> - 
Ajoutez le composant
Labyrinthedans le composantViewpour afficher le labyrinthe :return (
<View style={styles.container}>
<View>
<Labyrinthe labyrinthe={labyrinthe} />
</View>
</View>
); - 
Testez votre application pour vous assurer que le labyrinthe s'affiche correctement :

 
Une solution
Vous devez être connecté pour voir le contenu.
Vous pouvez inspecter le code HTML généré par l'exécution du code Javascript par votre navigateur (clic droit + Inspecter) :

Vous êtes invités à créer un autre tableau pour dessiner un autre labyrinthe :
const labyrinthe = [
  ...
];
et à actualiser la page dans votre navigateur pour découvrir le nouveau labyrinthe et tester votre application.
Pour générer un tableau de façon aléatoire.
Vous devez être connecté pour voir le contenu.