ticTacToe

ticTacToeChristophe Béasse [x]

Proglet Tic-Tac-Toe version réseau.

Auteur : Christophe Béasse

Présentation: jeu du Tic-Tac-Toe et primitives réseau.

On propose ici de réaliser le jeu du "TicTacToe" (version anglaise du morpion qui se joue sur une grille de 3x3 cases) en version réseau à l'aide d'une implémentation type client/serveur utilisant les sockets. On dispose de deux postes (1 poste ou le jeu tourne en mode serveur et 1 autre poste ou le jeu tourne en mode client. Dans le film WarGames (1984), le jeu de Tic-Tac-Toe est utilisé pour apprendre à un ordinateur pris de folie destructrice qu'il existe des jeux auxquels on ne peut pas toujours gagner.

Proglet exemple (version serveur et version client).

Voici un exemple minimal qui permet de tester cette proglet. Attention, il faut lancer la version serveur en premier, puis la version client. Ici les deux proglets peuvent être lancés sur la même machine.Dans ce cas, il vous faut lancer deux fois la proglet ticTacToe sur l'ordinateur en chargeant dans l'une la version serveur ci-dessous et dans l'autre la version client.

Code source des programmes de test.

Version serveur.

void main() {
    openSocketServer(6000);
    String str = getMessageViaSocketServer();
    int i = Integer.parseInt(str.substring(0,1));
    int j = Integer.parseInt(str.substring(2,3));
    setGrille(i,j,'O');
    sendMessageViaSocketServer("1,3");
    setGrille(1,3,'X');
    closeSocketServer();
}

Version client.

void main() {
    openSocketClient("127.0.0.1",6000);
    setGrille(3,3,'O');
    sendMessageViaSocketClient("3,3");
    String str = getMessageViaSocketClient();
    int i = Integer.parseInt(str.substring(0,1));
    int j = Integer.parseInt(str.substring(2,3));
    setGrille(i,j,'X');
    closeSocketClient();
}

Principes de fonctionnement.

  • Une fois lancé, le proglet serveur ouvre un socket sur le port 6000 (openSocketServer) puis il se met en attente d'un coup envoyé par le proglet client (getMessageViaSocketServer()). Il récupère les coordonnées de la case choisie (Integer.parseInt) met à jour la grille en conséquence (setGrille(i,j,'O')) puis joue à son tour en envoyant les coordonnées de la case choisie au client (sendMessageViaSocketServer("1,3")) tout en mettant à jour sa propre grille (setGrille(1,3,'X')). Il ne faut pas oublier de fermer le socket server (closeSocketServer()) pour libérer le port 6000 pour une future utilisation.
  • Une fois lancé, le proglet client essaye d'ouvrir un socket (openSocketClient) communiquant via le port 6000 avec le serveur spécifié, ici localhost/127.0.0.1 .Puis il envoie le premier coup par le proglet client (sendMessageViaSocketClient("3,3")) tout en mettant à jour sa propre grille (setGrille(3,3,'O')).Puis, il se met en attente d'un coup envoyé par le proglet Server (getMessageViaSocketClient()). Il récupère les coordonnées de la case choisie (Integer.parseInt) met à jour la grille en conséquence (setGrille(i,j,'X')). Il ne faut pas oublier de fermer le socket Client (closeSocketClient()) pour libérer le port ouvert par le client pour une future utilisation.

remarques:.

  • Le port utilisé pour accéder au serveur est le port 6000. (A changer si ce port est déjà utilisé).
  • Le format d'un coup est une chaîne de 3 caractères correspondant aux coordonnées de la case choisie "numligne,numcolonne" , par exemple "3,3".
  • Au niveau de la grille du jeu, la marque utilisée par le joueur/serveur est une croix 'X' alors que la marque utilisée par le joueur/client est un rond 'O'.
  • Dans cet exemple minimal aucun test n'est fait pour vérifier que les ouvertures de sockets ce sont bien passées, etc. Tests qui seront bien sûr à faire dans la version finale du jeu.
  • Dans cet exemple le client joue en premier le coup (3,3) auquel le serveur répond par le coup (1,3).
  • En cas de problèmes éventuels de droits/Firewall sur le réseau, on peut très bien utiliser cette application client/serveur sur un même poste (au moins pour les développements) en utilisant l'adresse de serveur localhost (127.0.0.1). On peut aussi raccorder les deux postes à l'aide d'un câble croisé ou d'un mini-switch.

Variantes au niveau de la mise en oeuvre.

On peut prévoir deux versions:
  • Une version, comme celle présenté ici du type [1 client / 1 serveur] ou un joueur active la version serveur sur un poste et ou le deuxième active la version client.
  • Une version type [2 clients / 1 serveur]. Le serveur tournant sur un poste dédié sert à mettre en relation au début du jeu les deux versions clientes (voir le proglet Client/Serveur.

Liste des fonctions à disposition.

Gestion de la grille de jeu.

Pour la gestion de la grille de jeu (taille 3x3) proposée au niveau de la console "graphique" vous disposez des fonctions suivantes :
setGrille(int i , int j ,char mark)
Permet de positionner une marque (caractère 'X' ou 'O') sur la grille à la position spécifiée (coordonnées comprises entre 1 et 3). La marque ronde 'O' est Bleu, la croix 'X' est verte
Exemple : setGrille(1,2,'X')
getGrille(int i , int j )
Cette fonction retourne la marque (caractère 'X' ou 'O' ou ' ') (type char) présente sur la grille à la position spécifiée (coordonnées comprises entre 1 et 3).
exemple : char mark = getGrille(3,3);

Gestion de la communication réseau via les sockets.

Au niveau communication TCP/IP on dispose d'une fonction d'initialisation du port (via une "socket"), d'une fonction de lecture, d'une fonction d'écriture et enfin d'une fonction de libération de la connection. Chacune de ses fonctions est déclinée en version serveur et en version client.
openSocketServer(int numport)
Initialisation du socket server, il écoute sur le port spécifié.
getMessageViaSocketServer()
Retourne un message (type String) lu sur le socket server. Message en provenance du client.
sendMessageViaSocketServer(String text)
Permet d'écrire un message sur le socket server. Message à destination du client.
closeSocketServer()
Fermeture du socket server. Cette fonction retourne true si tout c'est bien passé false dans le cas contraire.
openSocketClient(String serverName, int numport)
Initialisation socket client vers server spécifié (Nom et numéro de port) Cette fonction retourne true si tout c'est bien passé false dans le cas contraire.
sendMessageViaSocketClient(String text)
Permet d'envoyer un message via le socket client vers le serveur.
getMessageViaSocketClient()
Retourne un message (type String) lu sur le socket client, message en provenance du serveur.
closeSocketClient()
Fermeture du socket client. Cette fonction retourne true si tout c'est bien passé false dans le cas contraire.