ajout tp5
This commit is contained in:
parent
4db5fb7c97
commit
4625ec8e2c
98
R1.02/tp/tp5/README.md
Normal file
98
R1.02/tp/tp5/README.md
Normal file
@ -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.
|
BIN
R1.02/tp/tp5/img/jeu.png
Normal file
BIN
R1.02/tp/tp5/img/jeu.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
44
R1.02/tp/tp5/src/index.html
Normal file
44
R1.02/tp/tp5/src/index.html
Normal file
@ -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>
|
207
R1.02/tp/tp5/src/script.js
Normal file
207
R1.02/tp/tp5/src/script.js
Normal file
@ -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();
|
Loading…
Reference in New Issue
Block a user