Le but de ce TD est de se remémorer les techniques de base de la programmation, les algorithmes et structures de données, acquis au cours INF311.
Nous allons implémenter une version simplifiée du jeu de cartes BlackJack. Notre version est la suivante :
Chaque carte vaut un certain nombre de points: As vaut 1, les figures valent 10 et toutes les autres cartes valent le nombre inscrit sur la carte.
Un joueur humain joue contre l'ordinateur. Il commence par tirer les cartes ("draw") une par une en essayant de se rapprocher le plus possible de 21 points sans dépasser. Dès que le total de ses cartes dépasse 21 points il a perdu et le jeu s'arrête. Il peut décider d'arrêter de tirer les cartes ("stand"), c'est alors au tour de l'ordinateur de tirer ses cartes une par une. Le jeu s'arrête dès que la somme des cartes de l'ordinateur dépasse 21 (et c'est le joueur qui a gagné) ou dès qu'elle dépasse la somme des cartes du joueur humain (c'est alors l'ordinateur qui a gagné).
Avant d'implémenter de notre jeu BlackJack, nous allons commencer par mettre en place notre environnement de travail et raviver nos connaissances en écrivant et compilant le programme basique "Hello World".
Créer un répertoire dédié à INF421, dans lequel tous les fichiers se rapportant aux TDs seront stockés :
Assurez-vous que les fichiers pour chaque TD soient bien stockés dans leur répertoire correspondant (par exemple les fichiers du TD d'aujourd'hui seront stockés dans le répertoire ~/INF421/TD1/).
Dans ce cours INF421, l'environnement de développement recommandé est Emacs, un puissant éditeur intégrant le surlignage syntaxique en couleur, la compilation et le débogage. Les instructions pour installer, configurer et utiliser Emacs sont dans ce guide.
Il est important que vous vous respectiez les règles suivantes :
Ecrire un programme HelloWorld.java qui affiche le texte "Hello World" sur l'écran. Compiler et exécuter le programme.
Déposez votre implémentation de HelloWorld.java ici:
Dans cet exercice, nous allons implémenter une classe Card. Chaque objet de cette classe représente une carte, et possède par conséquent une valeur et une couleur (coeur, carreau, trèfle, pique). Cette classe Card sera utilisée dans l'exercice 2, où nous implémenterons un jeu de cartes ("Deck") avec des opérations comme "tirer", "battre". Cette dernière classe nous servira finalement en exercice 3 où nous allons implémenter le jeu BackJack.
Notre implémentation devra être générique de sorte que l'on puisse la réutiliser un jour pour d'autres jeux de cartes, donc ce ne sera pas dans cette classe qu'on mettera la méthode qui donne le nombre de points d'une carte.
Implémenter une classe Card, comportant les champs suivants:
La classe doit avoir un constructeur explicite Card(int color, int value), qui prend comme paramètres la couleur, et la valeur d'une carte.
Le constructeur prend en argument la valeur numérique représentant la couleur et au contructeur de la transformer en 'H', 'D', 'S' or 'C' (indication : utiliser ''switch'') en suivant la spécification suivante:
Ajouter une méthode static String toString(Card c), qui renvoie une cha”ne de caractères décrivant la carte. Par example, pour la "Dame de Pique", Card.toString(...) va renvoyer :
S12
La classe Card sera testée en ajoutant la méthode suivante a la classe Card:
public static void main(String[] args){ Card c0 = new Card(0,1); Card c1 = new Card(1,10); Card c2 = new Card(2,11); Card c3 = new Card(3,13); System.out.println(Card.toString(c0)); System.out.println(Card.toString(c1)); System.out.println(Card.toString(c2)); System.out.println(Card.toString(c3)); }
qui affichera :
h2 D10 S11 C13
Deposez votre implémentation de Card.java ici:
Maintenant que vous avez écrit la classe Card, implémentez une classe CardList, comportant les champs suivants:
La classe doit avoir un constructeur explicite CardList(Card c, CardList l), qui prend comme paramètres une carte et une liste et qui renvoie une nouvelle liste avec la carte c en tête.
Ajouter une méthode static String toString(CardList l), qui renvoie une flêche (''->''), puis la valeur des cartes en utilisant Card.toString(Card c) dans la liste comme suit:
->H1->C3->S13
La classe CardList sera testée en ajoutant la méthode suivante a la classe CardList:
public static void main(String[] args){ CardList l = new CardList(new Card(0,1),null); l = new CardList(new Card(1,10),l); l = new CardList(new Card(2,11),l); l = new CardList(new Card(3,13),l); System.out.println(CardList.toString(l)); }
qui affichera :
->C13->S11->D10->H1
Deposez votre implémentation de CardList.java ici:
Ajouter une méthode static void swap(CardList l, int i, int j) à la classe CardList. Cette méthode devra échanger les cartes aux position i et j dans la liste. Attention: ne faire qu'un seul parcours de la liste.
Cette méthode sera testée en utilisant la méthode suivante:
public static void main(String[] args){ CardList l = new CardList(new Card(0,1),null); l = new CardList(new Card(1,10),l); l = new CardList(new Card(2,11),l); l = new CardList(new Card(3,13),l); System.out.println(CardList.toString(l)); CardList.swap(l, 0, 3); System.out.println(CardList.toString(l)); }
qui affichera :
->C13->S11->D10->H1 ->H1->S11->D10->C13
Déposez le code modifié de CardList.java ici:
Ajouter une méthode static CardList insert(Card c, int pos, CardList l), qui ajoute la carte c en position pos dans la liste l, et qui renvoie une référence à une nouvelle liste avec la carte c ajoutée.
La méthode insert sera testée en utilisant le programme test suivant:
public static void main(String[] args){ List l = new CardList(new Card(0,1),null); l = new CardList(new Card(1,10),l); l = new CardList(new Card(2,11),l); l = new CardList(new Card(3,13),l); System.out.println(CardList.toString(l)); l = CardList.insert(new Card(1,8), 2, l); System.out.println(CardList.toString(l)); }
qui affichera :
->C13->S11->D10->H1 ->C13->S11->D8->D10->H1
Déposez le code modifié de CardList.java ici:
La pioche contient une liste ordonnée de cartes, ainsi que les opérations "shuffle" (battre les cartes) et "draw" (tirer une carte). L'opération "shuffle" change l'ordre des cartes dans la liste de manière aléatoire, sans être nécessairement uniforme. L'opération "draw" enlève et retourne la première carte de la liste.
Implémenter une classe Deck comportant les champs suivants:
La classe doit avoir un constructeur explicite Deck(), qui crée a CardList cl avec les 52 cartes du jeu, 13 de chaque couleur.
Ajouter une méthode static String toString(Deck p), qui renvoie une cha”ne de caractères décrivant les cartes dans la pioche en utilisant la méthode CardList.toString(...).La classe Deck sera testée en utilisant le programme test suivant:
public static void main(String[] args){ Deck d = new Deck(); System.out.println(Deck.toString(d)); }
qui affichera par exemple (mais sur une seule ligne que nous avons découpée ici pour plus de lisibilité):
->C13->C12->C11->C10->C9->C8->C7->C6->C5->C4->C3->C2->C1 ->S13->S12->S11->S10->S9->S8->S7->S6->S5->S4->S3->S2->S1 ->D13->D12->D11->D10->D9->D8->D7->D6->D5->D4->D3->D2->D1 ->h23->h22->h21->h20->H9->H8->H7->H6->H5->H4->H3->h3->h2
Déposez votre implémentation de Deck.java ici:
Ajouter une méthode static void shuffle(Deck d) à la classe Deck, qui change l'ordre des cartes dans la liste de manière aléatoire en appelant plusieurs fois les méthodes swap et insert (une seule des deux suffirait, mais vous savez : les bretelles et la ceinture ...).
La méthode shuffle sera testée en utilisant le programme test suivant:
public static void main(String[] args){ Deck d = new Deck(); System.out.println(Deck.toString(d)); Deck.shuffle(d); System.out.println(); System.out.println(Deck.toString(d)); }
qui affichera (par exemple) :
->C13->C12->C11->C10->C9->C8->C7->C6->C5->C4->C3->C2->C1 ->S13->S12->S11->S10->S9->S8->S7->S6->S5->S4->S3->S2->S1 ->D13->D12->D11->D10->D9->D8->D7->D6->D5->D4->D3->D2->D1 ->h23->h22->h21->h20->H9->H8->H7->H6->H5->H4->H3->h3->h2 ->S13->C12->S5->D3->C9->C8->S11->C6->S6->C4->D7->C10->C2 ->S4->S12->D2->D10->S9->S2->S7->D11->C3->D13->h3->S8->H4 ->h22->H6->C5->S10->D9->D8->D12->C7->D4->h20->C1->S3->D1 ->h23->C13->h21->h2->H9->H8->H7->C11->H5->S1->H3->D6->D5
Déposez le code modifié de Deck.java ici:
Ajouter une méthode static Carte draw(Deck p), qui renvoie et enlève la première carte de la pioche. Si la pioche est vide, draw renvoie null.
La méthode draw sera testée en utilisant le programme test suivant:
public static void main(String[] args){ Deck d = new Deck(); System.out.println(Deck.toString(d)); Card c = Deck.draw(d); System.out.println("Drew the card: "+Card.toString(c)); System.out.println("The deck now contains:"); System.out.println(Deck.toString(d)); }
qui affichera :
->C13->C12->C11->C10->C9->C8->C7->C6->C5->C4->C3->C2->C1 ->S13->S12->S11->S10->S9->S8->S7->S6->S5->S4->S3->S2->S1 ->D13->D12->D11->D10->D9->D8->D7->D6->D5->D4->D3->D2->D1 ->h23->h22->h21->h20->H9->H8->H7->H6->H5->H4->H3->h3->h2 Drew the card: C13 The deck now contains: ->C12->C11->C10->C9->C8->C7->C6->C5->C4->C3->C2->C1 ->S13->S12->S11->S10->S9->S8->S7->S6->S5->S4->S3->S2->S1 ->D13->D12->D11->D10->D9->D8->D7->D6->D5->D4->D3->D2->D1 ->h23->h22->h21->h20->H9->H8->H7->H6->H5->H4->H3->h3->h2
Déposez le code modifié de Deck.java ici:
Nous avons maintenant à notre disposition toutes les classes pour réaliser le jeu BlackJack ...
Implémenter une classe BlackJack, comportant une méthode public static int getPoints(Card c). Cette méthode renvoie le nombre de points de la carte donnée en argument, comme défini dans l'introduction.
Cette méthode sera testée en utilisant le programme test suivant:
public static void main(String[] args){ Card c0 = new Card(0,1); Card c1 = new Card(1,10); Card c2 = new Card(2,11); Card c3 = new Card(3,13); System.out.println(BlackJack.getPoints(c0)); System.out.println(BlackJack.getPoints(c1)); System.out.println(BlackJack.getPoints(c2)); System.out.println(BlackJack.getPoints(c3)); }
qui affichera:
1 10 10 10
Déposez votre implémentation de BlackJack.java ici:
Ajouter à la classe BlackJack une méthode static int getScore(CardList l), qui prend comme paramètre une liste de cartes et qui renvoie la somme de points des cartes de la liste.
Cette méthode sera testée en utilisant le programme test suivant:
public static void main(String[] args){ List l = new CardList(new Card(0,1),null); l = new CardList(new Card(1,10),l); l = new CardList(new Card(2,11),l); l = new CardList(new Card(3,13),l); System.out.println(BlackJack.getScore(l)); }
qui affichera :
31
Déposez le code modifié de BlackJack.java ici:
Le joueur humain peut donner les commandes draw ou stay, en tappant 'd' ou 's' au clavier. Pour cela, ajouter à la classe BlackJack une méthode static String getCommand() comme suit :
static char getCommand(){ char c = ' '; try{ java.io.Reader in = new java.io.InputStreamReader(System.in); while (c!='d' && c!='s'){ System.out.print("Enter d for draw, s for stand: "); c = (char)in.read(); } } catch (java.io.IOException e){ System.out.println("IO Exception: "+e); } return c; }
Ajouter une méthode
static CardList humanPlayer(Deck d)à la classe BlackJack qui prend en argument une pioche déjà initialisée, et qui renvoie la liste des cartes (la main) obtenue par la joueur humain.
La méthode humanPlayer(...) va donc boucler jusqu'à ce que le joueur décide d'arrêter (en tapant 's' sur la clavier) ou jusqu'à ce que la somme de ses cartes dépasse 21. A chaque itération, l'ordinateur va soliciter la décision du joueur. Si le joueur humain tape 'd', une carte est tirée de la pioche, elle est affichée sur l'écran et ajoutée à la liste des cartes du joueur.
Si la somme des cartes du joueur dépasse 21, l'ordinateur affichera sur l'écran "You lost, your score was > 21".
Un exemple de dialogue où le joueur humain s'arrête avant que la somme de ses cartes ne dépasse 21 est comme suit:
Enter 'd' for draw, 's' for stand: d ->C7 -- Score: 7 Enter 'd' for draw, 's' for stand: d ->C12->C7 -- Score: 17 Enter 'd' for draw, 's' for stand: s
Un exemple de dialogue où le joueur humain perd parce que la somme de ses cartes dépasse 21 est comme suit:
Enter 'd' for draw, 's' for stand: d ->C5 -- Score: 5 Enter 'd' for draw, 's' for stand: d ->H8->C5 -- Score: 13 Enter 'd' for draw, 's' for stand: d ->C11->H8->C5 -- Score: 23 You lost, your score was > 21
Déposez le code modifié de BlackJack.java ici:
Si le joueur humain décide de s'arrêter avant que la somme de ses cartes ne dépasse 21, c'est à l'ordinateur de jouer. Ajouter une méthode static CardList computerPlayer(Deck d, int humanScore) à la classe BlackJack qui prend en argument la pioche déjà utilisée par le joueur humain et le score du joueur humain, et qui renvoie la liste des cartes (la main) obtenues par l'ordinateur.
La stratégie de cette méthode est pour l'ordinateur de tirer des cartes jusqu'à ce que son score dépasse le score du joueur humain. Quand le score de l'ordinateur dépasse 21 ou quand le score de l'ordinateur dépasse le score du joueur humain, la méthode computerPlayer(...) renvoie la liste des cartes obtenues par l'ordinateur.
Déposez le code modifié de BlackJack.java ici:
Ajouter une méthode public static void main (String[] args) à la classe BlackJack qui initialise le jeu et intègre les méthodes humanPlayer(...) et computerPlayer(...) pour jouer au BlackJack.
Si l'ordinateur a perdu, la méthode affiche:
You won, your score was 21 and the computer scored 27
Si l'ordinateur a gagné, la méthode affiche:
You lost, your score was 17 and the computer scored: 18
Déposez le code modifié de BlackJack.java ici: