Document ID: /fineweb-2-swissfilter-quality_10-filterrobots/filtered/07189.jsonl.gz/353

Programmes principaux
Javass – étape 11
1 Introduction
Le but de cette étape est de terminer le projet en écrivant les classes contenant les deux programmes principaux qui permettent de jouer au Jass et qui sont :
- un programme permettant de jouer à une partie locale, à laquelle des joueurs distants peuvent éventuellement participer,
- un programme permettant de participer à une partie distante, qui se déroule sur un autre ordinateur.
1.1 Partie locale
Une partie locale est une partie qui se déroule sur l'ordinateur sur lequel on exécute le programme correspondant et à laquelle participent quatre joueurs, qui peuvent être de trois types différents :
- un ou (rarement) plusieurs joueurs humains, dont l'interface graphique s'affiche sur l'ordinateur sur lequel la partie se déroule,
- un ou plusieurs joueurs simulés, qui s'exécutent sur l'ordinateur sur lequel la partie se déroule,
- un ou plusieurs joueurs distants, qui s'exécutent sur un autre ordinateur, et qui peuvent être d'un type quelconque (mais en général humain).
1.1.1 Configuration
La configuration d'une partie locale se fait en passant des arguments au programme correspondant. Depuis Eclipse, cela peut se faire de la manière décrite dans notre guide sur l'exécution de programmes.
Le programme accepte 4 ou 5 arguments. Les 4 premiers spécifient les joueurs, et le dernier, optionnel, spécifie la graine à utiliser pour générer les graines des différents générateurs aléatoires du programme, selon la technique décrite à la §2.1.
Chaque joueur est spécifié au moyen d'une chaîne de caractères composée de une à trois composantes, séparées les unes des autres par un deux-points (
:). La première composante ne comporte qu'une seule lettre, qui peut être :
hpour un joueur humain (local), ou
spour un joueur simulé (local), ou
rpour un joueur distant.
La seconde composante, optionnelle, est le nom du joueur. Par défaut, les noms suivants sont attribués aux joueurs, dans l'ordre : Aline, Bastien, Colette et David.
La troisième composante, elle aussi optionnelle, dépend du type de joueur :
- pour un joueur simulé, elle donne le nombre d'itérations de l'algorithme MCTS (10 000 par défaut),
- pour un joueur distant, elle donne le nom ou l'adresse IP de l'hôte sur lequel le serveur du joueur s'exécute (
localhostpar défaut).
Par exemple, les arguments suivants :
s h:Marie r:Céline:<ip-pii> s::20000
spécifient une partie à laquelle participent les joueurs suivants :
- un joueur simulé nommé Aline, avec 10 000 itérations,
- un joueur humain nommé Marie,
- un joueur distant nommé Céline dont le serveur s'exécute sur l'ordinateur dont l'adresse IP est <ip-pii>,
- un joueur simulé nommé David, avec 20 000 itérations.
1.1.2 Paramètres fixes
Pour simplifier les choses, deux aspects d'une partie locale ne sont pas configurables mais fixés ainsi :
- les joueurs simulés ne jouent jamais leur carte en moins de 2 secondes,
- à la fin de chaque pli, une pause de 1 seconde est observée pour permettre aux joueurs de voir la dernière carte posée.
1.1.3 Gestion des erreurs
Lors de l'analyse des arguments passés au programme, ou lors de la connexion aux serveurs des éventuels joueurs distants, il est possible que des erreurs se produisent. Elles doivent être traitées de la manière décrite ci-après.
Une première erreur qui peut se produire est que le nombre d'arguments passés au programme soit invalide, c-à-d différent de 4 ou 5. Dans ce cas, un message d'aide expliquant comment exécuter correctement le programme est affiché sur la console, et le programme se termine. Le message pourrait commencer ainsi :
Utilisation: java ch.epfl.javass.LocalMain <j1>…<j4> [<graine>] où : <jn> spécifie le joueur n, ainsi: h:<nom> un joueur humain nommé <nom> …
Attention : le message affiché en réalité doit être plus long et expliquer la totalité des types de joueurs et des arguments qu'il est possible de spécifier.
Les autres erreurs qui peuvent se produire sont :
- la première composante d'une spécification de joueur n'est pas
h,
sou
r,
- la spécification d'un joueur comporte trop de composantes (p.ex.
h:Marie:12),
- une erreur se produit lors de la connexion au serveur d'un joueur distant,
- la graine aléatoire n'est pas un entier
longvalide,
- le nombre d'itérations d'un joueur simulé n'est pas un entier
intvalide, ou est inférieur à 10.
Lorsqu'une de ces erreurs se produit, un message d'erreur concis mais clair est affiché sur la console, puis le programme se termine. Par exemple, appelé avec les arguments invalides suivants :
bla bli blo blu
le programme affiche sur la console un message ressemblant à :
Erreur : spécification de joueur invalide : bla
et se termine immédiatement.
Si les arguments comportent plusieurs erreurs, comme dans cet exemple, il suffit que l'une d'entre elles soit affichée.
1.2 Partie distante
Une partie distante est une partie qui se déroule sur un ordinateur autre que celui du joueur. La participation à une telle partie est très simple, car il n'y a aucune configuration à faire : comme nous l'avons vu, celle-ci est faite au niveau de la partie locale.
Même s'il serait possible, et simple, d'offrir la possibilité à des joueurs simulés de jouer à distance, cela ne présente pas de véritable intérêt. Dès lors, nous ne permettrons que à des joueurs humains de jouer à distance.
Le programme de jeu à distance ne prend donc aucun argument, et au démarrage il affiche un message court sur la console pour informer le joueur humain que la partie commencera dès que le client correspondant de la partie distante se sera connecté au serveur. Ce message pourrait ressembler à :
La partie commencera à la connexion du client...
La fenêtre graphique s'ouvre dès que le client s'est connecté au serveur et lui a envoyé le message
PLRS lui communiquant l'identité des joueurs.
2 Mise en œuvre Java
Attention : les classes
LocalMain et
RemoteMain décrites ci-dessous sont les classes principales de votre programme, et il est donc capital qu'elles portent effectivement le nom proposé, et qu'elles se trouvent dans le paquetage
ch.epfl.javass. Notre système de rendu refusera votre projet s'il ne contient pas ces deux classes, si elles sont placées dans un autre paquetage, ou si elles sont nommées différemment.
2.1 Classe
LocalMain
La classe
LocalMain du paquetage
ch.epfl.javass contient le programme principal permettant de jouer une partie locale.
Comme ce programme est doté d'une interface graphique JavaFX, la classe
LocalMain hérite de
Application. Comme toujours, sa méthode (statique)
main ne fait rien d'autre qu'appeler la méthode
launch de
Application, et le code démarrant effectivement l'application se trouve dans la méthode
start.
La méthode
start analyse les arguments et crée les 4 joueurs en fonction, en signalant bien entendu les éventuelles erreurs rencontrées. Si les 4 joueurs peuvent être créés sans problème, un fil d'exécution séparé est démarré, dans lequel la partie se déroule.
2.1.1 Conseils de programmation
- Arguments du programme
- Gestion des erreurs
Pour transformer une chaîne de caractères en un entier
int, vous pouvez utiliser la méthode
parseIntde la classe
Integer. Notez qu'elle lève l'exception
NumberFormatExceptionsi la chaîne ne représente pas un entier
intvalide, exception qu'il vous faut donc rattraper afin d'afficher un message d'erreur.
Lorsqu'une erreur de connexion au serveur se produit, le constructeur de votre classe
RemotePlayerClientdevrait lever l'exception
IOException(indirectement, car en réalité c'est le constructeur de
Socketqui la lève), qu'il vous faut également rattraper pour afficher un message d'erreur.
Les autres erreurs ne sont pas signalées au moyen d'exceptions, il vous faut donc les détecter vous-même, et afficher un message d'erreur au besoin.
Dans tous les cas, les messages d'erreurs doivent être affichés sur le flot
System.erret pas
System.out. En effet, le flot
System.errest dédié aux messages d'erreur.
De plus, lorsqu'une erreur est détectée, le programme doit se terminer immédiatement, ce qui peut se faire en appelant la méthode
exitde la classe
System, en lui passant 1 en argument. Cet argument est le code de retour du programme, et toute valeur différente de 0 indique par convention que le programme s'est terminé anormalement.
- Graines de générateurs aléatoires
Pour faciliter les tests, le programme principal permettant de jouer une partie locale prend un argument optionnel, qui représente une graine de générateur aléatoire.
Le but de cette graine est d'être utilisée pour initialiser un générateur aléatoire principal, utilisé ensuite pour obtenir les graines des autres générateurs aléatoires du projet.
Si l'argument optionnel représentant la graine est fourni au programme principal, alors le générateur aléatoire principal doit être obtenu en passant cette graine au constructeur de
Randomprenant une graine en argument. Par contre, si cet argument n'est pas fourni, alors le générateur aléatoire principal doit être obtenu au moyen du constructeur de
Randomne prenant aucun argument, ce qui implique que sa graine sera aléatoire.
Une fois construit, le générateur aléatoire principal doit être utilisé pour générer exactement 5 valeurs de type
long, qui doivent être passées (dans l'ordre) :
- au constructeur de
JassGame,
- au constructeur du joueur 1 (
PLAYER_1) ssi il s'agit d'un joueur simulé,
- au constructeur du joueur 2 (
PLAYER_2) ssi il s'agit d'un joueur simulé,
- au constructeur du joueur 3 (
PLAYER_3) ssi il s'agit d'un joueur simulé,
- au constructeur du joueur 4 (
PLAYER_4) ssi il s'agit d'un joueur simulé.
On garantit ainsi qu'en passant la même graine au programme, on obtienne toujours la même partie. D'autre part, étant donné que la manière dont
JassGameutilise la graine qu'on lui passe pour choisir l'atout et mélanger les cartes a été clairement spécifiée à l'étape 5, une graine donnée devrait produire une même distribution des cartes, et un même choix de l'atout pour tous les projets.
- au constructeur de
- Ralentissement des joueurs simulés
Pour garantir que les joueurs simulés ne jouent jamais une carte en moins de 2 secondes, il faut bien entendu utiliser la classe
PacedPlayerécrite lors de l'étape 5.
- Fil d'exécution
Comme illustré dans le programme d'exemple donné à la fin de l'étape 10, la partie doit se dérouler dans un fil d'exécution séparé. Afin que l'application se termine correctement, il est nécessaire d'appeler la méthode
setDaemonen lui passant
trueavant de démarrer le fil au moyen de la méthode
start. En d'autres termes, le fil doit être créé et démarré ainsi :
Thread gameThread = new Thread(/* … */); gameThread.setDaemon(true); gameThread.start();
2.2 Classe
RemoteMain
La classe
RemoteMain du paquetage
ch.epfl.javass contient le programme principal permettant de jouer à une partie distante.
Comme ce programme est doté d'une interface graphique JavaFX, la classe
RemoteMain hérite également de
Application.
Sa méthode
start est très simple et ne fait rien d'autre que créer un fil d'exécution séparé exécutant un serveur, puis afficher le message mentionné plus haut (« La partie commencera à la connexion du client… ») sur la console.
Attention, le fil exécutant le serveur doit être créé de la même manière que celui dans laquelle se déroule la partie, c-à-d avec un appel à
setDaemon avant l'appel à
start.
2.3 Tests
Etant donné que les classes contenant vos programmes principaux doivent avoir un nom précis, nous vous fournissons à nouveau un fichier de vérification de signatures pour cette étape, contenu comme d'habitude dans une archive Zip à importer dans votre projet.
Pour tester votre projet, vous pouvez bien entendu jouer au Jass contre des joueurs simulés ou d'autres joueurs humains distants. Il est de plus fortement conseillé d'effectuer des tests combinant des clients et serveurs de différents projets, car cela vous permet de vérifier que vous avez bien mis en œuvre le protocole de communication spécifié à l'étape 7. Cela est capital car un des aspect de vos projets que nous testerons est justement qu'ils mettent correctement en œuvre le protocole de communication.
3 Résumé
Pour cette étape, vous devez :
- écrire les classes
LocalMainet
RemoteMainen fonction des indications données plus haut,
- tester votre code,
- documenter la totalité des entités publiques que vous avez définies,
- rendre votre projet dans le cadre du rendu final anticipé, si vous désirez tenter d'obtenir un bonus, ou dans le cadre du rendu final normal sinon ; les instructions concernant ces rendus seront publiées ultérieurement.