INF 421 - TD 1
Révision & BlackJack

T. Clausen


 Login :  Mot de passe :

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é).

0. Préparation & Introduction

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".

0.1 Organiser ses fichiers

Créer un répertoire dédié à INF421, dans lequel tous les fichiers se rapportant aux TDs seront stockés :

  • Ouvrir un terminal
  • Entrer la commande mkdir ~/INF421
  • Créer un sous-répertoire par TD : mkdir ~/INF421/TD{1,2,3,4,5,6,7,8,9}
  • 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/).

    0.2 Emacs

    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.

    0.3 Pré-requis et indices pour la résolution des exercices de ce TD

    Il est important que vous vous respectiez les règles suivantes :

  • nommer les classes, variables et méthodes EXACTEMENT comme demandé dans l'énoncé
  • utiliser un fichier différent pour chaque classe java et nommer ce fichier en rapport avec le nom de la classe
  • coder de manière claire et organisée de sorte que votre code soit aisément lisible par un tiers. Des commentaires pertinents seront appréciés.
  • 0.4 Hello World

    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:

    Le nom du fichier à déposer
    Il faut se connecter avant de pouvoir déposer

    1. Cartes

    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.

    1.1 Les Cartes

    Implémenter une classe Card, comportant les champs suivants:

  • color - un caractère qui peut prendre une valeur parmis
  • 'H' - pour Coeur
  • 'D' - pour Carreaux
  • 'S' - pour Pique
  • 'C' - pour Trèfle
  • value - qui est un entier dans [1,13] indiquant la valeur d'une carte
  • 1 - As
  • 2-10 - la valeur inscrite sur la carte
  • 11 - Valet
  • 12 - Dame
  • 13 - Roi
  • 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:

  • 0 == Coeur
  • 1 == Carreaux
  • 2 == Pique
  • 3 == Trèfle
  • 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:

    Le nom du fichier à déposer
    Il faut se connecter avant de pouvoir déposer

    2 Liste de Cartes

    Maintenant que vous avez écrit la classe Card, implémentez une classe CardList, comportant les champs suivants:

  • content - la première carte de la liste
  • next - la suite de la liste après la première carte
  • 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:

    Le nom du fichier à déposer
    Il faut se connecter avant de pouvoir déposer

    2.1 échange de deux cartes

    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:

    Le nom du fichier à déposer
    Il faut se connecter avant de pouvoir déposer

    2.2 Inserer une carte dans la liste à une position donnée

    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:

    Le nom du fichier à déposer
    Il faut se connecter avant de pouvoir déposer

    3 Pioche

    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:

  • cl - une Liste de Cartes
  • 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:

    Le nom du fichier à déposer
    Il faut se connecter avant de pouvoir déposer

    3.1 Battre les Cartes

    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:

    Le nom du fichier à déposer
    Il faut se connecter avant de pouvoir déposer

    3.2 Tirer les Cartes

    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:

    Le nom du fichier à déposer
    Il faut se connecter avant de pouvoir déposer

    4 Jouer au BlackJack

    Nous avons maintenant à notre disposition toutes les classes pour réaliser le jeu BlackJack ...

    4.1 Le nombre de points d'une carte

    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:

    Le nom du fichier à déposer
    Il faut se connecter avant de pouvoir déposer

    4.2 La Valeur d'une Main

    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 nom du fichier à déposer
    Il faut se connecter avant de pouvoir déposer

    4.3 Interaction avec le Joueur Humain

    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;
    }
    

    4.4 Le joueur humain

    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:

    Le nom du fichier à déposer
    Il faut se connecter avant de pouvoir déposer

    4.5 L'ordinateur

    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:

    Le nom du fichier à déposer
    Il faut se connecter avant de pouvoir déposer

    4.6 La dernière étape

    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:

    Le nom du fichier à déposer
    Il faut se connecter avant de pouvoir déposer