:: Enseignements :: Master :: Master TTT :: 2011-2012 :: Programmation réseau en Java ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) | Projet Nejagar (NEtworked JAva Game Arbiter) |
Nous souhaitons réaliser une logiciel en Java facilitant l'implantation de jeux de plateau en réseau. Celui-ci consiste en un serveur central qui gère la demande et la réception des coups de jeu de chacun des joueurs et maintient en conséquence à jour l'état du plateau de jeu avec les scores. Ce serveur central joue un rôle d'arbitre. Les joueurs sont des clients se connectant à ce serveur d'arbitrage.
Un client peut utiliser une interface graphique ou textuelle pour obtenir les coups à jouer d'un humain ou bien être connecté à une intelligence artificielle.
L'objectif de ce projet sera de réaliser une interface de programmation (API) générique et simple permettant d'implanter rapidement des jeux de plateau spécifiques. Reposant sur cette API, une bibliothèque gérant les communications réseau entre serveur et clients en utilisant le protocole TCP devra être mise en place. On implantera ensuite deux jeux de plateau avec leur interface cliente.
API pour jeu de plateau
Un jeu de plateau peut être défini par un ensemble de règles. Ces règles nous permettent de savoir :
- Combien de joueurs peuvent participer au jeu (nombre minimum et maximum)
- Le comportement de l'arbitre face à un état donné du plateau de jeu : faut-il inviter un ou plusieurs joueurs à proposer leur coups, notifier le coup d'un adversaire à un joueur ou alors déclarer la partie terminée ?
- Comment mettre à jour le plateau de jeu lorsqu'un coup est fourni par un joueur
On pourra par exemple proposer une interface
ArbitreJeu qui sera implantée par des arbitres de jeu spécifique et appliquera les règles :
public interface ArbitreJeu
{
public int minJoueurs();
public int maxJoueurs();
public Plateau preparePlateau(Joueur[] joueurs);
public MessageArbitral[] signaleCoup(Plateau plateau, Coup coup);
}
La méthode preparePlateau() initialise un plateau de jeu pour les joueurs donnés. La méthode signaleCoup() est appelée lorsque le coup d'un joueur est reçu : l'arbitre met à jour l'état du plateau et détermine le ou les message(s) à envoyer aux joueurs.
Il faut définir pour chaque jeu spécifique les informations stockées par le plateau ainsi que les données apportées par un coup.
Prenons l'exemple d'un jeu de dames classique. Le plateau contient une matrice de dimensions 8x8 dont les valeurs peuvent indiquer une case vide, un pion ou une dame noire ou blanche. Le plateau comporte également le trait (joueur dont le coup est attendu). Un coup est défini par les coordonnées de la case de départ et la case d'arrivée du joueur. Un coup étant fourni, le plateau est mis à jour par l'arbitre en déplaçant une pièce de la matrice et en supprimant éventuellement certaines pièces de l'adversaire mangées. Après chaque coup, on met à jour le trait du plateau afin de connaître le prochain joueur à proposer un coup. Les coups illégaux doivent également être gérés (par exemple en terminant la partie et en déclarant l'adversaire vainqueur --- méchant --- ou alors en ne modifiant pas le plateau et en reproposant au joueur de fournir un coup).
On écrit donc à cet effet les interfaces Java qui vont contenir les méthodes utiles afin que la bibliothèque de communication réseau côté serveur puisse communiquer des messages d'invitation à fournir un coup, recevoir des messages contenant un coup d'un joueur, envoyer les coups d'un joueur à d'autres joueurs, mettre à jour le plateau de jeu...
On intégrera à la documentation du logiciel une partie dédiée aux développeurs souhaitant utiliser l'API pour implanter la gestion de leur propre jeu.
Bibliothèque de communication réseau
Cette bibliothèque permet de gérer les communications entre le serveur et le client. On écrira d'abord une RFC décrivant le protocole de communication entre les machines, le comportement attendu du serveur et des clients et les éventuels cas d'erreurs ; ce protocole est libre, le seul pré-requis réside dans l'usage d'une connexion TCP entre chaque client et le serveur. Cette RFC doit rester générique en décrivant les types de messages échangés sans spécifier de détails relatifs à des jeux spécifiques. Elle devra décrire également le fonctionnement avant le démarrage effectif du jeu (inscription du joueur sur le serveur, mise en attente de celui-ci, signalement de début de partie).
La RFC rédigée, on pourra s'attaquer à l'implantation des classes gérant la communication. On utilisera de préference le paquetage java.net du JDK avec l'usage de plusieurs threads concurrentes pour gérer la communication avec plusieurs joueurs au niveau du serveur. On souhaite gérer bien entendu plusieurs joueurs par partie mais également plusieurs parties simultanées. On apportera une attention particulière à une bonne gestion de la synchronisation des threads.
Discussion par datagrammes UDP (facultatif)
Outre la communication des coups du jeu, il pourrait être agréable aux joueurs de discuter librement entre-eux. Les messages devront être échangés par datagrammes UDP de pair à pair (le serveur d'arbitrage ne relaie pas les messages). Chaque client pourra interroger le serveur pour connaître l'adresse IP d'un autre joueur. Le serveur proposera également pour chaque partie une adresse spécifique de multicast à laquelle s'abonne tous les joueurs : un joueur pourra adresser un message à cette adresse s'il souhaite l'envoyer à tous les joueurs de la partie. On écrira une seconde RFC afin de décrire comment discuter par datagrammes UDP.
Implantation de jeux spécifiques
Le pierre/feuille/ciseaux
Le jeu pierre/feuille/ciseaux nécessite deux joueurs. Il se décompose en un nombre de manches initialement fixé. Lors de chacune de ces manches, les deux adversaires jouent simultanément en optant chacun pour l'un de ces trois objets : la pierre, la feuille et les ciseaux. La pierre l'emporte sur les ciseaux qu'elle casse mais perd face à la feuille en étant recouverte ; la feuille perd face aux ciseaux en étant coupée. Le jeu s'arrête lorsque le nombre de manches fixé est atteint.
On notera que ce jeu dispose d'un plateau très simple puisque seule la conservation d'un compteur de score pour chaque joueur est nécessaire. Pour chaque manche, l'invitation de coup doit être adressée en même temps aux deux joueurs, la notification du coup d'un joueur à l'autre ne pouvant bien sûr intervenir qu'après avoir joué.
On réalisera une implantation simple du jeu pierre/feuille/ciseaux avec une interface textuelle ou (mieux) une interface graphique Swing simple.
Un autre jeu...
On devra implanter dans un second temps un deuxième jeu avec un plateau et des règles plus complexe que le pierre/feuille/ciseaux. Par exemple (en suivant un niveau de complexité croissant) un jeu de puissance 4, de go, de dames, d'échecs, de Monopoly (bonne chance ;) pourra être envisagé. Pour d'autres idées, n'hésitez pas à envoyer un email au chargé de cours/TD qui étudiera votre proposition.
Consignes
Afin de faciliter la correction des projets, les consignes suivantes doivent être absolument respectées :
Lancement du serveur
Le serveur de jeu doit être lancé par la ligne de commande suivante :
java fr.upemlv.nejagar.communication.server.Server PORT chemin.vers.classe.de.l.arbitre.de.jeu argumentA argumentB ...
Le serveur va récupérer le chemin vers la classe de l'implantation de l'arbitre, charger la classe (on pourra utiliser la méthode statique Class.forName(String nomClasse)), l'instantier (méthode Class.newInstance()) et la paramétrer avec les arguments fournis. On pourrait avoir par exemple la commande suivante créant un arbitre de pierre/feuille/ciseaux avec jeu à 10 manches sur le port 2012 :
java fr.upemlv.nejagar.communication.server.Server 2012 fr.upemlv.nejagar.games.rockpaperscissors.server.RPSArbiter 10
Idéalement, le serveur doit être fermable proprement en envoyant un signal SIGTERM à la JVM (penser à un ShutdownHook).
Lancement du client
Le client est lançable par une classe spécifique selon le jeu souhaité avec indication du nom du joueur et du port du serveur, par exemple :
java fr.upemlv.nejagar.games.rockpaperscissors.client.RPSClient 2012 Toto
On conviendra que l'on utilisera par défaut le port 4096 pour les communications de discussion UDP entre joueurs.
Rendu
Le projet est à réaliser absolument en binôme : un seul trinôme sera toléré si le nombre d'étudiants est impair (et il en sera attendu l'implantation d'un jeu plus complexe). Le rendu du projet doit être effectué par une archive zip adressée par courrier électronique au chargé de cours/TD avec pour sujet [Nejagar M2TTT]" login1 login2.
L'archive doit contenir les sources du projet en Java (répertoire src/) ainsi qu'un script (Makefile ou build.xml) permettant sa compilation. Le répertoire doc/ contient la documentation du projet : RFCs rédigées, rapport de développement, documentation à destination d'un développeur de jeu. Un fichier LISEZMOI doit décrire brièvement le fonctionnement du projet avec quelques exemples.
En ce qui concerne les sources, celles-ci doivent être claires et bien commentées, avec une organisation en paquetage judicieuse qu'il sera utile de préciser dans le rapport de développement. Elles ne doivent reposer que sur l'utilisation de l'API du JDK et ne pas utiliser de code d'un auteur extérieur au binôme. Les sources seront distribuables selon la licence Affero GPL 3.
Le rendu se déroule en deux phases :
- Les RFCs du protocole de communication Nejagar client/serveur et du protocole de dialogue UDP entre joueurs. La date limite de rendu est fixée au 6 janvier 2012 à 19h (TZ Europe/Paris).
- Le projet complet Nejagar (documentation et sources). La date limite de rendu est fixée au 29 février 2012 à 19h (TZ Europe/Paris). Les retards sont acceptés mais font l'objet d'1/2 point de malus par jour de retard.
Il est conseillé de commencer le projet précocément et de privilégier une implantation fiable des fonctionnalités essentielles à un projet implantant de nombreuses fonctionnalités buggées. Une soutenance pourra avoir lieu à l'issue du rendu à une date qui reste à déterminer.
© Université de Marne-la-Vallée