Conception et de veloppement en Java d`un logiciel de poker en re
Transcription
Conception et de veloppement en Java d`un logiciel de poker en re
Xavier GUIHOT Conception et developpement en Java d'un logiciel de poker en reseau Rapport d'initiative IDEE Tuteur : Fabrice FRANCES Juin 2012 - Janvier 2014 ISAE - ENSICA GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Table des matières Partie I. L'Architecture du logiciel ..................................................................................................................................... 6 1. Architecture globale :............................................................................................................................................ 6 2. Architecture client :............................................................................................................................................. 10 3. Architecture serveur : ......................................................................................................................................... 11 4. Architecture multi-clients - serveur : .................................................................................................................. 12 5. La base de données : ........................................................................................................................................... 14 Partie II. Le côté client..................................................................................................................................................... 17 1. La connexion et l'inscription : ............................................................................................................................. 17 a. La connexion : ..................................................................................................................................... 17 b. L'inscription : ...................................................................................................................................... 17 c. La gestion de l'absence de liaison internet lors de la connexion : .......................................................... 19 2. Le menu :............................................................................................................................................................. 21 3. La table : .............................................................................................................................................................. 23 4. La fenêtre des statistiques et d'options : ............................................................................................................ 25 5. Les raccourcis clavier :......................................................................................................................................... 32 6. Les boutons de décision en avance :................................................................................................................... 33 7. Lutte contre l'addiction : ..................................................................................................................................... 34 8. Empêcher l'envoie de la même action plusieurs fois :........................................................................................ 35 Partie III. Le Serveur et la gestion des clients et du jeu .................................................................................................. 36 1. Le jeu de cartes : ................................................................................................................................................. 36 2. Le calcul de la combinaison :............................................................................................................................... 39 3. Actualisation de la partie : .................................................................................................................................. 42 4. Le tirage au sort : ................................................................................................................................................ 43 5. L'affichage des blindes : ...................................................................................................................................... 46 6. Ecoute des actions des joueurs : ......................................................................................................................... 52 7. Recherche du joueur et de l'étape suivants :...................................................................................................... 55 8. Fin d'une main :................................................................................................................................................... 58 a. Fin d'une main par élimination de tous les adversaires : ....................................................................... 58 b. Fin d'une main par l'abattage : ............................................................................................................ 59 9. Les pourcentages à tapis : ................................................................................................................................... 62 a. Les probabilités de gagner avant le turn et avant la river : .................................................................... 62 b. Les probabilités de gagner avant le flop avec deux joueurs all-in :......................................................... 64 c. Les probabilités de gagner avant le flop avec plus de deux joueurs all-in : ............................................. 66 Partie IV. Développement logiciel................................................................................................................................... 68 3 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 1. Faciliter le développement : ............................................................................................................................... 68 2. Mise à jour automatique :................................................................................................................................... 69 3. Mise à niveau sur les différents systèmes d'exploitation : ................................................................................. 72 4. Gestion de la perte de connexion : ..................................................................................................................... 73 5. L'obfuscation : ..................................................................................................................................................... 74 6. Utilisation d'un serveur dédié : ........................................................................................................................... 76 7. L'administration du serveur : .............................................................................................................................. 78 Partie V. La personnalisation des composants Java Swing ............................................................................................. 79 1. JButton personnalisé :......................................................................................................................................... 79 2. JTextField personnalisé : ..................................................................................................................................... 82 3. JProgressBar personnalisée : .............................................................................................................................. 83 4. Une JTable personnalisée : ................................................................................................................................. 85 5. Une JScrollBar personnalisée : ............................................................................................................................ 88 6. Une JCheckBox personnalisée :........................................................................................................................... 90 7. Le chat : ............................................................................................................................................................... 91 8. Ajouter une icône à une fenêtre : ....................................................................................................................... 93 9. Ajouter des info-bulles : ...................................................................................................................................... 94 10. Centrer un String : ............................................................................................................................................... 95 Conclusion ....................................................................................................................................................................... 96 1. Quantité de travail effectué : .............................................................................................................................. 96 2. Difficultés rencontrées : ...................................................................................................................................... 97 4 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Etant passionné par le poker dont la popularité a décollé ces dernières années avec la légalisation autorisant les sites de poker avec argent réel, me spécialisant dans l'informatique, et souhaitant me diriger vers du développement logiciel, j’ai pris l'initiative de développer en Java un logiciel de poker en réseau. Les objectifs fixés au début du projet consistaient en l'élaboration d'un logiciel de poker en réseau, utilisable en Java sur ordinateur et en Android sur Smartphone. L'utilisateur pourrait alors jouer en partie libre ou en tournois. En partie libre, il aurait accès à des tables de différents niveaux de cave1. Le joueur aurait de plus accès à différents tournois se déroulant à intervalles réguliers. Une autre partie du projet reposait sur le développement d'une intelligence artificielle de poker. Le tout devant être ergonomique et sans disfonctionnements. 1 Cave : nombre minimum de jetons qu’un joueur doit utiliser pour s'asseoir à une table. 5 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Partie I. L'Architecture du logiciel 1. Architecture globale : Quatre programmes ont été créés pour assurer l'ensemble des fonctionnalités. On peut voir dans le diagramme de classes ci-dessous l'architecture globale du système et l'ensemble des liaisons entre classes (flèches noires) et entre programmes via des liaisons TCP/IP (flèches bleues). Ce diagramme de classes a été réalisé avec le logiciel Bouml très pratique de par sa génération plus ou moins automatique de diagrammes de classes à partir de code source Java. Le logiciel de poker étant construit autour d'une architecture client-serveur, il est composé de deux parties principales : le côté client et le côté serveur. Le côté client est le logiciel que le client va utiliser sur son ordinateur, lui permettant de jouer par le biais d'une interface graphique utilisant Java Swing. Le côté serveur est le logiciel situé sur un serveur dédié tournant en continue et s'occupant de l'ensemble des joueurs connectés et du bon fonctionnement des parties de poker. En plus de ces deux principaux programmes, ont été créés un outil d'administration du serveur et un "lanceur" permettant les mises à jour automatiques. 6 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 7 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 8 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 1 : Diagramme de classe de l'ensemble du projet. 9 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 2. Architecture client : L'utilisateur devra télécharger le dossier compressé WinABarriere.zip et le décompresser pour pouvoir lancer l'exécutable WinABarriere/WinABarriere.jar. Figure 2 : Architecture du client. Ce dossier contient le répertoire Sources/, contenant lui-même l'exécutable Client.jar et le répertoire Images/. Images/ contient l'ensemble des images utilisées par les interfaces graphiques, et Client.jar est l'exécutable contenant la partie client. WinABarriere.jar est un "lanceur" qui va permettre de vérifier si des mises à jour doivent être faites avant de lancer Client.jar. WinABarriere/ contient également un Readme.txt contenant les informations utiles à l'utilisateur, SeSouvenirDeMoi.txt où sont sauvegardés les identifiants du joueurs pour accélérer ses prochaines connexions, et Version.txt où est indiquée la version courante du logiciel que possède l'utilisateur. 10 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 3. Architecture serveur : Au niveau du serveur dédié, sont présents la base de données (BDD) au format .txt sous la forme d'un Object Java sérialisé, un Readme.txt indiquant en détail comment utiliser le serveur, un fichier JournalServeur.txt dans lequel sont sauvegardées l'ensemble des informations concernant l'état du serveur et du jeu, le dossier compressé Sources2.zip qui sera automatiquement envoyé aux utilisateurs ayant une version du logiciel périmée, et enfin l'exécutable ServerPoker.jar qui est lancé avec la ligne de commande : nohup Java -jar ServerPoker.jar &. Figure 3 : Architecture du serveur. 11 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 4. Architecture multi-clients - serveur : Au démarrage du côté serveur du logiciel, plusieurs sockets sont ouverts pour écouter les clients. Sur la figure ci-dessous, est représenté le code créant le socket écoutant les clients : Figure 4 : Ouverture du socket côté serveur écoutant les clients. L'un des sockets sur lequel le serveur écoute est celui écoutant les connections des clients dans le thread SasDeConnexion sur le port 18002. Lorsqu'un client ouvre le logiciel, un socket est créé le liant au serveur. Le serveur, dans le thread SasDeConnexion va accepter la connexion du socket client en créant un thread ClientVoulantSeConnecter. Une fois le client connecté, il est détourné vers un socket écoutant le port 18001 du serveur s'occupant des interactions entre le serveur et le client pour tout ce qui concerne les informations du menu et des statistiques du joueur. L'outil d'administration du serveur possède également une liaison avec le serveur via le port 18003. Figure 5 : Les différents ports d'écoute. Enfin, chaque table de poker est un serveur écoutant sur son propre port : 12 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 6 : Le tableau des serveurs des tables, le port utilisé étant le dernier paramètre du constructeur. Du serveur vers le client ne sont transférés via les Sockets que des objets sérialisés et quelques Strings. Ainsi on peut citer l'envoie de divers objets tels que celui contenant les informations d'une table ou encore celui contenant les informations que le client verra dans son menu. Du client vers le serveur, seules des requêtes sous forme de Strings très courts sont envoyées. En effet, le client ne fait que demander des informations alors que le serveur répond à ces questions de manière plus lourde. 13 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 5. La base de données : Au départ, la base de données a été développée avec PostgresSQL. Cependant, pour des raisons de facilité et de place mémoire sur le serveur dédié, la base de données a été remplacée par un objet Java sérialisé sauvegardé dans un fichier .txt. Au lancement du serveur, la base de données BDD.txt est lue et transformée en un objet Java. Pendant l'ensemble des phases du jeu, la base de données, c’est-à-dire l'objet Java sérialisé, va être modifiée. On pourra par exemple ajouter les gains d'une main au joueur gagnant, créer un nouveau joueur… Ainsi toute la gestion de la base de données se passe dans le code. Pour être sûr que la base de données soit utilisable au redémarrage du serveur, il faut la sauvegarder régulièrement. Pour cela, un timer, nommé TimerTrenteSecondes, sauvegarde toutes les 30 secondes l'objet Java sérialisé représentant la base de données dans le fichier BDD.txt. La base de données est de plus sauvegardée quotidiennement. Pour ce faire, elle est automatiquement envoyée à ma messagerie personnelle tous les jours à minuit. L'objet sérialisé BDD comprend une variable représentant le nombre total de mains jouées par les joueurs ainsi que la liste de tous les joueurs inscrits : Figure 7 : L'objet BDD sérialisé représentant la base de données. Un joueur est représenté dans la base de données par l'objet sérialisé JoueurBDD. Les variables représentant un joueur dans JoueurBDD sont son pseudo, son mot de passe, son adresse mail, sa date de naissance, son bankroll2, son nombre de mains jouées, ses nombres de jours gagnants et perdants, sa date d'inscription, ses options (couleur de fond, raccourcis clavier, …) et trois tableaux contenant l'historique de son bankroll sur une semaine, sur un mois et sur six mois (tableaux d'entiers de longueurs autour de 150). Au niveau utilisation mémoire, on arrive ainsi pour chaque joueur à un peu moins de 3Ko. 2 Bankroll : Nombre total de jetons que possède le joueur sur le logiciel. 14 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 8 : L'objet sérialisé utilisé par l'objet BDD, représentant un joueur. 15 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 9 : Récupération de la base de données au démarrage du serveur. La classe ActionBDD contient un ensemble de méthodes statiques permettant d'interagir avec la base de données. Le timer TimerTrenteSecondes possède la méthode sauverBDD() qui permet l'enregistrement de la base de données modifiée lors des 30 dernières secondes dans le fichier BDD.txt. Figure 10 : Sauvegarde de la base de données. 16 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Partie II. Le côté client 1. La connexion et l'inscription : a. La connexion : A l'exécution du client, une connexion avec le serveur est créée par l'intermédiaire d'un socket TCP Java. Lorsque l'ensemble des champs demandés sont renseignés, et que le client demande à se connecter, une requête est envoyée au serveur avec l'ensemble des informations de connexion. Si les informations correspondent à celles d'un joueur existant dans la base de données, si le client n'est pas déjà connecté avec un autre compte sur son ordinateur (comparaison de l'adresse IP avec celle des joueurs connectés) et si ce compte n'est pas déjà connecté sur un autre ordinateur, alors le serveur répond favorablement à la demande de connexion. Figure 11 : La fenêtre de connexion. Sont demandés lors de la connexion le pseudo, le mot de passe et une date de naissance. Si la check-box est cochée au moment de la connexion, alors sont sauvegardés l'identifiant et la date de naissance dans le fichier WinABarriere/SeSouvenirDeMoi.txt via un objet sérialisé. Ainsi, lors de la prochaine connexion, les champs de texte du pseudo et de la date de naissance seront automatiquement remplis. L'utilisateur n'aura ainsi plus qu'à rentrer son mot de passe. Une fois les différents champs complétés, l'utilisateur peut demander à se connecter par l'intermédiaire du bouton "SE CONNECTER" ou en pressant la touche "entrée". En effet, à chaque JTextField est associé un KeyListener (composant awt) écoutant la touche "entrée". b. L'inscription : Le bouton "S'INSCRIRE" de la fenêtre connexion permet quant à lui d'accéder à la fenêtre d'inscription visible ci-dessous : 17 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 12 : La fenêtre d'inscription. L'inscription requiert un pseudo, un mot de passe, une adresse mail et une date de naissance. A chaque perte de focus d'un champ de texte, est demandé au serveur si l'information, est pertinente ou non. On vérifie ainsi que le pseudo n'existe pas déjà, que les deux champs de texte demandant le mot de passe sont identiques, que l'adresse mail est plausible (un '@' au milieu, un '.' avant la fin, et pas de caractères spéciaux) et que la date de naissance existe. Si l'information renseignée n'est pas bonne, alors celle-ci est coloriée en rouge. Lorsque le client demande à s'inscrire, le serveur va vérifier les informations et leur validité. Si toutes les conditions d'inscription sont remplies alors le serveur va créer un nouveau joueur dans la base de données et envoyer un mail de confirmation d'inscription grâce à l'API JavaMail. Les identifiants du joueur lui sont rappelés, l'expéditeur du mail étant [email protected] : Figure 13 : Mail de confirmation d'inscription. 18 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 14 : Comment utiliser JavaMail pour envoyer ce mail de confirmation. Que ce soit dans le cas de la connexion ou de l'inscription, si les informations transmises au serveur sont bonnes, alors le serveur autorise le client à ouvrir le jeu, en lui ouvrant la fenêtre du menu. c. La gestion de l'absence de liaison internet lors de la connexion : Dans le cas où le client n'est pas connecté à internet, ou s'il utilise un réseau dont la majorité des ports sont bridés, il tombera sur la fenêtre suivante. Si la perte de connexion internet n'est que provisoire, il pourra essayer de se reconnecter grâce au bouton "SE RECONNECTER" tentant de recréer le socket liant le client au serveur. 19 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 15 : La fenêtre de non connexion internet. 20 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 2. Le menu : Une fois le joueur connecté, le menu remplace la fenêtre de connexion. Sont affichés le bankroll du joueur et les différentes tables de parties libres où il peut s'asseoir. Il existe différents niveaux de tables accessibles. En fonction de son bankroll, le joueur pourra ainsi jouer à des niveaux de blinde3 allant de 10 à 100 000 jetons. Figure 16 : Le menu. Le joueur a plusieurs possibilités pour s'asseoir à une table. Il peut par exemple double-cliquer sur une ligne du tableau des tables (le tableau est une JTable de Java Swing), par exemple sur Nice-6-01. Sont affichées pour chaque table de cette JTable, son nom, sa hauteur de blinde et le nombre de joueurs présents. Le joueur peut aussi cliquer sur une ligne de la JTable pour afficher plus d'informations sur la table sélectionnée dans le cadre en bas à gauche. Il verra alors les places où il peut s'asseoir sous forme de boutons "S'ASSEOIR" et n'a plus alors qu'à cliquer sur l'un de ces boutons. Enfin, si la table n'a plus de places libres, il peut utiliser le bouton "LISTE D'ATTENTE" et sera mis en attente d'une place libre. La fenêtre de la table apparaîtra automatiquement lorsqu'une place se libère. Il faut bien faire attention à empêcher un joueur de s'asseoir deux fois à la même table. Si le joueur tente cette action, il lui sera réaffiché la table où il est déjà assis. Sur les petites tables dessinées en bas à gauche, pour éviter que des caves trop importantes ne dépassent des cadres, on utilise les abréviations K pour un millier et M pour un million. Ainsi, une cave de 3 547 000 jetons devient dans la micro-table 3M. Sur la figure ci-dessous, une cave de 1 078 jetons est devenue sur la micro-table 1K. 3 Blinde : mise obligatoire versée par deux joueurs avant la distribution des cartes. 21 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 17 : Exemple d'abréviation : 1250 jetons deviennent 1K sur la micro-table. Figure 18 : Code associé à la réduction de la taille de l'affichage du stack. Le menu est réactualisé par le serveur toutes les 30 secondes grâce au timer TimerTrenteSecondes. Pour cela, le serveur transmet l'objet sérialisé InfoMenu, contenant l'ensemble des informations du menu du joueur (cet objet contient également les données de la fenêtre compte). Figure 19 : InfoMenu, l'objet sérialisé permettant le transfert des données du menu et du compte. On reçoit ainsi pour le menu via l'objet InfoJoueur, les informations des différentes tables et du bankroll du joueur. 22 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 3. La table : La fenêtre représentant la table est la fenêtre que l'utilisateur aura le plus souvent sous les yeux. Il faut donc avant tout, créer une belle image qui va servir de fond à cette fenêtre. Figure 20 : L'image de fond. Une fois la table ouverte par un utilisateur, il va lui être proposé de s'asseoir. Pour cela, on pose des boutons au niveau de chaque place libre (que ce soit pour une table de 2, de 6 ou de 9 joueurs). Ainsi, lorsque le joueur clique sur l'un de ces boutons, les options pour prendre une place vont s'afficher dans le cadre en bas à droite. Par défaut, il lui est proposé de s'asseoir avec la plus petite cave possible, mais il peut choisir le nombre de jetons qu'il veut utiliser grâce à une JSlider (composant Java Swing permettant de faire glisser un curseur sur une barre). De plus les boutons "MINIMUM" et "MAXIMUM" permettent de choisir rapidement de déposer le minimum (20 blindes) ou le maximum (100 blindes) de jetons possible. Une fois le montant choisi, il ne reste plus qu'à cliquer sur le bouton bleu "S'ASSEOIR" et le joueur est placé à la place qu'il a choisie. Figure 21 : S'asseoir à la table. Une fois assis, si personne n'est encore présent à la table, on attend qu'un autre joueur s'assoie pour démarrer le jeu. Le cadre an bas à droite est réservé aux indications de jeu et aux boutons permettant de prendre des décisions. 23 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 22 : Une fois assis. Le bouton "PLACE" situé en haut de la fenêtre permet à tout moment de faire une permutation circulaire des places autour de la table : Figure 23 : Permutation circulaire de la table. Lorsqu'un joueur est absent, que ce soit parce qu'il l'a demandé en ayant appuyé sur le bouton "S'ABSENTER" ou parce qu'il n'a pas joué dans les 30 secondes qui lui étaient imparties, alors son cadre est grisé. Pour revenir, il lui suffit de cliquer sur le bouton "REVENIR". Figure 24 : Cadre grisé d'un joueur absent. 24 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 4. La fenêtre des statistiques et d'options : Un logiciel de poker n'est rien s'il ne propose pas un ensemble d'options, de statistiques de jeu ou encore de raccourcis clavier. L'ensemble de ces informations sont contenues dans la fenêtre des statistiques et sont réactualisées toutes les 30 secondes en même temps que les informations du menu. Figure 25 : La fenêtre des statistiques et de choix des options. En haut à gauche : le classement général. Les joueurs sont affichés ainsi que leurs bankroll du premier au dernier. Pour repérer son classement, il suffit de regarder quelle ligne est surlignées en bleu. Lors de l'ouverture de cette fenêtre, la ligne affichée par défaut est celle correspondant au joueur. On centre cette ligne au milieu de la JTable, en affichant deux joueurs au-dessus et deux en dessous. Figure 26 : Affichage par défaut de la ligne du joueur au milieu de la JTable. Figure 27 : Code permettant de mettre la vue de la JTable sur la ligne du joueur. En bas à gauche : les données globales du site. Sont affichés le nombre de joueurs connectés et le nombre de joueurs inscrits ainsi que le mail permettant de prendre contact avec l'administrateur. En haut au milieu : les statistiques du joueur. Sont affichés sa date d'inscription, le nombre de ses jours gagnants et perdants (nombre de jours où le joueur a gagnés ou perdu des jetons), le nombre total de ses mains jouées, son profit par main (le bankroll du joueur moins 1000 jetons divisé par le nombre de main jouées) et son profit par jour (le bankroll du joueur moins 1000 jetons divisé par le nombre de jours où le joueur a joué). 25 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Au milieu : deux options. Le joueur peut choisir en cochant la case "rebuy automatique" de pouvoir recaver automatiquement en jeu à chaque nouvelle main à la cave maximale autorisée. Cela permet, si la cave maximale autorisée est de 1000 jetons et qu'il a perdu 150 jetons lors de sa dernière main, de jouer la main suivante avec 1000 jetons de manière automatique au lieu de 850. L'option "checker au lieu de passer si check possible" permet quant à elle, lorsque le joueur a la possibilité de checker4 et qu'il appuie par inadvertance sur passer, de le faire checker au lieu de passer. Ces deux options font parties des attributs du joueur dans la base de données. Les quatre carrés de couleur au milieu permettent de changer le thème de fond des fenêtres. Le joueur peut ainsi choisir d'avoir un fond bleu clair, bleu foncé, marron ou violet. Cette option est aussi sauvegardée dans la base de données. Elle se caractérise simplement par le changement de l'image peinte en fond. Figure 28 : Les 4 couleurs de thème. Au milieu en bas : les graphiques d'évolution du bankroll. Trois graphiques accessibles via les boutons "UNE SEMAINE", "UN MOIS" et "SIX MOIS" donnent l'évolution du bankroll du joueur sur les périodes correspondantes. 4 Checker : action consistant à continuer à jouer sans miser de jetons si personne n'a relancé. 26 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 29 : Les graphiques d'évolution du bankroll. Pour réaliser ces courbes, on utilise l'ensemble des points qui ont été régulièrement sauvegardés dans la base de données. En effet, chaque joueur possède dans la base de données trois tableaux d'entiers contenant par exemple 168 cases (7 jours * 24 heures) pour celui de la semaine. La première case contient le bankroll que le joueur a pour l'heure en cours, la deuxième contient le bankroll que le joueur avait une heure auparavant et ainsi de suite. Le timer TimerTrenteSecondes du serveur va regarder toutes les trente secondes si par rapport à trente secondes auparavant, on est passé d'une heure à une autre. Si c'est le cas, alors pour tous les joueurs de la base de données, le serveur va décaler l'ensemble des valeurs d'une case vers la droite et remplacer la première par le bankroll courant. Il en va de même pour le tableau du mois contenant 120 cases (30 jours * 4 relevés par jours) et modifié à 6 heures, midi, 18 heures et minuit et le tableau de la demi année contenant 180 cases (6 mois * 30 jours) et modifié tous les jours à minuit. 27 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 30 : Timer mettant à jour si besoin les graphiques d'évolution du bankroll. Figure 31 : Méthodes de modification des tableaux des données des graphiques dans la base de données. 28 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Au niveau du graphisme, on récupère le minimum et le maximum des valeurs de la courbe et on dessine des lignes entre chaque point de la courbe. On ajoute aussi des lignes noires permettant de bien distinguer les passages d'une période à l'autre, c’est-à-dire les passages d'un jour à l'autre pour le graphique d'une semaine par exemple. On dessine enfin les indications d'abscisse et d'ordonnée. Figure 32 : Exemple du dessin des légendes du graphique d'évolution du bankroll sur la semaine. Figure 33 : Exemple du dessin de la courbe de l'évolution du bankroll sur la semaine. En haut à droite : les raccourcis clavier. Les raccourcis clavier permettent au joueur d'effectuer l'ensemble des actions de jeu depuis le clavier. Cette zone de la fenêtre lui permet de les modifier en remplaçant la lettre ou suite de lettres représentant le raccourci actuel par la nouvelle touche. Une fois le raccourci modifié, en pressant le bouton "APPLIQUER" le joueur envoie la nouvelle touche de raccourcis au serveur qui va l'enregistrer dans la base de données. 29 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 34 : La zone de modification des raccourcis. En bas à droite : la variation du jour. La variation du jour indique le pourcentage d'amélioration du bankroll depuis minuit. Si la variation depuis minuit est positive, alors le texte de la variation sera dessiné en vert. Sinon il sera dessiné en rouge (variation positive en vert sur la figure de droite ci-dessous). De plus, à chaque fois que le TimerTrenteSecondes s'enclenche et à chaque fois qu'une main se finit, le menu étant réactualisé, le logiciel compare l'ancienne valeur du bankroll (celle d'il y a quelques secondes) à la nouvelle et si elle est supérieure, la variation est encadrée en vert pendant un court instant. Sinon, elle est encadrée en rouge. Figure 35 : L'affichage du bankroll et de la variation du jour. Figure 36 : Affichage de la variation du jour. 30 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 37 : Dessin du cadre rouge ou vert montrant la variation sur les dernières secondes. Enfin, le bouton "RECHARGER" en bas à droite permet aux joueurs passés sous les 1000 jetons de repasser à 1000 jetons. 31 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 5. Les raccourcis clavier : Les raccourcis clavier permettent de ne plus avoir à manipuler la souris et ainsi de minimiser le nombre de mouvements à effectuer. Figure 38 : Les touches des raccourcis clavier sont rappelées sur les boutons correspondant. Pour cela, il suffit d'ajouter un MouseListener au JPanel de la table, réagissant pour la figure ci-dessus par exemple, à la pression sur la touche A pour passer, sur la touche Z pour checker, sur la touche E pour relancer… Un autre raccourci clavier utilisable et paramétré par défaut par la touche Espace permet de mettre au premier plan et de donner le focus à la table du joueur où la décision à prendre est la plus pressante. Figure 39 : Exemple du raccourci clavier d'affichage de la table la plus pressante. Les raccourcis clavier sont sauvegardés dans la base de données et restitués au logiciel client lorsque l'utilisateur se connecte. 32 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 6. Les boutons de décision en avance : Les boutons de prise de décision en avance permettent au joueur de sélectionner l'action qu'il effectuera lorsque ce sera son tour. Ainsi il peut se concentrer sur une autre table pendant que la table où il a pris sa décision en avance jouera automatiquement pour lui. Figure 40 : Les boutons de prise de décision en avance. 33 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 7. Lutte contre l'addiction : Pour lutter contre l'addiction, une fenêtre d'avertissement s'ouvre automatiquement à chaque fois que le joueur a passé 2 heures de plus à jouer. Figure 41 : L'avertisseur de temps de jeu. La fenêtre d'avertissement est particulière du fait de l'utilisation de la méthode setAlwaysOnTop(true) qui force son placement au-dessus de toutes les autres fenêtres, y compris des fenêtres d'autres programmes. Ainsi, on est sûr que le joueur la voit. Elle est réaffichée toutes les deux heures. 34 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 8. Empêcher l'envoie de la même action plusieurs fois : Un problème à résoudre absolument est la possibilité de pouvoir utiliser un bouton d'action plus d'une fois et par là la possibilité d'envoyer au serveur une action plusieurs fois et qui serait traitée plusieurs fois. On veut par exemple éviter qu'un joueur ne puisse relancer 2 fois au même moment en cliquant deux fois très rapidement sur le bouton "RAISE". Il en va de même pour la connexion, on ne souhaite pas que le joueur puisse se connecter deux fois parce qu'il a réussi à appuyer deux fois sur le bouton connexion. Pour ce faire, on utilise un booléen global nommé actionEnCoursDEnvoie qui est placé à true lorsqu'une action est communiquée au serveur et remise à false (dans ReceptionPartie) lorsque le serveur répond en envoyant les données actualisées de la partie. Ainsi, en vérifiant que actionEnCoursDEnvoie n'est pas à true lorsqu'on appuie sur un bouton (dans l'ActionListener associé au bouton) ou lorsqu'on utilise un raccourci clavier (dans le MouseListener associé au raccourci clavier), on peut empêcher l'envoie multiple de la même action. Figure 42 : ActionListener possédant une barrière empêchant l'envoie simultané de la même action. 35 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Partie III. Le Serveur et la gestion des clients et du jeu 1. Le jeu de cartes : Un jeu de cartes au poker est représenté par 52 cartes, elles-mêmes représentées par une couleur et une hauteur. La méthode suit(Carte carte) de l'objet Carte représenté ci-dessous permet de vérifier si une carte suit immédiatement une autre carte. Figure 43 : Une carte. Figure 44 : La couleur d'une carte. 36 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 45 : La hauteur d'une carte. Le jeu de cartes est donc représenté par un tableau de 52 cartes nommé jeu[]. La méthode melanger() repose sur le changement de place aléatoire dans le tableau de chacune des cartes. La méthode tirerUneCarte() mélange le jeu de cartes autant de fois que nécessaire pour que jeu[1] contienne une carte à tirer (lorsqu'une carte est tirée, elle est retirée du jeu de cartes et la case correspondante de jeu[] est mise à null). Enfin, la méthode tirerCartesCommunes() permet de tirer les 5 cartes qui apparaîtrons sur le plateau de jeu. 37 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 46 : Un jeu de cartes. Une étape envisageable serait le remplacement du random de Java par une autre méthode de création de hasard dans le but de renforcer la sécurité et le caractère aléatoire du tirage des cartes. Certains sites de poker payant se basent par exemple sur la température de leur serveur ou sur le mouvement de la souris de leurs clients. 38 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 2. Le calcul de la combinaison : Un logiciel de poker a besoin de calculer rapidement et efficacement les combinaisons de poker. En effet, le calcul d'une combinaison intervient lors de la recherche du gagnant, de l'affichage des probabilités de gagner et de l'indication au joueur du type de main qu'il possède. Une combinaison de poker en Texas Hold'em est la meilleure combinaison de 5 cartes parmi 7 cartes (les 2 pocket-cards5 et les 5 cartes du plateau). Nous allons découvrir ici une manière parmi d'autres de calculer la puissance d'une main. Pour pouvoir quantifier une combinaison, il faut transformer une entrée formée de 7 cartes en une sortie numérique (un entier) permettant de comparer la puissance de la combinaison par rapport à d'autres. Non seulement il faut classer la combinaison (suite, couleur, brelan …), mais il faut aussi prendre en compte dans la sortie diverses autres informations. Par exemple, la puissance d'une couleur doit tenir compte de la carte la plus haute de cette couleur : la couleur AJ943 est plus forte que la couleur KQ852. De même, si deux joueurs ont la même paire, il faut tenir compte des autres cartes de la main : la paire KKJ67 est plus forte que la paire KK983. Lors de l'initialisation de l'algorithme, on remplit en fonction des cartes placées en entrée, trois tableaux : un tableau de longueur 4 (4 couleurs) contenant le nombre de cartes de chaque couleur, un tableau de longueur 13 (13 hauteurs) contenant le nombre de cartes de chaque hauteur, et un tableau de booléens à deux dimension de taille 13 (13 hauteurs) sur 4 (4 couleurs) dont les cases sont à true si la main possède une carte de cette hauteur et de cette couleur. Ces tableaux permettent de visualiser très facilement le fonctionnement de l'algorithme et de l'optimiser. Figure 47 : Initialisation du calcul de la combinaison. On cherche ensuite les classes de combinaison possibles dans l'ordre décroissant de puissance (Quinte flush royale, Quinte flush, Carré, Full, Couleur, Suite, Brelan, Double Paire, Paire puis Carte haute) afin de sortir de l'algorithme au plus tôt. En effet, comme on doit retourner la combinaison la plus puissante, il ne servirait à rien de commencer à regarder si l'on a une simple paire bien qu'elle soit plus probable. Une fois la classe de la combinaison trouvée, on va déterminer la puissance de cette combinaison dans sa classe. Ainsi, on renverra par exemple 80005 pour une quinte flush hauteur 5 et 80013 pour une quinte flush hauteur roi. 5 Pocket-cards : Les deux cartes que le joueur à en main. 39 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 48 : Exemple de la recherche de la quinte flush. Figure 49 : Exemple de la recherche du carré. Une fois ces informations trouvées, on sort de l'algorithme sans chercher à trouver les combinaisons plus faibles. L'algorithme de calcul de combinaison a été soumis à une série de tests sous JUnit afin d'être sûr de son fonctionnement. 40 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 50 : Exemple de tests validant le calcul de combinaison. 41 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 3. Actualisation de la partie : Pour actualiser la partie, et ainsi montrer graphiquement l'avancement du jeu aux joueurs, le serveur va envoyer à chaque joueur présent à la table l'objet sérialisé InfoPartie contenant l'ensemble des données de la partie. Cet objet contient entre autre la liste de tous les joueurs à la table (liste d'objets sérialisés InfoJoueur) contenant les informations relatives à chaque joueur, ainsi que les cartes communes, l'étape du jeu … On fera bien attention lors de l'envoie de n'envoyer à chaque joueur que ses cartes et pas celles des autres joueurs. En effet, on aurait une faille de sécurité, car toute personne voulant modifier le code pourrait alors savoir ce que les autres joueurs ont en main. Il en va de même pour les cartes communes du plateau qui n'ont pas encore été affichées. La méthode est synchronisée pour éviter d'envoyer aux joueurs des informations différentes si la partie est modifiée lors de l'envoie. Figure 51 : Envoie des données de la partie. Côté client, un thread nommé ReceptionPartie s'occupe d'écouter ce qu'envoie la méthode envoieDonneePartie ci-dessus pour actualiser l'ensemble des éléments graphiques permettant au joueur de suivre l'évolution de l'état de la partie. 42 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 4. Le tirage au sort : Lorsqu'un joueur s'assoie et qu'on atteint un nombre de deux joueurs assis et non absents, alors on peut démarrer le jeu. Pour ce faire, il faut choisir quel sera le joueur qui sera dealer6 en premier. Pour cela on va tirer deux cartes, une pour chaque joueur, les afficher et le joueur dont la carte sera la plus haute deviendra dealer. Cidessous, le joueur ayant un valet sera dealer. Figure 52 : Le tirage au sort. Les différentes étapes du tirage sont séparées et placées dans des timers non cyclique (setRepeats(false)) qui seront lancés l'un après l'autre. La première étape consiste en l'actualisation du statut des deux joueurs commençant à jouer (joueurs dont les booléen "estAssis" et "joueLaProchaineMain" sont à true). Si l'un d'entre eux était absent ou couché (booléens "estAbsent" et "estCouche"), on le remet dans les états non absent et non couché. Cette initialisation des paramètres est placée dans un premier timer, qui envoie ces informations aux joueurs avec la méthode envoieDonneePartie(). 6 Dealer : donneur fictif des cartes. 43 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 53 : Initialisation du tirage. Vient ensuite le tirage en lui-même. Pour cela, est créé un jeu de cartes dont on tire une carte pour chaque joueur. On évitera le tirage de deux cartes de même hauteur en continuant à tirer une carte tant que les deux cartes sont de la même hauteur. On place ensuite les cartes tirées dans les variables carteTirage des deux joueurs et on envoie les données de la partie avec un nouveau timer pour que les joueurs puissent observer les cartes tirées. Figure 54 : Le tirage en lui-même. 44 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Une fois un délai de 2,5 secondes écoulé laissant aux joueurs le temps de bien observer les cartes tirées, on commence le jeu en lançant l'affichage du prélèvement des blindes via le Thread AffichageBlindes. Le booléen jeuEnCour est alors placé à true. Figure 55 : La fin du tirage et le début du jeu. 45 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 5. L'affichage des blindes : L'affichage des blindes s'effectue au début de chaque nouvelle main. Cette étape consiste à prélever une demi-blinde au joueur situé à la gauche du dealer et une blinde au joueur situé à gauche du joueur en demi-blinde. Figure 56 : L'affichage des blindes. La première étape consiste en la recherche des joueurs small-blinde7 et big-blinde8. Pour cela, on part de la position du dealer sur la table, et on regarde chaque place dans le sens horaire si un joueur y est assis et n'est ni couché ni absent (tableau pseudoDesJoueursJouant). 7 8 Small-blinde : joueur dont on prélève la moitié d'une blinde. Big-blinde : joueur dont on prélève une blinde. 46 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 57 : Recherche des joueurs small-blinde et big-blinde. On utilise ensuite deux timers, l'un affichant le prélèvement de la small-blinde et l'autre celui du big-blinde. Il faut faire attention au cas où le joueur subissant le prélèvement a un tapis9 plus petit que le prélèvement. Cette situation pouvant provoquer une situation de jeu à tapis dès l'affichage des blindes. Ci-dessous est affiché le timer du prélèvement de la big-blinde, celui de la small-blinde étant très similaire. 9 Etre à tapis : fais d'avoir misé tous ses jetons. 47 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 58 : Exemple du prélèvement de la big-blinde. Ci-dessous, le code déterminant si on est en situation de tapis suite au prélèvement d'une blinde d'un joueur ayant un nombre de jetons trop faible. Cette situation se déclenche s'il ne reste qu'un joueur ayant des jetons parmi les joueurs jouant. Si tel est le cas, est lancé le thread TraitementTapis. 48 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 59 : Traitement du cas d'un joueur ayant trop peu de jetons, entraînant une situation de tapis. Une fois les deux blindes affichées, on lance le jeu. On tire d'abord les cartes communes et les cartes des joueurs. On cherche ensuite le joueur devant prendre en premier une décision (variable aQuiDeJouer de InfoPartie), situé à gauche du joueur en big-blinde. Est alors noté le moment du début du tour de décision du premier joueur (serverTable.debutTimer) pour afficher, côté client, l'avancement de la barre de progression. Est aussi activé le timer timerAbsence qui permettra au serveur, si le joueur ne joue pas dans son temps imparti, de le mettre absent. 49 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 60 : Lancement du jeu après l'affichage des blindes. C'est aussi durant cette étape qu'on effectue le rebuy automatique des joueurs ayant demandés cette option. Pour cela, il suffit de regarder la différence entre la cave maximale autorisée à cette table et le tapis du joueur et de vérifier s'il a suffisamment de jetons en bankroll pour effectivement recaver. 50 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 61 : Rebuy automatique pour les joueurs utilisant cette option. Et c'est aussi au moment de l'affichage des blindes que l'on en profite pour incrémenter le nombre de mains jouées par chaque joueur et le nombre de mains jouées sur le site. Figure 62 : Incrément du nombre de mains jouées. 51 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 6. Ecoute des actions des joueurs : L'ensemble des actions demandées par les joueurs sont écoutées au niveau du serveur dans les threads Joueur associés à chaque joueur. Ainsi, on écoute si le joueur veut s'asseoir, se coucher, relancer, s'absenter… Les demandes d'action envoyées sont en fait des Strings suivant une syntaxe précise. Par exemple, si le joueur demande à s'asseoir, le String envoyé au serveur est de la forme "a31000". Le serveur analyse le premier caractère du String envoyé et celui-ci étant un 'a', il comprend qu'il s'agit d'asseoir le joueur. Si ce caractère avait été un 'r', c'aurait été le signe que le joueur relance, et ainsi de suite. En reprenant l'exemple, ayant compris qu'il s'agit d'asseoir le joueur, le serveur va lire le deuxième caractère du String qui correspond au numéro de la place sur la table que le joueur a demandé. Ici, il s'agit de la 3 ème place. Enfin, le serveur va lire tous les caractères suivants qui correspondent au nombre de jetons que le joueur veut utiliser à savoir pour cet exemple, 1000 jetons. Figure 63 : Ecoute par le serveur des actions du joueur. 52 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Voici le traitement de l'action très simple répondant à la demande de se coucher. Le serveur modifie quelques variables représentant l'état du joueur. Ainsi, le joueur prend les statuts couché (booléen estCouche à true), a pris une décision dans ce tour de jeu (booléen aParlé à true) et sa mise est placée à 0 (Integer mise à 0). Le thread JoueurSuivant est lancé à chaque fois qu'un joueur a pris une décision, que ce soit pour se coucher, relancer … Ce thread recherche qui est le joueur suivant devant prendre une décision, s'il faut passer à l'étape suivante, si la main est finie ou s'il faut afficher les pourcentages de tapis. Figure 64 : Réaction du serveur suite à une demande du joueur pour se coucher. Cela se complique un peu lorsque le joueur demande à suivre la mise du joueur précédent ou à relancer. En effet, il faut alors vérifier que la mise à suivre (serverTable.miseASuivre) n'est pas supérieure au stack10 du joueur. Figure 65 : Réaction du serveur suite à une demande du joueur pour suivre. Pour reprendre l'exemple consistant à asseoir un joueur, la place et le nombre de jetons étant contrôlés du côté client pour éviter d'asseoir le joueur sur une place déjà prise ou de lui autoriser l'utilisation de plus jetons qu'il ne possède, le serveur va ensuite pouvoir changer l'état du joueur en spécifiant qu'il est assis (booléen estAssis à true) et qu'il souhaite jouer la prochaine main (booléen joueLaProchaineMain à true) dans InfoJoueur. Enfin, si c'est le deuxième joueur en attente de jouer, on peut démarrer la partie en lançant un thread Tirage. 10 Stack : Montant du tapis d'un joueur, c’est-à-dire le nombre de jetons qu'il possède à la table. 53 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 66 : Demande d'un joueur pour s'asseoir. L'objet Joueur écoute un certain nombre d'autres informations, telles que la demande de recavage, de mise en attente ou de retour dans la partie, de sortie de table et d'envois de messages. 54 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 7. Recherche du joueur et de l'étape suivants : Un thread JoueurSuivant est lancé à chaque fois qu'un joueur a pris une décision de jeu. C'est cet objet qui va déterminer qui est le prochain joueur devant prendre une décision de jeu, s'il faut passer d'un tour d'enchère à un autre (passer par exemple du flop11 au turn12), lancer le traitement d'un tapis, recommencer une main… Tout d'abord et peu importe l'étape à laquelle on se trouve, on vérifie s'il faut s'occuper d'un tapis (tous les joueurs non couchés (sauf peut-être un ayant plus de jetons que les autres) ont misés l'ensemble de leurs jetons) ou si un joueur a fait se coucher tous les autres. Dans le premier cas, on lance le thread TraitementTapis et dans le second le thread FinMainParElimination. Figure 67 : Recherche au début de JoueurSuivant d'une situation de tapis ou de fin de main. On cherche ensuite quel est le joueur suivant devant prendre une décision. Un joueur est éligible à la prise de décision s'il est le premier joueur à gauche du joueur venant de prendre une décision, s'il n'est ni couché ni absent et s'il n'est pas déjà à tapis. Figure 68 : Recherche du joueur suivant. Vient ensuite la recherche du passage à l'étape suivante (passage au tour d'enchère suivant, par exemple s'il faut passer du turn à la river13). Pour ce faire, on détermine d'abord la plus grosse mise des joueurs non couchés. 11 Flop : les trois cartes communes affichées après le premier tour d'enchères. ème Turn : la 4 carte commune affichée. 13 ème River : la 5 et dernière carte commune affichée. 12 55 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Pour ne pas passer à l'étape suivante, il suffit qu'un joueur ne soit pas couché et puisse suivre la mise la plus importante misé jusqu'alors (qu'il n'ait pas misé la plus grosse mise et qu'il lui reste des jetons à miser) ou alors tout simplement qu'il n'ait pas encore parlé pendant ce tour d'enchère (tous les joueurs doivent avoir parlé (pris une décision) avant de passer au tour d'enchère suivant). On modélise l'étape courante dans InfoPartie avec l'entier indiceEtape compris entre 0 et 3 : 0 pour le pré-flop14, 1 pour le flop, 2 pour le turn et 3 pour la rivière. Figure 69 : Recherche du passage au tour d'enchère suivant. Si l'on ne peut pas encore passer à l'étape suivante, alors on donne simplement la parole au joueur suivant. Si au contraire on passe à l'étape suivante, alors il faut effectuer quelques actions supplémentaires. Premièrement, on réinitialise le statut des joueurs non couchés : la mise affichée devant les joueurs est replacée à 0 et leur booléen aParle est remis à false. Il faut de plus chercher à nouveau le joueur devant prendre une décision. En effet, quand on passe à l'étape suivante, le joueur devant parler est le premier non couché situé à gauche du dealer. Enfin, il faut traiter le cas du passage à l'étape suivante après la river : à cette étape, les tours d'enchère sont finis et on lance le thread FinMain s'occupant de la répartition des gains et du passage à la main suivante. 14 Pré-flop : premier tour d'enchères lorsqu'aucune carte commune n'est encore dévoilée. 56 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 70 : Traitement du passage à l'étape suivante. 57 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 8. Fin d'une main : Il y a deux façons de terminer une main : soit en forçant tous les joueurs à se coucher, soit en allant jusqu'au bout de tous les tours d'enchères pour voir l'abattage15. La première des possibilités étant gérée par le thread FinMainParElimination et la deuxième par le thread FinMain. a. Fin d'une main par élimination de tous les adversaires : Lorsqu'un jouer a réussi à forcer tous ses adversaires à se coucher (en misant de telle sorte qu'aucun adversaire n'ai envie de le suivre en risquant autant de jetons), le thread FinMainParElimination prend le relais pour lui distribuer ses gains. Figure 71 : Distribution des gains au gagnant. Une fois la distribution des gains faite, on réinitialise les paramètres de la partie pour recommencer une nouvelle main. On fera bien attention à ne pas relancer une donne s'il n'y a pas suffisamment de joueurs. En effet, si l'on a moins de deux joueurs, alors le jeu doit être arrêté. Si au contraire le jeu peut continuer, alors on lance le thread AffichageBlindes d'affichage des blindes. 15 Abattage : moment où les joueurs montrent leurs cartes pour définir qui a la meilleure main. 58 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 72 : Décision d'arrêt du jeu ou du lancement d'une nouvelle donne. b. Fin d'une main par l'abattage : Dans le cas où les joueurs vont jusqu'à l'abattage, on lance le thread FinMain. La première chose à faire est de montrer tour à tour les mains de tous les joueurs encore en lice. Pour cela, un timer est créé pour chaque joueur dont le temps de réveil sera décalé de 0.75 secondes à partir du dealer, permettant de dévoiler les pocket-cards. 59 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 73 : Création des timers permettant la visualisation tour à tour des cartes des joueurs restants. Figure 74 : ActionListener enclenché au moment où les timers de visualisation des cartes des joueurs se réveillent. Une fois les cartes des joueurs dévoilées, on procède au classement des joueurs. Pour ce faire, on cherche la combinaison de chacun des joueurs non couchés. La distribution des gains lorsque plusieurs joueurs sont encore en jeu suit des règles très précises. Prenons par exemple un trio de joueurs dont l'un est à tapis parce qu'il avait moins de jetons que les deux autres. Dans le cas où les deux autres joueurs ont continués à miser après le tapis du joueur à tapis et où ce joueur à tapis à la meilleure combinaison, alors ce joueur ne pourra pas récupérer l'ensemble du pot. En effet, mettons qu'il ait misé 100 jetons, que les deux autres aient continué à jouer et aient donc misés chacun 200 jetons, alors le joueur à tapis ne pourra, étant gagnant, ne récupérer que 300 jetons sur les 500 constituant le pot. En effet, il ne peut prélever des autres joueurs plus que ce qu'il a misé, c’est-à-dire trois fois les 100 jetons qu'il a misé. Le reste du pot, s'élevant à 200 jetons, sera distribué à celui des deux joueurs restant possédant la meilleure main. Mais cela ne s'arrête pas là. Il est possible que plusieurs joueurs soient à tapis avec des hauteurs de tapis différentes! Il se peut alors qu'il faille répéter l'exemple précédent autant de fois qu'il y a de tapis de hauteur différentes. Enfin, il faut aussi vérifier les cas d'égalité où plusieurs joueurs ont la même combinaison, qui se concrétisent par une division des gains entre les joueurs à égalité. Dernière chose à laquelle il faut faire attention : les partages de jetons ne fournissent pas toujours des nombres entiers. Prenons le cas simple de deux joueurs visualisant l'abattage et devant se partager un pot de 71 jetons. Les deux joueurs ayant la même combinaison, il faut diviser le pot en deux et chacun se retrouverait avec 35.5 jetons. Or ne travaillant qu'avec des jetons entiers, le serveur doit faire disparaître un jeton pour que chaque joueur récupère 35 jetons. Une fois l'ensemble de ces calculs effectués, on va enfin pouvoir faire visualiser aux joueurs les différentes étapes de distribution de gain avec des timers décalés de 0.75 secondes à partir du meilleur classement. 60 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 75 : ActionListener enclenché au moment où les timers de visualisation des distributions des gains se réveillent. Enfin, comme dans le thread FinMainParElimination, on va redémarrer une main si l'on a suffisamment de joueurs. 61 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 9. Les pourcentages à tapis : Lorsque tous les joueurs non couchés sont à tapis, alors les tours d'enchères16 sont finis et on procède à l'abattage. Le parti pris a été de coupler cette phase avec un affichage des probabilités que chaque joueur à tapis a de gagner : Figure 76 : Affichage des pourcentages de réussite à tapis. Cette étape répondant à des contraintes de "temps-réel mou" et d'utilisation minimale du processeur du serveur, a dû être traitée avec la plus grande attention. Sont distingués trois cas : le tapis à partir du flop, du turn ou de la river, le tapis à partir du pré-flop à deux joueurs et le tapis à partir du pré-flop à plus de deux joueurs. a. Les probabilités de gagner avant le turn et avant la river : L'idée lorsque l'on est au flop, ou au turn, c’est-à-dire lorsqu'il ne reste qu'une ou deux cartes communes à afficher sur le plateau, est de calculer l'ensemble des combinaisons restantes possibles. Prenons l'exemple de l'étape du turn, en attente de l'affichage de la river, étape à laquelle il ne reste plus qu'une carte à afficher. On va alors simuler pour chaque joueur quel serait sa combinaison si l'on utilisait à la river une carte qui n'est pas encore tombée. On procède ainsi pour chaque carte restante dans le jeu de cartes (sont retirées des cartes possibles les quatre cartes du plateau et les pocket-cards des joueurs à tapis). On calcule ainsi pour chaque joueur un peu plus d'une quarantaine de combinaisons possibles (si par exemple deux joueurs sont à tapis, il reste 52 (paquet de cartes) - 2 (joueurs) * 2 (pocket-cards) - 4 (cartes sur le plateau : flop + river) = 44 cartes possibles) et pour chacune on regarde qui gagne. C'est ainsi que l'on obtient très rapidement et avec un usage limité du processeur les pourcentages de chaque joueurs à tapis. Pour ce faire, il faut tout d'abord construire un jeu de cartes sur lequel vont être testées l'ensemble des combinaisons possibles à la river pour chaque joueur. On retirera de ce jeu les cartes du flop et du turn déjà visibles ainsi que les pocket-cards des joueurs à tapis. 16 Tour d'enchères : étape où les joueurs ont la possibilité de miser. Un tour d'enchères se termine lorsque la dernière mise ou la dernière relance a été faite. 62 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 77 : Construction du jeu de cartes sur lequel vont être testées toutes les combinaisons pouvant tomber au turn. Est alors calculé le gagnant de chaque combinaison restante possible. Pour ce faire, on calcule pour chaque carte restante du jeu de cartes pouvant servir de river, la puissance de la combinaison de chaque joueur et ainsi incrémenter le nombre de combinaisons gagnées par le(les) joueur(s) gagnant(s) de "1 / nombre de gagnants". 63 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 78 : Calcul du gagnant de chaque combinaison restante. Enfin, il faut actualiser les probabilités de gagner de chaque joueur à tapis en modifiant la variable pourcentageTapis des objets InfoJoueur, et envoyer les données de la partie pour actualiser la vue des clients. Figure 79 : On actualise les pourcentages de chaque joueur dans les objets InfoJoueur. b. Les probabilités de gagner avant le flop avec deux joueurs all-in : 64 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Au pré-flop, cette méthode n'est plus envisageable du fait du nombre de combinaisons qu'il faudrait calculer (si par exemple deux joueurs sont à tapis, il reste alors 48 cartes possibles, et il faut calculer l'ensemble des possibilités d'affichage pour les 5 cartes du plateau à apparaître, c’est-à-dire 1,7 million de combinaisons possibles par joueur, et donc un total de 3,4 millions de combinaisons à calculer). A coup de 100.000 calculs de combinaison par seconde, on se retrouverait à plus de 30 secondes de calcul et la contrainte temps-réel mou permettant au jeu d'être fluide ne serait plus respectée. Ainsi, pour les tapis pré-flop à deux joueurs, le parti prit a été de calculer au préalable l'ensemble des confrontations possibles entre deux joueurs (par exemple AK versus J9) et de les placer dans une base de donnée. Un joueur pouvant obtenir en pré-flop 169 combinaisons de pocket-cards différentes (AA, AK, AQ, AJ, AT, A9, A8, A7, A6, A5, A4, A3, A2, KK, KQ, KJ, KT, K9, K8, K7, K6, K5, K4, K3, K2, QQ, QJ, QT, Q9, Q8, Q7, Q6, Q5, Q4, Q3, Q2, JJ, JT, J9, J8, J7, J6, J5, J4, J3, J2, TT, T9, T8, T7, T6, T5, T4, T3, T2, 99, 98, 97, 96, 95, 94, 93, 92, 88, 87, 86, 85, 84, 83, 82, 77, 76, 75, 74, 73, 72, 66, 65, 64, 63, 62, 55, 54, 53, 52, 44, 43, 42, 33, 32, 22, AKs, AQs, AJs, ATs, A9s, A8s, A7s, A6s, A5s, A4s, A3s, A2s, KQs, KJs, KTs, K9s, K8s, K7s, K6s, K5s, K4s, K3s, K2s, QJs, QTs, Q9s, Q8s, Q7s, Q6s, Q5s, Q4s, Q3s, Q2s, JTs, J9s, J8s, J7s, J6s, J5s, J4s, J3s, J2s, T9s, T8s, T7s, T6s, T5s, T4s, T3s, T2s, 98s, 97s, 96s, 95s, 94s, 93s, 92s, 87s, 86s, 85s, 84s, 83s, 82s, 76s, 75s, 74s, 73s, 72s, 65s, 64s, 63s, 62s, 55s, 54s, 53s, 52s, 43s, 42s, 32s - 's' significant de la meme couleur), cela fait 28561 (169 * 169) confrontations possibles entre deux joueurs. On construit donc un tableau à deux dimensions contenant la probabilité du joueur de gagner pour chaque confrontation. Pour cela, un programme a été créé pour calculer l'ensemble des combinaisons gagnantes des deux joueurs pour chaque confrontation et ainsi trouver la probabilité associée. Il faut donc calculer pour chaque case du tableau 3,4 millions de combinaisons et ceci pour chacune des 28561 cases. Cela fait tout de même près de 100 milliards de combinaisons à calculer. Sur mon petit EeePC et son processeur AMD C-50 double cœur, ce calcul prend tout de même 250h, soit une dizaine de jours. Le calcul a donc été effectué sur un calculateur de l'ENSICA ne prenant ainsi qu'une nuit. Nous avons ainsi une base de données de l'ensemble des confrontations pré-flop à deux joueurs. Lorsque le jeu arrive à ce stade, le serveur n'a plus qu'à récupérer dans ce tableau la bonne case et afficher la probabilité de gagner à chaque joueur. Le traitement est alors instantané. 65 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 80 : Calcul des pourcentages à tapis en pré-flop pour deux joueurs. c. Les probabilités de gagner avant le flop avec plus de deux joueurs all-in : Lorsque plusieurs joueurs sont à tapis (plus de deux) en pré-flop, alors le procédé précédent n'est plus possible. En effet, la table précédente utilisée pour deux joueurs ne peut être utilisée telle quelle pour des confrontations à plus de deux joueurs. De plus, une table similaire pour trois joueurs ou plus serait beaucoup trop longue à calculer et serait trop gourmande en mémoire. Le principe dans ce cas est de simuler de manière aléatoire 1000 tirages et de voir le nombre de mains gagnées par chaque joueur pour en faire une probabilité de gagner. La probabilité ainsi calculée n'est alors plus exacte, mais se rapproche suffisamment de la valeur réelle pour être 66 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 admissible. On a ainsi un moyen très rapide et peu gourmand de proposer à plusieurs joueurs à tapis en pré-flop une bonne approximation de leurs chances de gagner. Figure 81 : Calcul des pourcentages à tapis en pré-flop pour plus de deux joueurs. 67 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Partie IV. Développement logiciel 1. Faciliter le développement : Lorsque l'on doit alterner régulièrement entre le développement sous éclipse et l'utilisation du logiciel avec le serveur dédié, il est utile d'utiliser certaines variables de développement. Figure 82 : Le choix entre l'utilisation du serveur dédié ou du localHost. Dans le code précédent, la variable booléenne "enLigne", définie au point d'entrée du programme (dans Connexion), permet de choisir facilement de se connecter au serveur dédié si elle est à true, ou d'utiliser le serveur en localHost (sur sa machine) si elle est à false. On n'a donc plus qu'à modifier cette simple variable pour changer de mode de fonctionnement. Une autre variable de développement est la variable booléenne "sousEclipse" utilisée dans le lanceur. Lorsqu'on développe sous Eclipse, on utilise sousEclipse à true. Cela permet d'indiquer textuellement le chemin absolu de Client.jar à lancer lorsqu'on lance le code depuis Eclipse. Lorsque le logiciel est utilisé par le client, on met sousEclipse à false. En effet le lanceur dans ce cas est un .jar et on sait que Client.jar est situé dans Sources/. Du coup on récupère le chemin absolue de Client.jar à partir de celui du lanceur, grâce à la méthode getLocation(). Figure 83 : Le choix entre l'utilisation sous Eclipse et en exécutable. 68 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 2. Mise à jour automatique : Pour utiliser l'application, le joueur lancera l'exécutable WinABarriere/WinABarriere.jar. Cet exécutable est un "lanceur", ce n'est pas l'exécutable qui permettra au joueur de jouer. Il permet, avant lancement de l'exécutable contenant le jeu, de vérifier si la version du client que le joueur possède est bien la dernière en activité. C'est grâce à cet exécutable que les mises à jours se font de manière automatique, permettant l'amélioration et la correction du logiciel en me permettant de fournir régulièrement de nouvelles versions. L'intérêt fondamental étant que l'utilisateur n'a plus besoin de télécharger le logiciel à chaque nouvelle version, ce travail étant effectué pour lui de manière automatique. Plus en détail, WinABarriere/WinABarriere.jar va lire la version utilisée par le joueur dans le fichier WinABarriere/Version.txt et se connecter au serveur pour lui demander si la version utilisée est celle qu'attend le serveur. Figure 84 : Récupération du numéro de version. Si le serveur confirme que le client utilise la dernière version en vigueur alors WinABarriere/WinABarriere.jar va exécuter l'exécutable contenant le logiciel de poker, à savoir WinABarriere/Sources/Client.jar : Figure 85 : Exécution du client depuis le lanceur. Au contraire, si la version n'est pas celle qu'attend le serveur, alors le client est périmé et le serveur va envoyer un .zip de la nouvelle version et demander au lanceur de remplacer l'ancienne par la nouvelle : Figure 86 : Envoie du fichier compressé contenant la nouvelle version via une Socket. 69 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Le lanceur décompresse alors le .zip reçu, détruit l'ancienne version, à savoir WinABarriere/Sources/ et la remplace par la nouvelle version. Figure 87 : Décompression d'un fichier .zip sous Java. WinABarriere/WinABarriere.jar va alors pouvoir exécuter le nouveau WinABarriere/Sources/Client.jar contenant le logiciel de poker qui lors de son exécution modifiera WinABarriere/Version.txt en y plaçant le nouveau numéro de version. Figure 88 : Vues de la mise à jour. 70 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 La mise à jour ne serait pas complète si le lanceur s'occupant de la mise à jour ne pouvait pas être lui-même mis à jour. Pour cela, lors de l'exécution de Client.jar et si une mise à jour vient d'être effectuée, le lanceur va être remplacé par le nouveau lanceur téléchargé en même temps que le nouveau Client.jar. Ce remplacement de WinABarriere.jar doit s'effectuer depuis Client.jar et non depuis WinABarriere.jar comme pour les autres mises à jour car il n'est pas possible de remplacer un exécutable pendant son exécution. 71 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 3. Mise à niveau sur les différents systèmes d'exploitation : Le développement et les tests ayant été effectués sous Windows, il a fallu effectuer la transition vers Ubuntu et Mac pour contenter le maximum de joueurs. On peut observer sur l'image ci-dessous, rien qu'au niveau graphique, la nécessité de la vérification sous les différents systèmes d'exploitation. Figure 89 : Illustrations des principaux problèmes graphiques rencontrés lors de l'utilisation sous Linux. On peut par exemple observer dans les cadres blancs, que la taille de la police est différente sur les différents systèmes d'exploitation, et fait déborder certaines indications des boutons, que les caractères spéciaux ne sont pas encodés de la même manière et que les tailles de fenêtres sont différentes de la version Windows. Pour prendre en charge ces différences, on prend note au lancement du logiciel du type de système d'exploitation utilisé en appelant la méthode System.getProperty("os.version"). Suivant que l'on soit sous Windows, Ubuntu ou Mac, certaines constantes vont être assignées différemment. Le client possède ainsi une classe contenant une soixantaine de constantes prenant des valeurs différentes selon le système d'exploitation utilisé. Les caractères spéciaux ont été remplacés par leur caractère Unicode correspondant reconnu indépendamment du système d'exploitation. Cependant, les différences ne s'arrêtent pas au simple aspect graphique. On pourra citer par exemple la récupération du chemin absolue de l'emplacement du logiciel. En effet, l'exécutable WinABarriere/WinABarriere.jar permettant de vérifier la présence de mises à jour a aussi pour rôle de trouver le chemin absolu de l'emplacement du logiciel afin de pouvoir utiliser les dossiers associés. Sous Windows, on récupérera un chemin du type : "/C:/Users/Xavier/ … /WinABarriere" alors que sous Linux et Mac, on aura plutôt "/home/xavier/…/WinABarriere" (différence au début du chemin absolue). Cette différence entraînant un problème lors de l'utilisation de la commande Runtime.getRuntime().exec(Java -jar "cheminAbsolue") permettant d'exécuter un .jar. 72 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 4. Gestion de la perte de connexion : Lorsqu'un joueur est connecté au serveur mais perd sa liaison internet, il est nécessaire d'appliquer un certain nombre de mesures. Le serveur vérifie toutes les 30 secondes si le client est connecté en lui demandant de lui confirmer qu'il est toujours lié. Si le client ne renvoie pas de confirmation au bout de 20 secondes, alors le joueur est retiré du serveur. De même, le client possède un timer cyclique qui est redémarré à chaque fois que le serveur fait une demande de vérification de liaison. Si au bout de 40 secondes, le client n'a pas reçu de nouvelles du serveur, alors le timer s'enclenche et ferme le client et le redirige vers la fenêtre de connexion. Il faut faire attention à déconnecter proprement le client. En effet, si le client n'est pas retiré de la liste des joueurs connectés au serveur, alors il ne pourrait plus se connecter puisque le serveur le considèrerait comme toujours présent. Cela passe par une fermeture du socket entre le client et le serveur, le retrait du joueur des tables où il se trouve et du retrait du joueur du serveur. 73 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 5. L'obfuscation : L'obfuscation est une étape nécessaire du développement logiciel lorsque l'on veut protéger son code source ou si l'on veut éviter pour des questions de sécurité que quelqu'un puisse modifier le code à son avantage. Comme du code source Java peut être décompilé très facilement pour être observé, la seule possibilité de le protéger est de le rendre incompréhensible. L'obfuscation permet ainsi par divers moyens de rendre le code le plus illisible et le plus compliqué possible à analyser. La principale méthode consiste à changer le nom de l'ensemble des variables, des méthodes et des classes. En effet, lors du développement, on choisit les noms les plus explicites possibles pour pouvoir s'y retrouver dans son code et permettre par la suite le maintien de son application et l'utilisation de son code par d'autres personnes. On peut voir ci-dessous un exemple de code avant et après obfuscation où l'ensemble des noms ont été remplacés par une suite aléatoire de 4 lettres : Figure 91 : Le même code obfusqué. Figure 90 : Code non obfusqué. Intérêt supplémentaire, pouvant se révéler intéressant sur de gros programmes, le fait que le code source est moins volumineux après obfuscation. En effet, en réduisant les noms de variables en générales assez long par 4 caractères, on obtient un code source moins lourd. Concernant les commentaires, pas besoin de s'en soucier soi-même pour les enlever puisqu'ils ne sont pas intégrés au binaire lors de la compilation. D'autres méthodes peuvent être utilisées, telle que le clonage de méthodes qui consiste à placer une méthode deux fois dans le code source mais avec des noms différents ou avec des paramètres additionnels. Si l'on veut quelque chose d'encore plus sécurisé, on peut carrément retoucher l'architecture du code, en utilisant de l'héritage à des endroits où il n'y en a pas besoin. 74 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 L'obfuscation n'est pas un outil empêchant totalement la compréhension du code. Cependant, plus l'obfuscation sera poussée et plus on y passe du temps, plus il sera difficile à un œil extérieur malveillant de comprendre le code. Divers outils gratuits, tel que ProGuard, permettent de faire l'obfuscation de manière automatique. Cependant, j'ai préféré réaliser mon propre programme d'obfuscation afin de bien comprendre les divers mécanismes possibles et surtout pour pouvoir garder une bonne vision de mon code pour le maintien et la correction des bugs. La première étape est de récupérer au sein du code l'ensemble des noms de variables, de méthodes et de classes. Cela est faisable grâce à l'introspection, qui est la capacité d'un programme à examiner son propre état et que Java possède. On va d'abord récupérer les noms de classes en parcourant tout simplement la liste des fichiers sources .java. Ayant ces noms de classes, on va charger dynamiquement ces classes : Class myClass = ClassLoader.getSystemClassLoader().loadClass(String nomDeLaClasseACharger); . Pour chaque classe ainsi chargée, on va récupérer l'ensemble de ses variables avec la méthode myClass.getDeclaredFields(); qui renvoie une liste. On fait de même avec ses méthodes en utilisant myClass.getDeclaredMethods(); . On a ainsi une liste des noms des classes, des variables et des méthodes du projet. On associe ensuite à chacun de ces noms une chaîne de 4 caractères choisie aléatoirement. Et finalement, on va transformer les fichiers sources .java en remplaçant les noms explicites par leur chaine de 4 caractères associée (lecture du fichier puis réécriture). On peut ajouter à cette couche d'obfuscation l'utilisation de la cryptographie. On peut par exemple crypter de la manière de son choix l'ensemble des variables de type String du code ou du moins les variables critiques telles que l'adresse IP du serveur, la version du client ou les ports utilisés. La méthode chargée de crypter ces informations devra être cachée dans le code. 75 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 6. Utilisation d'un serveur dédié : Pour que l'utilisateur puisse jouer à tout moment, il a fallu utiliser un serveur dédié permettant de faire tourner sans interruption le côté serveur du logiciel. J'ai ainsi loué un serveur pour moins de 2€ par mois, utilisant une distribution Ubuntu, disposant de 200Mo d'espace libre et d'une bonne bande passante. Le serveur contient ainsi ServerPoker.jar, le côté serveur, lancé via la commande "nohup Java -jar ServerPoker.jar &" permettant une exécution continue. Il contient aussi la base de données, le journal de bord de ce qui se passe sur le serveur et le dossier compressé contenant les mises à jour. Au lancement d'une nouvelle version du logiciel, un ensemble d'instructions doit être suivi de manière précise. Celles-ci sont regroupées dans un Readme placé sur le serveur et décrit ci-dessous : I. Changer le numéro de version : 1. Le passer dans la classe Encryption du pakage cryptage du projet Obfuscation. 2. Le mettre dans Connexion (en encrypté). 3. Le mettre dans ServerGeneral (en clair). 4. Le mettre dans Version.txt (en clair). II. Switcher les variables de développements a leurs vraies valeurs : 1. Dans Connexion : a. enLigne = true. 2. Dans Lanceur : a. enLigne = true. b. sousEclipse = false. 3. Dans AdministrationPoker : a. enLigne = true. 4. Dans ServerGeneral : a. empecherDeSeConnecterAvecPlusieursComptesSurUnMemePC = true. III. Fabrication des .jar : 1. WinABarriere.jar (projet Lanceur) a. Export -> JAR file b. Le mettre dans WinABarriere/ 2. ServerPoker.jar : a. ServerPoker -> Export -> Runnable JAR file b. L'appeler ServerPoker.jar Cocher : Extract required librairies into generated JAR (c'est comme ça qu'on inclue javax.mail.jar dans ServerPoker.jar) Launch configuration : MainServerPoker - ServerPoker c. Le mettre dans ServerPoker/ d. Le mettre sur le serveur dédié dans /root/ 3. Client.jar : a. Copier les classes de UPoker dans le package main du projet Eclipse Obfuscateur. b. Rafraichir Obfuscateur. c. Lancer l'obfuscation (package codeObfuscation, classe Obfuscateur) - (Traitement d'à peu près 1 minute). d. Rafraichir absolument avant de faire le .jar. e. Vérifier s'il n'y a pas des nouvelles variables locales à passer à l'obfuscation. Si oui recommencer l'étape e avec les modifications. f. Faire Client.jar a partie du projet Obfuscateur (ne prendre que le package main). g. Le mettre dans WinABarriere/Sources/ 76 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 IV. Fabrication du fichier de mise à jour : 1. Copier Sources/. 2. Y ajouter WinABarriere.jar. 3. Y ajouter le Readme. 4. Renommer ce Sources/ en Sources2/. 5. Compresser Sources2/ en Sources2.zip. 6. Supprimer Sources2 non compressé. 7. Le mettre dans ServerPoker/. 8. Le mettre sur le serveur dédié dans /root/. V. Terminer WinABarriere/ : 1. Retirer s'il y est le fichier SeSouvenirDeMoi.txt. VI. Lancement du serveur : 1. nohup java -jar ServerPoker.jar & Lors du fonctionnement du côté serveur du logiciel, le régime CPU du serveur dédié est à peu près nul sauf en cas de calcul intensif de combinaisons pour le traitement des tapis, et l'utilisation mémoire varie entre 20% et 50%. 77 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 7. L'administration du serveur : Pour gérer facilement le serveur, un programme a été créé, se connectant au serveur et proposant une IHM permettant d'interagir avec. L'accès au serveur par cet outil est restreint par un mot de passe. Figure 92 : Fenêtre administrateur. Sont affichés dans cette fenêtre, le nombre total de mains jouées sur le serveur, un tableau contenant pour l'ensemble des joueurs, leur classement, leur pseudo, leur nombre de jetons, leur adresse mail, leur date d'inscription, s'ils sont en ligne ou non, et leur nombre de mains jouées. Un autre tableau représente l'ensemble des tables ainsi que le nombre de joueurs présents. Enfin, est affiché pour la table sélectionnée, un aperçu de ce qu'il se passe sur la table. L'outil permet également de supprimer un joueur et d'arrêter le serveur proprement. La fermeture du serveur de cette manière est intéressante, car contrairement à un kill en ligne de commande sur le serveur dédié, le serveur recevant cette demande de fermeture, va attendre que tous les joueurs soient absents pour effectuer la fermeture. On retrouve au milieu de la fenêtre, un historique des activités du serveur dans la section Journal de Bord. Cela permet d'afficher les erreurs lorsqu'elles apparaissent, de suivre les connexions, déconnexions et inscriptions, ainsi que l'état général du serveur. Enfin, un avertisseur sonore est déclenché lorsqu'un joueur se connecte, de manière à avertir l'administrateur qui peut ainsi s'atteler à une autre occupation. 78 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Partie V. La personnalisation des composants Java Swing 1. JButton personnalisé : Les boutons proposés par Swing ne pouvant être utilisés tel-quels du fait de la pauvreté de leur apparence, il a fallu les redéfinir. Voici ci-dessous l'exemple d'un bouton retouché. Figure 93 : Un JButton personnalisé. Figure 94 : Un JButton personnalisé au survole de la souris. Figure 95 : Un JButton personnalisé au clic de la souris. La première étape réside dans la création de l'image qui servira de fond au bouton, sous GIMP par exemple. On en fait trois versions : une pour le bouton dans son état normal, une pour représenter le bouton lorsque la souris le survole et une pour représenter le bouton lorsque la souris clic dessus. On peut voir ci-dessous la classe héritant de JButton personnalisant le bouton de base. Le constructeur prend en paramètre le nom de l'image de fond, le texte qu'on désire lui appliquer ainsi que la position et la police du texte dans le bouton. On redéfinit la méthode paint(Graphics g) pour mettre en place l'ensemble de ces paramètres graphiques. On obtient donc un bouton avec une image de fond et un texte dont on peut choisir la position et la police. 79 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 96 : Un JButton personnalisé. Pour éviter d'avoir un bouton statique, on doit associer au bouton ainsi personnalisé un MouseListener qui va réagir au passage et au clic de la souris. Pour cela, on redéfinit la classe MouseListener prédéfinit dans Java en chargeant les trois images du bouton correspondant à ses trois états possibles. On redéfinit ainsi, de manière à changer l'image affichée, les méthodes mouseEntered(MouseEvent e) et mouseExited(MouseEvent e) qui permettent de capter l'entrée et la sortie de la souris dans le bouton, ainsi que les méthodes mousePressed(MouseEvent e) et mouseReleased(MouseEvent e) qui permettent de capter la pression et le relâchement du curseur dans le bouton. On profitera aussi du sur-chargement de ces méthodes pour changer la forme du curseur lorsque la souris est dans les limites du bouton en affichant une main à la place de la flèche, en utilisant la méthode setCursor(new Cursor(Cursor.Hand_CURSOR)). 80 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 97 : Un MouseListener associé au JButton personnalisé. On peut voir dans le bout de code suivant la mise en place d'un bouton dans une fenêtre. On utilise la méthode setBorder(null) pour empêcher Java de mettre une bordure au bouton. La méthode addMouseListener() permet d'associer le MouseListener redéfinit ci-dessus au bouton. Figure 98 : Utilisation du bouton personnalisé dans un JPanel. 81 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 2. JTextField personnalisé : Le JTextField (champs de texte) de base présent dans Java Swing a été retouché pour avoir un meilleur look and feel. Figure 99 : Un JTextField personnalisé n'ayant pas le focus. Figure 100 : Un JTextField personnalisé ayant le focus. Le principe est de rendre le JTextField invisible et de dessiner une image de zone de texte à la place dans la méthode paintComponent(Graphics g) du JPanel. La méthode setOpaque(false) permet de ne plus voir le JTextField, tout en laissant apparaitre le texte et le curseur. Figure 101 : Un JTextField personnalisé. On associe au JTextField un FocusListener qui est un élément de Java permettant de réagir à la perte et au gain du focus d'un élément. Cela permet d'écrire dans le JTextField, via les méthodes focusGained(FocusEvent e) et FocusLost(FocusEvent e), une information concernant ce qu'on doit y remplir et de l'enlever lorsqu'on clique dessus pour laisser l'utilisateur remplir le champ de texte. 82 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 3. JProgressBar personnalisée : Chaque joueur reçoit un temps imparti de 30 secondes pour prendre sa décision. Cette information est transmise visuellement grâce à une barre de progression. On redéfinit pour cela la JProgressBar de Java Swing. Figure 102 : Une JProgressBar personnalisée. On utilise pour cet élément au minimum deux images. Une image représentant le fond de la barre de progression (l'image de ce qui est visible quand la barre se retire) et une image représentant la barre. Ici, ont été utilisées trois images de la barre, la bleue utilisée lorsqu'il reste entre 30 et 15 secondes au joueur pour se décider, la jaune lorsqu'il lui reste moins de 15 secondes et la rouge lorsqu'il lui reste moins de 7,5 secondes. La barre de progression personnalisée hérite de BasicProgressBarUI. On surcharge la méthode paintDeterminate() qui dessine l'image placée dans la barre de progression. On va y dessiner le fond de la barre puis la barre elle-même en récupérant l'avancement de la progression avec la méthode getAnimationIndex(). L'index d'animation étant modifié par un timer prenant appui sur l'ActionListener DecrementeProgressBar dont le code est visible ci-dessous, après le code de MyBar. Figure 103 : Comment décrémenter la JProgressBar personnalisée. 83 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 104 : Une JProgressBar personnalisée. 84 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 4. Une JTable personnalisée : Une JTable est un tableau présent dans la bibliothèque Java Swing. Il ne peut pas non plus rester tel quel, et doit être personnalisé : Figure 105 : Un JTable personnalisée. La méthode setDefaultRenderer() permet d'associer un DefaultTableCellRenderer qui permet de gérer les cellules. Cela permet ici par exemple, lorsqu'une cellule est sélectionnée, de colorier la ligne qui la contient en bleu. Figure 106 : Un DefaultTableCellRenderer permettant de gérer les cellules. La méthode setBackground(Color color) permet de définir la couleur de fond, setForeground(Color color) de définir la couleur du texte et setGridColor(Color color) de définir la couleur de la grille. Figure 107 : Modification des couleurs de la JTable. La JTable est insérée dans un JScrollPane permettant d'afficher une scroll-bar verticale et ainsi de se déplacer verticalement dans le tableau. Avec la méthode getColumnModel().getColumn(0).setPreferredWidth(160), on peut modifier la largeur de chaque colonne. 85 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 108 : Modification de la taille des colonnes. On ajoute enfin un MouseListener à la JTable permettant d'écouter les clics de la souris. Pour réagir au double clic sur une ligne de la JTable et ainsi ouvrir la fenêtre de la table de poker correspondante, on utilise la méthode e.getClickCount() quand on redéfinit la méthode mouseClicked(MouseEvent e) du MouseListener. Figure 109 : MouseListener associé à la JTable personnalisée pour réagir aux clics souris. A une JTable est toujours associé un AbstractTableModel permettant de gérer son contenu. Il prend en paramètre le tableau d'Objects représentant le contenu des cases de la JTable et le titre de la JTable. 86 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 110 : L'AstractTableModel utilisé par la JTable personnalisée. 87 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 5. Une JScrollBar personnalisée : La JScrollBar est l'élément de Java Swing permettant de parcourir verticalement une JTable trop longue pour entrer dans son cadre. Comme les autres composants Java Swing, la JScrollBar de base doit être améliorée. Figure 111 : Une JScrollBar personnalisée. Pour récupérer la JScrollBar associée à un JScrollPane et ainsi pouvoir la retoucher, on utilise la méthode getVerticalScrollBar(). Un fois la JScrollBar récupérée, on la modifie en la plaçant dans une MetalScrollBarUI personnalisée. Figure 112 : Récupération de la scroll-bar verticale pour pouvoir la modifier. La classe MyScrollbarUI personnalisée héritant de MetalScrollBarUI permet de redéfinir complètement la JScrollBar. On peut ainsi changer le Thumb, qui est la barre que l'on déplace, en modifiant son image et sa taille : Figure 113 : Personnalisation de l'image du Thumb. Figure 114 : Personnalisation de la taille du Thumb. On peut faire de même pour le Track, qui est le contenant de la scroll-bar en redéfinissant les méthodes paintTrack() et setTrackBounds(). On peut aussi modifier les boutons permettant de monter ou descendre la JScrollBar, situés en haut et en dessous la JScrollBar : 88 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 115 : Personnalisation des boutons d'extrémité de la JScrollBar. 89 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 6. Une JCheckBox personnalisée : La JCheckBox proposée dans Java Swing est très laide et quasiment pas personnalisable. Le parti pris a donc été de se passer de la JCheckBox proposée par Swing et de simplement dessiner une image de check-box. On utilise donc les deux images de la figure ci-dessous et un booléen est utilisé pour savoir si la case est cochée ou non et donc pour afficher la bonne image. Pour cocher ou décocher la check-box, un MouseListener est associé à la fenêtre (au JPanel) contenant la check-box pour écouter si l'utilisateur clic sur la zone où est la check-box. Figure 116 : Les images utilisées pour représenter une check-box. Figure 117 : Dessin de la check-box en fonction du booléen seSouvenirDeMoi. Figure 118 : Le MouseListener écoutant les clics de la souris dans la zone de la check-box. 90 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 7. Le chat : Le chat est un outil indispensable d'une table de poker en ligne. Il a été situé en bas à gauche de la fenêtre représentant la table. Figure 119 : La zone du chat. La zone où les messages s'affichent est un JTextArea proposé par Java Swing. La méthode setLineWrap(true) permet de retourner à la ligne quand le message dépasse la largeur du cadre de la zone de texte. Sinon, on aurait une scroll-bar horizontale qui s'afficherait. La méthode setWrapStyleWord(true) permet de ne pas couper un mot en deux lors du passage à la ligne. La méthode setEditable(false) rend la zone de texte non éditable, le joueur ne peut ainsi y écrire. Le JTextArea est placé dans un JScrollPane, qui est un composant affichant une scroll-bar verticale lorsqu'il y a plus de lignes de messages que de lignes visibles dans le cadre de la zone de texte. Figure 120 : La zone de texte où s'affichent les messages. Au niveau du transfert de messages, lorsque le client appuie sur la touche entrée ou sur le bouton "ENVOYER", le message est envoyé au serveur qui va le redistribuer à l'ensemble des personnes ayant cette table ouverte (qu'ils soient assis à la table ou juste spectateurs). Figure 121 : Le transfert des messages au niveau du serveur. Au moment où le joueur reçoit un message, on fait en sorte d'afficher cette ligne. En effet, cela permet dans le cas où le joueur est remonté voir des messages plus anciens, de lui afficher la dernière ligne de la zone de texte et donc le message qui vient d'apparaître. 91 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Figure 122 : Affichage du message qui vient d'arriver. Enfin, il faut faire attention à l'affichage des caractères spéciaux. En effet, un message contenant des caractères spéciaux, envoyé depuis Windows, transitant par le serveur dédié Ubuntu, et revenant chez un utilisateur Windows, ne pourra afficher correctement les caractères spéciaux. Pour résoudre ce problème, on peut modifier avant l'envoie du message les principaux caractères spéciaux en une chaîne de caractères spécifique. Cette chaîne de caractères représentant un caractère spécial sera ensuite retransformée en le caractère spécial original lors de la réception par les destinataires. Par exemple, le caractère 'é' dont le code Unicode est \u00e9 est transformé en la chaîne de caractères "//e". Figure 123 : Modification des principaux caractères spéciaux avant envoie du message. 92 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 8. Ajouter une icône à une fenêtre : Pour plus de visibilité, il est intéressant d'ajouter une icône aux fenêtres du programme. Figure 124 : Ajout d'une icône à la fenêtre visible en haut à gauche de la fenêtre. Figure 125 : Ajout d'une icône à la fenêtre, visible depuis la barre des tâches. Figure 126 : Code associé à l'ajout dans une JFrame d'une icône. 93 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 9. Ajouter des info-bulles : On utilise des info-bulles pour préciser, au passage de la souris sur un composant, les détails de son utilisation. La méthode setToolTipText(String texte) permet d'associer à un composant une info-bulle. Figure 127 : Utiliser des info-bulles. Figure 128 : Associer une info-bulle à un composant (ici un JButton). Pour modifier certains paramètres de l'ensemble des info-bulles, on utilise par exemple, au point d'entrée du programme, les méthodes du ToolTopManager setInitialDelay(int tpsAvantDeclenchement) et setDismissDelay(int dureedAffichage) : Figure 129 : Modifier les paramètres des info-bulles globalement. 94 GUIHOT Xavier 10. Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Centrer un String : Il arrive très régulièrement de vouloir afficher du texte dont la largeur va varier (dont le contenu va varier) autour d'une position centrale. Dans la figure ci-dessous, le pseudo du joueur va varier d'un joueur à l'autre, mais l'on désire lui afficher son pseudo de manière centrée. Figure 130 : Exemple de texte centré. Pour ce faire, on récupère la police (Font) que l'on va utiliser et l'utiliser en entrée de l'objet FontMetrics qui permet de connaître la taille d'un String utilisant cette police. Pour récupérer les dimension du String, on utilise la méthode getStringBounds() qui renvoie un Rectangle de la taille du String. On n'a plus qu'à dessiner le String en donnant comme abscisse le pixel autour duquel il est centré (ici 108) soustrait de la moitié de la taille du String (tailleString.widht / 2). Figure 131 : Centrage horizontal du pseudo autour du pixel 108. 95 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 Conclusion 1. Quantité de travail effectué : Ce travail s'est déroulé sur un an et demi et la charge horaire de travail est représentée ci-dessous. 140 Administrateur 120 OS 100 Hébergement Mise à jour 80 Obfuscation 60 Tests 40 BDD 20 01/11/2… 01/10/2… 01/09/2… 01/08/2… 01/07/2… 01/06/2… 01/05/2… 01/04/2… 01/03/2… 01/02/2… 01/01/2… 01/12/2… 01/11/2… 01/10/2… 01/09/2… 01/08/2… 01/07/2… GIMP 01/06/2… 0 Combinaison Code Figure 132 : Charge de travail. Le projet complet s'est déroulé sur un total de 700 heures et contient une centaine de classes et 15000 lignes de codes (partie serveur : 5000, partie client : 7500, lanceur : 750, administrateur : 1500, obfuscateur : 500). 96 GUIHOT Xavier Initiative IDEE Programmation d’un logiciel de poker ISAE - ENSICA 13/01/2014 2. Difficultés rencontrées : Le fait de commencer avec des connaissances rudimentaires en Java a pesé sur le temps de travail accordé à ce projet. Que ce soit pour les aspects graphiques de Java dont la documentation est foisonnante sur internet mais dont la redéfinition des composants peut être longue à prendre en main ou que ce soit sur certaines subtilités orientées système ou langage, la prise en main de Java a représenté un vrai chalenge. Pour un logiciel dont l'aspect graphique représente une bonne partie, à moins d'avoir une âme de graphiste, il peut être bon de faire appel à un graphiste! Bien qu'ayant réfléchit à l'architecture du logiciel en phase amont du projet, j'ai pu me rendre compte, par cet exemple concret, de ce qui nous a été enseigné en cours concernant le cycle de vie d'un logiciel et du fait qu'une erreur d'architecture en début de conception peut se révéler très pénible à corriger lorsque le projet est déjà bien avancé! Concernant le cahier des charges initial, beaucoup de points n’ont pas été atteints. Premièrement, je n'ai pas mis en ligne le téléchargement de ce logiciel et seuls les élèves de l'ENSICA et de SUPAERO y ont accès. Dans l'état actuel de l'offre de poker, comprenant des centaines de logiciels et de sites, l'intérêt d'ajouter le mien à la diversité actuelle est très limité. En effet, par rapport aux grandes plateformes telles PokerStar proposant des logiciels de poker très évolués à télécharger, l'intérêt du client pour mon logiciel serait restreint. De plus, l'utilisation de Java pour le poker induit plusieurs barrières telles que le fait de devoir télécharger le logiciel plutôt que de jouer directement sur un site en ligne ou tout simplement le fait de devoir installer Java pour pouvoir jouer. Concernant les tournois, bien que cela soit très intéressant à réaliser, le côté technique ne serait pas très nouveau et ne m'apporterai rien de plus au vu de la charge de travail annexe que j'ai actuellement. Enfin, le développement de l'application est quelque chose que je garde en tête pour un moment où j'aurais un peu plus de temps. En effet, l'apprentissage d'Android et le développement d'applications mobiles me semblent indispensables pour un développeur. De plus, ce serait le moyen de faire connaître mon logiciel car contrairement à un logiciel à télécharger, une application Android aurait le potentiel de toucher beaucoup plus de monde. 97