Plis
Javass – étape 4

1 Introduction

Le but de cette quatrième étape est d'écrire les classes permettant de manipuler des plis, sous forme empaquetée et sous forme d'objets.

1.1 Pli

Comme cela a été expliqué précédemment, un tour d'une partie de Jass est constitué d'une succession de 9 plis (tricks en anglais). Durant chacun d'entre eux, les joueurs posent successivement sur la table une des cartes de leur main. Le premier joueur peut déposer n'importe quelle carte de son jeu, mais les suivants doivent respecter certaines règles, décrites plus bas.

Une fois que tous les joueurs ont déposé une carte, celui qui a posé la plus forte remporte le pli. Cela implique d'une part qu'il débute le pli suivant, et d'autre part que son équipe remporte les points associés au pli.

1.2 Cartes jouables

On l'a vu, le joueur qui pose la première carte du pli peut jouer n'importe laquelle des cartes de sa main. La couleur de cette carte est appelée la couleur de base du pli. Les joueurs suivants ont moins de liberté que lui et, en règle générale, peuvent soit :

  • suivre, c-à-d jouer une carte de la couleur de base, soit
  • couper, c-à-d jouer une carte d'atout.

Bien entendu, couper n'a de sens que si la couleur de base n'est pas atout.

Il faut noter que dès qu'un joueur coupe, les joueurs suivants n'ont le droit de couper qu'en jouant une carte d'atout plus forte que la plus forte déjà posée. On dit qu'il est interdit de sous-couper.

La règle générale ci-dessus admet les exceptions suivantes :

  1. un joueur qui ne possède aucune carte de la couleur de base, et qui ne peut donc suivre, peut jouer n'importe laquelle de ses cartes,
  2. lorsque la couleur de base est atout, un joueur qui ne possède plus d'autre carte d'atout que le valet n'est pas obligé de suivre et peut poser n'importe laquelle de ses cartes,
  3. un joueur qui n'a plus que des cartes d'atout plus faibles que la plus forte carte d'atout posée a le droit de sous-couper.

1.3 Carte gagnante

La carte gagnante d'un pli, c-à-d celle qui permet au joueur l'ayant posée de remporter le pli, se détermine en parcourant les cartes du pli dans l'ordre dans lequel elles ont été posées.

Par défaut, la carte gagnante du pli est la première carte posée. Toutefois, si une deuxième carte a été posée et qu'elle est comparable à, et plus forte que, la première — selon l'ordre partiel décrit à la §1.2 de l'étape 1 —, alors elle devient la carte gagnante. Et ainsi de suite avec la troisième et la quatrième carte, pour peu qu'elles aient été posées.

1.4 Valeur d'un pli

La valeur d'un pli, c-à-d le nombre de points que gagne l'équipe qui le remporte, est généralement la somme de la valeur des cartes qu'il contient. La seule exception à cette règle est le dernier pli d'un tour, qui remporte 5 points supplémentaires, souvent appelés les « 5 de der ».

En raison de ces 5 points supplémentaires, et du fait que la valeur totale des cartes d'un jeu de Jass est de 152 points, le nombre de points total d'un tour de jeu vaut :

  • 157 (152+5) si chacune des équipe remporte au moins un pli, ou
  • 257 (152+5+100) si une équipe « fait match » en remportant la totalité des plis.

1.5 Pli empaqueté

Au même titre que les cartes, les scores et les ensembles de cartes, nous représenterons les plis de deux manières : premièrement sous forme empaquetée dans un entier, et deuxièmement sous forme d'objets.

Pour ce projet, les informations dont nous avons besoin au sujet d'un pli sont :

  • la couleur d'atout,
  • l'identité du joueur débutant le pli,
  • l'index du pli dans le tour (de 0 à 8 inclus),
  • les 0 à 4 cartes posées.

Rigoureusement, la couleur d'atout n'est pas un attribut du pli, mais du tour de jeu. Cela dit, stocker l'atout dans chaque pli du tour simplifie certaines choses.

Ces différentes informations peuvent tout juste être empaquetées dans un entier de 32 bits, de la manière suivante :

Bits 31 à 30 29 à 28 27 à 24 23 à 18 5 à 0
Contenu atout joueur 1 index carte 3 carte 0

Les quatre premières plages de 6 bits (0 à 5, 6 à 11, 12 à 17, et 18 à 23) contiennent les 4 cartes du pli, sous forme empaquetée. La première carte occupe les bits de poids faible, la seconde ceux qui suivent, et ainsi de suite.

Les plis partiels, c-à-d ceux pour lesquels moins de 4 cartes ont été jouées, contiennent la carte empaquetée invalide (PackedCard.INVALID) dans les position inoccupées. Cela implique que la taille du pli, c-à-d le nombre de cartes qu'il contient, peut être déterminée en cherchant la première carte invalide (si elle existe) en partant de la carte 0.

2 Mise en œuvre Java

2.1 Classe PackedTrick

La classe PackedTrick du paquetage ch.epfl.javass.jass, finale et non instanciable, possède des méthodes permettant de manipuler des plis empaquetés dans des valeurs de type int.

Cette classe possède un attribut public, statique et final, nommé INVALID et représentant un pli empaqueté invalide. Plusieurs valeurs pourraient être utilisées ici, nous choisirons celle composée de 32 bits valant 1.

En plus de cet attribut, la classe PackedTrick offre les méthodes — publiques et statiques, bien entendu — suivantes :

  • boolean isValid(int pkTrick), qui retourne vrai ssi l'entier donné représente un pli empaqueté valide, c-à-d si l'index est compris entre 0 et 8 (inclus) et si les éventuelles cartes invalides sont groupées dans les index supérieurs — c-à-d que le pli ne possède soit aucune carte invalide, soit une seule à l'index 3, soit deux aux index 3 et 2, soit trois aux index 3, 2 et 1, soit quatre aux index 3, 2, 1 et 0,
  • int firstEmpty(Color trump, PlayerId firstPlayer), qui retourne le pli empaqueté vide — c-à-d sans aucune carte — d'index 0 avec l'atout et le premier joueur donnés,
  • int nextEmpty(int pkTrick), qui retourne le pli empaqueté vide suivant celui donné (supposé plein), c-à-d le pli vide dont l'atout est identique à celui du pli donné, l'index est le successeur de celui du pli donné et le premier joueur est le vainqueur du pli donné ; si le pli donné est le dernier du tour, alors le pli invalide (INVALID ci-dessus) est retourné,
  • boolean isLast(int pkTrick), qui retourne vrai ssi le pli est le dernier du tour, c-à-d si son index vaut 8,
  • boolean isEmpty(int pkTrick), qui retourne vrai ssi le pli est vide, c-à-d s'il ne contient aucune carte,
  • boolean isFull(int pkTrick), qui retourne vrai ssi le pli est plein, c-à-d s'il contient 4 cartes,
  • int size(int pkTrick), qui retourne la taille du pli, c-à-d le nombre de cartes qu'il contient,
  • Color trump(int pkTrick), qui retourne l'atout du pli,
  • PlayerId player(int pkTrick, int index), qui retourne le joueur d'index donné dans le pli, le joueur d'index 0 étant le premier du pli,
  • int index(int pkTrick), qui retourne l'index du pli,
  • int card(int pkTrick, int index), qui retourne la version empaquetée de la carte du pli à l'index donné (supposée avoir été posée),
  • int withAddedCard(int pkTrick, int pkCard), qui retourne un pli identique à celui donné (supposé non plein), mais à laquelle la carte donnée a été ajoutée,
  • Color baseColor(int pkTrick), qui retourne la couleur de base du pli, c-à-d la couleur de sa première carte (supposée avoir été jouée),
  • long playableCards(int pkTrick, long pkHand), qui retourne le sous-ensemble (empaqueté) des cartes de la main pkHand qui peuvent être jouées comme prochaine carte du pli pkTrick (supposé non plein),
  • int points(int pkTrick), qui retourne la valeur du pli, en tenant compte des « 5 de der »,
  • PlayerId winningPlayer(int pkTrick), qui retourne l'identité du joueur menant le pli (supposé non vide),
  • String toString(int pkTrick), qui retourne une représentation textuelle du pli, qui doit au minimum inclure une représentation des cartes jouées, dans l'ordre de jeu et séparées par une virgule.

2.2 Classe Trick

La classe Trick, du paquetage ch.epfl.javass.jass, publique, finale et immuable, représente un pli.

Tout comme la classe PackedTrick, elle offre un attribut public, final et statique représentant un pli invalide, nommé lui aussi INVALID.

De plus, et comme d'habitude, elle offre des méthodes qui correspondent pour la plupart à des méthodes de PackedTrick, la seule exception étant la paire ofPacked / packed, qui permet de passer de la version empaquetée d'un pli à sa version objet, et inversement. Les méthodes de Trick sont donc listées ci-dessous sans commentaires, sauf dans les quelques cas où une validation quelconque doit être faite :

  • static Trick firstEmpty(Color trump, PlayerId firstPlayer),
  • static Trick ofPacked(int packed), qui retourne le pli dont la version empaquetée est celle donnée, ou lève IllegalArgumentException si celui-ci n'est pas valide (selon PackedTrick.isValid),
  • int packed(),
  • Trick nextEmpty(), qui se comporte comme la méthode correspondante de PackedTrick ou lève l'exception IllegalStateException si le pli n'est pas plein,
  • boolean isEmpty(),
  • boolean isFull(),
  • boolean isLast(),
  • int size(),
  • Color trump(),
  • int index(),
  • PlayerId player(int index), qui se comporte comme la méthode correspondante de PackedTrick ou lève IndexOutOfBoundsException si l'index n'est pas compris entre 0 (inclus) et 4 (exclus),
  • Card card(int index), qui se comporte comme la méthode correspondante de PackedTrick ou lève IndexOutOfBoundsException si l'index n'est pas compris entre 0 (inclus) et la taille du pli (exclus),
  • Trick withAddedCard(Card c), qui se comporte comme la méthode correspondante de PackedTrick ou lève IllegalStateException si le pli est plein,
  • Color baseColor(), qui se comporte comme la méthode correspondante de PackedTrick ou lève IllegalStateException si le pli est vide,
  • CardSet playableCards(CardSet hand), qui se comporte comme la méthode correspondante de PackedTrick ou lève IllegalStateException si le pli est plein,
  • int points(),
  • PlayerId winningPlayer(), qui se comporte comme la méthode correspondante de PackedTrick ou lève IllegalStateException si le pli est vide,

Finalement, la classe Trick redéfinit les méthodes equals, hashCode et toString de Object. La méthode hashCode se contente de retourner la version empaquetée du pli.

2.3 Tests

Comme d'habitude, nous ne vous fournissons pas de tests mais un fichier de vérification de signatures contenu dans une archive Zip à importer dans votre projet.

3 Résumé

Pour cette étape, vous devez :

  • écrire les classes PackedTrick et Trick selon les instructions données plus haut,
  • tester votre code,
  • documenter la totalité des entités publiques que vous avez définies,
  • rendre votre code au plus tard le 15 mars 2019 à 16h30, via le système de rendu.

Ce rendu est un rendu testé, auquel 18 points sont attribués, au prorata des tests unitaires passés avec succès. Notez que la documentation de votre code ne sera pas évaluée avant le rendu intermédiaire. Dès lors, si vous êtes en retard, ne vous en préoccupez pas pour l'instant.

N'attendez surtout pas le dernier moment pour effectuer votre rendu, car vous n'êtes pas à l'abri d'imprévus. Souvenez-vous qu'aucun retard, aussi insignifiant soit-il, ne sera toléré !