Aller au contenu

Chapitre 2. Programmation orientée objet (POO)

Évaluation des prérequis

Quizz introductif

Exceptionnellement, en cas d’oubli ou de décharge de votre ordinateur, vous pouvez participer au quizz depuis votre smartphone.

Avant tout, vérifier que le son de votre appareil est coupé.

Dans la suite, pour participer au quizz, il vous sera demandé :

  • d’entrer un code PIN. Ce code PIN est affiché au tableau pendant les minutes qui précèdent le lancement du quizz.
  • de choisir un pseudo. Veuillez s’il vous plaît choisir comme pseudo votre prénom pour que l’on puisse identifier les scores au cours du quizz.

Une fois ces deux étapes réalisées, vous devrez patienter le temps que tous les élèves de la classe soient connecté-e-s.

Attention, chaque question à choix multiples du quizz est chronométrée (20 à 30 secondes) et plus vous êtes rapide, plus vous recevez de points !

Pour rejoindre la salle d’attente du quizz, rendez-vous à l’adresse www.kahoot.it et suivre les étapes proposées.

Information destinée au/à la professeur-e

Pour projeter puis lancer le quizz, réaliser les étapes ci-dessous.

  1. Cliquez sur le lien donné ci-apprès.
  2. Cliquez sur le bouton Connexion (si vous avez déjà un compte Kahoot) ou sur le bouton S’inscrire pour vous créer un compte Kahoot.
  3. La page vous proposant des forfaits payants est susceptible de s’afficher. Scrollez vers la bas et choisissez Continue with basic qui permet une utilisation gratuite de Kahoot.
  4. Ouvrez la salle d’attente du quizz en appuyant sur le bouton Commencer.
  5. Les élèves se connectent à l’aide du code PIN depuis leur téléphone ou leur ordinateur, leurs prénoms apparaissent à l’écran.
  6. Lorque toute la classe est connectée, appuyez sur le bouton Commencer.

Lien vers le quizz

Correction du QCM (Google Colab)

Activités d’introduction

Activité 1. Voitures

Objectif. Découvrir le vocabulaire de la POO

Enoncé

Pour découvrir le vocabulaire de la POO, prenons l'exemple de voitures.

Définir la catégorie d'objets Voiture c'est lister l'ensemble de ses caractéristiques et fonctionnalités. Par exemple donnons une définition minimale d'une catégorie Voiture.

  • La catégorie Voiture a pour caractéristiques :
    • couleur
    • nombre de places
    • motorisation
  • La catégorie Voiture a pour fonctionnalités :
    • avancer
    • reculer
    • freiner
    • tourner à droite ou à gauche
  • Une voiture_1 en particulier est une représentante de la catégorie Voiture. La valeur de chacune de ses caractéristiques est spécifique. Par exemple :
    • couleur : 'rouge'
    • nombre de places : 5
    • motorisation : 'essence'
    Les valeurs des caractéristiques peuvent être différentes ou identiques entre deux représentantes de la catégorie Voiture. Par exemple, une voiture_2 pourrait avoir les caractéristiques suivantes :
    • couleur : 'rouge'
    • nombre de places : 7
    • motorisation : 'électrique'
  • Contrairement aux valeurs des caractéristiques qui peuvent être différentes entre représentants de la catégorie Voiture, tous les représentants de la catégorie Voiture partagent les mêmes fonctionnalités c'est-à-dire :
    • avancer
    • reculer
    • freiner
    • tourner à droite ou à gauche

Compléter le tableau ci-après avec les mots suivants : Classe, Instance, Méthodes, Attributs.

Vocabulaire courant Vocabulaire de la POO
Catégorie d'objets ... d'objets
Représentant d'une catégorie d'objets ... d'une classe d'objets
Caractéristiques d'une catégorie d'objets ... d'une classe d'objets
Fonctionnalités d'une catégorie d'objets ... d'une classe d'objets
Correction
Vocabulaire courant Vocabulaire de la POO
Catégorie d'objets Classe d'objets
Représentant d'une catégorie d'objets Instance d'une classe d'objets
Caractéristiques d'une catégorie d'objets Attributs d'une classe d'objets
Fonctionnalités d'une catégorie d'objets Méthodes d'une classe d'objets

Activité 2. Danse de tortues

Objectif. Utiliser les méthodes d’une classe d’objets prédéfinie

Activité 3. Points du plan

Objectif. Définir une nouvelle classe d’objets

Résumé des notions sur un exemple

Diaporama

Travaux pratiques

TP1. Points, segments et polygones

Objectifs. Définir des classes d’objets, programmer avec des objets

TP2. Listes, files et piles

Objectif. Implémenter listes, files et piles par des classes d’objets sans utiliser les types construits Python préexistants (tuple, list, dict)

TP3. Bulles

Objectif. Programmmer une animation à partir de classes d’objets

calhier Jupyter dans Capytale

Exercices type Bac

Laser game (Métropole, 11 mai 2022)

Les participants à un jeu de laser game sont répartis en équipes et s’affrontent dans ce jeu de tir, revêtus d’une veste à capteurs et munis d’une arme factice émettant des infrarouges. Les ordinateurs embarqués dans ces vestes utilisent la programmation orientée objet pour modéliser les joueurs. La classe Joueur est définie comme suit :

class Joueur:

    def __init__(self, pseudo, identifiant, equipe):
        """Constructeur"""
        self.pseudo = pseudo
        self.equipe = equipe
        self.id = identifiant
        self.nb_de_tirs_emis = 0
        self.liste_id_tirs_recus = []
        self.est_actif = True

    def tire(self):
        """Méthode déclenchée par l'appui sur la gachette"""
        if self.est_actif:
            self.nb_de_tirs_emis = self.nb_de_tirs_emis + 1

    def est_determine(self):
        """Méthode qui renvoie True si le joueur réalise un grand nombre de tirs"""
        return self.nb_de_tirs_emis > 500

    def subit_un_tir(self, id_recu):
        """Méthode déclenchée par les capteurs de la veste"""
        if self.est_actif:
            self.est_actif = False
            self.liste_id_tirs_recus.append(id_recu)
  1. Parmi les instructions suivantes, recopier celle qui permet de déclarer un objet joueur1, instance de la classe Joueur, correspondant à un joueur dont le pseudo est "Sniper", dont l’identifiant est 319 et qui est intégré à l’équipe "A":
    • Instruction 1 : joueur1 = ["Sniper", 319, "A"]
    • Instruction 2 : joueur1 = new Joueur["Sniper", 319, "A"]
    • Instruction 3 : joueur1 = Joueur("Sniper", 319, "A")
    • Instruction 4 : joueur1 = Joueur{"pseudo": "Sniper", "id": 319, "equipe": "A"}
    Réponse attendue

    Instruction 3 : joueur1 = Joueur("Sniper", 319, "A")

    Explications. Pour déclarer une instance de la classe Joueur, on écrit le nom de la classe suivi de parenthèses contenant la liste des valeurs prises par les paramètres positionnels obligatoires du constructeur de cette classe, ici pseudo, identifiant, equipe.

  2. La méthode subit_un_tir réalise les actions suivantes. Lorsqu’un joueur actif subit un tir capté par sa veste, l’identifiant du tireur est ajouté à l’attribut liste_id_tirs_recus et l’attribut est_actif prend la valeur False (le joueur est désactivé). Il doit alors revenir à son camp de base pour être de nouveau actif.
    1. Écrire la méthode redevenir_actif qui rend à nouveau le joueur actif uniquement s’il était précédemment désactivé.
      Réponse attendue

      Le symbole ... représente ci-après le début de la classe Joueur qui n'a pas été écrit. On propose ci-dessous deux solutions possibles, la première étant plus élégante, utilisant l'opérateur logique not.

      Solution 1.

      class Joueur:
          ...
          def redevenir_actif(self):
              if not self.est_actif:
                  self.est_actif = True
      

      Solution 2.

      class Joueur:
          ...
          def redevenir_actif(self):
              if self.est_actif == False:
                  self.est_actif = True
      

      Remarque. La méthode redevenir_actif est une opération de type opérateur : elle modifie l'instance de classe en changeant la valeur de son attribut est_actif. La méthode redevenir_actif ne renvoie donc rien d'où l'absence du mot-clé return.

    2. Écrire la méthode nb_de_tirs_recus qui renvoie le nombre de tirs reçus par un joueur en utilisant son attribut liste_id_tirs_recus.
      Réponse attendue

      Le symbole ... ci-après représente le début de la classe Joueur qui n'a pas été écrit.

      class Joueur:
          ...
          def nb_de_tirs_recus(self):
              return len(self.liste_id_tirs_recus)
      

      Explications. Dans le constructeur __init__ de la classe Joueur, l'attribut liste_id_tirs_recus est initialisé comme liste vide []. La méthode subit_un_tir de la classe Joueur ajoute en bout de cette liste (avec la méthode de liste append) l'identifiant de chaque joueur qui touche self avec son laser. Ainsi, pour connaître le nombre de tirs reçus, il suffit de connaître la longueur de la liste liste_id_tirs_recus obtenu à l'aide de la fonction len. La méthode nb_de_tirs_recus est une opération du type accesseur : elle ne modifie pas l'instance de classe mais fournit une information sur elle : le nombre de tirs recus. On utilise donc le mot-clé return pour renvoyer cette information.

  3. Lorsque la partie est terminée, les participants rejoignent leur camp de base respectif où un ordinateur, qui utilise la classe Base, récupère les données. La classe Base est définie par :
    • ses attributs :
      • equipe : nom de l’équipe (str), par exemple "A" ;
      • liste_des_id_de_l_equipe qui correspond à la liste (list) des identifiants connus des joueurs de l’équipe ;
      • score : score (int) de l’équipe dont la valeur initiale est 1000 ;
    • ses méthodes :
      • est_un_id_allie qui renvoie True si l’identifiant passé en paramètre est un identifiant d’un joueur de l’équipe, False sinon ;
      • incremente_score qui fait varier l’attribut score du nombre passé en paramètre ;
      • collecte_information qui récupère les statistiques d’un participant passé en paramètre (instance de la classe Joueur) pour calculer le score de l’équipe .
    On présente ci-dessous la méthode collecte_information de la classe Base. Les caractères ... représentent le début de la classe Base qui n'a pas été écrit.
    class Base:
        ...
        def collecte_information(self, participant):
            if participant.equipe == self.equipe : # test 1
                for id in participant.liste_id_tirs_recus:
                    if self.est_un_id_allie(id): # test 2
                        self.incremente_score(-20)
                    else:
                        self.incremente_score(-10)
    
    1. Indiquer le numéro du test (test 1 ou test 2) qui permet de vérifier qu’en fin de partie un participant égaré n’a pas rejoint par erreur la base adverse.
      Réponse attendue

      test 1.

      Explications. Lorsqu'un participant (joueur) s'approche d'une base, la méthode collecte_information doit prendre en compte le joueur uniquement si son équipe correspond à celle de la base. Cela est assuré par le test participant.equipe == self.equipeparticipant représente le joueur et self représente la base. Si le joueur est bien de l'équipe de la base, alors la boucle for parcours la liste des identifiants de joueurs à l'origine de tirs reçus par le joueur et incrémente le score. Le test 2. permet pour chaque tir reçu de savoir si ce tir provient d'un joueur ennemi ou allié.

    2. Décrire comment varie quantitativement le score de la base lorsqu’un joueur de cette équipe a été touché par le tir d’un coéquipier.
      Réponse attendue

      Lorsqu'un joueur de cette équipe a été touché par le tir d'un coéquipier (si self.est_un_id_allie(id) renvoie True, test 2.), 20 points sont retirés au score de l'équipe.

  4. On souhaite accorder à une base un bonus de 40 points pour chaque joueur de son équipe particulièrement déterminé (qui réalise un grand nombre de tirs). On a réécrit ci-dessous la méthode collecte_information que l'on souhaite modifier.
    class Base:
        ...
        def collecte_information(self, participant):
            if participant.equipe == self.equipe : # test 1
                for id in participant.liste_id_tirs_recus:
                    if self.est_un_id_allie(id): # test 2
                        self.incremente_score(-20)
                    else:
                        self.incremente_score(-10)
                # si le participant réalise un grand nombre de tirs
                ...
                    # le score de la base augmente de 40 points
                    ...
    
    Recopier et compléter la méthode collecte_information en remplaçant les deux derniers ... par les bonnes insructions. Utiliser les méthodes des classes Joueur et Base.
    Réponse attendue
    class Base:
        ...
        def collecte_information(self, participant):
            if participant.equipe == self.equipe : # test 1
                for id in participant.liste_id_tirs_recus:
                    if self.est_un_id_allie(id): # test 2
                        self.incremente_score(-20)
                    else:
                        self.incremente_score(-10)
                # si le participant réalise un grand nombre de tirs
                if participant.est_determine():
                    # le score de la base augmente de 40 points
                    self.incremente_score(40)
    

    Remarque. On utilise la méthode est_determine de la classe Joueur pour tester la "détermination" du joueur participant. C'est une méthode de classe, attention à penser aux parenthèses ! On ne précise aucun argument dans les parenthèses car cette méthode prend pour unique paramètre self. L'examen de cette méthode dans la classe Joueur indique qu'un joueur est considéré comme déterminé s'il a réalisé plus de 500 tirs.

  5. On suppose l'existence d'une troisième classe Equipe dont on donne une extrait de la définition ci-dessous.
    class Equipe:
    
        def __init__(self, nom):
            self.nom = nom
            self.liste_joueurs = []
    
        def ajouter_joueur(self, joueur):
            ...
    
    1. L'attribut self.liste_joueur de la classe Equipe est un tableau (type list) au départ vide qui va contenir la liste des joueurs de l'équipe, c'est-à-dire une liste d'objets de la classe Joueur. Compléter la définition de la méthode ajouter_joueur de la classe Equipe permettant d'ajouter un joueur à l'équipe.
      Réponse attendue
      class Equipe:
          ...
          def ajouter_joueur(self, joueur):
              self.liste_joueurs.append(joueur)
      
    2. Écrire une méthode est_determinee de la classe Equipe qui renvoie True si la proportion de joueurs déterminés de cette équipe est supérieure ou égale à 50% et False sinon.
      Réponse attendue
      class Equipe:
          ...
          def est_determinee(self):
              nb_joueurs_determines = 0
              for joueur in self.liste_joueurs:
                  if joueur.est_determine():
                      nb_joueurs_determines += 1
              return nb_joueurs_determines/len(self.liste_joueurs) >= 0.5