Examen de 2 h sur machine


L'examen est composé d'une partie écrite sur feuille de 45 minutes maximum, à faire en premier, et d'un exercice qui doit être traité ensuite.

Rappel : si ce n'est pas déjà le cas, vous devez configurer le workspace d'Eclipse (File > Switch Workspace) pour qu'il corresponde au répertoire EXAM présent dans le home de votre session de TP noté.

Vérifiez que tous vos fichiers sont bien dans le répertoire EXAM. Tout ce qui n'est pas dans ce répertoire est perdu quand vous vous déconnectez.

La Javadoc 27 est là : https://igm.univ-mlv.fr/~juge/javadoc-27/.

Vous avez le droit de consulter les transparents du cours pendant tout l'examen.

QCM (sur papier)

Survival game

Les classes de cet exercice doivent être dans le package fr.uge.concurrence.exo1.

Cet exercice consiste à simuler un jeu de Survival Games. Le jeu se déroule dans une arène qui ne peut accueillir qu'un joueur à la fois. Pour pouvoir commencer le jeu, il faut d'abord attendre que les nbPlayers joueurs s'inscrivent. Une fois que tous les joueurs se sont inscrits, les différents rounds peuvent commencer. À chaque round, les joueurs participent au jeu et peuvent être éliminés. Le jeu se termine lorsque le dernier joueur est éliminé.

Nous allons implémenter une classe thread-safe GameArena qui permet à plusieurs threads, représentant les joueurs, de participer au jeu. La classe GameArena possède les méthodes suivantes :

L'exercice comporte 6 questions.

En utilisant des blocs synchronized, écrivez la classe thread-safe GameArena, son constructeur prenant nbPlayers en paramètre, ainsi que les méthodes register() et registered().
La méthode register() doit bloquer tant que moins de nbPlayers joueurs sont inscrits. Si nbPlayers joueurs sont déjà inscrits, la méthode doit lever une IllegalStateException.
L'ensemble renvoyé par la méthode registered() ne doit plus changer une fois que l'enregistrement est terminé.

Ajoutez une méthode main à la classe GameArena. Elle crée une arène pour 12 joueurs, puis démarre 12 threads représentant ces joueurs. Chaque thread attend un petit temps aléatoire, s'inscrit et affiche qu'il est prêt pour le premier round. Pendant ce temps, le main affiche en boucle l'ensemble des threads inscrits. Il attend également un petit temps aléatoire après chaque affichage. Il s'arrête après avoir affiché les 12 threads inscrits. Votre programme doit terminer.
Voici la ligne de code qui permet d'attendre un petit temps aléatoire :

Thread.sleep(ThreadLocalRandom.current().nextInt(500));

Voici un exemple d'exécution possible :

Registered : []
Registered : []
Registered : [Thread[#26,Thread 2,5,main], Thread[#28,Thread 4,5,main]]
Registered : [Thread[#31,Thread 7,5,main], Thread[#32,Thread 8,5,main], Thread[#26,Thread 2,5,main], Thread[#24,Thread 0,5,main], Thread[#28,Thread 4,5,main], Thread[#33,Thread 9,5,main]]
Thread 2 is ready to play round 1
Thread 6 is ready to play round 1
Thread 8 is ready to play round 1
Thread 3 is ready to play round 1
Thread 9 is ready to play round 1
Thread 7 is ready to play round 1
Thread 0 is ready to play round 1
Thread 5 is ready to play round 1
Thread 1 is ready to play round 1
Thread 11 is ready to play round 1
Thread 4 is ready to play round 1
Thread 10 is ready to play round 1
Registered : [Thread[#31,Thread 7,5,], Thread[#35,Thread 11,5,], Thread[#32,Thread 8,5,], Thread[#27,Thread 3,5,], Thread[#25,Thread 1,5,], Thread[#28,Thread 4,5,], Thread[#33,Thread 9,5,], Thread[#34,Thread 10,5,], Thread[#29,Thread 5,5,], Thread[#30,Thread 6,5,], Thread[#26,Thread 2,5,], Thread[#24,Thread 0,5,]]
Dès que les nbPlayers joueurs sont inscrits, le premier round peut commencer.
Chaque thread (joueur) va pouvoir appeler la méthode playRound() pour participer au round en cours. La méthode doit respecter les règles suivantes :

Écrivez la méthode playRound() permettant aux joueurs de participer au round en cours.

Modifiez le main pour que chaque thread inscrit essaie de jouer les rounds successifs jusqu'à ce qu'il soit éliminé, auquel cas il s'arrête. Chaque thread attend un petit temps aléatoire avant d'appeler playRound() et affiche ensuite s'il a survécu ou s'il a été éliminé.

Vous devriez avoir un affichage similaire à ceci :
Registered : []
Registered : [Thread[#29,Thread 5,5,main]]
Registered : [Thread[#24,Thread 0,5,main], Thread[#29,Thread 5,5,main], Thread[#27,Thread 3,5,main], Thread[#30,Thread 6,5,main], Thread[#34,Thread 10,5,main], Thread[#28,Thread 4,5,main], Thread[#31,Thread 7,5,main]]
Thread 1 is ready to play round 1
Thread 4 is ready to play round 1
Thread 6 is ready to play round 1
Thread 10 is ready to play round 1
Thread 7 is ready to play round 1
Thread 5 is ready to play round 1
Thread 3 is ready to play round 1
Thread 0 is ready to play round 1
Thread 11 is ready to play round 1
Thread 9 is ready to play round 1
Thread 8 is ready to play round 1
Thread 2 is ready to play round 1
Thread 8 perished at round 1
Registered : [Thread[#32,Thread 8,5,], Thread[#31,Thread 7,5,main], Thread[#28,Thread 4,5,main], Thread[#34,Thread 10,5,main], Thread[#29,Thread 5,5,main], Thread[#30,Thread 6,5,main], Thread[#33,Thread 9,5,main], Thread[#24,Thread 0,5,main], Thread[#26,Thread 2,5,main], Thread[#25,Thread 1,5,main], Thread[#35,Thread 11,5,main], Thread[#27,Thread 3,5,main]]
Thread 1 survived round 1
Thread 10 survived round 1
Thread 2 survived round 1
Thread 11 survived round 1
Thread 3 survived round 1
Thread 9 perished at round 1
Thread 5 perished at round 1
Thread 7 survived round 1
Thread 6 survived round 1
Thread 4 survived round 1
Thread 0 survived round 1
Thread 10 perished at round 2
Thread 3 survived round 2
Thread 1 perished at round 2
Thread 4 survived round 2
Thread 6 survived round 2
Thread 11 survived round 2
Thread 2 survived round 2
Thread 0 survived round 2
Thread 7 survived round 2
Thread 6 perished at round 3
Thread 11 survived round 3
Thread 7 survived round 3
Thread 3 survived round 3
Thread 4 survived round 3
Thread 2 survived round 3
Thread 0 perished at round 3
Thread 11 survived round 4
Thread 7 survived round 4
Thread 4 survived round 4
Thread 3 survived round 4
Thread 2 survived round 4
Thread 7 survived round 5
Thread 4 perished at round 5
Thread 11 perished at round 5
Thread 2 survived round 5
Thread 3 perished at round 5
Thread 7 survived round 6
Thread 2 survived round 6
Thread 7 perished at round 7
Thread 2 survived round 7
Thread 2 survived round 8
Thread 2 perished at round 9

Copiez votre classe GameArena dans une classe GameArenaRL et réécrivez-la en utilisant des verrous ReentrantLock et, si c'est pertinent, plusieurs conditions Condition pour assurer la synchronisation entre les threads.

Copiez votre classe GameArena (celle avec les blocs synchronized) dans une classe GameArenaOrganizer et ajoutez un thread supplémentaire, l'organisateur qui surveille l'évolution du jeu. Il devra être capable d'afficher le numéro du round actuel dès qu'il constate que les joueurs ont avancé d'un round. Il doit aussi pouvoir afficher lorsque le jeu est terminé et dans ce cas, le programme s'arrête. Bien entendu, la classe GameArenaOrganizer doit rester thread-safe.

L'organisateur n'a aucune priorité particulière par rapport aux joueurs. Il peut donc ne pas observer certains changements de round ; lorsqu'il reprend la main, il affiche uniquement le round courant.

Vous devriez avoir un affichage similaire à ceci :
Registered : []
Registered : [Thread[#28,Thread 4,5,main], Thread[#33,Thread 9,5,main], Thread[#26,Thread 2,5,main], Thread[#29,Thread 5,5,main], Thread[#34,Thread 10,5,main], Thread[#24,Thread 0,5,main], Thread[#27,Thread 3,5,main], Thread[#30,Thread 6,5,main], Thread[#35,Thread 11,5,main], Thread[#31,Thread 7,5,main]]
Organizer: currently on round 1
Thread 7 is ready to play round 1
Thread 4 is ready to play round 1
Thread 10 is ready to play round 1
Thread 5 is ready to play round 1
Thread 1 is ready to play round 1
Thread 2 is ready to play round 1
Thread 11 is ready to play round 1
Thread 8 is ready to play round 1
Thread 6 is ready to play round 1
Thread 9 is ready to play round 1
Thread 0 is ready to play round 1
Thread 3 is ready to play round 1
Thread 8 survived round 1
Thread 4 survived round 1
Thread 5 survived round 1
Thread 0 perished at round 1
Thread 2 perished at round 1
Thread 6 perished at round 1
Thread 7 perished at round 1
Thread 3 survived round 1
Thread 10 survived round 1
Thread 1 perished at round 1
Thread 11 perished at round 1
Thread 9 perished at round 1
Thread 3 survived round 2
Organizer: currently on round 2
Thread 8 survived round 2
Thread 4 perished at round 2
Thread 5 survived round 2
Registered : [Thread[#27,Thread 3,5,main], Thread[#28,Thread 4,5,], Thread[#31,Thread 7,5,], Thread[#30,Thread 6,5,], Thread[#29,Thread 5,5,main], Thread[#33,Thread 9,5,], Thread[#35,Thread 11,5,], Thread[#25,Thread 1,5,], Thread[#34,Thread 10,5,main], Thread[#24,Thread 0,5,], Thread[#26,Thread 2,5,], Thread[#32,Thread 8,5,main]]
Thread 10 survived round 2
Organizer: currently on round 3
Thread 5 perished at round 3
Thread 8 survived round 3
Thread 10 perished at round 3
Thread 3 perished at round 3
Thread 8 survived round 4
Organizer: currently on round 4
Thread 8 perished at round 5
Organizer: game finished