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.
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
.
-
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 :
Réponse à la question 1
Le nom de l'utilisateur est
gestion
. Le nom de l'ordinateur estcapNSI-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 :Bashgestion@capNSI-ordinateur_central:~$ cd Contrats gestion@capNSI-ordinateur_central:~/Contrats$ ls
On peut aussi écrire plus simplement :
Bashgestion@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 commandechmod
permet de le faire -
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'utilisateurgestion
, on peut écrire :Bashgestion@capNSI-ordinateur_central:~$ mkdir Contrats/TURING_CONTRAT
Pour affecter les bons droits au dossier de chemin relatif
Contrats/TURING_CONTRAT
, on peut écrire :Bashgestion@capNSI-ordinateur_central:~$ chmod ug=rwx,o=r testContrats/TURING_CONTRAT
ou encore en notation octale (4 : lecture, 2: écriture, 1:exécution) :
Bashgestion@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.Bashprof@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 Pythontab_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.
-
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 Pythondef formatage(tab): tab2 = [] for (nom, prenom) in tab: tab2.append(nom + '_' + prenom) return tab2
Autre version en compréhension :
🐍 Script Pythondef formatage(tab): return [nom + '_' + prenom for (nom, prenom) in tab]
Ou encore sans déballage de tuple :
🐍 Script Pythondef formatage(tab): return [v[0] + '_' + v[1] for v in tab]
-
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 Pythondef 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 :
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;
-
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 :
📋 TexteDUMAS ; 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é.
- une hauteur \(h\) maximale pour un arbre où tous les noeuds internes ont un seul fils non
-
Recopier et compléter l'arbre de ce dernier exemple avec les noms
FLAUBERT, BALZAC, PROUST, SAND, WOOLF, COLETTE, CHRISTIE
etAUDIARD
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
etAUDIARD
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 :
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)
-
Que renvoie l'appel
mystere(A2,'SIMENON')
? Justifier la réponse.Réponse à la question 3
Cette fonction récursive renvoie
True
si la cleft
est une valeur d'un noeud de l'arbreABR
etFalse
sinon.'SIMENON'
est une valeur d'un noeud de l'arbreA2
doncmystere(A2,'SIMENON')
renvoieTrue
.
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.
-
Ecrire un algorithme de la fonction
hauteur(ABR)
qui prend en entréeABR
un arbre binaire de recherche et renvoie sa hauteur. On pourra avoir recours aux fonctionsMIN(val1, val2)
etMAX(val1, val2)
qui renvoient respectivement la plus petite et la plus grande valeur entreval1
etval2
.Réponse à la question 4
On suppose que tous les noeuds ont deux fils éventuellement
NULL
.📋 TexteFonction 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 :
Pour initialiser le jeu, on crée en langage Python une grille de dimension 8x8, modélisée par une liste de listes.
-
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 Pythonligne = [0,0,0,0,0,0,0,0] jeu = [] for i in range(8): jeu.append(ligne)
-
Choix 2
🐍 Script Pythonjeu = [] 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.
-
-
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 Pythonjeu[5][2] = 1
-
Question 3.
a. Ecrire en langage Python une fonction
remplissage(n, jeu)
qui prend en paramètres un entiern
et une grillejeu
, et qui ajoute aléatoirement exactementn
cellules vivantes dans le tableaujeu
.b. Quelles sont les préconditions de cette fonction pour la variable
n
?Réponse à la question 3
🐍 Script Pythonimport 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 Pythonassert 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 celluletab[i][j]
:🐍 Script Pythondef 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
-
Recopier et compléter les pointillés pour que la fonction réponde à la demande.
Réponse à la question 4
🐍 Script Pythondef 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 Pythondef 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
-
En utilisant la fonction
nombre_de_vivants(i, j, jeu)
précédente, écrire en langage Python une fonctiontransfo_cellule(i, j, jeu)
qui prend en paramètres deux entiersi
etj
ainsi qu'une grillejeu
et renvoie le nouvel état de la cellulejeu[i][j]
(0 ou 1)Réponse à la question 5
🐍 Script Pythondef 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⚓︎
Relation précisant les matchs joués.⚓︎
Relation précisant les différents terrains.⚓︎
Relation précisant les créneaux réservables.⚓︎
Script SQL pour générer la base de données
/*
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) ;
-
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
estid_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 relationjoueurs
id_terrain
clef primaire de la relationterrains
id_creneau
clef primaire de la relationcreneaux
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 primairecreneaux.id_creneau
matchs.id_terrain
fait référence à la clef primaireterrain.id_terrain
matchs.id_joueur1
fait référence à la clef primairejoueurs.id_joueur
matchs.id_joueur2
fait référence à la clef primairejoueurs.id_joueur
-
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.
-
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.
Réponse à la question 3
La requête suivante renvoie les prénoms des joueurs dont le nom est 'Dupont'.
SQLSELECT 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.
SQLUPDATE joueurs SET mdp = 1976 WHERE (nom_joueur = "Dupont") AND (prenom_joueur = "Dorine") ;
-
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
SQLINSERT INTO joueurs(id_joueur, nom_joueur, prenom_joueur, login, mdp) VALUES (5, "MAGID", "Zora", "zora", 2021) ;
-
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 relationjoueurs
sur les clefs étrangèresid_joueur1
etid_joueur2
.Une première solution avec un produit cartésien et une sélection.
SQLSELECT 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 :
SQLSELECT 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⚓︎
-
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 Pythondef 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 Pythondef somme(n) : total = 0 for i in range(1, n + 1) : total = total + 1/i return total
-
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 Pythondef 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 demaxi([-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 boucleindice
est égal àlen(L)
qui est en dehors de la plage de validité des indices (entre 0 etlen(L) - 1
)On corrige ce premier bug :
🐍 Script Pythondef 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 demaximum
.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 listeL
(à condition queL
soit non vide).🐍 Script Pythondef maxi(L) : indice = 0 maximum = L[0] while indice < len(L) : if L[indice] > maximum : maximum = L[indice] indice = indice + 1 return maximum
-
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 Pythondef 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 Pythondef genere(n) : L = [] for i in range(1, n+1) : L.append('Joueur ' + str(i)) return L
-
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 Pythondef 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)
Orsuite(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
puissuite(4) = 3 + 2 * suite(2) = 9
et enfinsuite(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)
. Orsuite(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 ! -
On considère le code Python ci-dessous :
🐍 Script Pythonx = 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 dex
etL
renvoyées parmodif(x, L)
. Ce sont des valeurs dex
etL
dans la portée locale de la fonctionmodif
: c'est-à-dire 5 pourx
et[10]
pourL
à la fin de l'évaluation de modif(x, L)`Le second
print
affiche les valeurs des variablesx
etL
après exécution demodif(x, L)
mais dans la portée globale du script. Les valeurs dex
etL
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 globalesx
etL
de valeurs initiales respectives 4 et[]
. La modification de la valeur reçue par la variable localex
n'a aucune incidence sur la variable globalex
car cette valeur est un entier de type simple. En revanche la valeur de la variable globaleL
de typelist
est une référence vers la séquence de valeurs. La variable localeL
et la variable globaleL
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 pasL
. Le secondprint
affiche la valeur 4 pourx
et la valeur[10]
pourL
.