Aller au contenu

Asie Mai 2022 sujet 2

Sujet complet sur le site de David Roche : https://pixees.fr/informatiquelycee/term/suj_bac/2022/sujet_09.pdf

Exercice 1⚓︎

L'entreprise capNSI gère les contrats de ses clients en créant pour chacun d'eux un sous-dossier dans le dossier Contrats sur leur ordinateur central. Le système d'exploitation de cet ordinateur est une distribution linux. Quelques commandes de bases pour ce système d'exploitation sont rappelées ci-dessous.

"commandes"

Dans la console représentée sur la figure ci-dessous, on peut visualiser les répertoires (ou dossiers) à la racine de l'ordinateur central avec l'instruction ls.

"commandes"

  1. Question 1.

    a. Donner le nom de l'utilisateur et le nom de l'ordinateur correspondant à la capture d'écran précédente. b. Ecrire les instructions permettant d'afficher la liste des dossiers clients du répertoire Contrats en partant de la situation ci-dessous :

    "commandes"

    Réponse à la question 1

    Le nom de l'utilisateur est gestion. Le nom de l'ordinateur est capNSI-ordinateur_central.

    Pour afficher la lises des dossiers clients du répértoire Contrats en partant du répertoire personnel représenté par le raccourci ~, on peut écrire :

    Bash
    gestion@capNSI-ordinateur_central:~$ cd Contrats
    gestion@capNSI-ordinateur_central:~/Contrats$ ls
    

    On peut aussi écrire plus simplement :

    Bash
    gestion@capNSI-ordinateur_central:~$ ls Contrats
    

    Après une campagne de démarchage, l'entreprise a gagné un nouveau client, Monsieur Alan Turing. Elle souhaite lui créer un sous-dossier nommé TURING_Alan dans le dossier Contrats. De plus, elle souhaite attribuer tous les droits à l'utilisateur et au groupe et seulement la permission en lecture pour tous les autres utilisateurs. La commande chmod permet de le faire

  2. Question 2.

    a. Ecrire les instructions permettant de créer le sous-dossier TURING_Alan à partir du répertoire racine. b. Ecrire l'instruction permettant d'attribuer les bons droits au sous-dossier TURING_Alan.

    Réponse à la question 2

    Pour créer le dossier TURING_CONTRAT depuis le répertoire personnel de l'utilisateur gestion, on peut écrire :

    Bash
    gestion@capNSI-ordinateur_central:~$ mkdir Contrats/TURING_CONTRAT
    

    Pour affecter les bons droits au dossier de chemin relatif Contrats/TURING_CONTRAT, on peut écrire :

    Bash
    gestion@capNSI-ordinateur_central:~$ chmod ug=rwx,o=r testContrats/TURING_CONTRAT
    

    ou encore en notation octale (4 : lecture, 2: écriture, 1:exécution) :

    Bash
    gestion@capNSI-ordinateur_central:~$ chmod 774 Contrats/TURING_CONTRAT
    

    Le chiffre des centaines 7 = 4 + 2 + 1 dénote les droits rwx pour le profil propriétaire. Le chiffre des dizaines 7 = 4 + 2 + 1 dénote les droits rwx pour le profil groupe. Le chiffre des dunités 4 = 4 + 0 + 0 dénote les droits r-- pour le profil autres.

    L'exemple de syntaxe de chmod fourni dans l'énoncé semble incorrect, en tout cas pour la version bash de la ligne de commande. Voici quelques exemples de syntaxe fournis par la commande tldr.

    Bash
    prof@nsi:~$ tldr chmod
    chmod
    Change the access permissions of a file or directory.More information: https://www.gnu.org/software/coreutils/chmod.
    
    - Give the [u]ser who owns a file the right to e[x]ecute it:
    chmod u+x {{ file }}
    
    - Give the [u]ser rights to [r]ead and [w]rite to a file/directory:
    chmod u+rw {{ file_or_directory }}
    
    - Remove e[x]ecutable rights from the [g]roup:
    chmod g-x {{ file }}
    
    - Give [a]ll users rights to [r]ead and e[x]ecute:
    chmod a+rx {{ file }}
    
    - Give [o]thers (not in the file owner's group) the same rights as the [g]roup:
    chmod o=g {{ file }}
    
    - Remove all rights from [o]thers:
    chmod o= {{ file }}
    
    - Change permissions recursively giving [g]roup and [o]thers the ability to [w]rite:
    chmod -R g+w,o+w {{ directory }}
    

    En Python, le module os permet d'interagir avec le système d'exploitation. Il permet de gérer l'arborescence des fichiers, des dossiers, de fournir des informations sur le système d'exploitation. Par exemple, le code de la page suivante, exécuté dans la console, permet de créer le sous-dossier TURING_Alan précédent :

    🐍 Script Python
    >>> import os
    >>> os.mkdir("Contrats/TURING_Alan")
    >>> os.chmod("Contrats/TURING_Alan", 774)
    

    L'entreprise dispose d'un tableau de nouveaux clients :

    🐍 Script Python
    tab_clients = [
    ('LOVELACE', 'Ada'),
    ('BOOLE', 'George'),
    ('VONNEUMANN', 'John'),
    ('SHANNON', 'Claude'),
    ('KNUTH', 'Donald')
    ]
    

    Elle souhaite automatiser le formatage des tableaux des nouveaux clients. Elle souhaite également automatiser la création et l'attribution des droits des dossiers portant les noms des nouveaux clients.

  3. Ecrire une fonction formatage(tab) qui prend en paramètre un tableau de tuplets (Nom, Prenom) des nouveaux clients et renvoie un tableau de chaines de caractères. Par exemple, formatage(tab_clients) renvoie :

    🐍 Script Python
    ['LOVELACE_Ada', 'BOOLE_George', 'VONNEUMANN_John','SHANNON_Claude', 'KNUTH_Donald']
    
    Réponse à la question 3
    🐍 Script Python
    def formatage(tab):
        tab2 = []
        for (nom, prenom) in tab:
            tab2.append(nom + '_' + prenom)
        return tab2
    

    Autre version en compréhension :

    🐍 Script Python
    def formatage(tab):
        return [nom + '_' + prenom for (nom, prenom) in tab]
    

    Ou encore sans déballage de tuple :

    🐍 Script Python
    def formatage(tab):
        return [v[0] + '_' + v[1] for v in tab]
    
  4. Ecrire une fonction creation_dossiers(tab) qui prend en paramètre un tableau de chaînes de caractères et qui crée et modifie les droits des dossiers au nom de ces chaines de caractères avec les mêmes droits que le sous-dossier TURING_Alan.

    Réponse à la question 4
    🐍 Script Python
    def creation_dossiers(tab):            
        for nom_dossier in tab:
            dossier = "Contrats/" + nom_dossier
            os.mkdir(dossier)
            os.chmod(dossier, 774)
    

Exercice 2⚓︎

Un arbre binaire de recherche est un arbre binaire pour lequel chaque nœud possède une étiquette dont la valeur est supérieure ou égale à toutes les étiquettes des nœuds de son fils gauche et strictement inférieure à celles des nœuds de son fils droit. On rappelle que :

  • sa taille est son nombre de nœuds ;
  • sa hauteur est le nombre de niveaux qu'il contient.

Un éditeur réédite des ouvrages. Il doit gérer un nombre important d'auteurs de la littérature. Pour stocker le nom des auteurs, il utilise un programme informatique qui les enregistre dans un arbre binaire de recherche.

L'arbre vide sera noté Null pour les algorithmes de cet exercice. Si A est un nœud non vide, valeur(A) renvoie le nom de l'auteur ; fils_gauche(A) renvoie le fils gauche du nœud A et fils_droit(A) renvoie le fils droit du nœud A.

L'ordre alphabétique est utilisé pour classer le nom des auteurs.

Par exemple, on a APOLLINAIRE < BAUDELAIRE.

Ainsi, pour tout nœud A, si fils_gauche(A) et fils_droit(A) ne sont pas Null, on a :

📋 Texte
valeur(fils_gauche(A)) <= valeur(A) < valeur(fils_droit(A)).

Par exemple, l'arbre binaire suivant A1 est un arbre binaire de recherche :

graph TD
    N0(ELUARD) --> N2(ARAGON)
    N0   --> N1(VOLTAIRE)
    N2  --> N5(APOLLINAIRE)
    N2  --> N6( )
    linkStyle 3 stroke-width:0px;
    style N6 opacity:0;
  1. Question 1.

    a. Recopier et compléter l'arbre binaire de recherche précédent en insérant successivement dans cet ordre les noms suivants :

    📋 Texte
    DUMAS ; HUGO ; ZWEIG ; ZOLA
    
    Réponse à la question 1. a.
    graph TD
    N0(ELUARD) --> N2(ARAGON)
    N0   --> N1(VOLTAIRE)
    N2  --> N5(APOLLINAIRE)
    N2  --> N6(DUMAS)
    N1 --> N7(HUGO)
    N1 --> N8(ZWEIG)
    N8 --> N9(ZOLA)
    N8 --> N10( )
    linkStyle 7 stroke-width:0px;
    style N10 opacity:0;

    b. Quelle est la taille de l'arbre obtenu ? Quelle est la hauteur de cet arbre ?

    Réponse à la question 1. b.

    La taille de l'arbre est son nombre de noeuds sout \(4+4=8\).

    La hauteur de cet arbre est son nombre de niveaux soit \(4\)

    c. Plus généralement, si l'arbre est de hauteur \(ℎ\), quel est le nombre maximal d'auteurs enregistrés dans cet arbre en fonction de \(ℎ\) ?

    Réponse à la question 1. c.

    Pour une taille \(n\) fixée, on a toujours :

    • une hauteur \(h\) maximale pour un arbre où tous les noeuds internes ont un seul fils non NULL et donc on a \(h \leqslant n\).
    • une hauteur \(h\) minimale lorsque tous les noeuds internes ont deux fils non NULL (tous les niveaux sont remplis), par exemple avec l'arbre ci-dessous. Dans ce cas, on a \(\boxed{n \leqslant 2^{h}-1}\).
    graph TD
    N0(ELUARD) --> N2(ARAGON)
    N0   --> N1(VOLTAIRE)
    N2  --> N5(APOLLINAIRE)
    N2  --> N6(DUMAS)
    N1 --> N7(HUGO)
    N1 --> N8(ZWEIG)

    On en déduit l'encadrement : \(\boxed{h \leqslant n \leqslant 2^{h}-1}\).

    Pour une taille \(h\) fixée, le nombre maximal d'auteurs \(n\) est donc \(\boxed{2^{h}-1}\).

    On peut noter que \(n < 2^{h} \Leftrightarrow \log_{2}(n) < h \Leftrightarrow \lfloor \log_{2}(n) \rfloor + 1 \leqslant h \).

    On a donc \(\boxed{\lfloor \log_{2}(n) \rfloor + 1 \leqslant h \leqslant n}\). La hauteur minimale de l'arbre est alors le nombre de chiffres de l'écriture de \(n\) en base \(2\) et le nombre maximal d'auteurs \(n\) pour un arbre de hauteur \(h\), est donc le plus grand nombre qui peut s'écrire sur \(h\) bits, soit \(2^{h}-1\).

    On définit ici l'équilibre d'un arbre binaire : il s'agit d'un nombre entier positif ou négatif. Il vaut 0 si l'arbre est vide. Sinon il vaut la différence des hauteurs des sous-arbres gauche et droit de l'arbre. Par exemple, si on considère l'arbre suivant que l'on nommera A2 :

    graph TD
    N0(KAFKA) --> N2(DURAS)
    N0   --> N1(SAGAN)
    N1  --> N4( )
    N1  --> N3(SIMENON)
    linkStyle 2 stroke-width:0px;
    style N4 opacity:0;

    Son équilibre vaut -1 car la hauteur de son sous-arbre gauche vaut 1, la hauteur de son sous-arbre droit vaut 2 et \(1 - 2 = -1\). Un arbre est dit équilibré si son équilibre vaut \(-1\), \(0\) ou \(1\). L'arbre précédent est donc équilibré.

  2. Recopier et compléter l'arbre de ce dernier exemple avec les noms FLAUBERT, BALZAC, PROUST, SAND, WOOLF, COLETTE, CHRISTIE et AUDIARD quitte à modifier l'ordre d'insertion de manière à ce que cet arbre reste équilibré.

    Réponse à la question 2
    On peut insérer dans l'ordre de l'énoncé et obtenir un arbre équlibré
    FLAUBERT, BALZAC, PROUST, SAND, WOOLF, COLETTE, CHRISTIE et AUDIARD
    graph TD
    N0(KAFKA) --> N2(DURAS)              
    N2 --> N5(BALZAC)
    N2 --> N11(FLAUBERT)    
    N5 --> N7(AUDIARD)
    N5 --> N6(COLETTE) 
    N6 --> N12(CHRISTIE) 
    N6 --> N13( )      
    N0 --> N1(SAGAN)
    N1  --> N4(PROUST)        
    N1  --> N3(SIMENON)
    N3 --> N14(SAND)
    N4 --> N15( )
    N3 --> N10( )
    N3 --> N9(WOOLF)
    
    linkStyle 6 stroke-width:0px;
    linkStyle 11 stroke-width:0px;
    linkStyle 12 stroke-width:0px;
    style N10 opacity:0;
    style N13 opacity:0;
    style N15 opacity:0;

L'éditeur souhaite utiliser une fonction récursive recherche_auteur(ABR, NOM) qui prend en paramètres ABR un arbre binaire de recherche et NOM un nom d'auteur. La fonction renvoie TRUE si NOM est une étiquette de l'arbre ABR et FALSE dans le cas contraire.

On donne la fonction suivante :

📋 Texte
Fonction mystere(ABR, t) :
    SI ABR = NULL :
        RENVOYER FAUX
    SINON SI valeur(ABR) = t :
        RENVOYER VRAI
    SINON :
        RENVOYER mystere(fils_gauche(ABR),t) OU mystere(fils_droit(ABR),t)
  1. Que renvoie l'appel mystere(A2,'SIMENON') ? Justifier la réponse.

    Réponse à la question 3

    Cette fonction récursive renvoie True si la clef t est une valeur d'un noeud de l'arbre ABR et False sinon.

    'SIMENON' est une valeur d'un noeud de l'arbre A2 donc mystere(A2,'SIMENON') renvoie True.

L'éditeur souhaite utiliser une fonction récursive hauteur(ABR) qui prend en paramètre un arbre binaire ABR et renvoie la hauteur de cet arbre.

  1. Ecrire un algorithme de la fonction hauteur(ABR) qui prend en entrée ABR un arbre binaire de recherche et renvoie sa hauteur. On pourra avoir recours aux fonctions MIN(val1, val2) et MAX(val1, val2) qui renvoient respectivement la plus petite et la plus grande valeur entre val1 et val2.

    Réponse à la question 4

    On suppose que tous les noeuds ont deux fils éventuellement NULL.

    📋 Texte
    Fonction hauteur(ABR)
        SI ABR = NULL:
            RENVOYER 0
        SINON:
            RENVOYER 1 + MAX(hauteur(fils_gauche(ABR)), hauteur(fils_droit(ABR)))
    

    Exercice 3⚓︎

Le « jeu de la vie » se déroule sur une grille à deux dimensions dont les cases, qu'on appelle des « cellules », par analogie avec les cellules vivantes,peuvent prendre deux états distincts : « vivante » (= 1) ou « morte » (= 0).

Une cellule possède au plus huit voisins, qui sont les cellules adjacentes horizontalement, verticalement et diagonalement. À chaque étape, l'évolution d'une cellule est entièrement déterminée par l'état de ses huit voisines de la façon suivante :

  • Règle 1 : une cellule morte possédant exactement trois voisines vivantes devient vivante (elle naît) ; sinon, elle reste à l'état « morte »
  • Règle 2 : une cellule vivante possédant deux ou trois voisines vivantes reste vivante, sinon elle meurt.

Voici un exemple dévolution du jeu de la vie appliquée à la cellule centrale :

"jeu de la vie"

Pour initialiser le jeu, on crée en langage Python une grille de dimension 8x8, modélisée par une liste de listes.

  1. Initialisation du tableau :

    a. Parmi les deux scripts proposés, indiquer celui qui vous semble le plus adapté pour initialiser un tableau de 0. Justifier votre choix.

    • Choix 1

      🐍 Script Python
      ligne = [0,0,0,0,0,0,0,0]
      jeu = []
      for i in range(8):
          jeu.append(ligne)
      
    • Choix 2

      🐍 Script Python
      jeu = []
      for i in range(8) :
          ligne = [0,0,0,0,0,0,0,0]
          jeu.append(ligne)
      
    Réponse à la question 1

    Le choix 1 duplique la même liste sur toutes les lignes de la grille. Le choix 2 crée bien une nouvelle liste pour chaque ligne. Il faut donc initialiser la grille avec le choix2.

  2. Donner l'instruction permettant de modifier la grille jeu afin d'obtenir

    🐍 Script Python
    >>> jeu
    [[0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 1, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0]]
    
    Réponse à la question 2

    On modifie la sixième ligne d'index 5 et la troisième colonne d'index 2, donc on écrit :

    🐍 Script Python
    jeu[5][2] = 1
    
  3. Question 3.

    a. Ecrire en langage Python une fonction remplissage(n, jeu) qui prend en paramètres un entier n et une grille jeu, et qui ajoute aléatoirement exactement n cellules vivantes dans le tableau jeu.

    b. Quelles sont les préconditions de cette fonction pour la variable n ?

    Réponse à la question 3
    🐍 Script Python
    import random
    
    def remplissage(n, jeu):
        # préconditions
        assert isinstance(n, int)  # n de type entier
        assert 0 <= n <= 64        # n positif et <= nombre de cellules dans la grille
        for _ in range(n):
            i = random.randint(0, 7)
            j = random.randint(0, 7)
            while jeu[i][j] == 1:
                i = random.randint(0, 7)
                j = random.randint(0, 7)
            jeu[i][j] = 1
    

    Les préconditions pour la variable n sont :

    🐍 Script Python
    assert isinstance(n, int)  # n de type entier
    assert 0 <= n <= 64        # n positif et <= nombre de cellules dans la grille
    

    On propose la fonction en langage Python nombre_de_vivants(i, j, jeu) qui prend en paramètres deux entiers i et j ainsi qu'une grille jeu et qui renvoie le nombre de voisins vivants de la cellule tab[i][j] :

    🐍 Script Python
    def nombre_de_vivants(i, j, jeu) :
        nb = 0
        voisins = [(i-1,j-1), (i-1,j), (i-1,j+1), (i,j+1),
                    (i+1,j+1), (i+1,j), (i+1,j-1), (i,j-1)]
        for e in voisins:
            if 0 <= ... < 8 and 0 <= ... < 8 :
                nb = nb + jeu[...][...]
        return nb
    
  4. Recopier et compléter les pointillés pour que la fonction réponde à la demande.

    Réponse à la question 4
    🐍 Script Python
    def nombre_de_vivants(i, j, jeu):
        nb = 0
        voisins = [(i-1,j-1), (i-1,j), (i-1,j+1), (i,j+1),
                    (i+1,j+1), (i+1,j), (i+1,j-1), (i,j-1)]
        for e in voisins:
            if 0 <= e[0] < 8 and 0 <= e[1] < 8 :
                nb = nb + jeu[e[0]][e[1]]
        return nb
    

    Ou une autre solution :

    🐍 Script Python
    def nombre_de_vivants(i, j, jeu):
        nb = 0
        voisins = [(i-1,j-1), (i-1,j), (i-1,j+1), (i,j+1),
                    (i+1,j+1), (i+1,j), (i+1,j-1), (i,j-1)]
        for (u, v) in voisins:
            if 0 <= u < 8 and 0 <= v < 8 :
                nb = nb + jeu[u][v]
        return nb
    
  5. En utilisant la fonction nombre_de_vivants(i, j, jeu) précédente, écrire en langage Python une fonction transfo_cellule(i, j, jeu) qui prend en paramètres deux entiers i et j ainsi qu'une grille jeu et renvoie le nouvel état de la cellule jeu[i][j] (0 ou 1)

    Réponse à la question 5
    🐍 Script Python
    def transfo_cellule(i, j, jeu):
        nb_voisins = nombre_de_vivants(i, j, jeu)
        mort = 0
        vie = 1
        etat = jeu[i][j]
        if (etat == mort):
            if nb_voisins == 3:
                etat = vie
        elif (nb_voisins < 2) or (nb_voisins > 3):
            etat = mort
        return etat
    

Exercice 4⚓︎

On souhaite gérer un club de tennis en ligne avec la possibilité de réserver un terrain à un créneau horaire. Le site ne gère que des réservations pour des matchs en simple. Voici la structure de la base de données :

Relation contenant l'ensemble des joueurs du club avec leurs identifiants⚓︎

"joueurs"

Relation précisant les matchs joués.⚓︎

"joueurs"

Relation précisant les différents terrains.⚓︎

"joueurs"

Relation précisant les créneaux réservables.⚓︎

"joueurs"

Script SQL pour générer la base de données
SQL
/*
Suppression des tables si elles existent 
si clef étrangère table A  -> clef primaire table B
on supprime d'abord table A
*/

DROP TABLE IF EXISTS matchs;
DROP TABLE IF EXISTS joueurs;    
DROP TABLE IF EXISTS terrains;
DROP TABLE IF EXISTS creneaux;

CREATE TABLE joueurs(
    id_joueur INT PRIMARY KEY,
    nom_joueur VARCHAR(30),
    prenom_joueur VARCHAR(30),
    login VARCHAR(30),
    mdp INT
    );


CREATE TABLE terrains(
    id_terrain INT PRIMARY KEY,
    nom_terrain VARCHAR(30),
    surface VARCHAR(30)
    );


    
CREATE TABLE creneaux(
    id_creneau INT PRIMARY KEY,
    plage_horaire VARCHAR(30)
    );
    


CREATE TABLE matchs(
    id_match INT PRIMARY KEY,
    date DATE,
    id_creneau INT,
    id_terrain INT,
    id_joueur1 INT,
    id_joueur2 INT,
    FOREIGN KEY(id_joueur1) REFERENCES joueurs(id_joueur),
    FOREIGN KEY(id_joueur2) REFERENCES joueurs(id_joueur),
    FOREIGN KEY(id_creneau) REFERENCES creneaux(id_creneau),
    FOREIGN KEY(id_terrain) REFERENCES terrains(id_terrain)
);

/*
Insertions dans la table joueurs
*/
INSERT INTO joueurs VALUES(1, "Dupont", "Alice", "alice", 1234) ;
INSERT INTO joueurs VALUES(2, "Durand", "Belina", "belina", 5694) ;
INSERT INTO joueurs VALUES(3, "Caron", "Camilia", "camilia", 9478) ;
INSERT INTO joueurs VALUES(4, "Dupont", "Dorine", "dorine", 1347) ;

/*
Insertions dans la table terrains
*/

INSERT INTO terrains VALUES(1, "stade", "terre battue") ;
INSERT INTO terrains VALUES(2, "gymnase", "synthétique") ;
INSERT INTO terrains VALUES(3, "hangar", "terre battue") ;

/*
Insertions dans la table créneaux
*/

INSERT INTO creneaux VALUES(1, "8h-9h") ;
INSERT INTO creneaux VALUES(2, "9h-10h") ;
INSERT INTO creneaux VALUES(3, "10h-11h") ;
INSERT INTO creneaux VALUES(4, "11h-12h") ;
INSERT INTO creneaux VALUES(5, "12h-13h") ;
INSERT INTO creneaux VALUES(6, "13h-14h") ;
INSERT INTO creneaux VALUES(7, "14h-15h") ;
INSERT INTO creneaux VALUES(8, "15h-16h") ;
INSERT INTO creneaux VALUES(9, "16h-17h") ;
INSERT INTO creneaux VALUES(10, "17h-18h") ;
INSERT INTO creneaux VALUES(11, "18h-19h") ;
INSERT INTO creneaux VALUES(12, "19h-20h") ;

/*
Insertions dans la table matchs
*/
INSERT INTO matchs VALUES(1, "2020-08-01", 2, 1, 1, 4) ;
INSERT INTO matchs VALUES(2, "2020-08-01", 3, 1, 2, 3) ;
INSERT INTO matchs VALUES(3, "2020-08-02", 6, 2, 1, 3) ;
INSERT INTO matchs VALUES(4, "2020-08-02", 7, 2, 2,4) ;
INSERT INTO matchs VALUES(5, "2020-08-08", 3, 3, 1,2) ;
INSERT INTO matchs VALUES(6, "2020-08-08", 5, 2, 3,4) ;
  1. Clés primaires/étrangères :

    a. Donner la clé primaire de la relation matchs.

    b. La relation matchs a-t-elle une ou des clés étrangères ? Si oui quelles sont-elles ?

    Réponse à la question 1

    La clef primaire de la la relation matchs est id_match, c'est le seul attribut de cette relation qui ne prend pas deux valeurs identiques sur deux nuplets/lignes distinct(e)s. La clef primaire est d'ailleurs soulignée dans le graphique.

    De même on a :

    • id_joueur clef primaire de la relation joueurs
    • id_terrain clef primaire de la relation terrains
    • id_creneau clef primaire de la relation creneaux

    La relation matchs possède quatre clefs étrangères pour lier ses nuplets à ceux des trois autres relations :

    • matchs.id_creneau fait référence à la clef primaire creneaux.id_creneau
    • matchs.id_terrain fait référence à la clef primaire terrain.id_terrain
    • matchs.id_joueur1 fait référence à la clef primaire joueurs.id_joueur
    • matchs.id_joueur2 fait référence à la clef primaire joueurs.id_joueur
  2. Par lecture et analyse des relations de la base de donnée.

    a. Déterminer le jour et la plage horaire du match entre Durand Belina et Caron Camilia.

    b. Déterminer le nom des deux joueurs qui sont les seuls à avoir joué dans le hangar.

    Réponse à la question 2

    Durand Belina (identifiant 2) et Caron Camilia (identifiant 3) s'affrontent le 01-08-2020 de 10 h à 11 h, sur le terrain de nom "stade" et d'identifiant 1.

    Le hangar, terrain d'identifiant 3, a vu s'affronter les joueurs d'identifiant 1 et 2, soit Dupont Alice et Durand Belina.

  3. Requêtes en langage SQL (On pourra s'aider de l'annexe ci-dessous) :

    a. Ecrire une requête qui renvoie les prénoms des joueurs dont le nom est 'Dupont'.

    b. Ecrire une requête qui modifie le mot de passe de Dorine Dupont, son nouveau mot de passe étant 1976.

    "annexe"

    Réponse à la question 3

    La requête suivante renvoie les prénoms des joueurs dont le nom est 'Dupont'.

    SQL
    SELECT 
        prenom_joueur 
    FROM 
        joueurs
    WHERE nom_joueur = 'Dupont' ;
    

    La requête suivante modifie le mot de passe de Dorine Dupont, son nouveau mot de passe étant 1976.

    SQL
    UPDATE
        joueurs
    SET 
        mdp = 1976
    WHERE 
        (nom_joueur = "Dupont") AND (prenom_joueur = "Dorine") ;
    
  4. Ecrire une requête permettant d'ajouter le nouveau membre « Zora MAGID » dont le login est « zora » et le mot de passe 2021.

    Réponse à la question 4
    SQL
    INSERT INTO joueurs(id_joueur, nom_joueur, prenom_joueur, login, mdp)
    VALUES  (5, "MAGID", "Zora", "zora", 2021) ;
    
  5. Ecrire une requête qui renvoie les jours où Alice joue.

    Réponse à la question 5

    Alice pouvant être joueur1 ou joueur2, il faut faire une double jointure de la relations matchs avec la relation joueurs sur les clefs étrangères id_joueur1 et id_joueur2.

    Une première solution avec un produit cartésien et une sélection.

    SQL
    SELECT 
        m.date, m.id_creneau
    FROM 
        joueurs AS j, matchs AS m
    WHERE 
        j.prenom_joueur = "Alice"
        AND (j.id_joueur = m.id_joueur1 OR j.id_joueur = m.id_joueur2) ;
    

    Une seconde solution :

    SQL
    SELECT 
        m.date, m.id_creneau
    FROM 
        joueurs AS j1 
        JOIN matchs AS m 
        ON j1.id_joueur = m.id_joueur1
        JOIN joueurs AS j2 
        ON j2.id_joueur = m.id_joueur2
    WHERE 
        j1.prenom_joueur = "Alice" OR j2.prenom_joueur = "Alice" ;
    

Exercice 5⚓︎

  1. On considère la fonction somme(n) qui reçoit en paramètre un entier n strictement positif et renvoie le résultat du calcul \(1+1/2+1/3+\cdots+1/n\).

    🐍 Script Python
    def somme(n) :
        total = 0
        for i in range(n) :
            total = total + 1 / i
        return total
    

    Lors de l'exécution de somme(10), le message d'erreur "ZeroDivisionError: division by zero" apparait. Identifier le problème et corriger la fonction pour qu'elle effectue le calcul demandé.

    Réponse à la question 1

    Il s'agit d'un problème d'indice mal parcouru par range(n) qui va parcourir les entiers entre 0 et \(n-1\) au lieu de \(1\) et \(n\).

    🐍 Script Python
    def somme(n) :
        total = 0
        for i in range(1, n + 1) :
            total = total + 1/i
        return total
    
  2. On considère la fonction maxi(L) qui prend comme paramètre une liste L de nombres et renvoie le plus grand nombre de cette liste :

    🐍 Script Python
    def maxi(L) :
        indice = 0
        maximum = 0
        while indice <= len(L) :
            if L[indice] > maximum :
                maximum = L[indice]
            indice = indice + 1
        return maximum
    

    a. Lors de l'exécution de maxi([2, 4, 9, 1]) une erreur est déclenchée. Identifier et corriger le problème. b. Le bug précédent est maintenant corrigé. Que renvoie à présent l'exécution de maxi([-2, -7, -3]) ? Modifier la fonction pour qu'elle renvoie le bon résultat.

    Réponse à la question 2

    Tout d'abord il s'agit d'un problème de dépassement d'indice dans la liste L, puisqu'au dernier tour de boucle indice est égal à len(L) qui est en dehors de la plage de validité des indices (entre 0 et len(L) - 1)

    On corrige ce premier bug :

    🐍 Script Python
    def maxi(L) :
        indice = 0
        maximum = 0
        while indice < len(L) :
            if L[indice] > maximum :
                maximum = L[indice]
            indice = indice + 1
        return maximum
    

    Ensuite comme on a initialisé maximum à 0, le parcours des éléments tous négatifs de [-2, -7, -3] ne peut modifier la valeur de maximum. maxi([-2, -7, -3]) a donc pour valeur 0 qui n'est pas le maximum de [-2, -7, -3].

    On corrige ce bug en initialisant maximum avec le premier élément de la liste L (à condition que L soit non vide).

    🐍 Script Python
    def maxi(L) :
        indice = 0
        maximum = L[0]
        while indice < len(L) :
            if L[indice] > maximum :
                maximum = L[indice]
            indice = indice + 1
        return maximum
    
  3. On souhaite réaliser une fonction qui génère une liste de n joueurs identifiés par leur numéro. Par exemple on souhaite que l'appel genere(3) renvoie la liste ['Joueur 1', 'Joueur 2', 'Joueur 3'].

    🐍 Script Python
    def genere(n) :
        L = []
        for i in range(1, n+1) :
            L.append('Joueur ' + i)
        return L
    

    L'appel genere(3) déclenche l'erreur suivante TypeError: can only concatenate str (not "int") to str. Expliquer ce message d'erreur et corriger la fonction afin de régler le problème.

    Réponse à la question 3

    Le message d'erreur signale que lors de l'exécution du code, Python a essayé de concaténer une chaîne de caractères et un entier. Cette opération n'est possible qu'entre deux chaînes de caractères (ou deux objets de même type qui l'autorisent comme deux listes). Pour corriger ce bug il suffit de convertir l'entier en chaîne de caractère avec le constructeur str.

    🐍 Script Python
    def genere(n) :
    L = []
    for i in range(1, n+1) :
        L.append('Joueur ' + str(i))
    return L
    
  4. On considère la fonction suite(n) qui reçoit un entier positif et renvoie un entier.

    🚷 Attention la fonction ci-dessous est récursive c'est-à-dire qu'elle s'appelle elle-même. Cette notion est étudiée uniquement en Terminale mais on peut réfléchir sur cet exemple dès la classe de première !

    🐍 Script Python
    def suite(n) :
        if n == 0 :                  # cas de base
            return 0
        else :
            return 3 + 2 * suite(n-2) # réduction (appel récursif)
    

    a. Quelle valeur renvoie l'appel de suite(6) ?

    b. Que se passe-t-il si on exécute suite(7) ?

    Réponse à la question 4

    On commence par évaluer suite(6). suite(6) = 3 + 2 * suite(6 -2) = 3 +2 * suite(4)
    Or suite(4) = 3 + 2 * suite(4 -2) = 3 +2 * suite(2)
    On continue la descente : suite(2) = 3 + 2 * suite(2 - 2)= 3 +2 * suite(0) \(0\) est un cas de base, la descente s'arrête : suite(0) = 0.
    On peut remonter pour calculer toutes les valeurs en attente : suite(2) = 3 + 2 * suite(0) = 3 puis suite(4) = 3 + 2 * suite(2) = 9 et enfin suite(6) = 3 + 2 * suite(4) = 21

    On essaie d'évaluer suite(7) de la même façon. suite(7) = 3 + 2 * suite(7 -2) = 3 +2 * suite(5). Or suite(5) = 3 + 2 * suite(5 -2) = 3 +2 * suite(3). On continue la descente : suite(3) = 3 + 2 * suite(3 - 2)= 3 +2 * suite(1). On continue la descente : suite(1) = 3 + 2 * suite(1 - 2)= 3 +2 * suite(-1). Zut, on a passé le cas de base et la descente ne s'arrêtera jamais, elle sera infinie !

    Le calcul de suite(7) ne s'arrête pas théoriquement, mais en pratique oui, car la mémoire de l'ordinateur est fini et la taille de la structure (une pile) où il stocke les calculs en attente de remontée (qui ne viendra jamais), est limitée : lorsque la pile déborde, on parle de Stack Overflow !

  5. On considère le code Python ci-dessous :

    🐍 Script Python
    x = 4
    L = []
    def modif(x, L) :
        x = x + 1
        L.append(2 * x)
        return x, L
    
    print(modif(x, L))
    print(x, L)
    

    a. Qu'affiche le premier print ? b. Qu'affiche le second print ?

    Réponse à la question 5

    Le premier print affiche les valeurs de x et L renvoyées par modif(x, L). Ce sont des valeurs de x et L dans la portée locale de la fonction modif : c'est-à-dire 5 pour x et [10] pour L à la fin de l'évaluation de modif(x, L)`

    Le second print affiche les valeurs des variables x et L après exécution de modif(x, L) mais dans la portée globale du script. Les valeurs de x et L ont été transmises en paramètres à modif et recopiées dans des variables locales de même nom. modif(x, L) a donc modifié des copies des variables globales x et L de valeurs initiales respectives 4 et []. La modification de la valeur reçue par la variable locale x n'a aucune incidence sur la variable globale x car cette valeur est un entier de type simple. En revanche la valeur de la variable globale L de type list est une référence vers la séquence de valeurs. La variable locale L et la variable globale L partagent la même référence donc par effet de bord, les modifications appliquées par la variable locale sont répercutées sur la variable globale.

    Ainsi, après évaluation de modif(x, L), x est modifiée mais pas L. Le second print affiche la valeur 4 pour x et la valeur [10] pour L.