Jeu
tCHu – étape 6
1. Introduction
Cette étape a pour but d'écrire la classe gérant la totalité du déroulement d'une partie de tCHu.
Notez que cette étape devra être rendue deux fois :
- pour le rendu testé habituel (délai : 9 avril, 17h00),
- pour le rendu intermédiaire (délai : 16 avril, 17h00).
Le deuxième de ces rendus sera corrigé par lecture de votre code pour les étapes 1 à 6, et il vous faudra donc soigner sa qualité et sa documentation. Il est fortement conseillé de lire notre guide à ce sujet.
2. Concepts
2.1. Déroulement d'une partie
La plupart des règles de tCHu ont été décrites dans les étapes précédentes mais sont résumées ici afin de vous en donner une vue d'ensemble.
2.1.1. Début de partie
Au début de la partie, le joueur qui jouera en premier est tiré au sort.
Cela fait, chaque joueur reçoit 40 wagons de sa couleur, 4 cartes wagon/locomotives tirées du sommet de la pioche de cartes, et 5 billets tirés du sommet de la pioche de billets.
Afin que la partie puisse effectivement débuter, chaque joueur doit choisir au moins 3 des 5 billets reçu, qu'il garde en mains. Les billets non retenus ne sont plus remis en jeu.
2.1.2. Milieu de partie
Tant et aussi longtemps que tous les joueurs possèdent au moins encore 2 wagons, ils jouent à tour de rôle, en commençant par le joueur tiré au sort précédemment.
Lorsque c'est à son tour, un joueur doit effectuer exactement l'une des trois actions suivantes :
- tirer les trois billets du sommet de la pioche, et en garder au moins 1, les billets non retenus n'étant plus remis en jeu,
- tirer deux cartes, chacune d'entre elles pouvant être soit celle du sommet de la pioche, soit l'une des 5 cartes disposées face visible ; dans ce dernier cas, la carte du sommet de la pioche est retournée afin de remplacer celle prise par le joueur,
- (tenter de) s'emparer d'une route, selon les règles décrites à la §2.2 de l'étape 2.
Dès que le joueur a effectué son action, son tour est terminé, et c'est au prochain joueur de jouer.
2.1.3. Fin de partie
Dès qu'un joueur termine son tour avec 2 wagons ou moins, le dernier tour commence. Chaque joueur, y compris celui qui vient de terminer son tour avec 2 wagons ou moins, jouent alors encore un tour chacun. Ensuite, le total des points de chaque joueur est déterminé en additionnant :
- les points « de construction », acquis en s'emparant de routes,
- les points gagnés ou perdus grâce aux billets,
- l'éventuel bonus de 10 points dû au chemin le plus long.
Le joueur ayant le plus grand nombre de points est déclaré vainqueur. En cas d'égalité, les deux joueurs sont ex æquo.
3. Mise en œuvre Java
3.1. Classe Game
La classe Game
du paquetage ch.epfl.tchu.game
, publique, finale et non instanciable, représente une partie de tCHu. Elle n'offre qu'une seule méthode publique et bien entendu statique :
void play(Map<PlayerId, Player> players, Map<PlayerId, String> playerNames, SortedBag<Ticket> tickets, Random rng)
, qui fait jouer une partie de tCHu aux joueurs donnés, dont les noms figurent dans la tableplayerNames
; les billets disponibles pour cette partie sont ceux detickets
, et le générateur aléatoirerng
est utilisé pour créer l'état initial du jeu et pour mélanger les cartes de la défausse pour en faire une nouvelle pioche quand cela est nécessaire ; lèveIllegalArgumentException
si l'une des deux tables associatives a une taille différente de 2.
Pour faire jouer une partie aux joueurs, la méthode play
doit appeler les différentes méthodes de chacun des deux joueurs afin de savoir comment ils désirent jouer. Ces méthodes sont bien entendu celles de l'interface Player
décrite à l'étape précédente.
Pour le début de la partie, les méthodes suivantes doivent être appelées, dans l'ordre donné :
- avant le véritable début de la partie, la méthode
initPlayers
de chaque joueur doit être appelée afin de lui communiquer sa propre identité, et le nom de chaque joueur — le sien inclus, - une fois que le joueur qui jouera en premier a été tiré au hasard, la méthode
receiveInfo
doit être appelée afin de communiquer cette information à tous les joueurs, en lui passant la chaîne produite par la méthodewillPlayFirst
de la classeInfo
, - la méthode
setInitialTicketChoice
de chaque joueur doit être appelée pour lui communiquer les billets qu'il reçoit initialement, - la méthode
chooseInitialTickets
de chaque joueur doit être appelée pour savoir quels billets chaque joueur a décidé de garder, - la méthode
receiveInfo
de chaque joueur doit être appelée pour communiquer à chacun le nombre de billets gardés par chaque joueur ; cette chaîne est produite par la méthodekeptTickets
deInfo
.
La partie commence ensuite. Jusqu'à sa fin, chaque joueur doit jouer à tour de rôle, et pour ce faire, la méthode play
appelle les méthodes suivantes du joueur courant, dans l'ordre donné :
- la méthode
nextTurn
est appelée pour savoir quelle action le joueur courant désire effectuer parmi les trois possibles, - si le joueur courant désire tirer des billets, alors :
- la méthode
chooseTickets
est appelée afin de déterminer quels billets il garde parmi ceux tirés,
- la méthode
- si le joueur courant désire tirer des cartes, alors :
- la méthode
drawSlot
est appelée une première fois pour savoir quelle carte il désire tirer en premier, - la méthode
drawSlot
est appelée une seconde fois pour savoir quelle carte il désire tirer en second,
- la méthode
- si le joueur courant désire (tenter de) s'emparer d'une route, alors :
- la méthode
claimedRoute
est appelée pour déterminer de quelle route il s'agit, - la méthode
initialClaimCards
est appelée pour déterminer les cartes (initiales) à utiliser, - si la route est en tunnel, que les trois cartes du sommet de la pioche impliquent l'utilisation d'au moins une carte additionnelle, et que le joueur courant a dans sa main les cartes additionnelles nécessaires, alors :
- la méthode
chooseAdditionalCards
est appelée pour déterminer s'il désire jouer des cartes additionnelles, et si oui, lesquelles.
- la méthode
- la méthode
De plus, la méthode receiveInfo
de l'interface Player
doit être appelée régulièrement pour informer les deux joueurs du déroulement de la partie. L'argument à passer à cette méthode est toujours obtenu au moyen d'une des méthodes de la classe Info
, qui devrait être claire en fonction du contexte. À noter qu'il est nécessaire de créer une instance de cette classe par joueur, puisque son constructeur prend en argument le nom du joueur pour lequel les informations doivent être produites.
La méthode receiveInfo
doit être appelée :
- (comme dit plus haut) dès que l'identité du premier joueur est connue — et avant de dire aux joueurs quels sont leurs cinq billets initiaux,
- (comme dit plus haut) dès que les joueurs ont choisi le nombre de billets qu'ils gardent initialement — mais seulement lorsque tous les joueurs ont fait leur choix, afin de ne pas donner un avantage au joueur choisissant en dernier,
- lorsque le tour d'un joueur commence,
- lorsqu'un joueur tire des billets,
- lorsqu'un joueur a choisi de garder un certain nombre de billets,
- lorsqu'un joueur tire une carte de la pioche ou une carte face visible,
- lorsqu'un joueur s'est emparé d'une route, en communiquant toutes les cartes utilisées — initiales et additionnelles dans le cas d'un tunnel,
- lorsqu'un joueur tente de s'emparer d'un tunnel,
- lorsqu'un joueur tente de s'emparer d'un tunnel et que les trois cartes du sommet de la pioche déterminant le nombre de cartes additionnelles à jouer ont été tirées,
- lorsqu'un joueur ne peut ou ne veut jouer les cartes additionnelles nécessaires pour s'emparer d'un tunnel,
- lorsque le dernier tour commence,
- lorsqu'un joueur obtient le bonus pour le plus long chemin,
- lorsqu'un joueur remporte la victoire, ou lorsque les deux joueurs sont ex æquo.
Finalement, la méthode updateState
de chacun des deux joueurs doit être appelée régulièrement afin de leur communiquer les changements d'état de la partie. Cette méthode pourrait être appelée à chaque changement d'état, mais l'appeler dans les cas suivants suffit :
- juste avant d'appeler la méthode
chooseInitialTickets
pour demander aux joueurs de choisir leurs billets initiaux, afin qu'ils puissent faire ce choix en connaissant l'état actuel de la partie — en particulier les cartes initiales qui leur ont été distribuées, - juste avant d'appeler la méthode
nextTurn
pour demander au joueur courant de choisir l'action qu'il désire effectuer, afin qu'il puisse faire ce choix en connaissant l'état actuel de la partie, - juste avant d'appeler
drawSlot
pour la seconde fois lorsqu'un joueur tire des cartes, afin qu'il sache p.ex. quelle carte a remplacé la carte face visible qu'il a éventuellement tirée en premier, - juste avant d'informer les joueurs du résultat final de la partie, afin qu'ils connaissent l'état dans lequel la partie s'est effectivement terminé.
Ces appels à updateState
provoqueront la mise à jour de l'interface graphique lorsque celle-ci sera écrite, et il est donc important qu'ils soient faits au bon moment.
3.1.1. Conseils de programmation
- Recréation de la pioche
Prêtez attention au fait qu'au cours du jeu, la pioche de cartes va progressivement se vider, et la défausse se remplir. Lorsque la pioche est totalement vide, elle doit être recréée à partir de la défausse. Il faut donc penser à appeler la méthode
withCardsDeckRecreatedIfNeeded
au bon moment !Notre conseil est de l'appeler systématiquement avant chaque appel à une méthode qui doit tirer une carte de la pioche, et de ne jamais tirer plus d'une carte à la fois en cours de partie. En particulier, les trois cartes à tirer lorsqu'un joueur tente de s'emparer d'un tunnel doivent absolument être tirées l'une après l'autre.
- Méthodes auxiliaires
Il peut être utile d'ajouter des méthodes privées à votre classe
Game
afin de simplifier votre code, par exemple :- une méthode permettant d'envoyer une information à tous les joueurs, en appelant la méthode
receiveInfo
de chacun d'eux, - une méthode permettant d'informer tous les joueurs d'un changement d'état, en appelant la méthode
updateState
de chacun d'eux.
- une méthode permettant d'envoyer une information à tous les joueurs, en appelant la méthode
3.2. Tests
Comme d'habitude, nous ne vous fournissons plus de tests mais un fichier de vérification de signatures contenu dans une archive Zip à importer dans votre projet.
4. Résumé
Pour cette étape, vous devez :
- écrire la classe
Game
selon les indications données ci-dessus, - tester votre code,
- documenter la totalité des entités publiques que vous avez définies,
- rendre votre code au plus tard le 9 avril 2021 à 17h00, via le système de rendu.
Ce rendu est un rendu testé, auquel 20 points sont attribués, au prorata des tests unitaires passés avec succès.
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é !