README.adoc 14.8 KB
Newer Older
Gerson Sunyé's avatar
Gerson Sunyé committed
1
= Échecs féeriques
Gerson Sunyé's avatar
Gerson Sunyé committed
2

Gerson Sunyé's avatar
Gerson Sunyé committed
3
Ce projet consiste à déployer une application web de jeu d'échecs féeriques jouable en multijoueur.
Gerson Sunyé's avatar
Gerson Sunyé committed
4
5
6
7

== Objectifs

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) !
Gerson Sunyé's avatar
Gerson Sunyé committed
8
9
10
11
12
13
14
15
16
17
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 féeriques jouable (et observable) en multijoueur réseau.

== Les échecs féériques

Le terme *échecs féeriques* désigne les variantes du jeu d'échecs, pour indiquer que les règles habituelles du jeu d'échecs ne sont pas respectées.
Dans notre cas, notre jeu aura les pièces suivantes:

- *Roi*, *Reine* et *Pion* des échecs traditionnels.
- Le *Chameau* à la place du Chevalier. Le Chameau se déplace comme un cavalier mais avec une case supplémentaire. Il saute de trois cases horizontalement et d'une case verticalement ou de trois cases verticalement et d'une case horizontalement.
- La *Princesse* à la place du Fou. La Princesse combine les mouvements d'un Cavalier et d'un Fou.
18
- L'*Impératrice* à la place de la Tour. L'Impératrice combine les mouvements d'une Tour et d'un Chevalier.
Gerson Sunyé's avatar
Gerson Sunyé committed
19
20
21

== Préparation

22
23
. Créez une divergence (en anglais, _fork_) du projet suivant sur votre compte GitLab: 
https://gitlab.univ-nantes.fr/naomod/idl/projet-2019/-/forks/new
24
25
26
27
28
. Configurez votre nouveau projet Gitlab obtenu via la divergence de la manière suivante :
.. Dans "_Paramètres → Général_", allez dans "_Visibility, project features, permissions_", et mettez "_Project visibility_" à "_Private_".
Ainsi, vous devenez le seul utilisateur autorisé à accéder à votre code source.
..  Dans "_Paramètres → Membres_", ajoutez comme nouveau membre l'utilisateur virtuel appelé *Naobot*, avec le statut "_Reporter_".
Cet utilisateur virtuel que nous controllons nous donne le droit d'accéder à votre travail et nous permettra de récupérer vos projets.
Gerson Sunyé's avatar
Gerson Sunyé committed
29
. Créez et configurez une copie locale du projet. Ouvrez le *Terminal* et exécutez les commandes suivantes:
30
+
Gerson Sunyé's avatar
Gerson Sunyé committed
31
32
33
34
35
36
37
38
[source,bash]
----
git clone https://gitlab.univ-nantes.fr/${USER}/projet-2019.git
cd projet-2019
npm install
----

. Regardez la structure du projet. Le projet est organisé en différents dossiers:
39
+
Gerson Sunyé's avatar
Gerson Sunyé committed
40
41
[source,txt]
----
42
    |-- projet-2019
Gerson Sunyé's avatar
Gerson Sunyé committed
43
44
45
      |-- client
         |-- script.js
         |-- style.css
sunye's avatar
sunye committed
46
47
      |-- views
         |-- index.ejs
Gerson Sunyé's avatar
Gerson Sunyé committed
48
      |-- src
49
50
51
52
53
54
55
56
57
58
59
60
        |-- main
          |-- ts
            |-- chessboard.ts
            |-- main.ts
            |-- move-validation.ts
            |-- movements.ts
            |-- piece.ts
            |-- position.ts
        |-- test
          |-- ts
            |-- move-validation.spec.ts
            |-- movements.spec.ts
Gerson Sunyé's avatar
Gerson Sunyé committed
61
62
63
64
65
      |-- node_modules
      |-- package.json
      |-- tsconfig.json
----

66
67
68
69
70
71
72
73
74
75
76
77
78
** `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/main/ts` contient le code source du serveur.
*** Dans ce dossier, vous allez modifier le fichier `move-validation.ts`.
*** *Attention:* *En aucun cas vous ne devez modifier le contenu des fichiers `chessboard.ts`, `movements.ts`, `piece.ts` et `position.ts`.*
** `main.ts` : programme principal de création et gestion du serveur web.  Vous ne devez pas modifier le contenu de ce fichier.
** `src/test/ts` contient les tests unitaires du serveur. Vous allez modifier le contenu de ce dossier.
** `node_modules` contient les modules Node.js utilisés dans le projet. Vous ne devez pas modifier le contenu de ce dossier.
** `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
79

sunye's avatar
sunye committed
80
81
82
83
84
85
86
=== Mise à jour du projet

Les erreurs ou manques de précision du projet seront corrigées dès que possible.
Cela impliquera la mise à jour des vos divergences pour récupérer les changements.
Pour cela, vous devez faire:

```sh
87
88
git remote add upstream https://gitlab.univ-nantes.fr/naomod/idl/projet-2019.git # pas besoin si déjà fait
git pull upstream master
sunye's avatar
sunye committed
89
90
```

91
92
* La première ligne ajoute le dépôt originel et le nomme "upstream"
* La deuxième ligne récupère les changements et les fusionne avec votre divergence
sunye's avatar
sunye committed
93
94


Gerson Sunyé's avatar
Gerson Sunyé committed
95
96
97
98
99
100
101
102
103
104
105
106
107
== 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 Alsatian, exécutez: `npm test`.
* Pour lancer le serveur en mode développement, exécutez: `npm run dev`.
* Pour accéder à l'application, ouvrez l'URL suivante: http://localhost:8080.
* Pour accéder au contenu JSON de l'échiquier en cours, utilisez l'URL suivante: http://localhost:8080/status.js.

== Manuel d'utilisation

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.

108
.Par exemple:
Gerson Sunyé's avatar
Gerson Sunyé committed
109
110
111
112
|===
|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.
Gerson Sunyé's avatar
Gerson Sunyé committed
113
| 2. |G1-F4 B8-C5 |Chameau  blanc en G1 se déplace à F4. Chameau noir en B8 se déplace à C5.
Gerson Sunyé's avatar
Gerson Sunyé committed
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|===

== 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 :

* 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;

Ces trois traitements correspondent aux différents appels à `app.get()` et `app.post()` du programme principal.

== Chronologie d'une partie

. 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.

. 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`.

. 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é.

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

. 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.
Gerson Sunyé's avatar
Gerson Sunyé committed
145
Vous devez mettre en oeuvre la validations des déplacements des autres pièces: le Roi, la Dame, le Chameau, la Princesse et l'Impératrice. 
Gerson Sunyé's avatar
Gerson Sunyé committed
146
147
148
149
150
151
152

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

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

. 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`).

153
154
. 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.
Gerson Sunyé's avatar
Gerson Sunyé committed
155
156
157

. 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.

158
. 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
159
160
161
162
163
164

Vous devez donc parcourir le module `move-validation` et implémenter les fonctions de validation contenant le commentaire "`// #TODO:`". 

=== Tests unitaires

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.
Gerson Sunyé's avatar
Gerson Sunyé committed
165
166
Les mouvements sont possibles (ou impossibles) en accord avec les https://fr.wikipedia.org/wiki/Échecs[règles des échecs],
ainsi qu'en accord avec les 3 pièces féériques.
Gerson Sunyé's avatar
Gerson Sunyé committed
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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.

Les signatures des fonctions du module `move-validation` suivent la même convention :

[source,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.

181
Les tests unitaires de la fonction `blackPawnMove()` ont déjà été implémentés, vous les trouverez dans le fichier `./src/test/ts/pawn-move-validation-spec.ts`.
182
*Vous devez compléter tous les squelettes de tests unitaires fournis à l'intérieur de ces fichiers !* 
Gerson Sunyé's avatar
Gerson Sunyé committed
183
184
185
186
187
188
189
190

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:

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

191
Par exemple, lorsque vous allez implémenter la fonction qui valide le mouvement des Impératrices (`empressMove()`, vous pouvez subdiviser leurs comportements en différentes fonctionnalités: 
Gerson Sunyé's avatar
Gerson Sunyé committed
192

Gerson Sunyé's avatar
Gerson Sunyé committed
193
* Validation des mouvements horizontaux, verticaux et diagonaux, sans se préoccuper des autres pièces.
194
* Invalidation des mouvements (horizontaux, verticaux et diagonaux) lorsque la case finale contient une pièce de même couleur.
Gerson Sunyé's avatar
Gerson Sunyé committed
195
196
* Validation des mouvements (horizontaux, verticaux et diagonaux) qui se terminent sur une case contenant une pièce d'une couleur différente.
* Invalidation des mouvements (horizontaux, verticaux et diagonaux) lorsque toutes les cases intermédiaires ne sont pas vides.
Gerson Sunyé's avatar
Gerson Sunyé committed
197

Gerson Sunyé's avatar
Gerson Sunyé committed
198
=== Exemple: validation des mouvements d'une Impératrice en plusieurs étapes
Gerson Sunyé's avatar
Gerson Sunyé committed
199
200
201
202
203
204
205
206

==== Etape 1

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

[source,ts]
----
// Dans le fichier "move-validation.ts"
Gerson Sunyé's avatar
Gerson Sunyé committed
207
export function empressMove(board: Chessboard, move: Move): boolean {
Gerson Sunyé's avatar
Gerson Sunyé committed
208
209
210
211
212
213
214
215
    return move.from.rank === move.to.rank; // Si les lignes de début de fin sont les mêmes, le déplacement est horizontal
}
----

Écrivez ensuite le test unitaire pour cette fonctionnalité:

[source,ts]
----
Gerson Sunyé's avatar
Gerson Sunyé committed
216
// Dans le fichier "empress-move-validation.spec.ts"
217
218
let chessboard : Chessboard;

Gerson Sunyé's avatar
Gerson Sunyé committed
219
export class TestEmpressMoves {
220
221
    @Setup
    beforeEach(){
Gerson Sunyé's avatar
Gerson Sunyé committed
222
223
224
        chessboard = createEmptyChessboard();

        // La variable "positionE4" a été créée au début du module pour simplifier le code des tests
Gerson Sunyé's avatar
Gerson Sunyé committed
225
226
227
        // Place une Impératrice sur la case E4 d'un échiquier vide:

        putPiece(chessboard, positionE4, pieces.blackEmpress);
228
    }
Gerson Sunyé's avatar
Gerson Sunyé committed
229

Gerson Sunyé's avatar
Gerson Sunyé committed
230
    @Test("An empress can move horizontally")
231
    testCanMoveHorizontally() {
Gerson Sunyé's avatar
Gerson Sunyé committed
232
233
234
        // Les variable "moveE4_H4" et "moveE4_14" ont été créées au début 
        // du module pour simplifier le code des tests.
        // Le déplacement doit être possible:
Gerson Sunyé's avatar
Gerson Sunyé committed
235
236
237

        Expect(isPossible.empressMove(chessboard, moveE4_H4)).toBeTruthy();
        Expect(isPossible.empressMove(chessboard, moveE4_A4)).toBeTruthy();
238
239
    }
}
Gerson Sunyé's avatar
Gerson Sunyé committed
240
241
242
243
----

==== Etape 2

244
Nouvelle fonctionnalité à implémenter: la validation des déplacements verticaux. 
Gerson Sunyé's avatar
Gerson Sunyé committed
245
Modifiez la fonction `empressMove()`:
Gerson Sunyé's avatar
Gerson Sunyé committed
246
247
248
249

[source,ts]
----
// Dans le fichier "move-validation.ts"
Gerson Sunyé's avatar
Gerson Sunyé committed
250
export function empressMove(board: Chessboard, move: Move): boolean {
Gerson Sunyé's avatar
Gerson Sunyé committed
251
252
253
254
255
256
257
258
259
    return move.from.rank === move.to.rank || // Si les lignes de début de fin sont les mêmes, le déplacement est horizontal
        move.from.file === move.to.file;  // 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é:

[source,ts]
----
Gerson Sunyé's avatar
Gerson Sunyé committed
260
// Dans le fichier "empress-move-validation.spec.ts"
261
export class TestRocoMoves {
262
263
    // (...)

Gerson Sunyé's avatar
Gerson Sunyé committed
264
    @Test("An empress can move vertically")
265
    testCanMoveVertically() {
Gerson Sunyé's avatar
Gerson Sunyé committed
266
267
        Expect(isPossible.empressMove(chessboard, moveE4_E8)).toBeTruthy();
        Expect(isPossible.empressMove(chessboard, moveE4_E1)).toBeTruthy();
268
269
    }
}
Gerson Sunyé's avatar
Gerson Sunyé committed
270
271
272
273
----

==== Autres étapes

Gerson Sunyé's avatar
Gerson Sunyé committed
274
Suivez la même démarche pour implémenter et tester les autres fonctionnalités, c'est à dire, les autres mouvements possibles des Impératrices.
Gerson Sunyé's avatar
Gerson Sunyé committed
275
276
277

=== Rendu

278
Pour rendre le projet, il vous suffit de vous assurer d'avoir :
Gerson Sunyé's avatar
Gerson Sunyé committed
279

280
- bien effectué toutes les validations (_commits_) et publications (_pushs_) nécessaires avec `git`,
281
- bien ajouté *Naobot* comme membre _Reporter_ de votre projet,
282
- bien validé (_commit_) et publié (_push_) tous vos changements et fichiers de travail.
Gerson Sunyé's avatar
Gerson Sunyé committed
283

284
Si vous le souhaitez, vous pouvez également 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.).
Gerson Sunyé's avatar
Gerson Sunyé committed
285

286
Tant que tout cela est bien fait avant la date limite de rendu, alors tout est bon !
Gerson Sunyé's avatar
Gerson Sunyé committed
287
288
289
290
291
292
293
294
295

=== Derniers conseils

* Rappelez-vous que « _Une fonction sans test unitaire ne fonctionne pas_ » !

* 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* » !

* É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.

296
* Faites bon usage de `git` : effectuez des validations (_commits_) et des publications (_pushs_) régulièrement ! Cela vous permet d'éviter de perdre votre travail, et de mieux collaborer en équipe.