README.md 13.9 KB
Newer Older
Gerson Sunyé's avatar
Gerson Sunyé committed
1
# Online Chess
2

Quentin's avatar
Quentin committed
3
4
Ce projet consiste à déployer une application web de jeu d'échecs jouable en multijoueur.

Gerson Sunyé's avatar
Gerson Sunyé committed
5
## Objectifs
6

Gerson Sunyé's avatar
Gerson Sunyé committed
7
8
La fin du semestre approche, il est temps de montrer tout ce que vous avez appris et de proposer au monde entier votre première application web (webapp) !
L'objectif de ce mini-projet est d'intégrer et adapter tout le travail réalisé lors des TP et TD précédents, afin de réaliser une application de jeu d'échecs jouable (et observable) en multijoueur réseau.
Quentin's avatar
Quentin committed
9

Gerson Sunyé's avatar
Gerson Sunyé committed
10
## Préparation
11

12
1. Créez une divergence (en anglais, *fork*) du projet sur votre compte GitLab: [Cliquez ici pour créer le Fork](https://gitlab.univ-nantes.fr/naomod/software-development-course/onlineChess/forks/new) (Éventuellement, Gitlab vous demandera de vous connecter).
13

Gerson Sunyé's avatar
Gerson Sunyé committed
14
2. Créez et configurez une copie locale du projet. Ouvrez le **Terminal** et exécutez les commandes suivantes:
Quentin's avatar
Quentin committed
15

Gerson Sunyé's avatar
Gerson Sunyé committed
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
```bash
git clone https://gitlab.univ-nantes.fr/${USER}/onlineChess.git
cd onlineChess
npm install
```

3. Regardez la structure du projet. Le projet est organisé en différents dossiers:

```txt
    |-- onlineChess
      |-- client
         |-- index.html
         |-- script.js
         |-- style.css
      |-- src
         |-- chessboard.ts
         |-- main.ts
         |-- move-validation.ts
         |-- movements.ts
         |-- piece.ts
         |-- position.ts
      |-- spec
         |-- move-validation-spec.ts
         |-- movements-spec.ts
         |-- support
            |-- jasmine.json
      |-- node_modules
      |-- package.json
      |-- tsconfig.json
```

- `client` contient le code Javascript qui sera exécuté sur le browser. Vous ne devez pas modifier le contenu de ce dossier.
  - `index.html` : page principale de l'application
  - `style.css` : mise en forme de l'application
  - `script.js` : algorithme(s) JavaScript côté client (affichage de l'échiquier)
- `src` contient le code source du serveur.
  - `main.ts` : programme principal de création et gestion du serveur web
- `spec` contient les tests unitaires du serveur.
- `node_modules` contient les modules Node.js utilisés dans le projet. Vous ne devez pas modifier le contenu de ce dossier.
Erwan Bousse's avatar
Erwan Bousse committed
55
56
- `package.json` est le fichier de configuration de **npm**. Vous n'avez pas besoin de le modifier.
- `tsconfig.json` est le fichier de configuration de **TypeScript**. Vous n'avez pas besoin de le modifier.
Gerson Sunyé's avatar
Gerson Sunyé committed
57
58
59
60
61

## Test et lancement

- Le projet utilise l'outil de construction et de gestion de modules **npm**.
- Pour lancer tous les tests unitaires du projet avec Jasmine, exécutez: `npm test`.
Erwan Bousse's avatar
Erwan Bousse committed
62
- Pour lancer le serveur en mode développement, exécutez: `npm run dev`.
Gerson Sunyé's avatar
Gerson Sunyé committed
63
64
- Pour accéder à l'application, ouvrez l'URL suivante: [http://localhost:8080](http://localhost:8080).
- Pour accéder au contenu JSON de l'échiquier en cours, utilisez l'URL suivante:  [http://localhost:8080/status.js](http://localhost:8080/status.js).
Quentin's avatar
Quentin committed
65
66

## Manuel d'utilisation
67

Gerson Sunyé's avatar
Gerson Sunyé committed
68
69
70
71
72
73
74
75
76
77
78
79
80
Pour déplacer les pièces sur l'échiquier, indiquez dans le formulaire en bas de page la pièce à déplacer et sa destination.
Utilisez la notation par coordonnées, qui inclut la place à partir de laquelle la pièce se déplace, ainsi que sa destination.
Par exemple:

| Coup | Coordonnées | Description |
| --- | --- | --- |
| 1. | E2-E4 E7-E5 | Pion blanc en E2 se déplace à E4. Pion noir en E7 se déplace à E5.
| 2. | G1-F3 B8-C6 | Cheval blanc en G1 se déplace à F3. Cheval noir en B8 se déplace à C6.

## Fonctionnement de l'application

Le programme principal du serveur (`main.ts`) est chargé de démarrer un mini-serveur web capable de recevoir les différentes requêtes provenant des navigateurs connectés à l'application :

Erwan Bousse's avatar
Erwan Bousse committed
81
82
83
84
- GET "`/`" : distribue le fichier `views/index.ejs`;
- GET "`/status.js`" : génère et distribue l'échiquier en cours au format JSON.
- POST "`/`" : reçoit et traite un coup à jouer;

Gerson Sunyé's avatar
Gerson Sunyé committed
85
86
87
88
89
90
91

Ces trois traitements correspondent aux différents appels à `app.get()` et `app.post()` du programme principal.
  
## Chronologie d'une partie

1. Lorsqu'un utilisateur se connecte à l'application (adresse **"/"**), le serveur distribue alors la page html principale composée d'un échiquier vierge et d'une zone de saisie permettant à l'utilisateur de remplir le coup à jouer.

Erwan Bousse's avatar
Typo    
Erwan Bousse committed
92
2. Le navigateur internet récupère immédiatement les informations de la partie en cours présentes à l'adresse `/status.js` et remplit l'échiquier à l'aide d'un script situé dans le fichier `script.js`. Ces deux scripts se trouvent dans le dossier `client`.
Gerson Sunyé's avatar
Gerson Sunyé committed
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116

3. Un clic sur le bouton "Envoyer" effectue une requête de type **POST** au à l'adresse **"/"** du serveur, contenant les informations du champs de texte associé. 
Le serveur traite alors la requête afin de jouer le coup demandé.

4. La page internet du joueur est alors rechargée automatiquement, affichant ainsi le nouvel état de la partie.

5. etc...

## Travail à réaliser

### Validation des mouvements

La version actuelle permet le déplacement libre des pièces, sans respecter les règles des échecs. 
Pour l'instant, seuls les déplacements des pions sont validés.
Vous devez mettre en oeuvre la validations des déplacements des autres pièces: le Roi, la Dame, le Cavalier, le Fou et la Tour. 

Le traitement des déplacements se fait de la façon suivante:

1. Lorsqu'une requête **POST** arrive, le serveur extrait la valeur du champ envoyé et appelle la fonction `processMove()` du module `movements`.

2. La fonction `processMove()` appelle une autre fonction, `parseMoveString()`, qui transforme une chaîne de caractères en un déplacement (`interface Move`) entre 2 positions (`interface Position`).

3. La fonction `processMove()` appelle ensuite la fonction `isMovePossible()`, qui fait appel à différentes fonctions de validation spécifiques aux pièces de l'échiquier (une par type de pièce). Le module `move-validation` contient toutes les fonctions de validation de déplacements.

117
4. Par exemple, lorsqu'il s'agit d'un Pion blanc, la fonction `isMovePossible()` appelle la fonction `whitePawnMove()`, qui retourne `true` si le déplacement est possible ou `false` si ce n'est pas le cas.
Gerson Sunyé's avatar
Gerson Sunyé committed
118
119
120
121

5. Si le mouvement est possible, c'est à dire la fonction `isMovePossible()` retourne `true`, la fonction  `processMove()` appelle la fonction `performMove(), qui effectue le déplacement.


Gerson Sunyé's avatar
Gerson Sunyé committed
122
123
Vous devez donc parcourir le module `move-validation` et implémenter les fonctions de validation contenant le commentaire "`// TODO:`". 

Gerson Sunyé's avatar
Gerson Sunyé committed
124
125
126

### Tests unitaires

127
128
129
Pour vérifier que les fonctions du module `move-validation` fonctionnent correctement, vous devez écrire des tests unitaires, qui vont vérifier que les fonctions acceptent les mouvements possibles et n'acceptent pas les mouvements impossibles.
Les mouvements sont possibles (ou impossibles) en accord avec les [règles des échecs](https://fr.wikipedia.org/wiki/Échecs). 
Comme ces règles sont complexes, vous serez mené à écrire plusieurs tests unitaires pour vérifier les mouvements possibles et impossibles d'une même pièce.
Gerson Sunyé's avatar
Gerson Sunyé committed
130

Erwan Bousse's avatar
Erwan Bousse committed
131
Les signatures des fonctions du module `move-validation` suivent la même convention :
Gerson Sunyé's avatar
Gerson Sunyé committed
132

133
134
135
136
137
138
139
140
141
142
```ts
function colorPieceMove(board: Chessboard, move: Move): boolean
```

Le paramètre `board` contient l'échiquier de la partie en cours et `move` contient le déplacement demandé par le joueur à travers le browser.
Le paramètre `move` contient 2 coordonnées de type `Position`, représentant le début et la fin du déplacement.
Les coordonnées indiquent **toujours** des cases à l'intérieur de l'échiquier, c'est à dire, une colonne entre `A` et `H` et une ligne entre `1` et `8`.
Donc, il n'y a pas besoin de vérifier si un déplacement conduit une pièce à l'extérieur de l'échiquier.

Les tests unitaires des fonctions `blackPawnMove()` et `whitePawnMove()` ont déjà été implémentés, vous les trouverez dans le fichier `./spec/move-validation-spec.ts`.
Erwan Bousse's avatar
Erwan Bousse committed
143
**Vous devez compléter tous les squelettes de tests unitaires fournis à l'intérieur de ce fichier !** 
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171

Vous devez procéder par itérations successives, n'essayez pas d'implémenter les fonctions d'un seul trait. Observez le cycle de développement suivant:

1. Implémentez une fonctionnalité  simple.
2. Écrivez le ou les tests unitaires qui vérifient cette fonctionnalité.
3. Exécutez les tests pour vérifier que la fonctionnalité marche correctement et la non-régression. 
4. Recommencez avec la fonctionnalité suivante.

Par exemple, lorsque vous allez implémenter les fonctions qui valident le mouvement des tours (`blackRoockMove()` et `whiteRoockMove()`) ,  vous pouvez subdiviser leurs comportements  en différentes fonctionnalités: 

- Validation des mouvements horizontaux, sans se préoccuper des autres pièces.
- Validation des mouvements verticaux, toujours sans se préoccuper des autres pièces.
- Invalidation d'des mouvements (horizontaux et verticaux)  lorsque la case finale contient une pièce de même couleur.
- Validation des mouvements (horizontaux et verticaux) qui se terminent sur une case contenant une pièce d'une couleur différente.
- Invalidation des mouvements (horizontaux et verticaux) lorsque toutes les cases intermédiaires ne sont pas vides.

### Exemple: validation des mouvements  d'une tour en plusieurs étapes

#### Etape 1

Commencez par la 1e fonctionnalité, la validation des déplacements horizontaux:

```ts
// Dans le fichier "move-validation.ts"
export function blackRoockMove(board: Chessboard, move: Move): boolean {
    return move.from.ligne === move.to.ligne; // Si les lignes de début de fin sont les mêmes, le déplacement est horizontal
}
```
Gerson Sunyé's avatar
Gerson Sunyé committed
172

173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
Écrivez ensuite le test unitaire pour cette fonctionnalité:

```ts
// Dans le fichier "move-validation-spec.ts"
describe("Test blackRoockMove()", () => {
    beforeEach( () => { // Fonction exécutée avant chaque test unitaires
        chessboard = createEmptyChessboard(); // Création d'un échiquier vide
    });

    it("A roock can move horizontally", () => {
        putPiece(chessboard, positionE4, pieces.blackPawn); // Place une tour sur la case E4 d'un échiquier vide.
        let moveE4-H4: Move = {from: positionE4, to: positionH4, isValid: true}; // Création d'un déplacement horizontal
        
        expect(isPossible.blackRoockMove(chessboard, moveE4-H4)).toBeTruthy(); // Le déplacement doit être possible
    });
```

#### Etape 2

Nouvelle fonctionnalité à implémenter: la validation des déplacements verticaux. Modifiez la fonction `blackRoockMove()`:

```ts
// Dans le fichier "move-validation.ts"
export function blackRoockMove(board: Chessboard, move: Move): boolean {
    return move.from.line === move.to.line || // Si les lignes de début de fin sont les mêmes, le déplacement est horizontal
        move.from.column === move.to.column;  // Si les colonnes de début de fin sont les mêmes, le déplacement est vertical
}
```

Écrivez ensuite un nouveau test unitaire pour cette nouvelle fonctionnalité:

```ts
// Dans le fichier "move-validation-spec.ts"
describe("Test blackRoockMove()", () => {
    beforeEach( () => { // Fonction exécutée avant chaque test unitaires
        chessboard = createEmptyChessboard(); // Création d'un échiquier vide
    });

    it("A roock can move horizontally", () => { // (...)
    });
    
    it("A roock can move vertically", () => {
        putPiece(chessboard, positionE4, pieces.blackPawn); // Place une tour sur la case E4 d'un échiquier vide.
        let moveE4-E8: Move = {from: positionE4, to: positionE8, isValid: true}; // Création d'un déplacement vertical
        
        expect(isPossible.blackRoockMove(chessboard, moveE4-E8)).toBeTruthy(); // Le déplacement doit être possible
    });
```

#### Autres étapes
Erwan Bousse's avatar
Typo    
Erwan Bousse committed
223

224
Suivez la même démarche pour implémenter et tester les autres fonctionnalités, c'est à dire, les autres mouvements possibles des tours.
Erwan Bousse's avatar
Typo    
Erwan Bousse committed
225

Gerson Sunyé's avatar
Gerson Sunyé committed
226
### Rendu
227

228
Vous allez pouvoir effectuer le rendu directement depuis l'interface de Gitlab, en réalisant ce qu'on appelle une **demande de fusion**.
Erwan Bousse's avatar
Erwan Bousse committed
229
Cela permet de nous envoyer tous les changements que vous avez effectué sur le projet en quelques clics.
230
231
232
233
234
235
236
237
238
239
240

0. Assurez vous d'avoir effectué tous les *commits* et *pushs* nécessaires avec git.
1. Dans le panneau de gauche, cliquez sur "Demandes de fusion".
2. Cliquez sur "Nouvelle demande de fusion".
3. Vérifiez que dans la partie droite on trouve bien `naomod/software-development-course/onlineChess` et `master`.
4. Dans la partie gauche, choisissez `<votre nom d'utilisateur>/onlineChess` (normalement déjà choisi) et également `master`.
5. Cliquez sur "Compare branches and continue".
6. Comme titre pour la demande de fusion, indiquez "Rendu NOM1 NOM2".
7. Enfin, cliquez en bas sur "Submit demande de fusion"

Vous atteignez alors une page qui résume la demande effectuée.
Erwan Bousse's avatar
Erwan Bousse committed
241
Nous vous recommandons alors de cliquer sur l'onglet "*Changes*" afin d'avoir accès une une représentation visuelle de tous les changements que vous avez effectué.
242
Les lignes rouges indiques ce que vous avez retiré, les lignes vertes indiquent ce que vous avez ajouté.
Erwan Bousse's avatar
Erwan Bousse committed
243
Vérifiez si tout votre travail réalisé est bien présent sous la forme de lignes vertes.
244
245

Si vous le souhaitez, vous pouvez ajouter un fichier "`RENDU.md`" à la racine du projet, afin de décrire les spécificités de votre projet (choix techniques, parties non traitées, extensions non demandées, etc.).
Quentin's avatar
Quentin committed
246

Gerson Sunyé's avatar
Gerson Sunyé committed
247
### Derniers conseils
Quentin's avatar
Quentin committed
248

Erwan Bousse's avatar
Erwan Bousse committed
249
- Rappelez-vous que « *Une fonction sans test unitaire ne fonctionne pas* » ! 
250
251
252

- Rappelez-vous aussi que «*N'importe qui peut écrire du code compréhensible par les ordinateurs, mais seulement les bon développeurs parviennent à écrire du code intelligible par les humains* » !

Gerson Sunyé's avatar
Gerson Sunyé committed
253
- Écrivez les tests unitaires avant ou en même temps que les fonctions. Ne les laissez pas pour la fin, les test unitaires sont très utiles pendant le développement et vous feront gagner du temps.
254
255
256

- Parfois, les règles de déplacement sont les mêmes pour les pièces noires et blanches. Dans ces cas, vous pouvez utiliser une fonction commune.

Erwan Bousse's avatar
Erwan Bousse committed
257
- Faites bon usage de `git` : effectuez des *commits* et des *pushs* régulièrement ! Cela vous permet d'éviter de perdre votre travail, et de mieux collaborer en équipe.
258

Quentin's avatar
Quentin committed
259

260