Projet de
Programmation
Premier Semestre
2004-2005
Projet de Programmation
Le jeu de Wargame.
Travailler en binôme :
Pour ce TER vous allez travailler avec une autre personne. Vous devez bien sûr travailler ensemble : concevoir le programme ensemble, le taper et le mettre au point ensemble sur l'ordinateur. Il n'est pas question que certains fassent le travail, et que d'autres y ajoutent leur nom ! Vous ne devrez rendre qu'un rapport en indiquant vos noms ainsi que le numéro de votre groupe de TD.
Comment rendre les rapports :
Il faudra rendre un programme : c'est-à-dire un ou plusieurs packages sous la forme de plusieurs fichiers. Vous devrez envoyer par mail vos fichiers à votre chargé de Projet (il vous indiquera son adresse lors de la première séance). N'envoyez qu'un et un seul mail par binôme (on vous renverra un accusé de réception). Utilisez la commande suivante depuis les machines du bât. 308 pour la licence ou du bât. 334 pour la MIAGe (pas de document attaché avec Netscape ou autre). On suppose que Toto et Titi sont deux étudiants binômés du groupe B, que le chargé de TD est dupont@ici.fr, et que les fichiers sont C1.java et C2.java; bien sûr les noms mentionnés ici sont des exemples, toute ressemblance avec de vraies personnes serait fortuite !!
tar cvf - C1.java C2.java
| uuencode Toto.Titi.B | mail dupont@ici.fr
Attention à ne pas oublier le - après le tar cvf sinon vous écraserez le fichier C1.java . . .
Les buts de ce projet :
· Vous apprendre à écrire un programme à partir de spécifications informelles (énoncé en français).
· Vous familiariser avec le fait que vos programmes seront réutilisés par d'autres plus tard; donc à les écrire lisiblement en les commentant judicieusement.
· Vous faire utiliser javadoc pour engendrer la documentation d'implémentation de vos classes.
· Vous entraîner à encapsuler vos données et méthodes pour obtenir des programmes robustes.
· Vous montrer l'intérêt de séparer la partie traitement d'un programme de sa partie interface utilisateur.
Le programme que vous allez
modifier :
Ce Projet se compose de trois parties que vous allez plus ou moins réutiliser . . .
Que devez vous faire dans ce TER ?
On se propose de réaliser un jeu de plateau de type « jeu de guerre » utilisant une interface graphique conviviale. On aura trois possibilités : jouer contre un autre joueur humain sur la même machine, observer une partie se déroulant entre deux autres joueurs ou jouer contre un autre joueur humain sur un autre machine.
Dans tous les cas on aura besoin d'une interface utilisateur qui permettra au joueur humain de dialoguer avec le moteur du jeu. On devra programmer trois versions de moteur jeu :
Le
jeu qu'il vous est demandé de développer s'inspire des jeux de stratégie à deux
joueurs de type jeux de plateau faisant évoluer les unités de deux
joueurs sur un espace géographique prédéterminé. Il s'agit plus précisément
d'une variante dans laquelle les intentions des joueurs sont belliqueuses, et où
la victoire découle de la suprématie de l'un des joueurs. Toutefois vous est
laissé la possibilité de modifier l’ambiance du jeu. En conservant les
caractéristiques techniques du jeu vous pouvez imaginer une version se déroulant
dans la Rome antique ou en l’an 2195. En poussant l’idée jusqu'à la dérision
nous invitons même ceux qui le souhaite à tourner la guerre en ridicule en
choisissant de remplacer le complètement le vocabulaire militaire et d’inventer
des guerres de tarte à la crème ou des guerres de bisous. Afin de garder une
cohérence à cet énoncé nous utiliserons ici un vocabulaire
guerrier.
Cases - Le jeu se déroule sur un plateau de taille
variable assimilable à une matrice rectangulaire de cases carrée. Les cases
représentent des éléments topographiques du terrain: route, prairie, forêt, eau,
etc. Le type des cases influe sur la capacité des unités à s'y déplacer: par
exemple, une unité de fantassins à pieds pourra progresser dans une zone de
forêt, alors que cela ne sera pas possible pour une unité d'artillerie. Cela
peut être modélisé par une caractéristique coût de déplacement propre à
chaque type de case.
En outre, certaines cases
représentent des constructions fixes: quartiers généraux, hôpitaux, bunkers,
ports, etc.
Unités - Chaque joueur dispose au début de la partie d'un
certain nombre d'unités, qui dépendent du type de jeu (époque, réalisme, etc.).
Ces unités ont des caractéristiques propres en ce qui concerne leurs capacités
d'attaque, de défense, et de mouvement. Les unités de transport possèdent
également une capacité de chargement, alors que les autres unités sont
caractérisées par une charge.
Les
unités ont toutes un niveau de vie, qui dépend initialement du type
d'unité et qui décroît au fur et à mesure des batailles et qui peut être
augmenté jusqu'à la valeur initiale par un séjour dans un hôpital. Un niveau de
vie nul implique la disparition de l'unité.
Les
unités ont également un niveau d'expérience, initialement nul, qui
augmente au fur et à mesure des batailles et qui influe sur la capacité au
combat (force d'attaque et résistance). Le niveau d'expérience augmente
proportionnellement au nombre de combats dans lequel une unité a été impliquée.
Il a une valeur maximale qui dépend du type d'unité, et il ne peut
diminuer.
Bâtiments - Les bâtiments occupent une case du plateau. Ils
possèdent une capacité d'accueil (assimilable à la capacité de chargement des
unités de transport). Une unité peut ainsi pénétrer dans un bâtiment si la
capacité d'accueil du bâtiment peut supporter la "charge" représentée par
l'unité.
Un
bâtiment appartient par ailleurs à un joueur (ce qui peut être indiqué
visuellement par un bandeau à la couleur du joueur sur le bâtiment). Si une
unité d'un joueur adverse pénètre dans le bâtiment, celui-ci passe sous son
contrôle et toutes les unités du premier joueur présentes dans le bâtiment sont
éliminées.
Un
bâtiment particulier est le quartier général: la prise d'un quartier
général ennemi est une condition de suprématie et donc de victoire du joueur
ayant effectué la prise.
Les
quartiers généraux et les hôpitaux ont la possibilité de "réparer" des unités en
fonction de leurs points de réparation. A la fin de chaque tour, ces points sont
augmentés en fonction du type de bâtiment jusqu'à un maximum suivant la formule
suivante (on dénote par Bx le bâtiment considéré):
Tours de jeu - Le jeu se décompose en deux modes de tours:
déplacement et attaque. A chaque tour, les joueurs sont en modes
opposés, ce qui signifie qu'un joueur est en mode déplacement et l'autre en mode
attaque. A la fin de chaque tour, les modes de jeu sont inversés. Chaque mode de
jeu se compose d'ordres donnés par le joueur à ses unités (toutes les unités
peuvent recevoir un et un seul ordre à chaque tour).
Mode déplacement - Chaque unité possède une caractéristique de
mouvement: il s'agit d'un nombre de points de déplacement. Donner un ordre de
déplacement à une unité correspond à lui indiquer une case où elle doit se
rendre, et qui est séparée de la case où elle se trouve actuellement par une
suite de cases contiguës (un chemin) dont la somme des coûts de
déplacement est inférieur ou égal au nombre de points de déplacement de l'unité.
Une case contenant une autre unité (amie ou ennemie) ne pourra pas faire partie
d'un chemin de déplacement.
Considérons par exemple le cas d'une unité dont le
nombre de points de déplacement vaut 9, et une configuration où le coût de
déplacement sur une case de type prairie vaut 2 et le coût de déplacement sur
une case de type forêt vaut 5. L'unité pourra donc effectuer un chemin constitué
de 2 cases de type prairie et d'une case de type forêt (coût total: 9 points),
ou de 4 cases de type prairie (coût total: 8 points).
Mode attaque - Chaque unité possède des caractéristiques
d'attaque qui se décomposent en une portée d'attaque (composée d'une portée
minimale et d'une portée maximale) et un nombre de points d'attaque de
référence. Elle possède également des caractéristiques de défense qui se
décomposent en un nombre de points de défense et un nombre de points de
contre-attaque.
Pour
qu'une attaque puisse avoir lieu, il faut que le chemin séparant l'unité
attaquée de l'unité attaquante ait une taille comprise dans la portée de l'unité
attaquante (par exemple, une unité d'artillerie pourra attaquer à une distance
comprise entre 3 et 7 cases, alors qu'une unité d'infanterie pourra attaquer à
une distance entre 1 et 2 cases). Il peut éventuellement se trouver d'autres
unités amies ou ennemies sur ce chemin sans que cela n'influence le
combat.
Pour
qu'une contre-attaque puisse avoir lieu, il faut nécessairement que l'attaque
ait eu lieu a une distance comprise dans la portée d'attaque de l'unité
attaquée. Par exemple, une unité d'infanterie attaquée à plusieurs cases de
distance par une unité d'artillerie ne pourra pas contre-attaquer si le nombre
de cases séparant ces deux unités est plus grand que la portée de l'unité
d'infanterie.
Une
attaque implique deux unités ennemies et se déroule comme suit: tout d'abord, le
nombre de points correspondant à l'attaque et celui correspondant à la défense
sont calculés. Le dommage porté à l'unité attaquée est alors reporté sur ses
points de vie. Si celle-ci est encore en vie, on calcule le nombre de points
correspondant à sa contre-attaque, qui est alors reporté sur les points de vie
de l'unité attaquante. Finalement, les points d'expérience des deux unités sont
mis à jour. Les différents éléments mentionnés se calculent ainsi (on dénote par
U1 l'unité attaquante et U2 l'unité attaquée):
Réparation d'unités - Lorsqu'une unité est dans un hôpital ou un
quartier général contrôlé par son joueur, elle peut être "réparée". Cette
réparation s'effectue à la place d'un tour de déplacement ou d'un tour d'attaque
(i.e., si l'unité est en cours de réparation, elle ne peut sortir du bâtiment;
si l'unité est parvenue dans la bâtiment pendant le tour courant par un
déplacement, elle ne peut être réparée). Une unité en cours de réparation est
immobilisée pendant deux tours (le tour où la réparation est demandée, et le
tour suivant). Le joueur doit pouvoir choisir le nombre de points de réparation
affecté à chaque unité qu'il décide de réparer à un tour donné, à concurrence
d'un nombre de points de vie maximal par type d'unité. Les points de réparation
sont enlevés au bâtiment lorsque l'ordre de réparation est donné. Les différents
éléments mentionnés se calculent ainsi (on dénote par Bx un bâtiment de réparation et Ux une unité amie):
Conditions de fin du jeu - Le jeu se termine soit lorsque un joueur
n'a plus d'unité, soit lorsque qu'un joueur pénètre dans le quartier général
adverse. Le jeu peut également se terminer automatiquement au bout d'un nombre
de tours prédéterminé; dans ce cas, le joueur déclaré victorieux est celui
disposant du plus grand nombre d'unités. En cas d'égalité, la somme des points
de vie et des points d'expérience des unités du joueur sera
considérée.
Après
une présentation générale des principes du jeu, nous présentons ici les
particularités du jeu que vous devez développer.
Plateau de jeu - La taille de la matrice rectangulaire servant à
représenter le plateau de jeu n'est pas prédéfinie. Elle dépend d'une
description de plateau lue depuis un fichier. Les cases ont chacune 8 cases
voisines (on considère une case située en haut à gauche, en haut à droite, en
bas à droite ou en bas à gauche d'une case comme sa voisine), hormis pour celles
situées en bordure de plateau.
Types de cases - Les types de cases retenus et leurs
caractéristiques sont décrites dans le tableau ci-dessous:
Type de case |
Dessin |
Coût de déplacement |
prairie |
|
1 |
forêt |
|
3 |
montagne |
|
4 |
eau |
|
10 |
Les
images pour ces différents types de case vous sont fournies en format PNG de
taille 48*48 (ceci dit, si vous vous sentez une âme d'artiste, rien ne vous
empêche de proposer les vôtres!).
Types d'unités - Les types d'unités retenus et leurs
caractéristiques sont décrites dans les deux tableaux
ci-dessous:
Type d'unité |
Niveau de vie MAX |
Niveau expérience MAX |
Points mouvement |
Charge |
Capacité de chargement |
infanterie |
20 |
6 |
4 |
1 |
0 |
infanterie d'élite |
20 |
8 |
5 |
1 |
0 |
cavalerie |
20 |
6 |
7 |
3 |
0 |
véhicule blindé |
20 |
4 |
6 |
6 |
0 |
artillerie légère |
10 |
6 |
3 |
3 |
0 |
artillerie lourde |
10 |
6 |
1 |
6 |
0 |
camion |
20 |
3 |
6 |
20 |
6 |
Type d'unité |
Points d'attaque |
Portée (min-max) |
Points de défense |
Points de contre-attaque |
infanterie |
5 |
1-1 |
2 |
3 |
infanterie d'élite |
6 |
1-2 |
3 |
3 |
cavalerie |
3 |
1-1 |
3 |
4 |
véhicule blindé |
7 |
1-2 |
6 |
2 |
artillerie légère |
7 |
2-4 |
2 |
1 |
artillerie lourde |
10 |
3-8 |
3 |
1 |
camion |
0 |
1-1 |
3 |
1 |
Types de bâtiments -
Les types de bâtiments
retenus et leur caractéristiques sont décrites dans le tableau
ci-dessous:
Type de bâtiment |
Capacité d'accueil |
Points de réparation initiaux |
Points de réparation à chaque tour |
Particularités |
quartier général |
6 |
10 |
3 |
Chaque joueur a initialement un et un seul quartier général. Si une unité ennemie y pénètre, son joueur est déclaré vainqueur. |
hôpital |
3 |
10 |
6 |
Un hôpital appartient à un joueur. Si une unité ennemie y pénètre, son joueur prend le contrôle de l'hôpital. Les unités du premier joueur se trouvant dans l'hôpital lors de sa prise sont éliminées. |
bibliothèque |
30 |
0 |
0 |
Une bibliothèque permet aux unités d'oublier le temps d'une lecture le caractère oppressant du champ de bataille. Si une unité ennemie y pénètre, son joueur en prend le contrôle et les unités prises en flagrant délit de lecture sont éliminées. |
Contrairement aux cases du plateau, les bâtiments
ne doivent pas exister sous forme d'images préexistantes mais doivent être
dessinés au-dessus de la case où ils sont situés (la qualité du graphisme n'est
pas primordiale, il faut simplement que les bâtiments soient bien
reconnaissables).
Nous
vous donnons ici quelques indications pour votre réalisation. Le jeu qui vous
est demandé est fortement inspiré d'un jeu de stratégie au tour par tour,
History Lines, dont vous pouvez télécharger une version pour Windows
ici (le jeu est considéré comme un abandonware
par son éditeur, il peut donc être utilisé librement). Vous pouvez vous inspirez
de ce jeu pour les éléments qui n'entrent pas en contradiction avec les
spécifications présentées.
Données utilisées par le
programme - Toutes les
données utilisées par le programme (telles que celles données ci-dessus) doivent
pouvoir facilement évoluer. Elles seront donc stockées dans des fichiers (dont
vous choisirez le format le plus adapté) et seront chargées au début du
jeu.
Initialisation d'une partie - Un plateau de jeu sera chargé au début du
jeu: sa description comprend la matrice rectangulaire des cases constituant le
plateau, et pour chaque joueur la description des bâtiments et des unités se
trouvant sur la carte. Par défaut, les bâtiments auront une capacité de
réparation maximale, et les unités des points de vie maximaux. Au début de la
partie, les joueurs doivent s'entendre sur les conditions de victoires: prise du
quartier général OU meilleur score au bout de tour OU destruction de toutes les
unités ennemies.
Déroulement d'un tour - Pour le déroulement d'un tour, les joueurs
"programment" leurs coups chacun leur tour. Le joueur programmant son tour
d'attaque joue le premier. Il ne faut pas qu'ils puissent voir les coups
programmés par leur adversaire. Lors de la programmation, chaque unité ne peut
recevoir qu'un seul ordre. Un ordre peut être déprogrammé pour une unité donnée
(par exemple, si un ordre est déjà programmé pour une unité, celle-ci peut
apparaître dans une couleur grisée. Si son joueur cherche à lui affecter un
autre ordre, le programme pourra commencer par lui demander s'il veut invalider
l'ordre précédent.).
Mode attaque - Pour donner un ordre d'attaque lors du mode
correspondant, il faut sélectionner l'unité. Toutes les unités ennemies qu'elle
peut attaquer (i.e. qui sont dans sa portée d'attaque) sont alors "mises en
valeur". En recliquant plus tard sur cette même unité, on veut pouvoir trouver
l'information comme quoi une attaque a été programmée pour cette unité (par
exemple, un trait peut être tiré entre les deux unités).
Mode déplacement - Pour donner un ordre de déplacement lors du mode
correspondant, il faut sélectionner l'unité. Toutes les cases atteignables par
un plus court chemin sont alors "mises en valeur". Cliquer sur une de ces cases
programme le déplacement, qui est affiché à l'écran (i.e. l'unité est
effectivement déplacée) afin que le joueur ait un aperçu de la position de ses
unités après le déplacement. Un déplacement peut être annulé en cliquant sur une
unité déjà déplacée (qui pourra par exemple être grisée). Attention cependant,
l'annulation d'un déplacement peut annuler d'autre déplacement: en effet, si une
unité A se déplace puis qu'une unité B se déplace et prend la place laissée
vacante par l'unité A, annuler le déplacement de l'unité A implique l'annulation
du déplacement de l'unité B. Dans un tel cas de figure, le joueur doit être
averti de la conséquence de son déplacement. Une alternative acceptable serait
de permettre le déplacement d'une unité déjà déplacée dans une des cases
atteignables depuis sa case d'origine (i.e. d'avant son
déplacement).
Le
cas des déplacements vers ou depuis des bâtiments et des unités de transport est
particulier. Un déplacement vers un bâtiment ou une unité de transport n'est
permis que si la capacité de chargement disponible de l'hôte est supérieure ou
égale à la charge de l'unité qu'on souhaite y déplacer. Un clic sur un bâtiment
ou une unité de transport doit afficher son "chargement" ou "contenu": la
sélection d'une unité présente active alors le mode déplacement de l'unité
depuis son hôte jusqu'à un autre point atteignable de la
carte.
Réparation d'unités - La réparation d'unités peut avoir lieu lors de
n'importe quel tour. Néanmoins, l'unité reste ensuite immobilisée pour le tour
courant et le tour suivant. Pour qu'une unité soit réparée, il faut qu'elle se
trouve dans un bâtiment ayant une capacité de réparation, et que la capacité
actuelle de réparation du bâtiment soit inférieure ou égale à la réparation
demandée pour l'unité. Pour chaque unité qu'il souhaite réparer, le joueur peut
spécifier une réparation comprise entre 1 et les points de vie maximums de
l'unité concernée.
Dessin des unités - Vous devez dessiner les unités par dessus les
dessins des cases où elles se trouvent (hormi pour les bâtiments et les unités
de transport, où on ne peut voir les unités que lorsque l'on demande à voir "à
l'intérieur" d'un hôte). Vous pouvez faire en sorte que l'orientation d'un unité
dépendent par exemple de la direction de son dernier déplacement, ou bien de
l'emplacement des unités qu'elle attaque ou qui
l'attaquent.
Sauvegarde de partie - Vous pouvez implémenter une sauvegarde de l'état
d'une partie dans un fichier (référence à la carte jouée, état des unités
restantes et des bâtiment, tour courant) et une
restauration.
Déroulement des batailles - Vous pouvez proposer des idées originales
pour illustrer le déroulement des batailles pour informer les joueurs des
résultats (ex: disparition d'unité, affaiblissement d'unité,
etc.).
Informations sur les unités - Vous pouvez implémenter une zone
d'information sur les unités, qui sera soit présente constamment dans une zone
de l'écran et correspondra à l'unité présente sous la souris, soit présente en
surimpression sur la carte lorsqu'une commande sera
déclenchée.
Intelligence artificielle - Vous pouvez implémenter une intelligence
artificielle pour permettre à un joueur humain d'affronter l'ordinateur... Non,
là c'est vraiment dur!!! Il s'agirait d'un autre projet en
soi!
Réalisation
Pour que votre code soit lisible vous mettrez un gros commentaire au début de chaque fichier indiquant à quoi servent les classes qui s'y trouvent, comment elles s'articulent pour constituer le module et à quoi sert ce module. Vous mettrez aussi un petit commentaire en tête de chaque méthode indiquant ce qu'elle fait, la signification de chacun de ses arguments, et celle de la valeur de retour. Enfin, mettez un petit commentaire indiquant ce que représente chaque champ de donnée de vos classes. Veillez aussi à respecter les conventions de nommage qui vous ont été indiquées dans le cours (verbe pour les fonction, noms pour les variables, etc.).
La fenêtre aura la géométrie suivante : en haut, une barre de menus pour initialiser, abandonner, charger une partie, sauver la partie en cours, quitte,et.. Au centre, et occupant toute la largeur de la fenêtre on aura le plateau de jeu, puis en bas de la fenêtre une ligne d’information (objet de classe JLabel) affichant les divers messages (qui a gagné, quel unité est déplacée). Pour jouer, l'utilisateur doit cliquer directement dans le plateau de jeu sur l'unité qu’il désire deplacée.
Un aspect important de ce projet est de bien prévoir que toutes les fonctionnalités seront facilement réalisables avec votre façon d’implanter une unité et avec l’organisation des données.
Si vous voyez des améliorations possibles, faites les et justifiez les. Par exemple avoir la possibilité de changer les images du terrain, afficher des animations lors des déplacements, afficher une fenêtre d'aide, etc.
Les commandes de sauvegarde et de rechargement de parties se feront par l'intermédiaire d'un sélecteur de fichiers (prévoir une boite de dialogue pour traiter les cas d'erreur, si on veut écraser un fichier déjà existant, ou charger un fichier inexistant par exemple . . . ).
Pour implémenter votre interface graphique vous pouvez utiliser un dérivé de la classe JPanel. Il vous faudra redéfinir la méthode d'affichage (paint) pour dessiner les cases et les unités. Vous pouvez utiliser des images gif ou jpeg pour représenter le plateau de jeu et les tuiles, ou bien les fonctions de dessin de la classe Graphics. Quand la partie est terminée le programme doit afficher qui a gagné (soit avec une boite de dialogue, soit par un message dans la fenêtre principale).
On désire réaliser une application, et non pas une applette, entre autres pour pouvoir accéder aux fichiers (pour charger ou sauver une partie). Pour cela, on fera dériver la classe principale de la classe JFrame, qui comportera tous les composants nécessaires au jeu.
Afin de vous aider à évaluer votre état d’avancement nous proposons vous proposons de respecter les étapes suivantes :
1. Une hiérarchie de classe pour représenter les unités et les batiments.
2. Une fenêtre simple avec son menu, sa barre d’état et un contenu vide
3. Insérer un contenu correspondant à une case avec une unité dessus.
4. Une grille de case avec le même type case partout. Une unité simple sur la case du milieu.
5. Réaliser l’interaction qui permet de sélectionner une unité, de la poser ailleurs. Réaliser l’interaction lorsque le joueur tente un coup illégal.
6. Créer les 2 joueurs, la liste des unités et des bâtiments.
7. Réaliser les algorithmes pour connaître les déplacements autorisés.
8. Réaliser les algorithmes pour les combats.
9. Réaliser la gestion des tours. Gestion des coups autorisées ou non.
10. Réaliser les fonctions de sauvegarde et de chargement
11. Réaliser un mini-serveur qui reçoit les coups joués par un client et les affiche simplement dans la grille.
12. Modifier le serveur pour que se soit lui qui gère les tours de jeu.
13. Modifier le serveur pour centraliser le démarrage, le chargement et la sauvegarde.
14. Modifier le serveur pour diffuser les coups joués à distance au client et vice-versa.
Structure du programme
C'est à vous de concevoir l'architecture de votre programme de façon à
ce qu'il ait toutes les qualités exigées d'un bon logiciel : simplicité,
concision, clarté, etc. Comme il s’agit de votre premier projet nous fournissons
quelques interfaces a respecter :
Les moteurs manuels
Vous devrez réaliser trois versions du moteur de jeu, la version bi-joueur qui fait jouer deux joueurs humains, la version espionne qui observe sans permettre de jouer, et enfin une version complète à travers le réseau. Bien sûr, le coup joué par l'humain numéro un doit être légal (son moteur doit le vérifier), alors que le coup de adversaire reçu par ce même moteur manuel est forcément légal (son propre moteur l'ayant vérifié).
Tant qu'aucun client n'est connecté, l'interface du serveur est inactive (le joueur ne peut rien faire). Une fois un client connecté, l'interface du serveur devient active et c'est à lui de jouer en premier. Quand un joueur décide d'arrêter de jouer, son moteur envoie le code 70 à son vis-à-vis pour le lui indiquer. Si c'est le client qui décide de s'arrêter, le serveur, sur réception du code de fin, se réinitialise (i.e. se remet en attente d'un nouveau client). Si c'est le serveur qui décide de s'arrêter, le client et les espions se terminent (de toutes façons, ils n'auront plus de serveur à qui parler!).
Si une panne, ou toute autre cause, provoque l'arrêt du client, le serveur s'en rendra compte par une exception et devra se réinitialiser; Si la panne provoque l'arrêt du serveur, tous les autres, le client et les éventuels espions, devront se terminer.
Un joueur a la possibilité d'abandonner la partie en cours, cela signifie qu'il a perdu de fait. Cette possibilité est donc à traiter de façon analogue à une fin de partie (perdante pour celui qui abandonne). La différence est que le code transmis à l'opposant a la valeur 71, et que les programmes ne s'arrêtent pas : on peut recommencer une nouvelle partie.
De même, un joueur a la possibilité de recharger une nouvelle partie (quand c'est à lui de jouer bien sûr) cela signifie qu'il abandonne la partie en cours, avec les conséquences citées plus haut.
Le moteur espion est une version simplifiée du moteur manuel client : il ne permet pas à l'utilisateur de jouer (il interdit tout coup, et toute demande de chargement ou de sauvegarde de partie). Il ne permet que de faire afficher par son interface utilisateur la partie qu'il observe.
On ne peut avoir qu'un seul moteur manuel client, mais plusieurs moteurs espions connectés au même moteur manuel serveur. Celui-ci devra gérer correctement tous ses clients : une bonne façon de faire est d'avoir un thread par client.
Attention : le moteur serveur doit indiquer aux moteurs espions tous les coups joués : les siens, et ceux de l'autre joueur.
Comme un moteur espion peut se connecter au serveur à tout moment de la partie, il est clair que le serveur doit pouvoir lui transmettre la totalité de son plateau de jeu. Initialement (avant que le client soit connecté), le serveur ne peut pas modifier le plateau de jeu : il ne peut pas jouer, ni charger de partie.
Le protocole de communication entre les moteurs est le suivant (fig. 5) :
· le moteur client, une fois connecté au moteur serveur, s'identifie en lui envoyant l'octet de valeur 67.
· les moteurs espions s'identifient auprès du serveur en envoyant l'octet de valeur 69.
· la transmission d'un plateau de jeu se fait en envoyant l'octet de valeur 64, une fin de ligne, puis le contenu complet du tableau, ligne par ligne, en ascii lisible avec un espace et une virgule entre chaque case (c'est à dire exactement le même format que pour la sauvegarde dans un fichier).
Pour indiquer le coup joué, un moteur envoie à son vis-à-vis l'octet de valeur 97 suivi des coordonnées de la case jouée (en ajoutant un décalage de 64 pour avoir de l'ascii lisible), soit trois octets en tout.
Figure 1 : Architecture du réseau.
A vous de voir quelles sont les relations entre les différents moteurs, pour réutiliser au maximum le code que vous allez écrire; pensez d'abord aux différentes classes dont vous allez avoir besoin, avant de vous lancer dans la programmation : faites un diagramme des relations entre les classes (utilisation croisée, dérivation, . . . ), énumérez les attributs et les méthodes de chaque classe, ce n'est qu'ensuite que vous écrirez le corps des méthodes.