diff --git a/R1.02/tp/tp5/README.md b/R1.02/tp/tp5/README.md
new file mode 100644
index 0000000..d0d9b2c
--- /dev/null
+++ b/R1.02/tp/tp5/README.md
@@ -0,0 +1,98 @@
+<h1> TP Js 1</h1>
+
+
+> Récupérez les fichiers sources utilisés pour le tp [ici](src/).
+
+## Exercices
+
+Le TP est une implantation en javasript du jeu de la vie. Il s'agit d'un automate cellulaire, dont les règles sont les suivantes : 
+ - Une cellule morte possédant exactement trois voisines vivantes devient vivante. 
+ - Une cellule vivante possédant deux ou trois voisines vivantes reste vivante, sinon elle meurt.
+
+Une cellule est une unité de la grille (carrée). Un tour est appelé une génération.
+
+
+>Pour plus d'informations, voir la page [Wikipédia](https://fr.wikipedia.org/wiki/Jeu_de_la_vie)
+
+> Le jeu est déjà codé, vous allez ajouter de nouvelles fonctionnalités au jeu dans ce TP.
+
+### Exercice 1 : Inclure du JS
+
+Chargez le fichier `script.js` dans la page html `index.html`
+
+> Il faut utiliser la balise `<script>` avec l'attribut `src` <br>
+> Attention ! Chargez le fichier  une fois que le DOM (la page HTML) est chargée. 
+
+Vous devez avoir le résultat suivant : 
+
+![gallerie](img/jeu.png ':-:')
+
+### Exercice 2 : Ajouter un bouton reset
+
+Ajoutez un bouton `reset` dans le HTML. Dans la fonction `main()` ajoutez ce qui est nécessaire pour pourvoir remettre à zéro le jeu. <br>
+
+> Pour remettre à zéro, il faut s'abonner à l'événement `click` sur le bouton reset, regardez comment le code est fait pour les autres boutons. <br>
+> Il faut ensuite:
+>  - stopper `autoplayInterval`, un timer est démarré avec la fonctionnalité auto play
+>  - détruire la grille courante avec la fonction `gridManager.destroyGrid();`
+>  - créer un nouvel object `GridManager` avec `gridManager = new GridManager(gridSize, DIV_CONTAINER_ID)`
+>  - initialiser le jeu avec `gridManager.setInitialState(INITIAL_STATE)`
+><br><br>
+
+> Vous avez des exemples dans le code.
+
+
+### Exercice 3 : Changer la taille de la grille
+
+Vous allez ajouter un bouton qui permet d'afficher lors du clic une popin. Vous allez pouvoir renseigner la taille de la grille. 
+
+> - Vous aurez besoin de la fonction [prompt](https://www.w3schools.com/jsref/met_win_prompt.asp).
+> - La valeur que vous récupérer est un type `string` (équivalent à char[] en C), il faut donc parser le type string en integer avec la fonction [parseInt()](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/parseInt)
+> - Vous allez réutiliser la fonction reset que vous avez écrite précédemment.
+
+> La grille est d'une taille minimum de 30.
+
+
+### Exercice 4 : Afficher la taille de la grille dans l'interface
+
+Vous allez afficher la taille à côté de la chaine de caractères `Taille de la grille:`. 
+
+> - Utilisez `document.getElementById(GRID_SIZE_VAL_ID)` 
+> - Utilisez la propriété `element.textContent = 'Hello World!`
+
+### Exercice 5 : Afficher la génération courante
+
+Vous allez afficher le numéro de la génération courante à côté de la chaine de caractères `Génération numéro:`. 
+
+> - Ajoutez ce qu'il manque dans la fonction `computeNextGeneration(gridManager, generation)`
+> - Pensez à incrémenter la variable `génération`
+
+### Exercice 6 : Vitesse d'execution du jeu
+
+Vous allez créer un bouton : 
+ - x1
+ - x2
+ - x10
+ - x100
+
+Lorsque le jeu est en mode auto play, il faut changer la vitesse à laquelle il faut appeler la fonction `computeNextGeneration(gridManager, generation)`. Si le jeu n'est pas en mode auto play mettre à jour la valeur de interval
+
+> - Il faut pensez à stopper le `setInterval` et le démarrer avec la nouvelle vitesse de jeu
+> - La vitesse normale du jeu est défini par la variable `GENERATION_INTERVAL`
+> - x2 = `GENERATION_INTERVAL/2`, x10 = `GENERATION_INTERVAL/10`, etc.  
+
+### Exercice 7 : (Bonus) Export de l'état de la grille
+
+On veut pouvoir sauvegarder la partie pour la reprendre plus tard. Pour cela il faut enregistrer l'état du jeu. <br>
+
+Créez une fonction d'export qui permet de : 
+ - récupérez la taille de la grille, connaitre les coordonnées des cellules actives, la génération courante et la vitesse d'éxecution du jeu si mode auto play
+ - sauvegardez l'état du jeu en `localStorage` lorsque l'on clique sur un bouton `Sauvegarder`
+
+
+ > - Réutilisez la fonction `logCurrentGridState` qui permet d'afficher les coordonnées des cellules actives dans la console
+ > - Un peu d'aide sur le [localStorage](https://developer.mozilla.org/fr/docs/Web/API/Window/localStorage)
+
+### Exercice 8 : (Bonus) Reprendre une partie
+
+A partir de l'exercice 7, écrire une fonction qui permet de reprendre une partie lorsque l'on clique sur un bouton `Reprendre` et si des données sont stockées en localStorage. 
diff --git a/R1.02/tp/tp5/img/jeu.png b/R1.02/tp/tp5/img/jeu.png
new file mode 100644
index 0000000..4586347
Binary files /dev/null and b/R1.02/tp/tp5/img/jeu.png differ
diff --git a/R1.02/tp/tp5/src/index.html b/R1.02/tp/tp5/src/index.html
new file mode 100644
index 0000000..e47af8e
--- /dev/null
+++ b/R1.02/tp/tp5/src/index.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html lang="fr">
+
+	<head>
+		<meta charset="utf-8">
+		<meta name="viewport" content="initial-scale=1,witdh=device-width">  
+		<title>Jeu de la vie</title>
+		<style>
+	* {
+		font-size : 1.1rem;
+	}
+	.menu {
+		text-align: center;
+	}
+
+	.row {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.cell {
+		width: 1.25rem;
+		height: 1.25rem;
+		border: 1px solid black;
+		box-sizing : border-box;
+	}
+		</style>
+	</head>
+
+	<body>
+		<menu class="menu">
+			<button id="next-gen">Prochaine Génération</button>
+			<button id="autoplay">Auto Play</button>
+			<p>
+			Génération numéro: <span id="generation-value"></span> | Taille de la grille: <span id="grid-size-value"></span>
+			</p>
+		</menu>
+
+		<div id="container"></div>
+		<script src="script.js"></script>
+	</body>
+
+</html>
diff --git a/R1.02/tp/tp5/src/script.js b/R1.02/tp/tp5/src/script.js
new file mode 100644
index 0000000..cd5bcb1
--- /dev/null
+++ b/R1.02/tp/tp5/src/script.js
@@ -0,0 +1,207 @@
+// ---------------------------------------------------------------------
+// ---------------------------------------------------------------------
+
+/**
+ * Cette partie du code, vous n'avez pas besoin d'y toucher. Elle permet 
+ * de gérer la grille et l'affichage des cellules
+ */
+
+class GridManager {
+  ACTIVE_COLOR = 'black';
+  INACTIVE_COLOR = 'grey';
+
+  gridContainerId;
+  gridSize;
+  grid = [];
+
+  constructor(gridSize, gridContainerId) {
+    if (!gridSize || gridSize < 30) {
+      throw new Error('The grid size must be at least 30');
+    }
+
+    if (!gridContainerId) {
+      throw new Error('gridContainerId must be set');
+    }
+
+    this.gridSize = gridSize;
+    this.gridContainerId = gridContainerId;
+    this.createGrid();
+  }
+
+  createGrid() {
+    const container = document.getElementById(this.gridContainerId);
+  
+    for (let i = 0; i < this.gridSize; i++) {
+      const row = document.createElement('div');
+      row.className = 'row';
+  
+      const gridRow = [];
+  
+      for (let j = 0; j < this.gridSize; j++) {
+        const cell = document.createElement('div');
+        cell.className = 'cell';
+        cell.style.backgroundColor = this.INACTIVE_COLOR;
+        row.appendChild(cell);
+  
+        gridRow.push(cell);
+      }
+  
+      container.appendChild(row);
+      this.grid.push(gridRow);
+    }
+  }
+
+  destroyGrid() {
+    for (let x = 0; x < this.gridSize; x++) {
+      for (let y = 0; y < this.gridSize; y++) {
+        const node = this.grid[y][x];
+        node.parentNode.removeChild(node);
+      }
+    }
+
+    const container = document.getElementById(this.gridContainerId);
+    while (container.firstChild) {
+      container.removeChild(container.lastChild);
+    }
+
+    this.grid = [];
+  }
+
+  setInitialState(initialState) {
+    const coords = initialState.split(';').map(coord => coord.split(','));
+    coords.forEach((coord) => this.activeCell(+coord[0], +coord[1]));
+  }
+
+  isInGridRange(x, y) {
+    return x >= 0 && x < this.gridSize && y >= 0 && y < this.gridSize;
+  }
+
+  isActiveCell(x, y) {
+    return this.isInGridRange(x, y) && this.grid[y][x].style.backgroundColor === this.ACTIVE_COLOR;
+  }
+
+  activeCell(x, y) {
+    if (!this.isInGridRange(x, y)) {
+      return;
+    }
+
+    this.grid[y][x].style.backgroundColor = this.ACTIVE_COLOR;
+  }
+  
+  deactiveCell(x, y) {
+    if (!this.isInGridRange(x, y)) {
+      return;
+    }
+    
+    this.grid[y][x].style.backgroundColor = this.INACTIVE_COLOR;
+  }
+  
+  getNumberActiveNeighbourCells(x, y) {
+    const neighbours = [
+      [x-1, y-1], [x, y-1], [x+1, y-1],
+      [x-1, y],             [x+1, y],
+      [x-1, y+1], [x, y+1], [x+1, y+1],
+    ];
+  
+    return neighbours.map(cell => this.isActiveCell(cell[0], cell[1])).filter(cell => cell === true).length; 
+  }
+
+  logCurrentGridState() {
+    const activeCells = [];
+  
+    for (let x = 0; x < this.gridSize; x++) {
+      for (let y = 0; y < this.gridSize; y++) {
+        if (this.isActiveCell(x, y)) {
+          activeCells.push(`${x},${y}`);
+        }
+      }
+    }
+  
+    console.log(activeCells.join(';'));
+  }
+}
+
+
+// ---------------------------------------------------------------------
+// ---------------------------------------------------------------------
+
+
+const INITIAL_STATE = '11,1;12,1;10,2;9,3;9,4;9,5;10,6;11,7;12,7;2,4;1,5;2,5;18,28;17,28;19,27;20,26;20,25;20,24;19,23;18,22;17,22;27,25;28,24;27,24;11,28;12,28;10,27;9,26;9,25;9,24;10,23;11,22;12,22;2,25;1,24;2,24;18,1;17,1;19,2;20,3;20,4;20,5;19,6;18,7;17,7;27,4;28,5;27,5';
+const GENERATION_INTERVAL = 1000; // 1 seconde
+const DIV_CONTAINER_ID = 'container'; 
+const BTN_AUTOPLAY_ID = 'autoplay';
+const BTN_NEXT_GEN_ID = 'next-gen';
+const GENERATION_VAL_ID = 'generation-value';
+const GRID_SIZE_VAL_ID = 'grid-size-value';
+
+function computeNextGeneration(gridManager, generation) 
+{
+
+  // incrémenter la valeur de la génération et l'afficher à côté de 'Génération numéro:'
+
+  const nextGrid = [];
+
+  for (let x = 0; x < gridManager.gridSize; x++) {
+    const row = [];
+    for (let y = 0; y < gridManager.gridSize; y++) {
+      const isActive = gridManager.isActiveCell(x, y);
+      const numberActiveNeighbourCells = gridManager.getNumberActiveNeighbourCells(x, y);
+
+      if (!isActive) {
+        row.push(numberActiveNeighbourCells === 3 ? true : false);
+      } else {
+        row.push(numberActiveNeighbourCells === 2 || numberActiveNeighbourCells === 3 ? true : false);
+      }
+    }
+
+    nextGrid.push(row);
+  }
+
+  for (let x = 0; x < nextGrid.length; x++) {
+    for (let y = 0; y < nextGrid[x].length; y++) {
+      nextGrid[x][y] ? gridManager.activeCell(x,y) : gridManager.deactiveCell(x,y);
+    }
+  }
+
+  gridManager.logCurrentGridState();
+  return generation;
+}
+
+// Fonction principale du jeu
+
+function main() 
+{
+  let autoplayInterval;
+  let gridSize = 30;
+  let generation = 0;
+
+  let gridManager = new GridManager(gridSize, DIV_CONTAINER_ID);
+  gridManager.setInitialState(INITIAL_STATE);
+  
+  // Lorsqu'un utilisateur clique sur 'Auto Play'
+  document.getElementById(BTN_AUTOPLAY_ID).addEventListener('click', () => {
+    if (autoplayInterval) {
+      return;
+    }
+  
+    autoplayInterval = setInterval(() => {
+      generation = computeNextGeneration(gridManager);
+    }, GENERATION_INTERVAL);
+  });
+
+  // Lorsqu'un utilisateur clique sur 'Prochaine Génération'
+	document.getElementById(BTN_NEXT_GEN_ID).addEventListener('click', () => {
+		if (autoplayInterval) {
+			clearInterval(autoplayInterval);
+			autoplayInterval = null;
+		}
+
+		computeNextGeneration(gridManager);
+	});
+
+}
+
+
+// Le jeu est démarré ici
+
+main();