TP: tic-tac-toe en réseau§

Prise en main (30 min)§

L'objectif§

Nous voulons programmer un tic-tac-toe en réseau.

Le projet est déjà entamé. Vous devez télécharger ce code puis l'enrichir.

Le projet est organisé en 4 packages:

Package noyau§

Il contient:

Regardez attentivement ces classes que vous utiliserez.

Positionnement§

Nous avons les conventions suivantes:

Package Entree§

Il contient:

Joueur vs Utilisateur§

Un objet Joueur, a une couleur, connait la configuration des pions, l'arbitre, ainsi qu'un objet de type LecteurPosition. Si cet objet est du sous-type LecteurPositionDeFlux, alors le joueur est en attente d'une chaine de caractères sur un flux d'entrée contenant la position qu'il doit jouer.

Un utilisateur peut donc transmettre par le flux d'entrée standard son déplacement à l'objet Joueur qui le représente.

Transmission textuelle§

Pour transmettre une position sur le flux d'entrée standard, un utilisateur doit respecter la convention suivante:

NB. la méthode toString des objets de type Position respecte cette convention.

Package Sortie§

Il contient pour l'instant:

A l'avenir, nous voulons aussi avoir:

Package App§

Il est vide! Créez vite une première application TicTacToeShell, dans laquelle les deux utilisateurs donnent la position de leur nouvelle marque, sous forme textuelle, dans le shell.

Dans la méthode main:

Vous pouvez jouer à l'aveugle: la grille n'est pas affichée!

Modèle et vue (30 min)§

Objectif§

La classe EnsembleDeMarques (le modèle) ne connait pas la classe VueShell (la vue).

On veut pourtant qu'elles puissent communiquer entre elles, pour que la vue soit mise à jour après la modification des données (ajout ou suppression d'un pion sur une position).

En même temps, on ne veut pas que le modèle dépende d'une vue particulière et on voudrait avoir la possibilité d'offrir aisément zéro, une ou plusieurs vues sur le modèle.

Pour réaliser cela, nous allons mettre en oeuvre le principe Observable/Observer.

Observable§

Notre modèle (EnsembleDeMarques) doit être observable (et observé par la vue).

Pour être observable, il doit dériver de la classe Observable.

Il hérite notamment des méthodes

que vous devez appeler, dans l'ordre, à la fin de la méthode ajouterMarque, pour demander à la vue de procéder à une mise à jour de l'affichage.

Observer§

Notre vue (VueShell) doit observer notre modèle et déclencher l'affichage à chaque fois que le modèle est mis à jour après l'ajout d'une nouvelle marque.

Elle doit satisfaire l'interface Observer, c'est-à-dire posséder une méthode update(Observable o, Object arg) (appelée par notifyObservers(Object arg)). C'est dans cette méthode que vous devez déclencher l'affichage.

L'objet o est l'objet observable qui appelle update (EnsembleDeMarques). Le paramètre arg permet d'ajouter une information pour la mise à jour; par exemple, la position à laquelle à été ajouté la nouvelle marque.

Dans l'application TicTacToeShell§

Dans la méthode main:

Vous pouvez commencer à jouer!

Serveur/Client (30 min)§

Objectif§

Jusqu'à maintenant, les deux utilisateurs jouent sur la même machine. Nous allons maintenant faire deux applications: TicTacToeShellServeur et TicTacToeShellClient.

Les deux applications auront toutes deux, un ensemble de marques, deux joueurs synchronisés par un arbitre, ainsi qu'une vue. Cependant, l'un des deux joueurs lira ses positions depuis la machine distante, tandis que l'autre enverra ses positions sur la machine distante.

Ainsi, seuls des positions, sous forme textuelle, seront communiquées.

Serveur§

Client§

Une fois que vous avez un serveur qui fonctionne, écrire l'application TicTacToeShellClient est un jeu d'enfant, car le code est parfaitement symétrique au code du serveur.

Vous pouvez maintenant jouer depuis deux machines différentes. Mais l'interface du jeu n'est pas confortable.

Interface graphique (45 min)§

Objectif§

Nous voulons créer une interface graphique pour notre jeu.

Le package Sortie du projet sera enrichi:

La package App sera enrichi de nouvelles applications:

Conception§

La conception est libre, mais si vous ne savez pas quoi faire, vous pouvez:

Vous pouvez commencer par tester votre affichage en donnant les positions par le shell. Mais comment lire les positions directement sur l'interface graphique ?

Evénements (45 min)§

Objectif§

Maintenant que nous avons une interface graphique, nous voulons aussi que les utilisateurs puissent prescrire leurs déplacements par des actions (clics) sur l'interface graphique.

Conception§

  1. Vous devez écrire un listener, par exemple CaseListener. Une instance de cette classe devrait récupérer la position de la case choisie (et c'est pourquoi il est utile qu'une case connaisse sa position).
  2. Puis écrire une classe LecteurPositionDeVueGraphique qui satisfait l'interface LecteurPosition. La vue, comme le listener, doivent connaitre le lecteur afin de lui transmettre la position de la case choisie.