WikiPrépaLivrets

X ENS Informatique Commune MP PC PSI 2019Sujet, corrigé et rapport du jury

Tetris couleurs

Pas encore noté
  • Algorithmique : boucles for et while, complexité
  • Structures de données : tableaux et grilles
  • Récursivité
  • Bases de données : requêtes SQL
  • Programmation en Python

Téléchargements

Présentation du sujet

Difficile
Programmation d'un jeu de type Tetris Couleurs : grille, mouvements, score, variante récursive et requêtes SQL
Afficher ou masquer la section

Le sujet, commun aux filières MP, PC et PSI, propose de programmer en Python un jeu de puzzle inspiré de Tetris, où des barreaux de blocs colorés descendent dans une grille. Il comporte cinq parties : le lancement du jeu (initialisation et affichage de la grille), les mouvements des barreaux, le calcul du score et l'élimination des alignements, une variante fondée sur des régions unicolores traitée par un algorithme récursif, et enfin la gestion d'une base de données de parties et de joueurs en SQL.

  1. 1Partie I : lancement du jeuCréation d'une grille vide et affichage de la grille à l'écran.
  2. 2Partie II : mouvements des barreauxDétection de place disponible, descente simple, déplacement latéral, permutation des blocs et descente rapide d'un barreau.
  3. 3Partie III : score et alignementsCalcul du score, détection des alignements de blocs de même couleur et tassement de la grille après élimination.
  4. 4Partie IV : variante du jeuÉcriture d'un algorithme récursif pour calculer une région unicolore maximale et analyse de son fonctionnement.
  5. 5Partie V : gestion de la base de donnéesÉcriture de requêtes SQL sur une base de données des parties jouées et des joueurs.

Difficile. Pour les candidats français de la filière PC, la note moyenne n'est que de 7,49/20 avec un écart-type de 3,08, et plusieurs questions (notamment Q14 et Q15 sur la partie récursive) affichent des taux de réussite complète inférieurs à 2%.

L'épreuve en chiffres

Moyenne 7,49 / 20 · écart-type 3,08 · 463 copies · où vous situez-vous ?
Afficher ou masquer la section
Moyenne
7,49/ 20
Écart-type
3,08
Copies
463
moyenne 7,4905101520
Deux tiers des copies environ (moyenne ± écart-type)

Votre note sur 20 à ce sujet, en conditions de concours.

Source : rapport du jury. Notes publiées par le concours (après harmonisation le cas échéant). Courbe : estimation par une loi normale.

Ce qu'a observé le jury

6 erreurs relevées
Confusion sur la syntaxe des boucles while · Confusion entre break et return · Recopie inutile et coûteuse de la grille
Afficher ou masquer la section

Pour les candidats français de la filière PC (463 candidats), la note moyenne s'établit à 7,49/20 avec un écart-type de 3,08. Le jury relève une incompréhension inquiétante de l'utilisation des boucles, une confusion fréquente entre plusieurs opérations Python de base, et une incompréhension profonde du calcul de complexité d'un algorithme, pourtant considérée comme une connaissance de base.

Les erreurs les plus sanctionnées

  1. 1
    Confusion sur la syntaxe des boucles while

    Pour écrire une condition combinée avec and, certaines copies proposent une syntaxe incorrecte du type while A if B, qui ne fonctionne pas du tout de la même manière.

    « pour écrire while A and B, certaines copies proposent while A if B, ce qui ne fonctionne pas du tout de la même manière »
  2. 2
    Confusion entre break et return

    Les correcteurs relèvent une confusion fréquente entre ces deux opérations, qui n'ont pourtant pas le même effet sur l'exécution du programme.

    « beaucoup de confusion entre les opérations break et return. »
  3. 3
    Recopie inutile et coûteuse de la grilleQ1 à Q7

    Plusieurs copies recopient systématiquement la grille donnée en argument, ce qui démontre une incompréhension du fonctionnement et de la complexité d'un programme.

    « C'est une opération coûteuse et inutile qui démontre une incompréhension majeure du fonctionnement d'un programme »
  4. 4
    Calcul de complexité mal maîtrisé

    Plusieurs copies expriment la complexité en fonction d'un paramètre 'n' jamais explicité, alors que le problème s'exprimait en fonction de la longueur et de la largeur de la grille.

    « Plusieurs copies ont exprimé la complexité en fonction d'un paramètre 'n' jamais explicité »
  5. 5
    Cas dx=0 et dy=0 non excluQ10

    Il fallait exclure ce cas particulier sous peine d'obtenir une boucle infinie, une subtilité presque jamais prise en compte par les candidats.

    « Cette subtilité n'a presque jamais été prise en compte par les candidats. »
  6. 6
    Comparaison de grilles au lieu de scoresQ13

    Pour la condition d'arrêt, il ne fallait surtout pas comparer les grilles entre elles, ce qui est de complexité élevée, mais simplement comparer les scores.

Ce qui a été bien réussi

  • La question 1, sur la création d'une grille vide, a été résolue avec la totalité des points par 80% des candidats malgré sa simplicité apparente.
  • La question 3, sur la détection de place disponible pour un barreau, a été globalement bien traitée.
  • La majorité des candidats a montré une bonne intuition de l'algorithme attendu pour le calcul du score (Q9), même si la mise en œuvre fut laborieuse.

Conseils du jury

  • Bien maîtriser la syntaxe et la différence de fonctionnement entre les boucles for et while.
  • Éviter de recopier inutilement des structures de données, ce qui alourdit la complexité du programme.
  • Exprimer une complexité algorithmique en fonction des paramètres réellement donnés dans l'énoncé.
  • Respecter précisément les consignes de l'énoncé, notamment la distinction entre fonction et procédure.
  • Vérifier systématiquement les cas particuliers et les bornes des boucles pour éviter les boucles infinies ou les erreurs de limite.

Synthèse rédigée par WikiPrépa à partir du rapport officiel du jury (à télécharger en PDF). Les citations sont extraites du rapport.

Ces sujets peuvent vous intéresser

Lecture du sujet en ligne

L'énoncé complet, avec les formules et les figures, sans ouvrir le PDF.
Afficher ou masquer la section
ECOLE POLYTECHNIQUE - ESPCI
ECOLES NORMALES SUPERIEURES
CONCOURS D’ADMISSION 2019
MERCREDI 24 AVRIL 2019-16h30-18h30
FILIERES MP, PC et PSI - Epreuve n^∘8

INFORMATIQUE B
(XELCR)

Durée : 2 heures
L'utilisation des calculatrices n'est pas autorisée pour cette épreuve
L'utilisation des calculatrices n'est pas autorisée pour cette épreuve.
Le langage de programmation sera obligatoirement Python.

Tetris Couleurs

On souhaite programmer un jeu de puzzle dont le principe ressemble au jeu de Tetris : des blocs de couleur apparaissent à l'écran en haut d'une aire de jeu et descendent sous l'effet de la «gravité » jusqu'à reposer sur un bloc déjà présent, ou sur le bas de l'aire de jeu. Les nouveaux blocs de couleur apparaissent par groupe de k blocs superposés en une tour verticale appelée « barreau ».
Lors de la descente, le joueur peut déplacer le barreau selon certaines règles. Il peut :
  • déplacer le barreau vers la gauche ou vers la droite,
  • permuter l'ordre des blocs dans le barreau,
  • faire descendre le barreau «rapidement ».
Le but du jeu est de réaliser le plus grand nombre possible d'alignements d'au moins trois blocs de la même couleur. Chaque alignement de trois blocs de la même couleur (horizontalement, verticalement ou en diagonale) donne un point au joueur. Les blocs appartenant à des alignements sont retirés de l'aire de jeu, et les blocs restants sont tassés (ils descendent sous l'effet de la gravité). Les blocs ainsi tassés peuvent à nouveau former des alignements unicolores qui sont à leur tour retirés, et ainsi de suite jusqu'à ce qu'il n'y ait plus aucun alignement unicolore dans l'aire de jeu.
La partie se termine quand l'aire de jeu est trop remplie pour accueillir un nouveau barreau. Le score du joueur est alors la somme des points accumulés lors de la partie.
Complexité. La complexité, ou le temps d'exécution, d'un programme P (fonction ou procédure) est le nombre d'opérations élémentaires (addition, multiplication, affectation, test, etc.) nécessaires à l'exécution de P. Lorsque cette complexité dépend de deux paramètres n et m, on dira que P a une complexité en O(φ(n, m)) lorsqu'il existe trois constantes A, n_0 et m_0 telles que la complexité de P est inférieure ou égale à A ⋅ φ(n, m), pour tout n ≥ n_0 et m ≥ m_0.
Lorsqu'il est demandé de donner la complexité d'un programme, le candidat devra justifier cette dernière si elle ne se déduit pas directement de la lecture du code.
Python. Dans ce sujet, nous adopterons la syntaxe du langage Python. On rappelle qu'en Python, les listes sont des tableaux dynamiques à une dimension. Sur les listes, on dispose des opérations suivantes, qui ont toutes une complexité constante :
  • [ ] crée une liste vide (c'est-à-dire ne contenant aucun élément).
  • len (liste) renvoie la longueur de la liste liste.
  • liste. append (x) ajoute l'élément x à la fin de la liste liste.
  • liste [i] renvoie le (i + 1)-ième élément de la liste liste s'il existe ou produit une erreur sinon (noter que le premier élément de la liste est liste [0]).
L'expression [k for i in range (n) ] construit une liste de longueur n contenant n occurrences de k.
Important : L'utilisation de toute autre fonction sur les listes telle que liste.insert (i,x), liste.remove(x), liste.index(x), ou encore liste.sort(x) est rigoureusement interdite. Ces fonctions devront être réécrites explicitement si nécessaire.
On rappelle que l'on peut récupérer directement les valeurs contenues dans un tuple de la façon suivante : après l'instruction a, b, c = (1, 2, 4), la variable a contient la valeur 1, b contient la valeur 2 et c contient la valeur 4 . Cette instruction engendre une erreur si le nombre de variables à gauche est différent de la taille du tuple à droite.
Dans la suite, nous distinguerons fonctions et procédures : les fonctions renvoient une valeur (un entier, une liste, un couple, etc.) tandis que les procédures ne renvoient aucune valeur.
La partie I contient les principales définitions, les parties II, III, IV et V sont indépendantes.
Nous attacherons la plus grande importance à la lisibilité du code produit par les candidats; aussi, nous encourageons les candidats à utiliser des commentaires et à introduire des procédures ou des fonctions intermédiaires pour faciliter la compréhension du code.

Partie I. Initialisation et affichage de l'aire de jeu

L'aire de jeu est représentée par une grille de dimensions largeur×hauteur. Dans l'exemple de la Figure 1(a), la grille est de dimensions 6 × 12.
Chaque case de la grille contient une valeur qui représente soit une case vide, soit une couleur. On utilisera les constantes entières suivantes pour représenter l'état des cases de la grille (une constante est une variable globale qui n'est jamais modifiée après création) :
  • VIDE pour une case vide;
  • R, V, B, N, J pour les couleurs.
On supposera bien sûr que ces constantes sont deux à deux distinctes et on n'utilisera aucune autre variable globale. La Figure 1(b) montre un exemple d'aire de jeu en cours de partie. Cidessous, sa représentation en Python sous la forme d'un tableau de tableaux, ou plus précisément d'un tableau de taille largeur (ici 6) contenant dans chaque case une colonne, qui est elle-même un tableau de taille hauteur (ici 12) :
grille = [ [J, R, R, N, V, R, VIDE, VIDE, VIDE, VIDE, VIDE, VIDE],
    [R, R, B, J, VIDE, R, N, V, VIDE, VIDE, VIDE, VIDE],
    [J, N, N, R, VIDE, J, VIDE, VIDE, VIDE, VIDE, VIDE, VIDE],
    [J, J, VIDE,R, VIDE, VIDE, VIDE, VIDE, VIDE, VIDE, VIDE, VIDE],
    [N, VIDE,R, VIDE, VIDE, R, VIDE, VIDE, VIDE, VIDE, VIDE, VIDE],
    [VIDE, V, VIDE, VIDE, VIDE, VIDE, VIDE, VIDE, VIDE, VIDE, VIDE, VIDE]]
À noter que la valeur de la case supérieure droite de la grille est grille [5] [11]. On veillera à respecter l'ordre des dimensions afin que la case de coordonnées ( i, j ) avec 0 ≤ i < largeur et 0 ≤ j < hauteur (voir Figure 1(a)) corresponde bien à la valeur grille[i][j] dans sa représentation en Python.
Question 1. Écrire une fonction creerGrille (largeur, hauteur) qui renvoie une grille de dimensions largeur × hauteur dont toutes les cases sont vides.
(a) Aire de jeu représentée par une grille.
(b) Grille en cours de partie.
Figure 1 - L'aire de jeu.
On souhaite pouvoir afficher à l'écran le contenu de l'aire de jeu. Pour cela, on suppose l'existence des procédures suivantes :
  • afficheCouleur(c) qui prend en argument une constante de couleur c ∈ {R, V, B, N, J} et affiche le caractère correspondant ;
  • afficheBlanc() qui affiche un espace vide;
  • nouvelleLigne() qui déplace le curseur au début de la ligne suivante.
Important : Il est rigoureusement interdit d'utiliser toute autre fonction d'affichage, notamment la commande print.
Question 2. Écrire une procédure afficheGrille(grille) qui affiche à l'écran
V
N
RRJ R
V
NJRR
RBN R
RRNJ V
JRJJN
le contenu de l'aire de jeu, encodé dans le tableau grille. On veillera à bien respecter l'orientation verticale de la grille : la ligne apparaissant en bas de l'écran doit correspondre aux éléments grille[i][0] pour 0 ≤ i < largeur. Par exemple, la grille de la Figure 1(b) sera affichée comme le montre la capture d'écran ci-contre.

Partie II. Création et mouvement du barreau

Au cours d'une partie, le joueur voit apparaître à l'écran un barreau consistant en une tour de k blocs colorés, où k ≥ 3. Le barreau apparaît en pointillé sur les figures. La valeur de k et la couleur des blocs du barreau sont choisies aléatoirement. La position d'un barreau est donnée par les coordonnées ( x, y ) de son bloc inférieur. Dans la suite, on supposera toujours que les coordonnées ( x, y ) définissent une case dans la grille (c'est-à-dire 0 ≤ x < largeur et 0 ≤ y < hauteur) et que y + k ≤ hauteur (et donc k ≤ hauteur).
Un barreau de taille k peut naître au sommet d'une colonne ayant ses k cases supérieures vides (voir Figure 2). Si aucune colonne n'a ses k cases supérieures vides, la partie s'arrête.
Question 3. Écrire une fonction grilleLibre (grille, k) qui renvoie True si dans au moins une colonne de la grille, les k premières cases (en partant du haut de la grille) sont vides, et renvoie False sinon. On ne fait pas d'hypothèse sur le contenu de la grille (en particulier, la grille n'est pas nécessairement tassée). Quelle est la complexité de votre fonction?
Figure 2 - Zone de naissance des barreaux.
zone de naissance des barreaux de hauteur k :
les k lignes supérieures de la grille
La position d'un barreau est donnée par les coordonnées ( x, y ) de son bloc inférieur
En l'absence d'intervention du joueur, le barreau descend d'une case à chaque unité de temps. La descente s'arrête dès que le barreau atteint le bas de la grille, ou rencontre un bloc déjà présent (le passage du temps est illustré à la Figure 3).
Question 4. Écrire une procédure descente (grille, x, y, k ) qui prend en arguments une grille et les coordonnées ( x, y ) du bloc inférieur d'un barreau de hauteur k, et modifie la grille en faisant descendre le barreau d'une case. Si le barreau ne peut pas descendre, la grille n'est pas modifiée.
Figure 3 - Descente du barreau.
Le joueur peut déplacer le barreau d'une colonne vers la gauche (ou vers la droite) en utilisant les flèches du clavier. Le déplacement du barreau vers la droite n'est possible que si le barreau n'est pas contre le bord droit de la grille et que les k cases se trouvant à sa droite sont toutes vides. Symétriquement, le déplacement du barreau vers la gauche n'est possible que si le barreau n'est pas contre le bord gauche de la grille et que les k cases se trouvant à sa gauche sont toutes vides (Figure 4).
Question 5. Écrire une procédure deplacerBarreau(grille, x, y, k, direction) qui prend en argument une grille et les coordonnées (x, y) du bloc inférieur d'un barreau de hauteur k, et un entier direction ∈ { − 1, 1}, et qui modifie la grille en déplaçant le barreau d'une case vers la gauche (si direction = − 1 ) ou vers la droite (si direction = 1 ). Si le déplacement du barreau n'est pas possible, la grille reste inchangée.
Figure 4 - Déplacements possibles du barreau.
Le joueur peut aussi modifier l'ordre des blocs dans le barreau par une permutation circulaire qui fait remonter chaque bloc d'un case, sauf le bloc le plus haut qui redescend à la place du bloc le plus bas (Figure 5).
Question 6. Écrire une procédure permuterBarreau (grille, x, y, k ) qui modifie la grille en effectuant, comme décrit ci-dessus, une permutation circulaire des couleurs du barreau de hauteur k dont le bloc inférieur est en position (x, y) dans la grille donnée en argument.
Figure 5 - Permutation circulaire du barreau.
Enfin, le joueur peut faire descendre le barreau «rapidement», ce qui signifie que le barreau descend du nombre maximum possible de cases (Figure 6), pour venir reposer au-dessus de la première case non vide de la grille située sous le barreau, ou sur le fond de la grille (si toutes les cases sous le barreau sont vides). Dans l'exemple de la Figure 6, la première case non vide sous le barreau a pour coordonnées (3, 1).
Question 7. Écrire une procédure descenteRapide (grille, x, y, k ) qui prend en argument une grille et les coordonnées (x, y) du bloc inférieur d'un barreau de hauteur k, et modifie la grille en faisant descendre le barreau «rapidement». On demande que la fonction ait une complexité en O(k + hauteur ) (et non O(k × hauteur ) ).
Figure 6 - Descente rapide du barreau.

Partie III. Détection des alignements et calcul du score

Lorsqu'un barreau ne peut plus descendre, le joueur gagne des points si des alignements d'au moins trois blocs de la même couleur sont réalisés dans la grille. Les alignements peuvent être réalisés sur une ligne, sur une colonne, ou en diagonale. Notre but est maintenant de détecter les alignements unicolores et de calculer le score du joueur.
Chaque alignement unicolore de longueur m ≥ 3 donne m − 2 points au joueur. Cette règle ne s'applique que si l'alignement de longueur m n'est pas lui-même inclus dans un alignement de longueur plus grande que m, donc on ne prend en considération que les alignements de longueur maximale pour calculer le score. Par exemple l'alignement horizontal de quatre blocs de couleur B dans la Figure 7 donne 2 points, ceux en diagonale de trois blocs de couleur B et V donnent chacun 1 point. Le bloc B de coordonnées (3, 4) compte à la fois pour l'alignement horizontal et l'alignement en diagonale. Le joueur marque donc 4 points dans cette configuration.
Tous les blocs appartenant à de tels alignements sont ensuite simultanément retirés de la grille et remplacés par des cases vides (deuxième grille de la Figure 7). Les blocs restants sont ensuite tassés, c'est-à-dire qu'ils descendent du maximum possible de cases. Il se peut que de nouveaux alignements se forment après le tassement de la grille (comme les cinq blocs de couleur R dans la troisième grille de la Figure 7). Ces nouveaux alignements donnent à nouveau des points au joueur (selon le même barème que précédemment) et le même processus d'élimination des alignements et de tassement de la grille est réalisé. Ce processus se poursuit jusqu'à ce qu'il n'y ait plus d'alignement unicolore de longueur m ≥ 3 dans la grille. Dans l'exemple, le joueur marque au total 7 points.
V
N
R R J R
V B B B B
N J R R B
R B N V R B
R R N J V V
J R J J N V

Figure 7 - Élimination des alignements unicolores et tassement de la grille.
Question 8. Calculer le nombre de points marqués par le joueur s'il laisse descendre le barreau dans l'aire de jeu ci-dessous. Justifier votre réponse.
Pour réaliser la fonction qui va détecter et comptabiliser les alignements unicolores de la grille, on va d'abord construire une fonction qui réalise cela sur un tableau simple (à une dimension).
Question 9. Écrire une fonction detecteAlignement (rangee) qui prend en argument un tableau rangee non vide à une dimension contenant des valeurs dans l'ensemble {VIDE, R, V, B, N, J}, et qui renvoie un tuple (marking, score) de deux éléments :
  • marking est un tableau de la même taille que rangee contenant des Booléens, tel que marking [i] = True si et seulement si rangee [i] appartient à un alignement unicolore de longueur au moins 3 .
  • score est le nombre de points obtenus par le joueur pour les alignements présents dans rangee (selon le barème donné plus haut).
Par exemple, pour le tableau rangee = [B, R, R, R, R, J, J, J, VIDE, VIDE, VIDE], la fonction detecteAlignement (rangee) renvoie:
  • marking = [False, True, True, True, True, True, True, True, False, False, False]
  • score = 3.
On demande que lors du traitement, la fonction detecteAlignement (rangee) n'accède qu'une seule fois à chaque élément du tableau rangee.
Indice : Parcourir le tableau et détecter les changements de couleur.
Pour détecter les alignements unicolores de la grille et comptabiliser les points marqués, nous allons explorer toutes les lignes, colonnes et diagonales de la grille. Pendant le traitement, on va conserver une copie de travail de la grille dans laquelle on remplacera les cases appartenant à un alignement unicolore par des cases vides. Dans la question suivante, on suppose que g est cette copie de travail.
Question 10. Écrire une fonction scoreRangee (grille, g, i, j, dx, dy) qui prend en argument une grille grille et une grille g de même dimensions que grille, les coordonnées (i, j) d'une case dans la grille et une direction ( dx, dy ) donnée par dx, dy ∈ { − 1, 0, 1}. La fonction construit un tableau rangee à une dimension contenant les valeur des cases de grille dont les coordonnées sont (i, j), (i + dx, j + dy), (i + 2dx, j + 2dy), etc. puis utilise la fonction detecteAlignement (rangee) de la Question 9 pour détecter les alignements unicolores dans le tableau rangee, déterminer le nombre de points marqués et mettre à jour la grille g pour que les cases appartenant à un alignement unicolore dans grille soient vides dans g. La grille grille ne doit pas être modifiée. La fonction renvoie le nombre de points marqués.
Question 11. Écrire une fonction effaceAlignement (grille) qui prend en argument une grille et renvoie un tuple ( g, score) de deux éléments :
  • g est la grille mise à jour où tous les blocs appartenant à un alignement unicolore sont remplacés par des cases vides.
  • score est le nombre total de points obtenus par le joueur pour les alignements présents dans la grille.
La grille grille ne doit pas être modifiée. Donner la complexité de votre fonction.
Question 12. Écrire une procédure tassementGrille(grille) qui modifie la grille donnée en argument en effectuant le tassement de ses cases non vides.
Question 13. Écrire une fonction calculScore (grille) qui met à jour la grille grille après élimination des alignements et tassement, répétés jusqu'à ce que la grille ne contienne plus aucun alignement unicolore de longueur m ≥ 3, et qui renvoie le nombre total de points marqués par le joueur pour les alignements éliminés de la grille.
Figure 8 - Régions unicolores (Partie IV).

Partie IV. Variante du jeu : régions unicolores

Dans cette partie, on considère une variante du jeu où le but du joueur est de former des régions unicolore au lieu d'alignements (par exemple un carré de 2 × 2 cases de la même couleur).
Une région unicolore est un ensemble de cases, toutes de la même couleur, qui est connexe pour la relation d'adjacence suivante : deux cases sont adjacentes si elles partagent un côté (Figure 8(a)).
La région grisée de la Figure 8(b) est une région unicolore maximale : si on y ajoute une case quelconque, elle ne reste plus connexe et unicolore. En particulier, la case supérieure droite ne peut être ajoutée car elle n'est adjacente à aucune case de la région grisée.
Question 14. Écrire une fonction récursive tailleRegionUnicolore (grille, x, y) qui renvoie le nombre de cases appartenant à la plus grande région unicolore de la grille contenant la case ( x, y ). Justifier la terminaison de votre fonction.
Considérons le code Python aux Figure 9 et Figure 10, dont le but est de réaliser le même travail que la fonction tailleRegionUnicolore de la Question 14 sans utiliser la récursivité.
Intuitivement, la fonction exploreRegion (grille, x, y ) effectue un balayage de la grille, d'abord verticalement à partir de la case ( x, y ), puis verticalement à partir de chaque voisine horizontale des cases déjà explorées.
Question 15. Déterminer si la fonction exploreRegion (grille, x, y ) renvoie le nombre de cases appartenant à la plus grande région unicolore de la grille contenant la case ( x, y ).
Si oui, justifier soigneusement que la fonction renvoie toujours une valeur correcte.
Si non, donner un exemple de paramètres grille, x, y pour lesquels la valeur renvoyée par la fonction est incorrecte (on pourra dessiner la grille).
def xDansGrille(grille, x):
    largeur = len(grille)
    return (x >= 0) and (x < largeur)
        = grille[x][y]
    couleur =
    v = y + dir
    while yDansGrille(grille, v):
        if grille[x][v] != couleur:
            return V - dir
def yDansGrille(grille, y):
    hauteur = len(grille[0])
    return (y >= 0) and (y < hauteur)
        v = v + dir
    if dir == 1:
        return hauteur - 1
    else:
        return 0
def exploreRegion(grille, x, y):
    inf = exploreVertical(grille, x, y, -1) # explore vers le bas
    sup = exploreVertical(grille, x, y, 1) # explore vers le haut
    d = exploreHorizontal(grille, x, y, 1) # explore vers la droite
    g = exploreHorizontal(grille, x, y, -1) # explore vers la gauche
    score = sup - inf + 1 + d + g
    return score
Figure 9 - Code Python pour la Question 15.
def exploreHorizontal(grille, x, y, dir):
    largeur = len(grille)
    couleur = grille[x][y]
    inf = exploreVertical(grille, x, y, -1) # explore vers le bas
    sup = exploreVertical(grille, x, y, 1) # explore vers le haut
    score = 0
    u = x + dir
    while xDansGrille(grille, u) and (inf <= sup):
        v = inf
        infNew = 1 # initialement, infNew > supNew
        supNew = 0
        while (v <= sup):
            if grille[u-dir][v] == couleur and grille[u][v] == couleur:
                infNew = exploreVertical(grille, u, v, -1) # explore vers le bas
                supNew = exploreVertical(grille, u, v, 1) # explore vers le haut
                score = score + supNew - infNew + 1
                v = supNew + 2
                while (v <= sup):
                    if grille[u-dir][v] == couleur and grille[u][v] == couleur:
                        supNew = exploreVertical(grille, u, v, 1) # explore vers le haut
                        score = score + supNew - v + 1
                        v = supNew + 1
                    v = v + 1
            v= v + 1
        inf = infNew
        sup = supNew
        u = u + dir
    return score
Figure 10 - Code Python pour la Question 15.

Partie V. Gestion des scores en SQL

On souhaite utiliser une base de données pour stocker les résultats obtenus par une communauté de joueurs. On suppose que l'on dispose d'une base de données comportant les tables JOUEURS(id_j, nom, pays) et PARTIES(id_p, date, duree, score, id_joueur) où :
  • id_j, de type entier, est la clé primaire de la table JOUEURS,
  • nom est une chaîne de caractères donnant le nom du joueur,
  • pays est une chaîne de caractères donnant le pays du joueur,
  • id_p, de type entier, est la clé primaire de la table PARTIES,
  • date est la date (AAAAMMJJ) de la partie,
  • duree, de type entier, est la durée en secondes de la partie,
  • score, de type entier, est le nombre de points marqués au cours de la partie,
  • id_joueur est un entier qui identifie le joueur de la partie.
Question 16. Étant donné une chaîne de caractères cc contenant le nom d'un joueur, écrire une requête SQL qui renvoie la date, la durée et le score de toutes les parties jouées par le joueur cc, listées par ordre chronologique (au choix, croissant ou décroissant).
Question 17. Étant donné un entier s (le score que vient de réaliser une joueuse nommée Alice), écrire une requête SQL qui renvoie la position qu'aura le score s dans le classement des parties par ordre de score (on suppose que la dernière partie d'Alice n'a pas encore été insérée dans la table des parties). En cas d'ex aequo pour le score s (une ou plusieurs parties déjà présentes ayant le score s ), le rang sera le même que s'il n'y avait qu'une seule partie avec le score s.
Par exemple, la requête renverra 1 (le score d'Alice est " 1 er") si aucun score n'est meilleur que s. Autre exemple, si la base de données contient 6 parties dont les scores sont 87, 75, 75, 63, 60, 60, alors le rang de s = 75 sera 2 , le rang de s = 70 sera 4 et le rang de s = 60 sera 5.
Question 18. Écrire une requête SQL qui renvoie le record de France de Tetris couleur, c'est-à-dire le meilleur score réalisé par un joueur dont le pays est la France.
Question 19. Étant donné une chaîne de caractères cc contenant le nom d'un joueur (ayant déjà joué au moins une partie de Tetris couleur), écrire une requête SQL qui renvoie le rang du joueur cc, c'est-à-dire sa position dans le classement des joueurs par ordre de leur meilleur score dans une partie de Tetris couleur (on traitera les ex aequo de la même manière qu'à la question 17).

Questions fréquentes

4 questions
Sur quels chapitres porte l'épreuve d'informatique commune X-ENS MP-PC-PSI 2019 ?
Afficher ou masquer la section

Sur quels chapitres porte l'épreuve d'informatique commune X-ENS MP-PC-PSI 2019 ?

Le sujet porte sur la programmation d'un jeu de type Tetris en Python : manipulation de grilles, algorithmique et complexité, récursivité pour une variante du jeu, et requêtes SQL pour la gestion d'une base de données de parties.

Quelles erreurs le jury a-t-il le plus relevées sur cette épreuve d'informatique X-ENS 2019 ?

Le jury relève une incompréhension des boucles while et for, une confusion entre les opérations break et return, une recopie inutile et coûteuse des structures de données, et une maîtrise insuffisante du calcul de complexité algorithmique.

Cette épreuve d'informatique commune X-ENS 2019 est-elle difficile ?

Pour les candidats français de la filière PC, la moyenne n'est que de 7,49/20, et certaines questions de la partie récursive n'ont été totalement réussies que par 1 à 2% des candidats.

La partie SQL du sujet X-ENS informatique commune 2019 est-elle bien réussie ?

Les résultats sont contrastés : la requête la plus simple (Q16) est réussie par environ la moitié des candidats, mais la question la plus complexe sur le classement d'un joueur (Q19) n'est réussie que par 10% d'entre eux.

Pas de description pour le moment