{
  "chapter": {
    "id": "algorithmique-programmation",
    "level": "seconde",
    "theme": "Algorithmique et programmation",
    "title": "Algorithmique et programmation",
    "description": "Types de variables (entier, flottant, chaîne de caractères),\naffectation et séquence d'instructions, instruction conditionnelle,\nboucles bornées et non bornées, fonctions : écrire, lire, compléter\net appeler. Programmes en Python ou en langage naturel.",
    "parties": [
      {
        "id": "variables",
        "title": "Variables, types et affectation"
      },
      {
        "id": "conditions",
        "title": "Instructions conditionnelles"
      },
      {
        "id": "boucles",
        "title": "Boucles bornées et non bornées"
      },
      {
        "id": "fonctions",
        "title": "Fonctions"
      }
    ],
    "prerequisites": [],
    "references": []
  },
  "questions": [
    {
      "id": "q01",
      "difficulty": 1,
      "skills": [
        "type",
        "chaine"
      ],
      "title": "Le type d'une valeur entre guillemets",
      "partie": "variables",
      "statement": "Après l'instruction `a = \"12\"`, quel est le type de la variable `a` ?",
      "options": [
        {
          "text": "Une chaîne de caractères",
          "correct": true,
          "feedback": "Bonne réponse : les guillemets signalent un texte. La variable\ncontient les caractères « 1 » et « 2 », pas le nombre douze."
        },
        {
          "text": "Un entier, le nombre douze",
          "correct": false,
          "feedback": "Erreur : sans les guillemets, `a = 12` serait bien un entier.\nLes guillemets transforment la valeur en texte."
        },
        {
          "text": "Un flottant, le nombre $12{,}0$",
          "correct": false,
          "feedback": "Erreur : un flottant s'écrit avec un point, comme `12.0`, et\nsans guillemets."
        },
        {
          "text": "Un booléen, vrai ou faux",
          "correct": false,
          "feedback": "Erreur : un booléen ne prend que les valeurs `True` et `False`."
        }
      ],
      "explanation": "En Python, le type se lit sur l'écriture de la valeur : `12` est un\nentier (`int`), `12.0` un flottant (`float`), `\"12\"` une chaîne de\ncaractères (`str`)."
    },
    {
      "id": "q02",
      "difficulty": 1,
      "skills": [
        "type",
        "flottant"
      ],
      "title": "Le type d'un quotient",
      "partie": "variables",
      "statement": "Après l'instruction `m = 7 / 2`, quel est le type de `m` ?",
      "options": [
        {
          "text": "Un flottant",
          "correct": true,
          "feedback": "Bonne réponse : l'opérateur `/` renvoie toujours un flottant.\nIci `m` vaut `3.5`."
        },
        {
          "text": "Un entier",
          "correct": false,
          "feedback": "Erreur : même `8 / 2` donne `4.0`, un flottant. Le quotient\nentier s'obtient avec `//`."
        },
        {
          "text": "Une chaîne",
          "correct": false,
          "feedback": "Erreur : aucun guillemet n'apparaît, le résultat est un nombre."
        },
        {
          "text": "Cela dépend des valeurs",
          "correct": false,
          "feedback": "Erreur : avec `/`, le résultat est un flottant quelles que\nsoient les valeurs, même lorsque la division tombe juste."
        }
      ],
      "explanation": "`7 / 2` vaut `3.5` (flottant), `7 // 2` vaut `3` (quotient entier)\net `7 % 2` vaut `1` (reste de la division euclidienne)."
    },
    {
      "id": "q03",
      "difficulty": 1,
      "skills": [
        "affectation",
        "sequence"
      ],
      "title": "Suivre deux affectations",
      "partie": "variables",
      "statement": "Quelle est la valeur de `x` après l'exécution de ces instructions ?\n\n```python\nx = 5\nx = x + 3\nx = 2 * x\n```",
      "options": [
        {
          "text": "$16$",
          "correct": true,
          "feedback": "Bonne réponse : `x` vaut d'abord $5$, puis $5 + 3$,\npuis le double de ce résultat, soit $16$."
        },
        {
          "text": "$13$",
          "correct": false,
          "feedback": "Erreur d'ordre : les instructions s'exécutent de haut en bas.\nOn ajoute $3$ avant de doubler."
        },
        {
          "text": "$10$",
          "correct": false,
          "feedback": "Erreur : la deuxième ligne a été oubliée. Elle modifie `x` avant\nle doublement."
        },
        {
          "text": "$8$",
          "correct": false,
          "feedback": "Erreur : la dernière ligne a été oubliée. La valeur de `x` est\nencore doublée."
        }
      ],
      "explanation": "Une affectation `x = expression` calcule d'abord l'expression avec\nla valeur actuelle de `x`, puis range le résultat dans `x`. On suit\nle programme ligne par ligne.",
      "variants": [
        {
          "statement": "Quelle est la valeur de `x` après l'exécution de ces instructions ?\n\n```python\nx = 5\nx = x + 3\nx = 2 * x\n```",
          "options": [
            {
              "text": "$16$",
              "correct": true,
              "feedback": "Bonne réponse : `x` vaut d'abord $5$, puis $5 + 3$,\npuis le double de ce résultat, soit $16$."
            },
            {
              "text": "$13$",
              "correct": false,
              "feedback": "Erreur d'ordre : les instructions s'exécutent de haut en bas.\nOn ajoute $3$ avant de doubler."
            },
            {
              "text": "$10$",
              "correct": false,
              "feedback": "Erreur : la deuxième ligne a été oubliée. Elle modifie `x` avant\nle doublement."
            },
            {
              "text": "$8$",
              "correct": false,
              "feedback": "Erreur : la dernière ligne a été oubliée. La valeur de `x` est\nencore doublée."
            }
          ],
          "explanation": "Une affectation `x = expression` calcule d'abord l'expression avec\nla valeur actuelle de `x`, puis range le résultat dans `x`. On suit\nle programme ligne par ligne."
        },
        {
          "statement": "Quelle est la valeur de `x` après l'exécution de ces instructions ?\n\n```python\nx = 4\nx = x + 7\nx = 2 * x\n```",
          "options": [
            {
              "text": "$22$",
              "correct": true,
              "feedback": "Bonne réponse : `x` vaut d'abord $4$, puis $4 + 7$,\npuis le double de ce résultat, soit $22$."
            },
            {
              "text": "$15$",
              "correct": false,
              "feedback": "Erreur d'ordre : les instructions s'exécutent de haut en bas.\nOn ajoute $7$ avant de doubler."
            },
            {
              "text": "$8$",
              "correct": false,
              "feedback": "Erreur : la deuxième ligne a été oubliée. Elle modifie `x` avant\nle doublement."
            },
            {
              "text": "$11$",
              "correct": false,
              "feedback": "Erreur : la dernière ligne a été oubliée. La valeur de `x` est\nencore doublée."
            }
          ],
          "explanation": "Une affectation `x = expression` calcule d'abord l'expression avec\nla valeur actuelle de `x`, puis range le résultat dans `x`. On suit\nle programme ligne par ligne."
        },
        {
          "statement": "Quelle est la valeur de `x` après l'exécution de ces instructions ?\n\n```python\nx = 9\nx = x + 2\nx = 2 * x\n```",
          "options": [
            {
              "text": "$22$",
              "correct": true,
              "feedback": "Bonne réponse : `x` vaut d'abord $9$, puis $9 + 2$,\npuis le double de ce résultat, soit $22$."
            },
            {
              "text": "$20$",
              "correct": false,
              "feedback": "Erreur d'ordre : les instructions s'exécutent de haut en bas.\nOn ajoute $2$ avant de doubler."
            },
            {
              "text": "$18$",
              "correct": false,
              "feedback": "Erreur : la deuxième ligne a été oubliée. Elle modifie `x` avant\nle doublement."
            },
            {
              "text": "$11$",
              "correct": false,
              "feedback": "Erreur : la dernière ligne a été oubliée. La valeur de `x` est\nencore doublée."
            }
          ],
          "explanation": "Une affectation `x = expression` calcule d'abord l'expression avec\nla valeur actuelle de `x`, puis range le résultat dans `x`. On suit\nle programme ligne par ligne."
        }
      ]
    },
    {
      "id": "q04",
      "difficulty": 2,
      "skills": [
        "affectation",
        "echange"
      ],
      "title": "Échanger deux variables",
      "partie": "variables",
      "statement": "On veut échanger les contenus des variables `a` et `b`. Quelle\nséquence d'instructions convient ?",
      "options": [
        {
          "text": "`c = a`, puis `a = b`, puis `b = c`",
          "correct": true,
          "feedback": "Bonne réponse : la variable `c` garde une copie de l'ancienne\nvaleur de `a` avant qu'elle soit écrasée."
        },
        {
          "text": "`a = b`, puis `b = a`",
          "correct": false,
          "feedback": "Erreur : après `a = b`, l'ancienne valeur de `a` est perdue.\nLes deux variables finissent avec la valeur de `b`."
        },
        {
          "text": "`b = a`, puis `a = b`",
          "correct": false,
          "feedback": "Erreur : même défaut dans l'autre sens. Les deux variables\nfinissent avec la valeur initiale de `a`."
        },
        {
          "text": "`c = a`, puis `b = c`, puis `a = b`",
          "correct": false,
          "feedback": "Erreur : `b` reçoit l'ancienne valeur de `a`, puis `a` reçoit\ncette même valeur. L'ancienne valeur de `b` est perdue."
        }
      ],
      "explanation": "Une affectation remplace l'ancienne valeur. Pour échanger deux\ncontenus, il faut une variable auxiliaire qui conserve l'une des\ndeux valeurs."
    },
    {
      "id": "q05",
      "difficulty": 2,
      "skills": [
        "formule",
        "variables"
      ],
      "title": "Traduire une formule en Python",
      "partie": "variables",
      "statement": "On connaît le rayon `r` et la hauteur `h` d'un cylindre. Quelle\ninstruction range son volume $V = \\pi r^2 h$ dans la variable `V` ?\nOn suppose que `pi` contient une valeur approchée de $\\pi$.",
      "options": [
        {
          "text": "`V = pi * r ** 2 * h`",
          "correct": true,
          "feedback": "Bonne réponse : `**` est l'opérateur de puissance, et chaque\nproduit s'écrit avec `*`."
        },
        {
          "text": "`V = pi * r ^ 2 * h`",
          "correct": false,
          "feedback": "Erreur : en Python, `^` n'est pas la puissance. La puissance\ns'écrit `**`."
        },
        {
          "text": "`V = pi r² h`",
          "correct": false,
          "feedback": "Erreur : Python n'accepte ni la multiplication sous-entendue ni\nl'exposant écrit en petit : chaque opération doit être écrite."
        },
        {
          "text": "`pi * r ** 2 * h = V`",
          "correct": false,
          "feedback": "Erreur : la variable qui reçoit la valeur s'écrit à gauche du\nsigne d'affectation, jamais à droite."
        }
      ],
      "explanation": "Une affectation s'écrit `variable = expression`. Dans l'expression,\nles produits s'écrivent `*` et les puissances `**`."
    },
    {
      "id": "q06",
      "difficulty": 2,
      "skills": [
        "type",
        "conversion"
      ],
      "title": "Additionner une saisie",
      "partie": "variables",
      "statement": "Un programme contient `n = input(\"Nombre ? \")`. L'utilisateur tape\n`5`. Pourquoi l'instruction `n + 1` provoque-t-elle une erreur ?",
      "options": [
        {
          "text": "`n` contient le texte `\"5\"`, pas un nombre",
          "correct": true,
          "feedback": "Bonne réponse : `input` renvoie toujours du texte. On écrit\n`n = int(input(\"Nombre ? \"))` pour obtenir un entier."
        },
        {
          "text": "`n` contient le flottant `5.0`, incompatible avec `1`",
          "correct": false,
          "feedback": "Erreur : un flottant s'additionne sans difficulté à un entier.\nLe problème vient du type chaîne."
        },
        {
          "text": "`n` est vide tant que le programme n'est pas relancé",
          "correct": false,
          "feedback": "Erreur : la saisie est bien rangée dans `n`, mais sous forme de\ntexte."
        },
        {
          "text": "Le nombre `1` doit s'écrire `1.0`",
          "correct": false,
          "feedback": "Erreur : le type du nombre ajouté n'est pas en cause. On ne peut\npas ajouter un nombre à une chaîne de caractères."
        }
      ],
      "explanation": "`input` renvoie une chaîne de caractères. Pour calculer, on la\nconvertit avec `int` (entier) ou `float` (flottant)."
    },
    {
      "id": "q07",
      "difficulty": 1,
      "skills": [
        "operateurs",
        "reste"
      ],
      "title": "Quotient et reste en Python",
      "partie": "variables",
      "statement": "Que valent `17 // 5` et `17 % 5` ?",
      "options": [
        {
          "text": "$3$ et $2$",
          "correct": true,
          "feedback": "Bonne réponse : $17 = 5 \\times 3 + 2$ avec\n$0 \\leq 2 < 5$ : `//` donne le quotient, `%` le reste."
        },
        {
          "text": "$2$ et $3$",
          "correct": false,
          "feedback": "Erreur : les rôles sont inversés. `//` donne le quotient\nentier, `%` donne le reste."
        },
        {
          "text": "$3$ et $0$",
          "correct": false,
          "feedback": "Erreur : `%` ne donne $0$ que lorsque la division tombe juste,\nce qui n'est pas le cas ici."
        },
        {
          "text": "$17$ et $5$",
          "correct": false,
          "feedback": "Erreur : ces opérateurs effectuent la division euclidienne de\n$17$ par $5$."
        }
      ],
      "explanation": "Division euclidienne : `a // b` est le quotient entier et `a % b`\nle reste, avec `a == b * (a // b) + a % b`.",
      "variants": [
        {
          "statement": "Que valent `17 // 5` et `17 % 5` ?",
          "options": [
            {
              "text": "$3$ et $2$",
              "correct": true,
              "feedback": "Bonne réponse : $17 = 5 \\times 3 + 2$ avec\n$0 \\leq 2 < 5$ : `//` donne le quotient, `%` le reste."
            },
            {
              "text": "$2$ et $3$",
              "correct": false,
              "feedback": "Erreur : les rôles sont inversés. `//` donne le quotient\nentier, `%` donne le reste."
            },
            {
              "text": "$3$ et $0$",
              "correct": false,
              "feedback": "Erreur : `%` ne donne $0$ que lorsque la division tombe juste,\nce qui n'est pas le cas ici."
            },
            {
              "text": "$17$ et $5$",
              "correct": false,
              "feedback": "Erreur : ces opérateurs effectuent la division euclidienne de\n$17$ par $5$."
            }
          ],
          "explanation": "Division euclidienne : `a // b` est le quotient entier et `a % b`\nle reste, avec `a == b * (a // b) + a % b`."
        },
        {
          "statement": "Que valent `23 // 4` et `23 % 4` ?",
          "options": [
            {
              "text": "$5$ et $3$",
              "correct": true,
              "feedback": "Bonne réponse : $23 = 4 \\times 5 + 3$ avec\n$0 \\leq 3 < 4$ : `//` donne le quotient, `%` le reste."
            },
            {
              "text": "$3$ et $5$",
              "correct": false,
              "feedback": "Erreur : les rôles sont inversés. `//` donne le quotient\nentier, `%` donne le reste."
            },
            {
              "text": "$5$ et $0$",
              "correct": false,
              "feedback": "Erreur : `%` ne donne $0$ que lorsque la division tombe juste,\nce qui n'est pas le cas ici."
            },
            {
              "text": "$23$ et $4$",
              "correct": false,
              "feedback": "Erreur : ces opérateurs effectuent la division euclidienne de\n$23$ par $4$."
            }
          ],
          "explanation": "Division euclidienne : `a // b` est le quotient entier et `a % b`\nle reste, avec `a == b * (a // b) + a % b`."
        },
        {
          "statement": "Que valent `38 // 7` et `38 % 7` ?",
          "options": [
            {
              "text": "$5$ et $3$",
              "correct": true,
              "feedback": "Bonne réponse : $38 = 7 \\times 5 + 3$ avec\n$0 \\leq 3 < 7$ : `//` donne le quotient, `%` le reste."
            },
            {
              "text": "$3$ et $5$",
              "correct": false,
              "feedback": "Erreur : les rôles sont inversés. `//` donne le quotient\nentier, `%` donne le reste."
            },
            {
              "text": "$5$ et $0$",
              "correct": false,
              "feedback": "Erreur : `%` ne donne $0$ que lorsque la division tombe juste,\nce qui n'est pas le cas ici."
            },
            {
              "text": "$38$ et $7$",
              "correct": false,
              "feedback": "Erreur : ces opérateurs effectuent la division euclidienne de\n$38$ par $7$."
            }
          ],
          "explanation": "Division euclidienne : `a // b` est le quotient entier et `a % b`\nle reste, avec `a == b * (a // b) + a % b`."
        }
      ]
    },
    {
      "id": "q08",
      "difficulty": 2,
      "skills": [
        "langage-naturel",
        "affectation"
      ],
      "title": "Une affectation en langage naturel",
      "partie": "variables",
      "statement": "Dans un algorithme en langage naturel, que signifie l'instruction\n$u \\leftarrow u + 3$ ?",
      "options": [
        {
          "text": "La valeur de $u$ augmente de $3$",
          "correct": true,
          "feedback": "Bonne réponse : on calcule $u + 3$ avec la valeur actuelle de\n$u$, puis on range le résultat dans $u$."
        },
        {
          "text": "Une équation d'inconnue $u$, sans solution",
          "correct": false,
          "feedback": "Erreur : la flèche désigne une affectation, pas une égalité à\nrésoudre."
        },
        {
          "text": "La variable $u$ prend la valeur $3$",
          "correct": false,
          "feedback": "Erreur : ce serait $u \\leftarrow 3$. Ici, on ajoute $3$ à la\nvaleur déjà présente."
        },
        {
          "text": "On compare $u$ et $u + 3$",
          "correct": false,
          "feedback": "Erreur : une comparaison ne modifie aucune variable. La flèche\nmodifie la valeur de $u$."
        }
      ],
      "explanation": "La flèche $\\leftarrow$ note l'affectation dans un algorithme en\nlangage naturel ; elle correspond au signe `=` de Python."
    },
    {
      "id": "q09",
      "difficulty": 1,
      "skills": [
        "condition",
        "si-sinon"
      ],
      "title": "Suivre un test",
      "partie": "conditions",
      "statement": "Quelle valeur le programme suivant affiche-t-il ?\n\n```python\nx = 7\nif x > 5:\n    y = 2 * x\nelse:\n    y = x + 1\nprint(y)\n```",
      "options": [
        {
          "text": "$14$",
          "correct": true,
          "feedback": "Bonne réponse : on compare $7$ à $5$ pour savoir quel bloc\ns'exécute, puis on applique le seul calcul de ce bloc."
        },
        {
          "text": "$8$",
          "correct": false,
          "feedback": "Erreur : c'est le calcul de l'autre bloc. La condition\n`x > 5` décide du bloc exécuté."
        },
        {
          "text": "$7$",
          "correct": false,
          "feedback": "Erreur : le programme affiche `y`, qui a été calculé à partir\nde `x`, pas `x` lui-même."
        },
        {
          "text": "Les deux valeurs $14$ et $8$",
          "correct": false,
          "feedback": "Erreur : un seul des deux blocs s'exécute, jamais les deux."
        }
      ],
      "explanation": "Avec `if … else`, exactement un bloc s'exécute : celui du `if` si la\ncondition est vraie, celui du `else` sinon.",
      "variants": [
        {
          "statement": "Quelle valeur le programme suivant affiche-t-il ?\n\n```python\nx = 7\nif x > 5:\n    y = 2 * x\nelse:\n    y = x + 1\nprint(y)\n```",
          "options": [
            {
              "text": "$14$",
              "correct": true,
              "feedback": "Bonne réponse : on compare $7$ à $5$ pour savoir quel bloc\ns'exécute, puis on applique le seul calcul de ce bloc."
            },
            {
              "text": "$8$",
              "correct": false,
              "feedback": "Erreur : c'est le calcul de l'autre bloc. La condition\n`x > 5` décide du bloc exécuté."
            },
            {
              "text": "$7$",
              "correct": false,
              "feedback": "Erreur : le programme affiche `y`, qui a été calculé à partir\nde `x`, pas `x` lui-même."
            },
            {
              "text": "Les deux valeurs $14$ et $8$",
              "correct": false,
              "feedback": "Erreur : un seul des deux blocs s'exécute, jamais les deux."
            }
          ],
          "explanation": "Avec `if … else`, exactement un bloc s'exécute : celui du `if` si la\ncondition est vraie, celui du `else` sinon."
        },
        {
          "statement": "Quelle valeur le programme suivant affiche-t-il ?\n\n```python\nx = 3\nif x > 5:\n    y = 2 * x\nelse:\n    y = x + 1\nprint(y)\n```",
          "options": [
            {
              "text": "$4$",
              "correct": true,
              "feedback": "Bonne réponse : on compare $3$ à $5$ pour savoir quel bloc\ns'exécute, puis on applique le seul calcul de ce bloc."
            },
            {
              "text": "$6$",
              "correct": false,
              "feedback": "Erreur : c'est le calcul de l'autre bloc. La condition\n`x > 5` décide du bloc exécuté."
            },
            {
              "text": "$3$",
              "correct": false,
              "feedback": "Erreur : le programme affiche `y`, qui a été calculé à partir\nde `x`, pas `x` lui-même."
            },
            {
              "text": "Les deux valeurs $6$ et $4$",
              "correct": false,
              "feedback": "Erreur : un seul des deux blocs s'exécute, jamais les deux."
            }
          ],
          "explanation": "Avec `if … else`, exactement un bloc s'exécute : celui du `if` si la\ncondition est vraie, celui du `else` sinon."
        },
        {
          "statement": "Quelle valeur le programme suivant affiche-t-il ?\n\n```python\nx = 12\nif x > 10:\n    y = 2 * x\nelse:\n    y = x + 1\nprint(y)\n```",
          "options": [
            {
              "text": "$24$",
              "correct": true,
              "feedback": "Bonne réponse : on compare $12$ à $10$ pour savoir quel bloc\ns'exécute, puis on applique le seul calcul de ce bloc."
            },
            {
              "text": "$13$",
              "correct": false,
              "feedback": "Erreur : c'est le calcul de l'autre bloc. La condition\n`x > 10` décide du bloc exécuté."
            },
            {
              "text": "$12$",
              "correct": false,
              "feedback": "Erreur : le programme affiche `y`, qui a été calculé à partir\nde `x`, pas `x` lui-même."
            },
            {
              "text": "Les deux valeurs $24$ et $13$",
              "correct": false,
              "feedback": "Erreur : un seul des deux blocs s'exécute, jamais les deux."
            }
          ],
          "explanation": "Avec `if … else`, exactement un bloc s'exécute : celui du `if` si la\ncondition est vraie, celui du `else` sinon."
        }
      ]
    },
    {
      "id": "q10",
      "difficulty": 1,
      "skills": [
        "comparaison",
        "egalite"
      ],
      "title": "Tester une égalité",
      "partie": "conditions",
      "statement": "Quelle condition teste si la variable `n` vaut $0$ ?",
      "options": [
        {
          "text": "`n == 0`",
          "correct": true,
          "feedback": "Bonne réponse : le double signe `==` compare deux valeurs et\ndonne `True` ou `False`."
        },
        {
          "text": "`n = 0`",
          "correct": false,
          "feedback": "Erreur : un seul signe `=` est une affectation. Il range $0$\ndans `n` au lieu de le comparer."
        },
        {
          "text": "`n => 0`",
          "correct": false,
          "feedback": "Erreur : cette écriture n'existe pas en Python. « Supérieur ou\négal » s'écrit `>=`, et ce n'est pas un test d'égalité."
        },
        {
          "text": "`n != 0`",
          "correct": false,
          "feedback": "Erreur : `!=` teste la **différence**. Cette condition est vraie\nquand `n` ne vaut pas $0$."
        }
      ],
      "explanation": "Comparaisons en Python : `==` (égal), `!=` (différent), `<`, `<=`,\n`>`, `>=`. Le signe `=` seul réalise une affectation."
    },
    {
      "id": "q11",
      "difficulty": 2,
      "skills": [
        "condition",
        "parite"
      ],
      "title": "Tester la parité",
      "partie": "conditions",
      "statement": "Quelle condition est vraie exactement lorsque l'entier `n` est\npair ?",
      "options": [
        {
          "text": "`n % 2 == 0`",
          "correct": true,
          "feedback": "Bonne réponse : un entier est pair lorsque le reste de sa\ndivision par $2$ est nul."
        },
        {
          "text": "`n / 2 == 0`",
          "correct": false,
          "feedback": "Erreur : `n / 2` vaut $0$ seulement si `n` vaut $0$. C'est le\nreste qu'il faut tester."
        },
        {
          "text": "`n // 2 == 0`",
          "correct": false,
          "feedback": "Erreur : le quotient entier `n // 2` vaut $0$ pour $n = 0$ ou\n$n = 1$ seulement."
        },
        {
          "text": "`n % 2 == 1`",
          "correct": false,
          "feedback": "Erreur : un reste égal à $1$ caractérise les entiers\n**impairs**."
        }
      ],
      "explanation": "L'entier $n$ est multiple de $d$ lorsque `n % d == 0`. Pour la\nparité, on prend $d = 2$."
    },
    {
      "id": "q12",
      "difficulty": 2,
      "skills": [
        "condition",
        "elif"
      ],
      "title": "Trois cas avec elif",
      "partie": "conditions",
      "statement": "Qu'affiche ce programme ?\n\n```python\nnote = 14\nif note >= 16:\n    print(\"TB\")\nelif note >= 12:\n    print(\"B\")\nelse:\n    print(\"P\")\n```",
      "options": [
        {
          "text": "`B`",
          "correct": true,
          "feedback": "Bonne réponse : $14 \\geq 16$ est faux, $14 \\geq 12$ est vrai :\nle bloc du `elif` s'exécute, puis le test s'arrête."
        },
        {
          "text": "`TB`",
          "correct": false,
          "feedback": "Erreur : $14$ n'est pas supérieur ou égal à $16$, la première\ncondition est fausse."
        },
        {
          "text": "`B` puis `P`",
          "correct": false,
          "feedback": "Erreur : dès qu'une condition est vraie, les blocs suivants sont\nignorés. Le `else` ne s'exécute pas."
        },
        {
          "text": "`P`",
          "correct": false,
          "feedback": "Erreur : le `else` ne s'exécute que si toutes les conditions\nprécédentes sont fausses, or $14 \\geq 12$."
        }
      ],
      "explanation": "`if … elif … else` examine les conditions dans l'ordre et exécute\nseulement le bloc de la première condition vraie."
    },
    {
      "id": "q13",
      "difficulty": 2,
      "skills": [
        "condition",
        "et-ou"
      ],
      "title": "Appartenir à un intervalle",
      "partie": "conditions",
      "statement": "Quelle condition est vraie exactement lorsque le nombre `x`\nappartient à l'intervalle $[2\\,;\\,5[$ ?",
      "options": [
        {
          "text": "`x >= 2 and x < 5`",
          "correct": true,
          "feedback": "Bonne réponse : les deux inégalités doivent être vraies en même\ntemps, d'où `and`. La borne $2$ est incluse, la borne $5$\nexclue."
        },
        {
          "text": "`x >= 2 or x < 5`",
          "correct": false,
          "feedback": "Erreur : avec `or`, une seule inégalité suffit. Tout réel\nvérifie alors la condition, par exemple $x = 100$."
        },
        {
          "text": "`x > 2 and x <= 5`",
          "correct": false,
          "feedback": "Erreur : cette condition traduit $]2\\,;\\,5]$. Les crochets sont\ninversés."
        },
        {
          "text": "`x >= 2 and x <= 5`",
          "correct": false,
          "feedback": "Erreur : cette condition accepte $x = 5$, alors que le crochet\nde droite est ouvert."
        }
      ],
      "explanation": "$x \\in [a\\,;\\,b[$ se traduit par `x >= a and x < b` : un crochet\nfermé donne une inégalité large, un crochet ouvert une inégalité\nstricte."
    },
    {
      "id": "q14",
      "difficulty": 3,
      "skills": [
        "condition",
        "completer"
      ],
      "title": "Compléter un test d'alignement",
      "partie": "conditions",
      "statement": "La fonction suivante doit renvoyer `True` lorsque les points\n$A(x_A\\,;\\,y_A)$, $B(x_B\\,;\\,y_B)$ et $C(x_C\\,;\\,y_C)$ sont\nalignés, les abscisses $x_A$, $x_B$ et $x_C$ étant distinctes.\nQuelle condition compléter ?\n\n```python\ndef alignes(xA, yA, xB, yB, xC, yC):\n    m1 = (yB - yA) / (xB - xA)\n    m2 = (yC - yA) / (xC - xA)\n    return ...\n```",
      "options": [
        {
          "text": "`m1 == m2`",
          "correct": true,
          "feedback": "Bonne réponse : les droites $(AB)$ et $(AC)$ ont un point\ncommun ; elles sont confondues si et seulement si elles ont le\nmême coefficient directeur."
        },
        {
          "text": "`m1 * m2 == -1`",
          "correct": false,
          "feedback": "Erreur : cette condition caractérise deux droites\nperpendiculaires dans un repère orthonormé, pas l'alignement."
        },
        {
          "text": "`m1 + m2 == 0`",
          "correct": false,
          "feedback": "Erreur : des coefficients opposés donnent des droites\nsymétriques, pas confondues."
        },
        {
          "text": "`m1 == 0 and m2 == 0`",
          "correct": false,
          "feedback": "Erreur : cette condition ne reconnaît que les points alignés sur\nune droite horizontale."
        }
      ],
      "explanation": "Trois points d'abscisses distinctes sont alignés lorsque les\ncoefficients directeurs de $(AB)$ et de $(AC)$ sont égaux. Avec des\nflottants, l'égalité peut échouer à cause des arrondis : on compare\nalors l'écart à une petite tolérance."
    },
    {
      "id": "q15",
      "difficulty": 1,
      "skills": [
        "boucle-bornee",
        "range"
      ],
      "title": "Combien de tours de boucle",
      "partie": "boucles",
      "statement": "Combien de fois le corps de la boucle `for i in range(10):`\nest-il exécuté ?",
      "options": [
        {
          "text": "$10$ fois",
          "correct": true,
          "feedback": "Bonne réponse : `i` prend les valeurs $0$, $1$, …, $9$, soit\n$10$ valeurs."
        },
        {
          "text": "$9$ fois",
          "correct": false,
          "feedback": "Erreur : `range(10)` commence à $0$. Les valeurs de $0$ à $9$\nsont au nombre de $10$."
        },
        {
          "text": "$11$ fois",
          "correct": false,
          "feedback": "Erreur : la borne $10$ est exclue. La dernière valeur de `i`\nest $9$."
        },
        {
          "text": "Tant que `i` est inférieur à $10$, sans fin",
          "correct": false,
          "feedback": "Erreur : une boucle `for` sur `range` est bornée : son nombre de\ntours est connu à l'avance."
        }
      ],
      "explanation": "`range(n)` produit les entiers de $0$ à $n - 1$, soit $n$ valeurs ;\n`range(a, b)` produit les entiers de $a$ à $b - 1$.",
      "variants": [
        {
          "statement": "Combien de fois le corps de la boucle `for i in range(10):`\nest-il exécuté ?",
          "options": [
            {
              "text": "$10$ fois",
              "correct": true,
              "feedback": "Bonne réponse : `i` prend les valeurs $0$, $1$, …, $9$, soit\n$10$ valeurs."
            },
            {
              "text": "$9$ fois",
              "correct": false,
              "feedback": "Erreur : `range(10)` commence à $0$. Les valeurs de $0$ à $9$\nsont au nombre de $10$."
            },
            {
              "text": "$11$ fois",
              "correct": false,
              "feedback": "Erreur : la borne $10$ est exclue. La dernière valeur de `i`\nest $9$."
            },
            {
              "text": "Tant que `i` est inférieur à $10$, sans fin",
              "correct": false,
              "feedback": "Erreur : une boucle `for` sur `range` est bornée : son nombre de\ntours est connu à l'avance."
            }
          ],
          "explanation": "`range(n)` produit les entiers de $0$ à $n - 1$, soit $n$ valeurs ;\n`range(a, b)` produit les entiers de $a$ à $b - 1$."
        },
        {
          "statement": "Combien de fois le corps de la boucle `for i in range(7):`\nest-il exécuté ?",
          "options": [
            {
              "text": "$7$ fois",
              "correct": true,
              "feedback": "Bonne réponse : `i` prend les valeurs $0$, $1$, …, $6$, soit\n$7$ valeurs."
            },
            {
              "text": "$6$ fois",
              "correct": false,
              "feedback": "Erreur : `range(7)` commence à $0$. Les valeurs de $0$ à $6$\nsont au nombre de $7$."
            },
            {
              "text": "$8$ fois",
              "correct": false,
              "feedback": "Erreur : la borne $7$ est exclue. La dernière valeur de `i`\nest $6$."
            },
            {
              "text": "Tant que `i` est inférieur à $7$, sans fin",
              "correct": false,
              "feedback": "Erreur : une boucle `for` sur `range` est bornée : son nombre de\ntours est connu à l'avance."
            }
          ],
          "explanation": "`range(n)` produit les entiers de $0$ à $n - 1$, soit $n$ valeurs ;\n`range(a, b)` produit les entiers de $a$ à $b - 1$."
        },
        {
          "statement": "Combien de fois le corps de la boucle `for i in range(15):`\nest-il exécuté ?",
          "options": [
            {
              "text": "$15$ fois",
              "correct": true,
              "feedback": "Bonne réponse : `i` prend les valeurs $0$, $1$, …, $14$, soit\n$15$ valeurs."
            },
            {
              "text": "$14$ fois",
              "correct": false,
              "feedback": "Erreur : `range(15)` commence à $0$. Les valeurs de $0$ à $14$\nsont au nombre de $15$."
            },
            {
              "text": "$16$ fois",
              "correct": false,
              "feedback": "Erreur : la borne $15$ est exclue. La dernière valeur de `i`\nest $14$."
            },
            {
              "text": "Tant que `i` est inférieur à $15$, sans fin",
              "correct": false,
              "feedback": "Erreur : une boucle `for` sur `range` est bornée : son nombre de\ntours est connu à l'avance."
            }
          ],
          "explanation": "`range(n)` produit les entiers de $0$ à $n - 1$, soit $n$ valeurs ;\n`range(a, b)` produit les entiers de $a$ à $b - 1$."
        }
      ]
    },
    {
      "id": "q16",
      "difficulty": 2,
      "skills": [
        "boucle-bornee",
        "somme"
      ],
      "title": "Une somme calculée par une boucle",
      "partie": "boucles",
      "statement": "Qu'affiche ce programme ?\n\n```python\ns = 0\nfor k in range(1, 5 + 1):\n    s = s + k\nprint(s)\n```",
      "options": [
        {
          "text": "$15$",
          "correct": true,
          "feedback": "Bonne réponse : la boucle ajoute les entiers de $1$ à $5$ :\n$1 + 2 + \\cdots + 5 = 15$."
        },
        {
          "text": "$10$",
          "correct": false,
          "feedback": "Erreur : la borne `5 + 1` est exclue, mais $5$ est bien\najouté. La somme s'arrête à $5$, pas à $5 - 1$."
        },
        {
          "text": "$21$",
          "correct": false,
          "feedback": "Erreur : la valeur $5 + 1$ n'est jamais prise par `k`, car la\nborne de droite de `range` est exclue."
        },
        {
          "text": "$5$",
          "correct": false,
          "feedback": "Erreur : `s` accumule les valeurs successives de `k`, elle ne\ngarde pas seulement la dernière."
        }
      ],
      "explanation": "Motif de l'accumulateur : initialiser `s = 0` avant la boucle, puis\najouter à chaque tour. `range(1, n + 1)` parcourt les entiers de\n$1$ à $n$.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n\n```python\ns = 0\nfor k in range(1, 5 + 1):\n    s = s + k\nprint(s)\n```",
          "options": [
            {
              "text": "$15$",
              "correct": true,
              "feedback": "Bonne réponse : la boucle ajoute les entiers de $1$ à $5$ :\n$1 + 2 + \\cdots + 5 = 15$."
            },
            {
              "text": "$10$",
              "correct": false,
              "feedback": "Erreur : la borne `5 + 1` est exclue, mais $5$ est bien\najouté. La somme s'arrête à $5$, pas à $5 - 1$."
            },
            {
              "text": "$21$",
              "correct": false,
              "feedback": "Erreur : la valeur $5 + 1$ n'est jamais prise par `k`, car la\nborne de droite de `range` est exclue."
            },
            {
              "text": "$5$",
              "correct": false,
              "feedback": "Erreur : `s` accumule les valeurs successives de `k`, elle ne\ngarde pas seulement la dernière."
            }
          ],
          "explanation": "Motif de l'accumulateur : initialiser `s = 0` avant la boucle, puis\najouter à chaque tour. `range(1, n + 1)` parcourt les entiers de\n$1$ à $n$."
        },
        {
          "statement": "Qu'affiche ce programme ?\n\n```python\ns = 0\nfor k in range(1, 6 + 1):\n    s = s + k\nprint(s)\n```",
          "options": [
            {
              "text": "$21$",
              "correct": true,
              "feedback": "Bonne réponse : la boucle ajoute les entiers de $1$ à $6$ :\n$1 + 2 + \\cdots + 6 = 21$."
            },
            {
              "text": "$15$",
              "correct": false,
              "feedback": "Erreur : la borne `6 + 1` est exclue, mais $6$ est bien\najouté. La somme s'arrête à $6$, pas à $6 - 1$."
            },
            {
              "text": "$28$",
              "correct": false,
              "feedback": "Erreur : la valeur $6 + 1$ n'est jamais prise par `k`, car la\nborne de droite de `range` est exclue."
            },
            {
              "text": "$6$",
              "correct": false,
              "feedback": "Erreur : `s` accumule les valeurs successives de `k`, elle ne\ngarde pas seulement la dernière."
            }
          ],
          "explanation": "Motif de l'accumulateur : initialiser `s = 0` avant la boucle, puis\najouter à chaque tour. `range(1, n + 1)` parcourt les entiers de\n$1$ à $n$."
        },
        {
          "statement": "Qu'affiche ce programme ?\n\n```python\ns = 0\nfor k in range(1, 8 + 1):\n    s = s + k\nprint(s)\n```",
          "options": [
            {
              "text": "$36$",
              "correct": true,
              "feedback": "Bonne réponse : la boucle ajoute les entiers de $1$ à $8$ :\n$1 + 2 + \\cdots + 8 = 36$."
            },
            {
              "text": "$28$",
              "correct": false,
              "feedback": "Erreur : la borne `8 + 1` est exclue, mais $8$ est bien\najouté. La somme s'arrête à $8$, pas à $8 - 1$."
            },
            {
              "text": "$45$",
              "correct": false,
              "feedback": "Erreur : la valeur $8 + 1$ n'est jamais prise par `k`, car la\nborne de droite de `range` est exclue."
            },
            {
              "text": "$8$",
              "correct": false,
              "feedback": "Erreur : `s` accumule les valeurs successives de `k`, elle ne\ngarde pas seulement la dernière."
            }
          ],
          "explanation": "Motif de l'accumulateur : initialiser `s = 0` avant la boucle, puis\najouter à chaque tour. `range(1, n + 1)` parcourt les entiers de\n$1$ à $n$."
        }
      ]
    },
    {
      "id": "q17",
      "difficulty": 2,
      "skills": [
        "boucle-non-bornee",
        "seuil"
      ],
      "title": "Une boucle tant que",
      "partie": "boucles",
      "statement": "Qu'affiche ce programme ?\n\n```python\nn = 1\nwhile n < 50:\n    n = 3 * n\nprint(n)\n```",
      "options": [
        {
          "text": "$81$",
          "correct": true,
          "feedback": "Bonne réponse : `n` prend les valeurs $1$, $3$, $9$, $27$, puis\n$81$. Comme $81 < 50$ est faux, la boucle s'arrête."
        },
        {
          "text": "$27$",
          "correct": false,
          "feedback": "Erreur : $27 < 50$ est vrai, donc la boucle fait encore un tour\net `n` devient $81$."
        },
        {
          "text": "$50$",
          "correct": false,
          "feedback": "Erreur : $50$ est le seuil de la condition, mais `n` ne prend que\ndes puissances de $3$."
        },
        {
          "text": "Rien, la boucle ne s'arrête jamais",
          "correct": false,
          "feedback": "Erreur : `n` augmente à chaque tour et finit par dépasser $50$ :\nla condition devient fausse."
        }
      ],
      "explanation": "Une boucle `while` répète son corps tant que la condition est vraie.\nÀ la sortie, la condition est fausse : ici, `n` est la première\npuissance de $3$ supérieure ou égale à $50$."
    },
    {
      "id": "q18",
      "difficulty": 2,
      "skills": [
        "boucle",
        "choix"
      ],
      "title": "Choisir le type de boucle",
      "partie": "boucles",
      "statement": "Un capital de $1\\,000$ euros augmente de $3\\ \\%$ par an. On cherche\nle nombre d'années nécessaires pour qu'il dépasse $1\\,500$ euros.\nQuelle boucle convient ?",
      "options": [
        {
          "text": "Une boucle `while`, arrêtée au seuil",
          "correct": true,
          "feedback": "Bonne réponse : on répète tant que le capital ne dépasse pas\n$1\\,500$, et l'on compte les tours."
        },
        {
          "text": "Une boucle `for`, car on connaît le taux",
          "correct": false,
          "feedback": "Erreur : connaître le taux ne donne pas le nombre de tours. C'est\njustement ce nombre que l'on cherche."
        },
        {
          "text": "Aucune boucle, un seul calcul suffit",
          "correct": false,
          "feedback": "Erreur : en seconde, sans outil pour inverser $1{,}03^n$, on\ncalcule les capitaux année après année."
        },
        {
          "text": "Une boucle `for i in range(1500)`",
          "correct": false,
          "feedback": "Erreur : $1\\,500$ est un montant, pas un nombre d'années. Cette\nboucle ferait $1\\,500$ tours sans s'arrêter au seuil."
        }
      ],
      "explanation": "Boucle bornée (`for`) : le nombre de répétitions est connu à\nl'avance. Boucle non bornée (`while`) : on répète jusqu'à ce qu'une\ncondition change, comme un dépassement de seuil."
    },
    {
      "id": "q19",
      "difficulty": 3,
      "skills": [
        "boucle-non-bornee",
        "compteur"
      ],
      "title": "Compléter un algorithme de seuil",
      "partie": "boucles",
      "statement": "On veut afficher le nombre d'années au bout duquel le capital de\n$1\\,000$ euros, placé à $3\\ \\%$ par an, dépasse $1\\,500$ euros.\nQuelle ligne manque ?\n\n```python\nc = 1000\nn = 0\nwhile c <= 1500:\n    c = c * 1.03\n    ...\nprint(n)\n```",
      "options": [
        {
          "text": "`n = n + 1`",
          "correct": true,
          "feedback": "Bonne réponse : `n` compte les années. Il augmente de $1$ à\nchaque tour, en même temps que le capital."
        },
        {
          "text": "`n = c`",
          "correct": false,
          "feedback": "Erreur : `n` recevrait le montant du capital, pas un nombre\nd'années."
        },
        {
          "text": "`c = c + 1`",
          "correct": false,
          "feedback": "Erreur : le capital est déjà mis à jour à la ligne précédente, et\n`n` resterait à $0$."
        },
        {
          "text": "`n = 1`",
          "correct": false,
          "feedback": "Erreur : `n` vaudrait toujours $1$, quel que soit le nombre de\ntours effectués."
        }
      ],
      "explanation": "Algorithme de seuil : une variable évolue dans la boucle et une\nautre compte les tours. À la sortie, le compteur donne le premier\nrang où la condition est dépassée."
    },
    {
      "id": "q20",
      "difficulty": 3,
      "skills": [
        "boucle-non-bornee",
        "terminaison"
      ],
      "title": "Une boucle qui ne s'arrête pas",
      "partie": "boucles",
      "statement": "Pourquoi ce programme ne s'arrête-t-il jamais ?\n\n```python\nx = 10\nwhile x > 0:\n    x = x + 2\n```",
      "options": [
        {
          "text": "`x` augmente, donc `x > 0` reste toujours vrai",
          "correct": true,
          "feedback": "Bonne réponse : la condition de sortie ne devient jamais fausse.\nIl faudrait par exemple `x = x - 2`."
        },
        {
          "text": "Une boucle `while` s'exécute toujours sans fin",
          "correct": false,
          "feedback": "Erreur : une boucle `while` s'arrête dès que sa condition\ndevient fausse."
        },
        {
          "text": "La variable `x` n'est pas initialisée",
          "correct": false,
          "feedback": "Erreur : la première ligne donne à `x` la valeur $10$."
        },
        {
          "text": "Il manque une instruction `print`",
          "correct": false,
          "feedback": "Erreur : l'absence d'affichage n'empêche pas un programme de se\nterminer."
        }
      ],
      "explanation": "Avant d'écrire une boucle `while`, on vérifie que le corps de la\nboucle fait évoluer les variables vers la sortie."
    },
    {
      "id": "q21",
      "difficulty": 2,
      "skills": [
        "boucle-bornee",
        "suite"
      ],
      "title": "Des tours qui modifient une valeur",
      "partie": "boucles",
      "statement": "Qu'affiche ce programme ?\n\n```python\nu = 2\nfor i in range(3):\n    u = 2 * u + 1\nprint(u)\n```",
      "options": [
        {
          "text": "$23$",
          "correct": true,
          "feedback": "Bonne réponse : la boucle applique $3$ fois la transformation\n« doubler puis ajouter $1$ » à partir de $2$."
        },
        {
          "text": "$11$",
          "correct": false,
          "feedback": "Erreur : il manque un tour. `range(3)` fait exactement $3$\ntours."
        },
        {
          "text": "$47$",
          "correct": false,
          "feedback": "Erreur : un tour de trop. `range(3)` fait $3$ tours, pas\n$3 + 1$."
        },
        {
          "text": "$16$",
          "correct": false,
          "feedback": "Erreur : l'ajout de $1$ à chaque tour a été oublié."
        }
      ],
      "explanation": "Pour lire une boucle, on dresse un tableau des valeurs successives\nde la variable, un tour par ligne.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n\n```python\nu = 2\nfor i in range(3):\n    u = 2 * u + 1\nprint(u)\n```",
          "options": [
            {
              "text": "$23$",
              "correct": true,
              "feedback": "Bonne réponse : la boucle applique $3$ fois la transformation\n« doubler puis ajouter $1$ » à partir de $2$."
            },
            {
              "text": "$11$",
              "correct": false,
              "feedback": "Erreur : il manque un tour. `range(3)` fait exactement $3$\ntours."
            },
            {
              "text": "$47$",
              "correct": false,
              "feedback": "Erreur : un tour de trop. `range(3)` fait $3$ tours, pas\n$3 + 1$."
            },
            {
              "text": "$16$",
              "correct": false,
              "feedback": "Erreur : l'ajout de $1$ à chaque tour a été oublié."
            }
          ],
          "explanation": "Pour lire une boucle, on dresse un tableau des valeurs successives\nde la variable, un tour par ligne."
        },
        {
          "statement": "Qu'affiche ce programme ?\n\n```python\nu = 1\nfor i in range(4):\n    u = 2 * u + 1\nprint(u)\n```",
          "options": [
            {
              "text": "$31$",
              "correct": true,
              "feedback": "Bonne réponse : la boucle applique $4$ fois la transformation\n« doubler puis ajouter $1$ » à partir de $1$."
            },
            {
              "text": "$15$",
              "correct": false,
              "feedback": "Erreur : il manque un tour. `range(4)` fait exactement $4$\ntours."
            },
            {
              "text": "$63$",
              "correct": false,
              "feedback": "Erreur : un tour de trop. `range(4)` fait $4$ tours, pas\n$4 + 1$."
            },
            {
              "text": "$16$",
              "correct": false,
              "feedback": "Erreur : l'ajout de $1$ à chaque tour a été oublié."
            }
          ],
          "explanation": "Pour lire une boucle, on dresse un tableau des valeurs successives\nde la variable, un tour par ligne."
        },
        {
          "statement": "Qu'affiche ce programme ?\n\n```python\nu = 5\nfor i in range(2):\n    u = 2 * u + 1\nprint(u)\n```",
          "options": [
            {
              "text": "$23$",
              "correct": true,
              "feedback": "Bonne réponse : la boucle applique $2$ fois la transformation\n« doubler puis ajouter $1$ » à partir de $5$."
            },
            {
              "text": "$11$",
              "correct": false,
              "feedback": "Erreur : il manque un tour. `range(2)` fait exactement $2$\ntours."
            },
            {
              "text": "$47$",
              "correct": false,
              "feedback": "Erreur : un tour de trop. `range(2)` fait $2$ tours, pas\n$2 + 1$."
            },
            {
              "text": "$20$",
              "correct": false,
              "feedback": "Erreur : l'ajout de $1$ à chaque tour a été oublié."
            }
          ],
          "explanation": "Pour lire une boucle, on dresse un tableau des valeurs successives\nde la variable, un tour par ligne."
        }
      ]
    },
    {
      "id": "q22",
      "difficulty": 3,
      "skills": [
        "boucle",
        "condition"
      ],
      "title": "Une condition dans une boucle",
      "partie": "boucles",
      "statement": "Qu'affiche ce programme ?\n\n```python\nc = 0\nfor k in range(1, 21):\n    if k % 3 == 0 or k % 5 == 0:\n        c = c + 1\nprint(c)\n```",
      "options": [
        {
          "text": "$9$",
          "correct": true,
          "feedback": "Bonne réponse : $6$ multiples de $3$ et $4$ multiples de $5$\nentre $1$ et $20$, mais $15$ est compté deux fois : $6 + 4 - 1$."
        },
        {
          "text": "$10$",
          "correct": false,
          "feedback": "Erreur : $15$ est multiple de $3$ et de $5$, mais le compteur\nn'augmente qu'une fois pour lui."
        },
        {
          "text": "$1$",
          "correct": false,
          "feedback": "Erreur : ce serait le nombre d'entiers multiples de $3$ **et**\nde $5$. Le mot `or` demande l'un ou l'autre."
        },
        {
          "text": "$8$",
          "correct": false,
          "feedback": "Erreur : l'entier $20$ est bien examiné, car `range(1, 21)`\ns'arrête à $20$."
        }
      ],
      "explanation": "Le compteur augmente une fois par valeur de `k` qui vérifie la\ncondition. Une condition avec `or` est vraie dès qu'une des deux\nparties l'est."
    },
    {
      "id": "q23",
      "difficulty": 1,
      "skills": [
        "fonction",
        "appel"
      ],
      "title": "Appeler une fonction",
      "partie": "fonctions",
      "statement": "On définit la fonction suivante. Que vaut `f(3)` ?\n\n```python\ndef f(x):\n    return x ** 2 - 4\n```",
      "options": [
        {
          "text": "$5$",
          "correct": true,
          "feedback": "Bonne réponse : on remplace `x` par $3$ dans l'expression renvoyée : on élève $3$ au carré, puis on retranche $4$, ce qui donne $5$."
        },
        {
          "text": "$2$",
          "correct": false,
          "feedback": "Erreur : `x ** 2` est le carré de `x`, pas son double."
        },
        {
          "text": "$13$",
          "correct": false,
          "feedback": "Erreur de signe : la fonction retranche $4$ au carré."
        },
        {
          "text": "`x ** 2 - 4`",
          "correct": false,
          "feedback": "Erreur : l'appel `f(3)` renvoie une valeur numérique, calculée\navec $x = 3$."
        }
      ],
      "explanation": "Appeler `f(a)`, c'est exécuter le corps de la fonction avec le\nparamètre `x` égal à `a`. L'instruction `return` renvoie le\nrésultat.",
      "variants": [
        {
          "statement": "On définit la fonction suivante. Que vaut `f(3)` ?\n\n```python\ndef f(x):\n    return x ** 2 - 4\n```",
          "options": [
            {
              "text": "$5$",
              "correct": true,
              "feedback": "Bonne réponse : on remplace `x` par $3$ dans l'expression renvoyée : on élève $3$ au carré, puis on retranche $4$, ce qui donne $5$."
            },
            {
              "text": "$2$",
              "correct": false,
              "feedback": "Erreur : `x ** 2` est le carré de `x`, pas son double."
            },
            {
              "text": "$13$",
              "correct": false,
              "feedback": "Erreur de signe : la fonction retranche $4$ au carré."
            },
            {
              "text": "`x ** 2 - 4`",
              "correct": false,
              "feedback": "Erreur : l'appel `f(3)` renvoie une valeur numérique, calculée\navec $x = 3$."
            }
          ],
          "explanation": "Appeler `f(a)`, c'est exécuter le corps de la fonction avec le\nparamètre `x` égal à `a`. L'instruction `return` renvoie le\nrésultat."
        },
        {
          "statement": "On définit la fonction suivante. Que vaut `f(-2)` ?\n\n```python\ndef f(x):\n    return x ** 2 - 4\n```",
          "options": [
            {
              "text": "$0$",
              "correct": true,
              "feedback": "Bonne réponse : on remplace `x` par $-2$ dans l'expression renvoyée : on élève $-2$ au carré, puis on retranche $4$, ce qui donne $0$."
            },
            {
              "text": "$-8$",
              "correct": false,
              "feedback": "Erreur : `x ** 2` est le carré de `x`, pas son double."
            },
            {
              "text": "$8$",
              "correct": false,
              "feedback": "Erreur de signe : la fonction retranche $4$ au carré."
            },
            {
              "text": "`x ** 2 - 4`",
              "correct": false,
              "feedback": "Erreur : l'appel `f(-2)` renvoie une valeur numérique, calculée\navec $x = -2$."
            }
          ],
          "explanation": "Appeler `f(a)`, c'est exécuter le corps de la fonction avec le\nparamètre `x` égal à `a`. L'instruction `return` renvoie le\nrésultat."
        },
        {
          "statement": "On définit la fonction suivante. Que vaut `f(5)` ?\n\n```python\ndef f(x):\n    return x ** 2 - 4\n```",
          "options": [
            {
              "text": "$21$",
              "correct": true,
              "feedback": "Bonne réponse : on remplace `x` par $5$ dans l'expression renvoyée : on élève $5$ au carré, puis on retranche $4$, ce qui donne $21$."
            },
            {
              "text": "$6$",
              "correct": false,
              "feedback": "Erreur : `x ** 2` est le carré de `x`, pas son double."
            },
            {
              "text": "$29$",
              "correct": false,
              "feedback": "Erreur de signe : la fonction retranche $4$ au carré."
            },
            {
              "text": "`x ** 2 - 4`",
              "correct": false,
              "feedback": "Erreur : l'appel `f(5)` renvoie une valeur numérique, calculée\navec $x = 5$."
            }
          ],
          "explanation": "Appeler `f(a)`, c'est exécuter le corps de la fonction avec le\nparamètre `x` égal à `a`. L'instruction `return` renvoie le\nrésultat."
        }
      ]
    },
    {
      "id": "q24",
      "difficulty": 2,
      "skills": [
        "fonction",
        "ecrire"
      ],
      "title": "Écrire une fonction affine",
      "partie": "fonctions",
      "statement": "Quelle définition correspond à la fonction $g : x \\mapsto 3x - 1$ ?",
      "options": [
        {
          "text": "```python\ndef g(x):\n    return 3 * x - 1\n```",
          "correct": true,
          "feedback": "Bonne réponse : l'en-tête nomme la fonction et son paramètre, et\n`return` renvoie l'image."
        },
        {
          "text": "```python\ndef g(x):\n    print(3x - 1)\n```",
          "correct": false,
          "feedback": "Erreur : `3x` n'est pas une écriture valide, et `print` affiche\nla valeur sans la renvoyer : `g(2) + 1` échouerait."
        },
        {
          "text": "```python\ndef g(x):\n    y = 3 * x - 1\n```",
          "correct": false,
          "feedback": "Erreur : la valeur est calculée puis perdue. Sans `return`, la\nfonction ne renvoie rien d'utilisable."
        },
        {
          "text": "```python\ng(x) = 3 * x - 1\n```",
          "correct": false,
          "feedback": "Erreur : c'est une écriture mathématique. En Python, une\nfonction se définit avec `def`."
        }
      ],
      "explanation": "Une fonction Python se définit par `def nom(paramètre):`, suivi d'un\nbloc indenté qui se termine par `return valeur`."
    },
    {
      "id": "q25",
      "difficulty": 2,
      "skills": [
        "fonction",
        "return-print"
      ],
      "title": "Renvoyer ou afficher",
      "partie": "fonctions",
      "statement": "Quelle différence y a-t-il entre `return` et `print` dans une\nfonction ?",
      "options": [
        {
          "text": "`return` rend la valeur réutilisable",
          "correct": true,
          "feedback": "Bonne réponse : la valeur renvoyée peut être rangée dans une\nvariable ou réutilisée dans un calcul. `print` se contente de\nl'afficher à l'écran."
        },
        {
          "text": "Aucune : les deux font apparaître le résultat",
          "correct": false,
          "feedback": "Erreur : une valeur affichée par `print` ne peut pas être\nréutilisée dans un calcul."
        },
        {
          "text": "`print` arrête la fonction, `return` non",
          "correct": false,
          "feedback": "Erreur : c'est l'inverse. `return` termine immédiatement la\nfonction."
        },
        {
          "text": "`return` ne s'utilise qu'avec des nombres entiers",
          "correct": false,
          "feedback": "Erreur : une fonction peut renvoyer un flottant, une chaîne ou un\nbooléen."
        }
      ],
      "explanation": "Une fonction mathématique associe une image à un nombre : en Python,\nc'est `return` qui fournit cette image au reste du programme."
    },
    {
      "id": "q26",
      "difficulty": 2,
      "skills": [
        "fonction",
        "parametres"
      ],
      "title": "Une fonction à deux paramètres",
      "partie": "fonctions",
      "statement": "On définit la fonction suivante. Que vaut `moyenne(12, 17)` ?\n\n```python\ndef moyenne(a, b):\n    return (a + b) / 2\n```",
      "options": [
        {
          "text": "$14{,}5$",
          "correct": true,
          "feedback": "Bonne réponse : $a$ vaut $12$ et $b$ vaut $17$ :\n$(12 + 17) / 2 = 14{,}5$."
        },
        {
          "text": "$20{,}5$",
          "correct": false,
          "feedback": "Erreur de priorité : les parenthèses imposent de faire la somme\navant la division, pas $12 + 17 / 2$."
        },
        {
          "text": "$29$",
          "correct": false,
          "feedback": "Erreur : la somme a bien été calculée, mais pas la division par\n$2$."
        },
        {
          "text": "$14{,}0$",
          "correct": false,
          "feedback": "Erreur : $12 + 17 = 29$ est impair, sa moitié n'est donc pas un entier."
        }
      ],
      "explanation": "Lors de l'appel, les arguments sont affectés aux paramètres dans\nl'ordre : le premier à `a`, le second à `b`."
    },
    {
      "id": "q27",
      "difficulty": 3,
      "skills": [
        "fonction",
        "booleen"
      ],
      "title": "Une fonction qui teste",
      "partie": "fonctions",
      "statement": "On veut une fonction `est_diviseur(d, n)` qui renvoie `True` si `d`\ndivise l'entier `n`, et `False` sinon. Quelle définition convient ?",
      "options": [
        {
          "text": "```python\ndef est_diviseur(d, n):\n    return n % d == 0\n```",
          "correct": true,
          "feedback": "Bonne réponse : la comparaison `n % d == 0` vaut déjà `True` ou\n`False`, on la renvoie directement."
        },
        {
          "text": "```python\ndef est_diviseur(d, n):\n    return d % n == 0\n```",
          "correct": false,
          "feedback": "Erreur : les rôles sont inversés. Ce test indique si `n` divise\n`d`."
        },
        {
          "text": "```python\ndef est_diviseur(d, n):\n    return n // d\n```",
          "correct": false,
          "feedback": "Erreur : cette fonction renvoie un quotient, pas un booléen."
        },
        {
          "text": "```python\ndef est_diviseur(d, n):\n    if n % d == 0:\n        return True\n```",
          "correct": false,
          "feedback": "Erreur : si `d` ne divise pas `n`, aucune instruction `return`\nn'est exécutée et la fonction ne renvoie pas `False`."
        }
      ],
      "explanation": "Une condition est une expression de type booléen : on peut la\nrenvoyer telle quelle, sans `if`."
    },
    {
      "id": "q28",
      "difficulty": 3,
      "skills": [
        "fonction",
        "hasard"
      ],
      "title": "Simuler un lancer de dé",
      "partie": "fonctions",
      "statement": "Le module `random` est importé. Quelle fonction renvoie le résultat\nd'un lancer de dé équilibré à six faces ?",
      "options": [
        {
          "text": "```python\ndef de():\n    return random.randint(1, 6)\n```",
          "correct": true,
          "feedback": "Bonne réponse : `randint(1, 6)` renvoie un entier au hasard entre\n$1$ et $6$, **bornes comprises**, chacun avec la même\nprobabilité."
        },
        {
          "text": "```python\ndef de():\n    return random.randint(0, 6)\n```",
          "correct": false,
          "feedback": "Erreur : cette fonction peut renvoyer $0$, qui n'est pas une face\ndu dé : il y aurait sept résultats possibles."
        },
        {
          "text": "```python\ndef de():\n    return 6 * random.random()\n```",
          "correct": false,
          "feedback": "Erreur : `random()` renvoie un flottant. On obtiendrait des\nvaleurs comme $3{,}74$, pas des entiers."
        },
        {
          "text": "```python\ndef de():\n    return random.randint(1, 7)\n```",
          "correct": false,
          "feedback": "Erreur : les deux bornes de `randint` sont comprises, donc $7$\npourrait sortir."
        }
      ],
      "explanation": "`random.randint(a, b)` renvoie un entier aléatoire de $a$ à $b$,\nbornes incluses ; `random.random()` renvoie un flottant de\n$[0\\,;\\,1[$."
    },
    {
      "id": "q29",
      "difficulty": 3,
      "skills": [
        "fonction",
        "frequence"
      ],
      "title": "Fréquence de six sur des lancers",
      "partie": "fonctions",
      "statement": "Le module `random` est importé. Que renvoie `f(1000)` ?\n\n```python\ndef f(n):\n    c = 0\n    for i in range(n):\n        if random.randint(1, 6) == 6:\n            c = c + 1\n    return c / n\n```",
      "options": [
        {
          "text": "La fréquence de six sur $1\\,000$ lancers",
          "correct": true,
          "feedback": "Bonne réponse : `c` compte les six obtenus, puis on divise par\nle nombre de lancers. Le résultat est souvent proche de\n$\\dfrac{1}{6}$."
        },
        {
          "text": "Le nombre de six sur $1\\,000$ lancers",
          "correct": false,
          "feedback": "Erreur : ce serait `return c`. La division par `n` transforme\nl'effectif en fréquence."
        },
        {
          "text": "Exactement $\\dfrac{1}{6}$",
          "correct": false,
          "feedback": "Erreur : le résultat dépend du hasard et varie d'un appel à\nl'autre, autour de $\\dfrac{1}{6}$."
        },
        {
          "text": "Le dernier résultat du dé",
          "correct": false,
          "feedback": "Erreur : les résultats des lancers ne sont pas conservés. Seul\nle compteur `c` l'est."
        }
      ],
      "explanation": "Fonction de simulation : répéter une expérience aléatoire, compter\nles succès, renvoyer la fréquence. La loi des grands nombres\nexplique qu'elle se rapproche de la probabilité quand `n` grandit."
    },
    {
      "id": "q30",
      "difficulty": 3,
      "skills": [
        "fonction",
        "modifier"
      ],
      "title": "Modifier une fonction de seuil",
      "partie": "fonctions",
      "statement": "La fonction ci-dessous renvoie le nombre d'années nécessaires pour\nqu'un capital de $1\\,000$ euros, placé à $3\\ \\%$ par an, dépasse le\nmontant `m`. Comment la modifier pour que le taux devienne un\nparamètre `t` exprimé en pourcentage ?\n\n```python\ndef annees(m):\n    c = 1000\n    n = 0\n    while c <= m:\n        c = c * 1.03\n        n = n + 1\n    return n\n```",
      "options": [
        {
          "text": "En-tête `def annees(m, t):`, facteur `1 + t / 100`",
          "correct": true,
          "feedback": "Bonne réponse : une hausse de $t\\ \\%$ multiplie par\n$1 + \\dfrac{t}{100}$. Pour $t = 3$, on retrouve $1{,}03$."
        },
        {
          "text": "En-tête `def annees(m, t):` et ligne `c = c * t`",
          "correct": false,
          "feedback": "Erreur : pour $t = 3$, le capital serait multiplié par $3$, soit\nune hausse de $200\\ \\%$."
        },
        {
          "text": "En-tête `def annees(m, t):` et ligne `c = c + t`",
          "correct": false,
          "feedback": "Erreur : on ajouterait $t$ euros par an, une évolution linéaire\net non une hausse en pourcentage."
        },
        {
          "text": "Ligne `c = c * (1 + t / 100)` sans changer l'en-tête",
          "correct": false,
          "feedback": "Erreur : `t` ne serait défini nulle part, ce qui provoque une\nerreur à l'exécution. Il doit figurer parmi les paramètres."
        }
      ],
      "explanation": "Transformer une valeur écrite en dur en paramètre rend la fonction\nréutilisable : on l'ajoute dans l'en-tête, puis on l'utilise dans le\ncorps."
    },
    {
      "id": "q31",
      "difficulty": 1,
      "skills": [
        "conditions",
        "elif",
        "signe"
      ],
      "title": "Le signe d'un nombre par un test à trois branches",
      "partie": "conditions",
      "statement": "Qu'affiche ce programme ?\n```python\nx = 0\nif x < 0:\n    print(\"negatif\")\nelif x == 0:\n    print(\"nul\")\nelse:\n    print(\"positif\")\n```",
      "options": [
        {
          "text": "`nul`",
          "correct": true,
          "feedback": "Bonne réponse : les tests sont examinés dans l'ordre et la\npremière condition vraie l'emporte ; pour $x = 0$, c'est la\nbranche `nul`.\n"
        },
        {
          "text": "`negatif`",
          "correct": false,
          "feedback": "Erreur : relisez la comparaison de $0$ avec $0$ dans chaque\ntest.\n"
        },
        {
          "text": "`positif`",
          "correct": false,
          "feedback": "Erreur : cette branche correspond à une autre valeur de $x$.\n"
        },
        {
          "text": "Les trois mots, chaque branche étant parcourue",
          "correct": false,
          "feedback": "Erreur : avec `elif` et `else`, une seule branche s'exécute.\n"
        }
      ],
      "explanation": "Une structure `if`, `elif`, `else` partage les valeurs en cas\ndisjoints : négatif, nul ou positif.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\nx = 0\nif x < 0:\n    print(\"negatif\")\nelif x == 0:\n    print(\"nul\")\nelse:\n    print(\"positif\")\n```",
          "options": [
            {
              "text": "`nul`",
              "correct": true,
              "feedback": "Bonne réponse : les tests sont examinés dans l'ordre et la\npremière condition vraie l'emporte ; pour $x = 0$, c'est la\nbranche `nul`.\n"
            },
            {
              "text": "`negatif`",
              "correct": false,
              "feedback": "Erreur : relisez la comparaison de $0$ avec $0$ dans chaque\ntest.\n"
            },
            {
              "text": "`positif`",
              "correct": false,
              "feedback": "Erreur : cette branche correspond à une autre valeur de $x$.\n"
            },
            {
              "text": "Les trois mots, chaque branche étant parcourue",
              "correct": false,
              "feedback": "Erreur : avec `elif` et `else`, une seule branche s'exécute.\n"
            }
          ],
          "explanation": "Une structure `if`, `elif`, `else` partage les valeurs en cas\ndisjoints : négatif, nul ou positif."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nx = -4\nif x < 0:\n    print(\"negatif\")\nelif x == 0:\n    print(\"nul\")\nelse:\n    print(\"positif\")\n```",
          "options": [
            {
              "text": "`negatif`",
              "correct": true,
              "feedback": "Bonne réponse : les tests sont examinés dans l'ordre et la\npremière condition vraie l'emporte ; pour $x = -4$, c'est la\nbranche `negatif`.\n"
            },
            {
              "text": "`nul`",
              "correct": false,
              "feedback": "Erreur : relisez la comparaison de $-4$ avec $0$ dans chaque\ntest.\n"
            },
            {
              "text": "`positif`",
              "correct": false,
              "feedback": "Erreur : cette branche correspond à une autre valeur de $x$.\n"
            },
            {
              "text": "Les trois mots, chaque branche étant parcourue",
              "correct": false,
              "feedback": "Erreur : avec `elif` et `else`, une seule branche s'exécute.\n"
            }
          ],
          "explanation": "Une structure `if`, `elif`, `else` partage les valeurs en cas\ndisjoints : négatif, nul ou positif."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nx = 7\nif x < 0:\n    print(\"negatif\")\nelif x == 0:\n    print(\"nul\")\nelse:\n    print(\"positif\")\n```",
          "options": [
            {
              "text": "`positif`",
              "correct": true,
              "feedback": "Bonne réponse : les tests sont examinés dans l'ordre et la\npremière condition vraie l'emporte ; pour $x = 7$, c'est la\nbranche `positif`.\n"
            },
            {
              "text": "`negatif`",
              "correct": false,
              "feedback": "Erreur : relisez la comparaison de $7$ avec $0$ dans chaque\ntest.\n"
            },
            {
              "text": "`nul`",
              "correct": false,
              "feedback": "Erreur : cette branche correspond à une autre valeur de $x$.\n"
            },
            {
              "text": "Les trois mots, chaque branche étant parcourue",
              "correct": false,
              "feedback": "Erreur : avec `elif` et `else`, une seule branche s'exécute.\n"
            }
          ],
          "explanation": "Une structure `if`, `elif`, `else` partage les valeurs en cas\ndisjoints : négatif, nul ou positif."
        }
      ]
    },
    {
      "id": "q32",
      "difficulty": 2,
      "skills": [
        "conditions",
        "maximum",
        "if-else"
      ],
      "title": "Afficher le plus grand de deux nombres",
      "partie": "conditions",
      "statement": "Qu'affiche ce programme ?\n```python\na = 7\nb = 12\nif a > b:\n    print(a)\nelse:\n    print(b)\n```",
      "options": [
        {
          "text": "`12`",
          "correct": true,
          "feedback": "Bonne réponse : le programme affiche `a` si `a > b`, sinon `b` ;\ndans les deux cas, c'est la plus grande des deux valeurs, ou leur\nvaleur commune si elles sont égales.\n"
        },
        {
          "text": "`7`, la plus petite",
          "correct": false,
          "feedback": "Erreur : le test `a > b` sélectionne la plus grande valeur.\n"
        },
        {
          "text": "`19`, la somme",
          "correct": false,
          "feedback": "Erreur : aucune addition n'est faite.\n"
        },
        {
          "text": "`7` puis `12`",
          "correct": false,
          "feedback": "Erreur : une seule des deux branches s'exécute.\n"
        }
      ],
      "explanation": "Ce programme calcule le maximum de deux nombres : une condition\nchoisit la valeur à afficher.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\na = 7\nb = 12\nif a > b:\n    print(a)\nelse:\n    print(b)\n```",
          "options": [
            {
              "text": "`12`",
              "correct": true,
              "feedback": "Bonne réponse : le programme affiche `a` si `a > b`, sinon `b` ;\ndans les deux cas, c'est la plus grande des deux valeurs, ou leur\nvaleur commune si elles sont égales.\n"
            },
            {
              "text": "`7`, la plus petite",
              "correct": false,
              "feedback": "Erreur : le test `a > b` sélectionne la plus grande valeur.\n"
            },
            {
              "text": "`19`, la somme",
              "correct": false,
              "feedback": "Erreur : aucune addition n'est faite.\n"
            },
            {
              "text": "`7` puis `12`",
              "correct": false,
              "feedback": "Erreur : une seule des deux branches s'exécute.\n"
            }
          ],
          "explanation": "Ce programme calcule le maximum de deux nombres : une condition\nchoisit la valeur à afficher."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\na = 15\nb = 9\nif a > b:\n    print(a)\nelse:\n    print(b)\n```",
          "options": [
            {
              "text": "`15`",
              "correct": true,
              "feedback": "Bonne réponse : le programme affiche `a` si `a > b`, sinon `b` ;\ndans les deux cas, c'est la plus grande des deux valeurs, ou leur\nvaleur commune si elles sont égales.\n"
            },
            {
              "text": "`9`, la plus petite",
              "correct": false,
              "feedback": "Erreur : le test `a > b` sélectionne la plus grande valeur.\n"
            },
            {
              "text": "`24`, la somme",
              "correct": false,
              "feedback": "Erreur : aucune addition n'est faite.\n"
            },
            {
              "text": "`15` puis `9`",
              "correct": false,
              "feedback": "Erreur : une seule des deux branches s'exécute.\n"
            }
          ],
          "explanation": "Ce programme calcule le maximum de deux nombres : une condition\nchoisit la valeur à afficher."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\na = 3\nb = 3\nif a > b:\n    print(a)\nelse:\n    print(b)\n```",
          "options": [
            {
              "text": "`3`",
              "correct": true,
              "feedback": "Bonne réponse : le programme affiche `a` si `a > b`, sinon `b` ;\ndans les deux cas, c'est la plus grande des deux valeurs, ou leur\nvaleur commune si elles sont égales.\n"
            },
            {
              "text": "`3`, la plus petite",
              "correct": false,
              "feedback": "Erreur : le test `a > b` sélectionne la plus grande valeur.\n"
            },
            {
              "text": "`6`, la somme",
              "correct": false,
              "feedback": "Erreur : aucune addition n'est faite.\n"
            },
            {
              "text": "`3` puis `3`",
              "correct": false,
              "feedback": "Erreur : une seule des deux branches s'exécute.\n"
            }
          ],
          "explanation": "Ce programme calcule le maximum de deux nombres : une condition\nchoisit la valeur à afficher."
        }
      ]
    },
    {
      "id": "q33",
      "difficulty": 2,
      "skills": [
        "conditions",
        "or",
        "intervalle"
      ],
      "title": "En dehors d'un intervalle",
      "partie": "conditions",
      "statement": "Qu'affiche ce programme ?\n```python\nx = 5\nif x < 2 or x > 8:\n    print(\"hors\")\nelse:\n    print(\"dans\")\n```",
      "options": [
        {
          "text": "`dans`, $5$ étant entre $2$ et $8$",
          "correct": true,
          "feedback": "Bonne réponse : la condition `x < 2 or x > 8` est vraie dès\nqu'une des deux comparaisons l'est ; sinon, `x` est dans\n$[2 ; 8]$.\n"
        },
        {
          "text": "`hors`, $5$ n'étant ni $2$ ni $8$",
          "correct": false,
          "feedback": "Erreur : testez chaque comparaison avec $x = 5$ ; un seul\n`or` vrai suffit à afficher `hors`.\n"
        },
        {
          "text": "Une erreur, deux comparaisons ne pouvant être combinées",
          "correct": false,
          "feedback": "Erreur : `or` sert précisément à combiner deux conditions.\n"
        },
        {
          "text": "`5`, la valeur de `x`",
          "correct": false,
          "feedback": "Erreur : le programme affiche un mot, pas la valeur de `x`.\n"
        }
      ],
      "explanation": "« En dehors de $[2 ; 8]$ » se traduit par `x < 2 or x > 8` ; « dans »\npar `2 <= x <= 8`.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\nx = 5\nif x < 2 or x > 8:\n    print(\"hors\")\nelse:\n    print(\"dans\")\n```",
          "options": [
            {
              "text": "`dans`, $5$ étant entre $2$ et $8$",
              "correct": true,
              "feedback": "Bonne réponse : la condition `x < 2 or x > 8` est vraie dès\nqu'une des deux comparaisons l'est ; sinon, `x` est dans\n$[2 ; 8]$.\n"
            },
            {
              "text": "`hors`, $5$ n'étant ni $2$ ni $8$",
              "correct": false,
              "feedback": "Erreur : testez chaque comparaison avec $x = 5$ ; un seul\n`or` vrai suffit à afficher `hors`.\n"
            },
            {
              "text": "Une erreur, deux comparaisons ne pouvant être combinées",
              "correct": false,
              "feedback": "Erreur : `or` sert précisément à combiner deux conditions.\n"
            },
            {
              "text": "`5`, la valeur de `x`",
              "correct": false,
              "feedback": "Erreur : le programme affiche un mot, pas la valeur de `x`.\n"
            }
          ],
          "explanation": "« En dehors de $[2 ; 8]$ » se traduit par `x < 2 or x > 8` ; « dans »\npar `2 <= x <= 8`."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nx = 9\nif x < 2 or x > 8:\n    print(\"hors\")\nelse:\n    print(\"dans\")\n```",
          "options": [
            {
              "text": "`hors`, $9$ étant supérieur à $8$",
              "correct": true,
              "feedback": "Bonne réponse : la condition `x < 2 or x > 8` est vraie dès\nqu'une des deux comparaisons l'est ; sinon, `x` est dans\n$[2 ; 8]$.\n"
            },
            {
              "text": "`dans`, $9$ étant supérieur à $2$",
              "correct": false,
              "feedback": "Erreur : testez chaque comparaison avec $x = 9$ ; un seul\n`or` vrai suffit à afficher `hors`.\n"
            },
            {
              "text": "Une erreur, deux comparaisons ne pouvant être combinées",
              "correct": false,
              "feedback": "Erreur : `or` sert précisément à combiner deux conditions.\n"
            },
            {
              "text": "`9`, la valeur de `x`",
              "correct": false,
              "feedback": "Erreur : le programme affiche un mot, pas la valeur de `x`.\n"
            }
          ],
          "explanation": "« En dehors de $[2 ; 8]$ » se traduit par `x < 2 or x > 8` ; « dans »\npar `2 <= x <= 8`."
        }
      ]
    },
    {
      "id": "q34",
      "difficulty": 3,
      "skills": [
        "conditions",
        "racine-carree",
        "domaine"
      ],
      "title": "Une condition avant une racine carrée",
      "partie": "conditions",
      "statement": "Avant de calculer `sqrt(x)` dans un programme, quelle condition\nfaut-il tester pour éviter une erreur ?",
      "options": [
        {
          "text": "`x >= 0`, la racine exigeant un nombre positif ou nul",
          "correct": true,
          "feedback": "Bonne réponse : $\\sqrt{x}$ n'existe que pour $x \\geq 0$ ; le\ntest protège l'appel de `sqrt`, qui échouerait pour un nombre\nnégatif.\n"
        },
        {
          "text": "`x > 0`, zéro n'ayant pas de racine carrée définie",
          "correct": false,
          "feedback": "Erreur : $\\sqrt{0} = 0$ existe ; exclure zéro est inutile.\n"
        },
        {
          "text": "`x != 0`, pour éviter une division par zéro cachée",
          "correct": false,
          "feedback": "Erreur : il n'y a pas de division ici ; le danger est un nombre\nnégatif.\n"
        },
        {
          "text": "`x <= 0`, la racine carrée demandant un nombre négatif",
          "correct": false,
          "feedback": "Erreur : c'est l'inverse, la racine carrée demande un nombre\npositif ou nul.\n"
        }
      ],
      "explanation": "Un test conditionnel sert aussi à vérifier qu'un calcul est\npossible : domaine de définition d'une racine, d'un quotient."
    },
    {
      "id": "q35",
      "difficulty": 1,
      "skills": [
        "type",
        "chaine",
        "concatenation"
      ],
      "title": "Additionner deux chaînes de chiffres",
      "partie": "variables",
      "statement": "Que vaut l'expression `\"3\" + \"4\"` ?",
      "options": [
        {
          "text": "`'34'`, la concaténation des deux chaînes",
          "correct": true,
          "feedback": "Bonne réponse : entre guillemets, `\"3\"` et `\"4\"` sont des\nchaînes de caractères ; `+` les met bout à bout.\n"
        },
        {
          "text": "`7`, la somme des deux entiers",
          "correct": false,
          "feedback": "Erreur : les guillemets font de `\"3\"` et `\"4\"` des chaînes,\npas des entiers ; il faudrait `int(\"3\") + int(\"4\")`.\n"
        },
        {
          "text": "`'7'`, la somme écrite entre guillemets",
          "correct": false,
          "feedback": "Erreur : Python ne calcule pas sur des chaînes, il les\njuxtapose.\n"
        },
        {
          "text": "Une erreur, les chaînes ne pouvant pas s'additionner",
          "correct": false,
          "feedback": "Erreur : `+` entre deux chaînes est autorisé et les concatène.\n"
        }
      ],
      "explanation": "Le même symbole `+` additionne des nombres et concatène des\nchaînes : le type des valeurs décide."
    },
    {
      "id": "q36",
      "difficulty": 2,
      "skills": [
        "affectation",
        "sequence"
      ],
      "title": "Deux affectations successives sur une variable",
      "partie": "variables",
      "statement": "Que vaut `a` à la fin de ce programme ?\n```python\na = 5\na = a + 3\na = a * 2\n```",
      "options": [
        {
          "text": "`16`, l'addition puis le produit, dans l'ordre",
          "correct": true,
          "feedback": "Bonne réponse : après la deuxième ligne `a` vaut $8$,\npuis la troisième la multiplie par $2$.\n"
        },
        {
          "text": "`11`, le produit étant prioritaire sur l'addition",
          "correct": false,
          "feedback": "Erreur : il n'y a pas une expression mais deux instructions\nexécutées l'une après l'autre.\n"
        },
        {
          "text": "`13`, le produit effectué avant l'addition",
          "correct": false,
          "feedback": "Erreur : les instructions s'exécutent dans l'ordre d'écriture.\n"
        },
        {
          "text": "`10`, les trois nombres additionnés",
          "correct": false,
          "feedback": "Erreur : la troisième ligne multiplie, elle n'additionne pas.\n"
        }
      ],
      "explanation": "Chaque affectation remplace la valeur de `a` par le résultat du\ncalcul fait avec sa valeur courante.",
      "variants": [
        {
          "statement": "Que vaut `a` à la fin de ce programme ?\n```python\na = 5\na = a + 3\na = a * 2\n```",
          "options": [
            {
              "text": "`16`, l'addition puis le produit, dans l'ordre",
              "correct": true,
              "feedback": "Bonne réponse : après la deuxième ligne `a` vaut $8$,\npuis la troisième la multiplie par $2$.\n"
            },
            {
              "text": "`11`, le produit étant prioritaire sur l'addition",
              "correct": false,
              "feedback": "Erreur : il n'y a pas une expression mais deux instructions\nexécutées l'une après l'autre.\n"
            },
            {
              "text": "`13`, le produit effectué avant l'addition",
              "correct": false,
              "feedback": "Erreur : les instructions s'exécutent dans l'ordre d'écriture.\n"
            },
            {
              "text": "`10`, les trois nombres additionnés",
              "correct": false,
              "feedback": "Erreur : la troisième ligne multiplie, elle n'additionne pas.\n"
            }
          ],
          "explanation": "Chaque affectation remplace la valeur de `a` par le résultat du\ncalcul fait avec sa valeur courante."
        },
        {
          "statement": "Que vaut `a` à la fin de ce programme ?\n```python\na = 4\na = a + 6\na = a * 3\n```",
          "options": [
            {
              "text": "`30`, l'addition puis le produit, dans l'ordre",
              "correct": true,
              "feedback": "Bonne réponse : après la deuxième ligne `a` vaut $10$,\npuis la troisième la multiplie par $3$.\n"
            },
            {
              "text": "`22`, le produit étant prioritaire sur l'addition",
              "correct": false,
              "feedback": "Erreur : il n'y a pas une expression mais deux instructions\nexécutées l'une après l'autre.\n"
            },
            {
              "text": "`18`, le produit effectué avant l'addition",
              "correct": false,
              "feedback": "Erreur : les instructions s'exécutent dans l'ordre d'écriture.\n"
            },
            {
              "text": "`13`, les trois nombres additionnés",
              "correct": false,
              "feedback": "Erreur : la troisième ligne multiplie, elle n'additionne pas.\n"
            }
          ],
          "explanation": "Chaque affectation remplace la valeur de `a` par le résultat du\ncalcul fait avec sa valeur courante."
        },
        {
          "statement": "Que vaut `a` à la fin de ce programme ?\n```python\na = 7\na = a + 1\na = a * 4\n```",
          "options": [
            {
              "text": "`32`, l'addition puis le produit, dans l'ordre",
              "correct": true,
              "feedback": "Bonne réponse : après la deuxième ligne `a` vaut $8$,\npuis la troisième la multiplie par $4$.\n"
            },
            {
              "text": "`11`, le produit étant prioritaire sur l'addition",
              "correct": false,
              "feedback": "Erreur : il n'y a pas une expression mais deux instructions\nexécutées l'une après l'autre.\n"
            },
            {
              "text": "`29`, le produit effectué avant l'addition",
              "correct": false,
              "feedback": "Erreur : les instructions s'exécutent dans l'ordre d'écriture.\n"
            },
            {
              "text": "`12`, les trois nombres additionnés",
              "correct": false,
              "feedback": "Erreur : la troisième ligne multiplie, elle n'additionne pas.\n"
            }
          ],
          "explanation": "Chaque affectation remplace la valeur de `a` par le résultat du\ncalcul fait avec sa valeur courante."
        }
      ]
    },
    {
      "id": "q37",
      "difficulty": 2,
      "skills": [
        "priorite",
        "puissance",
        "affectation"
      ],
      "title": "Priorité de la puissance dans une affectation",
      "partie": "variables",
      "statement": "Que vaut `x` après l'instruction `x = 2 ** 3 * 2` ?",
      "options": [
        {
          "text": "`16`, la puissance étant calculée avant le produit",
          "correct": true,
          "feedback": "Bonne réponse : `**` est prioritaire sur `*`, donc\n$2^3 \\times 2 = 16$.\n"
        },
        {
          "text": "`64`, le produit des exposants",
          "correct": false,
          "feedback": "Erreur : c'est `2 ** (3 * 2)` qui donnerait ce résultat.\n"
        },
        {
          "text": "`12`, les trois nombres multipliés",
          "correct": false,
          "feedback": "Erreur : `**` est une puissance, pas une multiplication.\n"
        },
        {
          "text": "`8`, le produit puis la somme",
          "correct": false,
          "feedback": "Erreur : il n'y a ni somme ni produit $2 \\times 3$.\n"
        }
      ],
      "explanation": "En Python comme en mathématiques, la puissance précède le produit.",
      "variants": [
        {
          "statement": "Que vaut `x` après l'instruction `x = 2 ** 3 * 2` ?",
          "options": [
            {
              "text": "`16`, la puissance étant calculée avant le produit",
              "correct": true,
              "feedback": "Bonne réponse : `**` est prioritaire sur `*`, donc\n$2^3 \\times 2 = 16$.\n"
            },
            {
              "text": "`64`, le produit des exposants",
              "correct": false,
              "feedback": "Erreur : c'est `2 ** (3 * 2)` qui donnerait ce résultat.\n"
            },
            {
              "text": "`12`, les trois nombres multipliés",
              "correct": false,
              "feedback": "Erreur : `**` est une puissance, pas une multiplication.\n"
            },
            {
              "text": "`8`, le produit puis la somme",
              "correct": false,
              "feedback": "Erreur : il n'y a ni somme ni produit $2 \\times 3$.\n"
            }
          ],
          "explanation": "En Python comme en mathématiques, la puissance précède le produit."
        },
        {
          "statement": "Que vaut `x` après l'instruction `x = 3 ** 2 * 4` ?",
          "options": [
            {
              "text": "`36`, la puissance étant calculée avant le produit",
              "correct": true,
              "feedback": "Bonne réponse : `**` est prioritaire sur `*`, donc\n$3^2 \\times 4 = 36$.\n"
            },
            {
              "text": "`6561`, le produit des exposants",
              "correct": false,
              "feedback": "Erreur : c'est `3 ** (2 * 4)` qui donnerait ce résultat.\n"
            },
            {
              "text": "`24`, les trois nombres multipliés",
              "correct": false,
              "feedback": "Erreur : `**` est une puissance, pas une multiplication.\n"
            },
            {
              "text": "`10`, le produit puis la somme",
              "correct": false,
              "feedback": "Erreur : il n'y a ni somme ni produit $3 \\times 2$.\n"
            }
          ],
          "explanation": "En Python comme en mathématiques, la puissance précède le produit."
        },
        {
          "statement": "Que vaut `x` après l'instruction `x = 2 ** 4 * 3` ?",
          "options": [
            {
              "text": "`48`, la puissance étant calculée avant le produit",
              "correct": true,
              "feedback": "Bonne réponse : `**` est prioritaire sur `*`, donc\n$2^4 \\times 3 = 48$.\n"
            },
            {
              "text": "`4096`, le produit des exposants",
              "correct": false,
              "feedback": "Erreur : c'est `2 ** (4 * 3)` qui donnerait ce résultat.\n"
            },
            {
              "text": "`24`, les trois nombres multipliés",
              "correct": false,
              "feedback": "Erreur : `**` est une puissance, pas une multiplication.\n"
            },
            {
              "text": "`11`, le produit puis la somme",
              "correct": false,
              "feedback": "Erreur : il n'y a ni somme ni produit $2 \\times 4$.\n"
            }
          ],
          "explanation": "En Python comme en mathématiques, la puissance précède le produit."
        }
      ]
    },
    {
      "id": "q38",
      "difficulty": 3,
      "skills": [
        "conditions",
        "and",
        "or"
      ],
      "title": "Année bissextile",
      "partie": "conditions",
      "statement": "Qu'affiche ce programme ?\n```python\na = 1900\nif a % 4 == 0 and a % 100 != 0 or a % 400 == 0:\n    print(\"bissextile\")\nelse:\n    print(\"non bissextile\")\n```",
      "options": [
        {
          "text": "`non bissextile`, $1900$ étant divisible par $100$ mais pas par $400$",
          "correct": true,
          "feedback": "Bonne réponse : `a % 4 == 0 and a % 100 != 0` est faux car\n$1900$ est multiple de $100$, et `a % 400 == 0` est faux\naussi.\n"
        },
        {
          "text": "`bissextile`, $1900$ étant un multiple de $4$",
          "correct": false,
          "feedback": "Erreur : être multiple de $4$ ne suffit pas, la condition\nexige aussi `a % 100 != 0`.\n"
        },
        {
          "text": "`bissextile`, la dernière condition l'emportant toujours",
          "correct": false,
          "feedback": "Erreur : `a % 400 == 0` est faux pour $1900$.\n"
        },
        {
          "text": "Une erreur, `and` et `or` ne pouvant pas se mélanger",
          "correct": false,
          "feedback": "Erreur : Python accepte le mélange ; `and` est évalué avant\n`or`.\n"
        }
      ],
      "explanation": "Une année est bissextile si elle est divisible par $4$ sans\nl'être par $100$, ou si elle est divisible par $400$."
    },
    {
      "id": "q39",
      "difficulty": 1,
      "skills": [
        "boucle-bornee",
        "range"
      ],
      "title": "Les valeurs parcourues par range",
      "partie": "boucles",
      "statement": "Quelles valeurs prend `i` dans la boucle `for i in range(2, 7):` ?",
      "options": [
        {
          "text": "`2`, `3`, `4`, `5` et `6`",
          "correct": true,
          "feedback": "Bonne réponse : `range(2, 7)` part de $2$ et s'arrête avant\n$7$.\n"
        },
        {
          "text": "`2`, `3`, `4`, `5`, `6` et `7`",
          "correct": false,
          "feedback": "Erreur : la borne de fin est exclue.\n"
        },
        {
          "text": "`1`, `2`, `3`, `4`, `5`, `6` et `7`",
          "correct": false,
          "feedback": "Erreur : la boucle commence à $2$ et exclut $7$.\n"
        },
        {
          "text": "`0`, `1`, `2`, `3`, `4`, `5` et `6`",
          "correct": false,
          "feedback": "Erreur : le premier argument fixe le départ à $2$.\n"
        }
      ],
      "explanation": "`range(a, b)` parcourt les entiers de $a$ inclus à $b$ exclu."
    },
    {
      "id": "q40",
      "difficulty": 2,
      "skills": [
        "boucle-bornee",
        "produit"
      ],
      "title": "Un produit calculé par une boucle",
      "partie": "boucles",
      "statement": "Qu'affiche ce programme ?\n```python\np = 1\nfor i in range(1, 5):\n    p = p * i\nprint(p)\n```",
      "options": [
        {
          "text": "`24`, le produit des entiers de $1$ à $4$",
          "correct": true,
          "feedback": "Bonne réponse : `range(1, 5)` s'arrête à $4$ et `p` est\nmultiplié par chaque entier rencontré.\n"
        },
        {
          "text": "`120`, le produit des entiers de $1$ à $5$",
          "correct": false,
          "feedback": "Erreur : $5$ est exclu de `range(1, 5)`.\n"
        },
        {
          "text": "`10`, la somme des entiers de $1$ à $4$",
          "correct": false,
          "feedback": "Erreur : l'instruction multiplie, elle n'additionne pas.\n"
        },
        {
          "text": "`4`, la dernière valeur de `i`",
          "correct": false,
          "feedback": "Erreur : le programme affiche `p`, pas `i`.\n"
        }
      ],
      "explanation": "Un accumulateur initialisé à $1$ et multiplié à chaque tour\ncalcule un produit.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\np = 1\nfor i in range(1, 5):\n    p = p * i\nprint(p)\n```",
          "options": [
            {
              "text": "`24`, le produit des entiers de $1$ à $4$",
              "correct": true,
              "feedback": "Bonne réponse : `range(1, 5)` s'arrête à $4$ et `p` est\nmultiplié par chaque entier rencontré.\n"
            },
            {
              "text": "`120`, le produit des entiers de $1$ à $5$",
              "correct": false,
              "feedback": "Erreur : $5$ est exclu de `range(1, 5)`.\n"
            },
            {
              "text": "`10`, la somme des entiers de $1$ à $4$",
              "correct": false,
              "feedback": "Erreur : l'instruction multiplie, elle n'additionne pas.\n"
            },
            {
              "text": "`4`, la dernière valeur de `i`",
              "correct": false,
              "feedback": "Erreur : le programme affiche `p`, pas `i`.\n"
            }
          ],
          "explanation": "Un accumulateur initialisé à $1$ et multiplié à chaque tour\ncalcule un produit."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\np = 1\nfor i in range(1, 6):\n    p = p * i\nprint(p)\n```",
          "options": [
            {
              "text": "`120`, le produit des entiers de $1$ à $5$",
              "correct": true,
              "feedback": "Bonne réponse : `range(1, 6)` s'arrête à $5$ et `p` est\nmultiplié par chaque entier rencontré.\n"
            },
            {
              "text": "`720`, le produit des entiers de $1$ à $6$",
              "correct": false,
              "feedback": "Erreur : $6$ est exclu de `range(1, 6)`.\n"
            },
            {
              "text": "`15`, la somme des entiers de $1$ à $5$",
              "correct": false,
              "feedback": "Erreur : l'instruction multiplie, elle n'additionne pas.\n"
            },
            {
              "text": "`5`, la dernière valeur de `i`",
              "correct": false,
              "feedback": "Erreur : le programme affiche `p`, pas `i`.\n"
            }
          ],
          "explanation": "Un accumulateur initialisé à $1$ et multiplié à chaque tour\ncalcule un produit."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\np = 1\nfor i in range(1, 7):\n    p = p * i\nprint(p)\n```",
          "options": [
            {
              "text": "`720`, le produit des entiers de $1$ à $6$",
              "correct": true,
              "feedback": "Bonne réponse : `range(1, 7)` s'arrête à $6$ et `p` est\nmultiplié par chaque entier rencontré.\n"
            },
            {
              "text": "`5040`, le produit des entiers de $1$ à $7$",
              "correct": false,
              "feedback": "Erreur : $7$ est exclu de `range(1, 7)`.\n"
            },
            {
              "text": "`21`, la somme des entiers de $1$ à $6$",
              "correct": false,
              "feedback": "Erreur : l'instruction multiplie, elle n'additionne pas.\n"
            },
            {
              "text": "`6`, la dernière valeur de `i`",
              "correct": false,
              "feedback": "Erreur : le programme affiche `p`, pas `i`.\n"
            }
          ],
          "explanation": "Un accumulateur initialisé à $1$ et multiplié à chaque tour\ncalcule un produit."
        }
      ]
    },
    {
      "id": "q41",
      "difficulty": 2,
      "skills": [
        "boucle-bornee",
        "condition",
        "compteur"
      ],
      "title": "Compter avec un test de divisibilité",
      "partie": "boucles",
      "statement": "Qu'affiche ce programme ?\n```python\nc = 0\nfor i in range(1, 21):\n    if i % 3 == 0:\n        c = c + 1\nprint(c)\n```",
      "options": [
        {
          "text": "`6`, les multiples de $3$ jusqu'à $20$",
          "correct": true,
          "feedback": "Bonne réponse : `c` augmente de $1$ à chaque fois que `i` est\ndivisible par $3$, soit $6$ fois jusqu'à $20$.\n"
        },
        {
          "text": "`7`, en comptant aussi $21$ comme multiple",
          "correct": false,
          "feedback": "Erreur : `range(1, 21)` s'arrête à $20$.\n"
        },
        {
          "text": "`20`, le nombre total de tours de boucle",
          "correct": false,
          "feedback": "Erreur : `c` ne compte que les tours où le test est vrai.\n"
        },
        {
          "text": "`3`, le diviseur utilisé dans le test",
          "correct": false,
          "feedback": "Erreur : le programme affiche le compteur, pas le diviseur.\n"
        }
      ],
      "explanation": "Un compteur placé sous un test ne compte que les valeurs qui\nvérifient la condition.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\nc = 0\nfor i in range(1, 21):\n    if i % 3 == 0:\n        c = c + 1\nprint(c)\n```",
          "options": [
            {
              "text": "`6`, les multiples de $3$ jusqu'à $20$",
              "correct": true,
              "feedback": "Bonne réponse : `c` augmente de $1$ à chaque fois que `i` est\ndivisible par $3$, soit $6$ fois jusqu'à $20$.\n"
            },
            {
              "text": "`7`, en comptant aussi $21$ comme multiple",
              "correct": false,
              "feedback": "Erreur : `range(1, 21)` s'arrête à $20$.\n"
            },
            {
              "text": "`20`, le nombre total de tours de boucle",
              "correct": false,
              "feedback": "Erreur : `c` ne compte que les tours où le test est vrai.\n"
            },
            {
              "text": "`3`, le diviseur utilisé dans le test",
              "correct": false,
              "feedback": "Erreur : le programme affiche le compteur, pas le diviseur.\n"
            }
          ],
          "explanation": "Un compteur placé sous un test ne compte que les valeurs qui\nvérifient la condition."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nc = 0\nfor i in range(1, 31):\n    if i % 4 == 0:\n        c = c + 1\nprint(c)\n```",
          "options": [
            {
              "text": "`7`, les multiples de $4$ jusqu'à $30$",
              "correct": true,
              "feedback": "Bonne réponse : `c` augmente de $1$ à chaque fois que `i` est\ndivisible par $4$, soit $7$ fois jusqu'à $30$.\n"
            },
            {
              "text": "`8`, en comptant aussi $31$ comme multiple",
              "correct": false,
              "feedback": "Erreur : `range(1, 31)` s'arrête à $30$.\n"
            },
            {
              "text": "`30`, le nombre total de tours de boucle",
              "correct": false,
              "feedback": "Erreur : `c` ne compte que les tours où le test est vrai.\n"
            },
            {
              "text": "`4`, le diviseur utilisé dans le test",
              "correct": false,
              "feedback": "Erreur : le programme affiche le compteur, pas le diviseur.\n"
            }
          ],
          "explanation": "Un compteur placé sous un test ne compte que les valeurs qui\nvérifient la condition."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nc = 0\nfor i in range(1, 41):\n    if i % 5 == 0:\n        c = c + 1\nprint(c)\n```",
          "options": [
            {
              "text": "`8`, les multiples de $5$ jusqu'à $40$",
              "correct": true,
              "feedback": "Bonne réponse : `c` augmente de $1$ à chaque fois que `i` est\ndivisible par $5$, soit $8$ fois jusqu'à $40$.\n"
            },
            {
              "text": "`9`, en comptant aussi $41$ comme multiple",
              "correct": false,
              "feedback": "Erreur : `range(1, 41)` s'arrête à $40$.\n"
            },
            {
              "text": "`40`, le nombre total de tours de boucle",
              "correct": false,
              "feedback": "Erreur : `c` ne compte que les tours où le test est vrai.\n"
            },
            {
              "text": "`5`, le diviseur utilisé dans le test",
              "correct": false,
              "feedback": "Erreur : le programme affiche le compteur, pas le diviseur.\n"
            }
          ],
          "explanation": "Un compteur placé sous un test ne compte que les valeurs qui\nvérifient la condition."
        }
      ]
    },
    {
      "id": "q42",
      "difficulty": 3,
      "skills": [
        "boucle-non-bornee",
        "seuil",
        "somme"
      ],
      "title": "Somme des premiers entiers jusqu'à un seuil",
      "partie": "boucles",
      "statement": "Qu'affiche ce programme ?\n```python\ns = 0\nn = 0\nwhile s <= 20:\n    n = n + 1\n    s = s + n\nprint(n)\n```",
      "options": [
        {
          "text": "`6`, premier rang où la somme dépasse $20$",
          "correct": true,
          "feedback": "Bonne réponse : la boucle ajoute $1$, puis $2$, puis $3$, et\ns'arrête dès que `s` dépasse $20$ ; cela se produit pour\n$n = 6$, avec `s` égal à $21$.\n"
        },
        {
          "text": "`5`, dernier rang où la somme reste sous $20$",
          "correct": false,
          "feedback": "Erreur : pour $n = 5$, `s` est encore inférieur ou égal à\n$20$ et la boucle fait un tour de plus.\n"
        },
        {
          "text": "`21`, la valeur finale de la somme `s`",
          "correct": false,
          "feedback": "Erreur : le programme affiche `n`, pas `s`.\n"
        },
        {
          "text": "`20`, le seuil comparé à la somme",
          "correct": false,
          "feedback": "Erreur : $20$ est la valeur comparée, pas le nombre de tours.\n"
        }
      ],
      "explanation": "Une boucle `while` répète tant que la condition est vraie : elle\ns'arrête au premier `n` pour lequel la somme dépasse le seuil.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\ns = 0\nn = 0\nwhile s <= 20:\n    n = n + 1\n    s = s + n\nprint(n)\n```",
          "options": [
            {
              "text": "`6`, premier rang où la somme dépasse $20$",
              "correct": true,
              "feedback": "Bonne réponse : la boucle ajoute $1$, puis $2$, puis $3$, et\ns'arrête dès que `s` dépasse $20$ ; cela se produit pour\n$n = 6$, avec `s` égal à $21$.\n"
            },
            {
              "text": "`5`, dernier rang où la somme reste sous $20$",
              "correct": false,
              "feedback": "Erreur : pour $n = 5$, `s` est encore inférieur ou égal à\n$20$ et la boucle fait un tour de plus.\n"
            },
            {
              "text": "`21`, la valeur finale de la somme `s`",
              "correct": false,
              "feedback": "Erreur : le programme affiche `n`, pas `s`.\n"
            },
            {
              "text": "`20`, le seuil comparé à la somme",
              "correct": false,
              "feedback": "Erreur : $20$ est la valeur comparée, pas le nombre de tours.\n"
            }
          ],
          "explanation": "Une boucle `while` répète tant que la condition est vraie : elle\ns'arrête au premier `n` pour lequel la somme dépasse le seuil."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\ns = 0\nn = 0\nwhile s <= 30:\n    n = n + 1\n    s = s + n\nprint(n)\n```",
          "options": [
            {
              "text": "`8`, premier rang où la somme dépasse $30$",
              "correct": true,
              "feedback": "Bonne réponse : la boucle ajoute $1$, puis $2$, puis $3$, et\ns'arrête dès que `s` dépasse $30$ ; cela se produit pour\n$n = 8$, avec `s` égal à $36$.\n"
            },
            {
              "text": "`7`, dernier rang où la somme reste sous $30$",
              "correct": false,
              "feedback": "Erreur : pour $n = 7$, `s` est encore inférieur ou égal à\n$30$ et la boucle fait un tour de plus.\n"
            },
            {
              "text": "`36`, la valeur finale de la somme `s`",
              "correct": false,
              "feedback": "Erreur : le programme affiche `n`, pas `s`.\n"
            },
            {
              "text": "`30`, le seuil comparé à la somme",
              "correct": false,
              "feedback": "Erreur : $30$ est la valeur comparée, pas le nombre de tours.\n"
            }
          ],
          "explanation": "Une boucle `while` répète tant que la condition est vraie : elle\ns'arrête au premier `n` pour lequel la somme dépasse le seuil."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\ns = 0\nn = 0\nwhile s <= 50:\n    n = n + 1\n    s = s + n\nprint(n)\n```",
          "options": [
            {
              "text": "`10`, premier rang où la somme dépasse $50$",
              "correct": true,
              "feedback": "Bonne réponse : la boucle ajoute $1$, puis $2$, puis $3$, et\ns'arrête dès que `s` dépasse $50$ ; cela se produit pour\n$n = 10$, avec `s` égal à $55$.\n"
            },
            {
              "text": "`9`, dernier rang où la somme reste sous $50$",
              "correct": false,
              "feedback": "Erreur : pour $n = 9$, `s` est encore inférieur ou égal à\n$50$ et la boucle fait un tour de plus.\n"
            },
            {
              "text": "`55`, la valeur finale de la somme `s`",
              "correct": false,
              "feedback": "Erreur : le programme affiche `n`, pas `s`.\n"
            },
            {
              "text": "`50`, le seuil comparé à la somme",
              "correct": false,
              "feedback": "Erreur : $50$ est la valeur comparée, pas le nombre de tours.\n"
            }
          ],
          "explanation": "Une boucle `while` répète tant que la condition est vraie : elle\ns'arrête au premier `n` pour lequel la somme dépasse le seuil."
        }
      ]
    },
    {
      "id": "q43",
      "difficulty": 2,
      "skills": [
        "fonction",
        "return",
        "none"
      ],
      "title": "Une fonction qui oublie de renvoyer",
      "partie": "fonctions",
      "statement": "Qu'affiche ce programme ?\n```python\ndef double(x):\n    y = 2 * x\n\nr = double(5)\nprint(r)\n```",
      "options": [
        {
          "text": "`None`, la fonction ne renvoyant rien",
          "correct": true,
          "feedback": "Bonne réponse : sans `return`, l'appel `double(5)` vaut\n`None`, même si `y` a été calculé à l'intérieur.\n"
        },
        {
          "text": "`10`, la valeur calculée dans la fonction",
          "correct": false,
          "feedback": "Erreur : `y` est calculé mais jamais renvoyé.\n"
        },
        {
          "text": "Une erreur, `y` n'existant pas en dehors de la fonction",
          "correct": false,
          "feedback": "Erreur : le programme n'utilise pas `y` à l'extérieur ; il\naffiche `r`, qui vaut `None`.\n"
        },
        {
          "text": "`5`, l'argument passé à la fonction",
          "correct": false,
          "feedback": "Erreur : la fonction ne renvoie pas son argument.\n"
        }
      ],
      "explanation": "Pour qu'un appel produise une valeur, la fonction doit se terminer\npar `return`."
    },
    {
      "id": "q44",
      "difficulty": 2,
      "skills": [
        "fonction",
        "condition",
        "appel"
      ],
      "title": "Deux appels d'une fonction à condition",
      "partie": "fonctions",
      "statement": "Qu'affiche ce programme ?\n```python\ndef tarif(age):\n    if age < 12:\n        return 5\n    else:\n        return 8\n\nprint(tarif(10) + tarif(15))\n```",
      "options": [
        {
          "text": "`13`, soit $5 + 8$",
          "correct": true,
          "feedback": "Bonne réponse : `tarif(10)` renvoie $5$ car $10 < 12$, et\n`tarif(15)` renvoie $8$.\n"
        },
        {
          "text": "`10`, soit $5 + 5$",
          "correct": false,
          "feedback": "Erreur : $15$ n'est pas strictement inférieur à $12$.\n"
        },
        {
          "text": "`16`, soit $8 + 8$",
          "correct": false,
          "feedback": "Erreur : $10$ est strictement inférieur à $12$.\n"
        },
        {
          "text": "`5 8`, les deux tarifs l'un après l'autre",
          "correct": false,
          "feedback": "Erreur : `print` reçoit la somme des deux valeurs renvoyées.\n"
        }
      ],
      "explanation": "Chaque appel est évalué séparément avec son argument, puis les\ndeux valeurs renvoyées sont additionnées.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\ndef tarif(age):\n    if age < 12:\n        return 5\n    else:\n        return 8\n\nprint(tarif(10) + tarif(15))\n```",
          "options": [
            {
              "text": "`13`, soit $5 + 8$",
              "correct": true,
              "feedback": "Bonne réponse : `tarif(10)` renvoie $5$ car $10 < 12$, et\n`tarif(15)` renvoie $8$.\n"
            },
            {
              "text": "`10`, soit $5 + 5$",
              "correct": false,
              "feedback": "Erreur : $15$ n'est pas strictement inférieur à $12$.\n"
            },
            {
              "text": "`16`, soit $8 + 8$",
              "correct": false,
              "feedback": "Erreur : $10$ est strictement inférieur à $12$.\n"
            },
            {
              "text": "`5 8`, les deux tarifs l'un après l'autre",
              "correct": false,
              "feedback": "Erreur : `print` reçoit la somme des deux valeurs renvoyées.\n"
            }
          ],
          "explanation": "Chaque appel est évalué séparément avec son argument, puis les\ndeux valeurs renvoyées sont additionnées."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\ndef tarif(age):\n    if age < 12:\n        return 6\n    else:\n        return 9\n\nprint(tarif(7) + tarif(30))\n```",
          "options": [
            {
              "text": "`15`, soit $6 + 9$",
              "correct": true,
              "feedback": "Bonne réponse : `tarif(7)` renvoie $6$ car $7 < 12$, et\n`tarif(30)` renvoie $9$.\n"
            },
            {
              "text": "`12`, soit $6 + 6$",
              "correct": false,
              "feedback": "Erreur : $30$ n'est pas strictement inférieur à $12$.\n"
            },
            {
              "text": "`18`, soit $9 + 9$",
              "correct": false,
              "feedback": "Erreur : $7$ est strictement inférieur à $12$.\n"
            },
            {
              "text": "`6 9`, les deux tarifs l'un après l'autre",
              "correct": false,
              "feedback": "Erreur : `print` reçoit la somme des deux valeurs renvoyées.\n"
            }
          ],
          "explanation": "Chaque appel est évalué séparément avec son argument, puis les\ndeux valeurs renvoyées sont additionnées."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\ndef tarif(age):\n    if age < 12:\n        return 3\n    else:\n        return 7\n\nprint(tarif(11) + tarif(12))\n```",
          "options": [
            {
              "text": "`10`, soit $3 + 7$",
              "correct": true,
              "feedback": "Bonne réponse : `tarif(11)` renvoie $3$ car $11 < 12$, et\n`tarif(12)` renvoie $7$.\n"
            },
            {
              "text": "`6`, soit $3 + 3$",
              "correct": false,
              "feedback": "Erreur : $12$ n'est pas strictement inférieur à $12$.\n"
            },
            {
              "text": "`14`, soit $7 + 7$",
              "correct": false,
              "feedback": "Erreur : $11$ est strictement inférieur à $12$.\n"
            },
            {
              "text": "`3 7`, les deux tarifs l'un après l'autre",
              "correct": false,
              "feedback": "Erreur : `print` reçoit la somme des deux valeurs renvoyées.\n"
            }
          ],
          "explanation": "Chaque appel est évalué séparément avec son argument, puis les\ndeux valeurs renvoyées sont additionnées."
        }
      ]
    },
    {
      "id": "q45",
      "difficulty": 3,
      "skills": [
        "fonction",
        "appel",
        "composition"
      ],
      "title": "Une fonction qui en appelle une autre",
      "partie": "fonctions",
      "statement": "Qu'affiche ce programme ?\n```python\ndef carre(x):\n    return x * x\n\ndef somme_carres(a, b):\n    return carre(a) + carre(b)\n\nprint(somme_carres(3, 4))\n```",
      "options": [
        {
          "text": "`25`, soit $3^2 + 4^2$",
          "correct": true,
          "feedback": "Bonne réponse : `somme_carres` appelle `carre` deux fois et\nadditionne les valeurs renvoyées.\n"
        },
        {
          "text": "`49`, soit $(3 + 4)^2$",
          "correct": false,
          "feedback": "Erreur : chaque nombre est élevé au carré avant l'addition.\n"
        },
        {
          "text": "`7`, la somme $3 + 4$",
          "correct": false,
          "feedback": "Erreur : `carre` est bien appliquée à chaque argument.\n"
        },
        {
          "text": "`12`, le produit $3 \\times 4$",
          "correct": false,
          "feedback": "Erreur : aucun produit de `a` par `b` n'est calculé.\n"
        }
      ],
      "explanation": "Une fonction peut en appeler une autre ; chaque appel renvoie une\nvaleur utilisée dans le calcul.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\ndef carre(x):\n    return x * x\n\ndef somme_carres(a, b):\n    return carre(a) + carre(b)\n\nprint(somme_carres(3, 4))\n```",
          "options": [
            {
              "text": "`25`, soit $3^2 + 4^2$",
              "correct": true,
              "feedback": "Bonne réponse : `somme_carres` appelle `carre` deux fois et\nadditionne les valeurs renvoyées.\n"
            },
            {
              "text": "`49`, soit $(3 + 4)^2$",
              "correct": false,
              "feedback": "Erreur : chaque nombre est élevé au carré avant l'addition.\n"
            },
            {
              "text": "`7`, la somme $3 + 4$",
              "correct": false,
              "feedback": "Erreur : `carre` est bien appliquée à chaque argument.\n"
            },
            {
              "text": "`12`, le produit $3 \\times 4$",
              "correct": false,
              "feedback": "Erreur : aucun produit de `a` par `b` n'est calculé.\n"
            }
          ],
          "explanation": "Une fonction peut en appeler une autre ; chaque appel renvoie une\nvaleur utilisée dans le calcul."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\ndef carre(x):\n    return x * x\n\ndef somme_carres(a, b):\n    return carre(a) + carre(b)\n\nprint(somme_carres(2, 5))\n```",
          "options": [
            {
              "text": "`29`, soit $2^2 + 5^2$",
              "correct": true,
              "feedback": "Bonne réponse : `somme_carres` appelle `carre` deux fois et\nadditionne les valeurs renvoyées.\n"
            },
            {
              "text": "`49`, soit $(2 + 5)^2$",
              "correct": false,
              "feedback": "Erreur : chaque nombre est élevé au carré avant l'addition.\n"
            },
            {
              "text": "`7`, la somme $2 + 5$",
              "correct": false,
              "feedback": "Erreur : `carre` est bien appliquée à chaque argument.\n"
            },
            {
              "text": "`10`, le produit $2 \\times 5$",
              "correct": false,
              "feedback": "Erreur : aucun produit de `a` par `b` n'est calculé.\n"
            }
          ],
          "explanation": "Une fonction peut en appeler une autre ; chaque appel renvoie une\nvaleur utilisée dans le calcul."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\ndef carre(x):\n    return x * x\n\ndef somme_carres(a, b):\n    return carre(a) + carre(b)\n\nprint(somme_carres(1, 6))\n```",
          "options": [
            {
              "text": "`37`, soit $1^2 + 6^2$",
              "correct": true,
              "feedback": "Bonne réponse : `somme_carres` appelle `carre` deux fois et\nadditionne les valeurs renvoyées.\n"
            },
            {
              "text": "`49`, soit $(1 + 6)^2$",
              "correct": false,
              "feedback": "Erreur : chaque nombre est élevé au carré avant l'addition.\n"
            },
            {
              "text": "`7`, la somme $1 + 6$",
              "correct": false,
              "feedback": "Erreur : `carre` est bien appliquée à chaque argument.\n"
            },
            {
              "text": "`6`, le produit $1 \\times 6$",
              "correct": false,
              "feedback": "Erreur : aucun produit de `a` par `b` n'est calculé.\n"
            }
          ],
          "explanation": "Une fonction peut en appeler une autre ; chaque appel renvoie une\nvaleur utilisée dans le calcul."
        }
      ]
    }
  ]
}