{
  "chapter": {
    "id": "python-conditions",
    "level": "snt",
    "theme": "Programmation",
    "title": "4. Conditions et booléens",
    "description": "L'instruction conditionnelle if, else et elif ; les comparaisons et\nla différence entre égalité et affectation ; les opérateurs and, or\net not ; l'ordre des tests ; l'indentation qui délimite un bloc ; les\nconditions imbriquées.",
    "prerequisites": [],
    "references": []
  },
  "questions": [
    {
      "id": "q01",
      "difficulty": 1,
      "skills": [
        "condition",
        "comparaison"
      ],
      "title": "Le bloc exécuté",
      "statement": "Une station météo déclenche une alerte.\n\n```python\ntemperature = 31\nif temperature > 30:\n    print(\"Alerte chaleur\")\nprint(\"Relevé terminé\")\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`Alerte chaleur` puis `Relevé terminé`",
          "correct": true,
          "feedback": "Bonne réponse : la condition est vraie, le bloc indenté\ns'exécute, puis le programme continue avec la ligne non\nindentée, qui s'exécute dans tous les cas.\n"
        },
        {
          "text": "`Relevé terminé` seulement",
          "correct": false,
          "feedback": "Erreur : 31 est bien supérieur à 30, la condition est vraie et\nl'alerte est affichée.\n"
        },
        {
          "text": "`Alerte chaleur` seulement",
          "correct": false,
          "feedback": "Erreur : la dernière ligne n'est pas indentée, elle ne dépend\npas de la condition et s'exécute toujours.\n"
        },
        {
          "text": "Rien, la condition est fausse",
          "correct": false,
          "feedback": "Erreur : `31 > 30` est vrai. Et même fausse, la condition ne\nbloquerait pas la dernière ligne.\n"
        }
      ],
      "explanation": "Le bloc indenté sous `if` ne s'exécute que si la condition est vraie.\nCe qui suit, au même niveau que `if`, s'exécute dans tous les cas.\nL'indentation délimite le bloc."
    },
    {
      "id": "q02",
      "difficulty": 1,
      "skills": [
        "comparaison",
        "egalite"
      ],
      "title": "Tester une égalité",
      "statement": "Quelle ligne teste si la variable `note` vaut 20 ?",
      "options": [
        {
          "text": "`if note == 20:`",
          "correct": true,
          "feedback": "Bonne réponse : le double égal compare deux valeurs et donne un\nbooléen.\n"
        },
        {
          "text": "`if note = 20:`",
          "correct": false,
          "feedback": "Erreur : un seul `=` est une affectation, interdite dans une\ncondition. Python signale une erreur de syntaxe.\n"
        },
        {
          "text": "`if note => 20:`",
          "correct": false,
          "feedback": "Erreur : l'opérateur « supérieur ou égal » s'écrit `>=`, et il ne\nteste pas l'égalité seule.\n"
        },
        {
          "text": "`if note === 20:`",
          "correct": false,
          "feedback": "Erreur : le triple égal n'existe pas en Python.\n"
        }
      ],
      "explanation": "`=` affecte, `==` compare. Confondre les deux est l'erreur la plus\nfréquente dans les conditions : Python refuse `if note = 20:`."
    },
    {
      "id": "q03",
      "difficulty": 1,
      "skills": [
        "condition",
        "else"
      ],
      "title": "Le sinon",
      "statement": "```python\nage = 15\nif age >= 18:\n    print(\"Majeur\")\nelse:\n    print(\"Mineur\")\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`Mineur`",
          "correct": true,
          "feedback": "Bonne réponse : 15 n'est pas supérieur ou égal à 18, la\ncondition est fausse et le bloc `else` s'exécute.\n"
        },
        {
          "text": "`Majeur`",
          "correct": false,
          "feedback": "Erreur : la condition `age >= 18` est fausse pour 15.\n"
        },
        {
          "text": "`Majeur` puis `Mineur`",
          "correct": false,
          "feedback": "Erreur : `if` et `else` s'excluent, un seul des deux blocs\ns'exécute.\n"
        },
        {
          "text": "Rien, aucune condition n'est vraie",
          "correct": false,
          "feedback": "Erreur : `else` s'exécute précisément quand la condition est\nfausse.\n"
        }
      ],
      "explanation": "`else` introduit le bloc exécuté quand la condition du `if` est\nfausse. Exactement un des deux blocs s'exécute, jamais les deux,\njamais aucun."
    },
    {
      "id": "q04",
      "difficulty": 2,
      "skills": [
        "booleens",
        "and-or-not"
      ],
      "title": "Un et logique",
      "statement": "```python\na = 5\nb = 12\nprint(a < 10 and b < 10)\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`False`",
          "correct": true,
          "feedback": "Bonne réponse : `and` exige que les deux comparaisons soient\nvraies. Or `b < 10` est fausse.\n"
        },
        {
          "text": "`True`",
          "correct": false,
          "feedback": "Erreur : une seule comparaison vraie ne suffit pas avec `and`.\n"
        },
        {
          "text": "`5`",
          "correct": false,
          "feedback": "Erreur : l'expression est un booléen, pas un nombre.\n"
        },
        {
          "text": "Une erreur, `and` ne s'applique pas à des comparaisons",
          "correct": false,
          "feedback": "Erreur : `and` combine justement des booléens, comme ceux que\nproduisent les comparaisons.\n"
        }
      ],
      "explanation": "`a and b` est vrai seulement si `a` et `b` sont tous les deux vrais.\nDès qu'une des deux conditions est fausse, le résultat est `False`."
    },
    {
      "id": "q05",
      "difficulty": 2,
      "skills": [
        "booleens",
        "and-or-not"
      ],
      "title": "Négation et ou logique",
      "statement": "```python\npluie = False\nvent = True\nprint(not pluie and vent)\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`True`",
          "correct": true,
          "feedback": "Bonne réponse : `not pluie` vaut `True`, et `True and True`\nvaut `True`.\n"
        },
        {
          "text": "`False`",
          "correct": false,
          "feedback": "Erreur : `not` inverse `pluie`, qui devient `True`. Les deux\ncôtés du `and` sont alors vrais.\n"
        },
        {
          "text": "`not pluie`",
          "correct": false,
          "feedback": "Erreur : l'expression est évaluée, pas affichée telle quelle.\n"
        },
        {
          "text": "Une erreur, `not` s'applique à un nombre",
          "correct": false,
          "feedback": "Erreur : `not` s'applique à un booléen et l'inverse.\n"
        }
      ],
      "explanation": "`not` inverse un booléen, `and` exige deux vrais, `or` se contente\nd'un seul. On évalue les `not` d'abord, puis les `and`, puis les\n`or`."
    },
    {
      "id": "q06",
      "difficulty": 2,
      "skills": [
        "elif",
        "condition"
      ],
      "title": "La première branche vraie",
      "statement": "```python\nvitesse = 52\nif vitesse > 50:\n    print(\"Excès\")\nelif vitesse > 30:\n    print(\"Vigilance\")\nelse:\n    print(\"Normal\")\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`Excès`",
          "correct": true,
          "feedback": "Bonne réponse : la première condition est vraie, son bloc\ns'exécute et les autres branches sont ignorées.\n"
        },
        {
          "text": "`Excès` puis `Vigilance`",
          "correct": false,
          "feedback": "Erreur : `vitesse > 30` est aussi vrai, mais `elif` n'est testé\nque si les conditions précédentes sont fausses.\n"
        },
        {
          "text": "`Vigilance`",
          "correct": false,
          "feedback": "Erreur : la première branche est vraie et prend la main.\n"
        },
        {
          "text": "`Normal`",
          "correct": false,
          "feedback": "Erreur : `else` ne s'exécute que si toutes les conditions sont\nfausses.\n"
        }
      ],
      "explanation": "Dans une chaîne `if`, `elif`, `else`, les conditions sont testées de\nhaut en bas et une seule branche s'exécute : la première dont la\ncondition est vraie."
    },
    {
      "id": "q07",
      "difficulty": 2,
      "skills": [
        "condition",
        "sequence"
      ],
      "title": "Deux if successifs",
      "statement": "```python\nn = 52\nif n > 50:\n    print(\"A\")\nif n > 30:\n    print(\"B\")\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`A` puis `B`",
          "correct": true,
          "feedback": "Bonne réponse : deux `if` indépendants sont testés chacun leur\ntour. Les deux conditions sont vraies.\n"
        },
        {
          "text": "`A` seulement",
          "correct": false,
          "feedback": "Erreur : ce serait le cas avec `elif`. Ici, le second `if` est\ntesté quoi qu'il arrive.\n"
        },
        {
          "text": "`B` seulement",
          "correct": false,
          "feedback": "Erreur : la première condition, `52 > 50`, est vraie.\n"
        },
        {
          "text": "Rien",
          "correct": false,
          "feedback": "Erreur : les deux conditions sont vraies pour 52.\n"
        }
      ],
      "explanation": "Deux `if` à la suite sont indépendants : chacun est testé. Avec\n`elif`, le second ne serait testé que si le premier était faux. Le\nchoix entre les deux change le comportement."
    },
    {
      "id": "q08",
      "difficulty": 2,
      "skills": [
        "comparaison",
        "chaine"
      ],
      "title": "Comparer des chaînes",
      "statement": "```python\nreponse = \"oui\"\nif reponse == \"Oui\":\n    print(\"Accepté\")\nelse:\n    print(\"Refusé\")\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`Refusé`",
          "correct": true,
          "feedback": "Bonne réponse : `\"oui\"` et `\"Oui\"` diffèrent par leur première\nlettre. Les chaînes sont comparées caractère par caractère.\n"
        },
        {
          "text": "`Accepté`",
          "correct": false,
          "feedback": "Erreur : la comparaison distingue majuscules et minuscules.\n"
        },
        {
          "text": "Une erreur, on ne compare pas des chaînes",
          "correct": false,
          "feedback": "Erreur : `==` compare des chaînes sans difficulté.\n"
        },
        {
          "text": "Rien, la condition ne peut pas être évaluée",
          "correct": false,
          "feedback": "Erreur : la condition vaut `False`, et le bloc `else` s'exécute.\n"
        }
      ],
      "explanation": "Deux chaînes sont égales si elles ont exactement les mêmes\ncaractères, majuscules comprises. Un programme qui accepte plusieurs\nécritures doit les prévoir dans sa condition."
    },
    {
      "id": "q09",
      "difficulty": 3,
      "skills": [
        "and-or-not",
        "comparaison"
      ],
      "title": "Tester un intervalle",
      "statement": "Quelle condition est vraie exactement quand `x` est compris entre 10\net 20, bornes comprises ?",
      "options": [
        {
          "text": "`x >= 10 and x <= 20`",
          "correct": true,
          "feedback": "Bonne réponse : il faut que les deux inégalités soient vraies en\nmême temps, d'où `and`.\n"
        },
        {
          "text": "`x >= 10 or x <= 20`",
          "correct": false,
          "feedback": "Erreur : avec `or`, tout nombre convient : 5 vérifie `x <= 20`\net 50 vérifie `x >= 10`.\n"
        },
        {
          "text": "`10 <= x or x <= 20`",
          "correct": false,
          "feedback": "Erreur : même problème, `or` rend la condition toujours vraie.\n"
        },
        {
          "text": "`x >= 10 and x >= 20`",
          "correct": false,
          "feedback": "Erreur : cette condition revient à `x >= 20`, elle laisse passer\n100.\n"
        }
      ],
      "explanation": "Un intervalle se traduit par deux inégalités reliées par `and`. Avec\n`or`, l'une ou l'autre suffirait, ce qui ne restreint plus rien.",
      "variants": [
        {
          "statement": "Quelle condition est vraie exactement quand `x` est compris entre 10\net 20, bornes comprises ?",
          "options": [
            {
              "text": "`x >= 10 and x <= 20`",
              "correct": true,
              "feedback": "Bonne réponse : il faut que les deux inégalités soient vraies en\nmême temps, d'où `and`.\n"
            },
            {
              "text": "`x >= 10 or x <= 20`",
              "correct": false,
              "feedback": "Erreur : avec `or`, tout nombre convient : 5 vérifie `x <= 20`\net 50 vérifie `x >= 10`.\n"
            },
            {
              "text": "`10 <= x or x <= 20`",
              "correct": false,
              "feedback": "Erreur : même problème, `or` rend la condition toujours vraie.\n"
            },
            {
              "text": "`x >= 10 and x >= 20`",
              "correct": false,
              "feedback": "Erreur : cette condition revient à `x >= 20`, elle laisse passer\n100.\n"
            }
          ],
          "explanation": "Un intervalle se traduit par deux inégalités reliées par `and`. Avec\n`or`, l'une ou l'autre suffirait, ce qui ne restreint plus rien."
        },
        {
          "statement": "Quelle condition est vraie exactement quand `x` est compris entre 5\net 15, bornes comprises ?",
          "options": [
            {
              "text": "`x >= 5 and x <= 15`",
              "correct": true,
              "feedback": "Bonne réponse : il faut que les deux inégalités soient vraies en\nmême temps, d'où `and`.\n"
            },
            {
              "text": "`x >= 5 or x <= 15`",
              "correct": false,
              "feedback": "Erreur : avec `or`, tout nombre convient : 2 vérifie `x <= 15`\net 40 vérifie `x >= 5`.\n"
            },
            {
              "text": "`5 <= x or x <= 15`",
              "correct": false,
              "feedback": "Erreur : même problème, `or` rend la condition toujours vraie.\n"
            },
            {
              "text": "`x >= 5 and x >= 15`",
              "correct": false,
              "feedback": "Erreur : cette condition revient à `x >= 15`, elle laisse passer\n80.\n"
            }
          ],
          "explanation": "Un intervalle se traduit par deux inégalités reliées par `and`. Avec\n`or`, l'une ou l'autre suffirait, ce qui ne restreint plus rien."
        },
        {
          "statement": "Quelle condition est vraie exactement quand `x` est compris entre 30\net 60, bornes comprises ?",
          "options": [
            {
              "text": "`x >= 30 and x <= 60`",
              "correct": true,
              "feedback": "Bonne réponse : il faut que les deux inégalités soient vraies en\nmême temps, d'où `and`.\n"
            },
            {
              "text": "`x >= 30 or x <= 60`",
              "correct": false,
              "feedback": "Erreur : avec `or`, tout nombre convient : 12 vérifie `x <= 60`\net 90 vérifie `x >= 30`.\n"
            },
            {
              "text": "`30 <= x or x <= 60`",
              "correct": false,
              "feedback": "Erreur : même problème, `or` rend la condition toujours vraie.\n"
            },
            {
              "text": "`x >= 30 and x >= 60`",
              "correct": false,
              "feedback": "Erreur : cette condition revient à `x >= 60`, elle laisse passer\n200.\n"
            }
          ],
          "explanation": "Un intervalle se traduit par deux inégalités reliées par `and`. Avec\n`or`, l'une ou l'autre suffirait, ce qui ne restreint plus rien."
        }
      ]
    },
    {
      "id": "q10",
      "difficulty": 3,
      "skills": [
        "and-or-not",
        "booleens"
      ],
      "title": "La négation d'une comparaison",
      "statement": "Quelle condition est équivalente à `not (age >= 18)` ?",
      "options": [
        {
          "text": "`age < 18`",
          "correct": true,
          "feedback": "Bonne réponse : ne pas être supérieur ou égal à 18, c'est être\nstrictement inférieur à 18.\n"
        },
        {
          "text": "`age <= 18`",
          "correct": false,
          "feedback": "Erreur : pour 18, `age >= 18` est vrai, donc sa négation est\nfausse, alors que `age <= 18` serait vrai.\n"
        },
        {
          "text": "`age > 18`",
          "correct": false,
          "feedback": "Erreur : 20 vérifie `age >= 18`, sa négation est donc fausse,\nalors que `age > 18` serait vrai.\n"
        },
        {
          "text": "`age != 18`",
          "correct": false,
          "feedback": "Erreur : 25 est différent de 18 mais vérifie `age >= 18`.\n"
        }
      ],
      "explanation": "La négation de `>=` est `<`, celle de `>` est `<=`, celle de `==` est\n`!=`. On vérifie toujours la borne : ici, 18 doit rendre la condition\nfausse.",
      "variants": [
        {
          "statement": "Quelle condition est équivalente à `not (age >= 18)` ?",
          "options": [
            {
              "text": "`age < 18`",
              "correct": true,
              "feedback": "Bonne réponse : ne pas être supérieur ou égal à 18, c'est être\nstrictement inférieur à 18.\n"
            },
            {
              "text": "`age <= 18`",
              "correct": false,
              "feedback": "Erreur : pour 18, `age >= 18` est vrai, donc sa négation est\nfausse, alors que `age <= 18` serait vrai.\n"
            },
            {
              "text": "`age > 18`",
              "correct": false,
              "feedback": "Erreur : 20 vérifie `age >= 18`, sa négation est donc fausse,\nalors que `age > 18` serait vrai.\n"
            },
            {
              "text": "`age != 18`",
              "correct": false,
              "feedback": "Erreur : 25 est différent de 18 mais vérifie `age >= 18`.\n"
            }
          ],
          "explanation": "La négation de `>=` est `<`, celle de `>` est `<=`, celle de `==` est\n`!=`. On vérifie toujours la borne : ici, 18 doit rendre la condition\nfausse."
        },
        {
          "statement": "Quelle condition est équivalente à `not (age >= 16)` ?",
          "options": [
            {
              "text": "`age < 16`",
              "correct": true,
              "feedback": "Bonne réponse : ne pas être supérieur ou égal à 16, c'est être\nstrictement inférieur à 16.\n"
            },
            {
              "text": "`age <= 16`",
              "correct": false,
              "feedback": "Erreur : pour 16, `age >= 16` est vrai, donc sa négation est\nfausse, alors que `age <= 16` serait vrai.\n"
            },
            {
              "text": "`age > 16`",
              "correct": false,
              "feedback": "Erreur : 19 vérifie `age >= 16`, sa négation est donc fausse,\nalors que `age > 16` serait vrai.\n"
            },
            {
              "text": "`age != 16`",
              "correct": false,
              "feedback": "Erreur : 30 est différent de 16 mais vérifie `age >= 16`.\n"
            }
          ],
          "explanation": "La négation de `>=` est `<`, celle de `>` est `<=`, celle de `==` est\n`!=`. On vérifie toujours la borne : ici, 16 doit rendre la condition\nfausse."
        },
        {
          "statement": "Quelle condition est équivalente à `not (age >= 21)` ?",
          "options": [
            {
              "text": "`age < 21`",
              "correct": true,
              "feedback": "Bonne réponse : ne pas être supérieur ou égal à 21, c'est être\nstrictement inférieur à 21.\n"
            },
            {
              "text": "`age <= 21`",
              "correct": false,
              "feedback": "Erreur : pour 21, `age >= 21` est vrai, donc sa négation est\nfausse, alors que `age <= 21` serait vrai.\n"
            },
            {
              "text": "`age > 21`",
              "correct": false,
              "feedback": "Erreur : 24 vérifie `age >= 21`, sa négation est donc fausse,\nalors que `age > 21` serait vrai.\n"
            },
            {
              "text": "`age != 21`",
              "correct": false,
              "feedback": "Erreur : 40 est différent de 21 mais vérifie `age >= 21`.\n"
            }
          ],
          "explanation": "La négation de `>=` est `<`, celle de `>` est `<=`, celle de `==` est\n`!=`. On vérifie toujours la borne : ici, 21 doit rendre la condition\nfausse."
        }
      ]
    },
    {
      "id": "q11",
      "difficulty": 2,
      "skills": [
        "condition",
        "trace"
      ],
      "title": "Une variable modifiée par la condition",
      "statement": "```python\nstock = 3\nif stock > 0:\n    stock = stock - 1\nprint(stock)\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`2`",
          "correct": true,
          "feedback": "Bonne réponse : la condition est vraie, le stock diminue de 1,\npuis la valeur 2 est affichée.\n"
        },
        {
          "text": "`3`",
          "correct": false,
          "feedback": "Erreur : `3 > 0` est vrai, la soustraction a lieu.\n"
        },
        {
          "text": "`0`",
          "correct": false,
          "feedback": "Erreur : le bloc ne s'exécute qu'une fois, un `if` n'est pas une\nboucle.\n"
        },
        {
          "text": "`-1`",
          "correct": false,
          "feedback": "Erreur : on retire 1 à 3, ce qui donne 2.\n"
        }
      ],
      "explanation": "Un `if` exécute son bloc au plus une fois. Pour répéter la\nsoustraction jusqu'à zéro, il faudrait une boucle.",
      "variants": [
        {
          "statement": "```python\nstock = 3\nif stock > 0:\n    stock = stock - 1\nprint(stock)\n```\n\nQu'affiche ce programme ?",
          "options": [
            {
              "text": "`2`",
              "correct": true,
              "feedback": "Bonne réponse : la condition est vraie, le stock diminue de 1,\npuis la valeur 2 est affichée.\n"
            },
            {
              "text": "`3`",
              "correct": false,
              "feedback": "Erreur : `3 > 0` est vrai, la soustraction a lieu.\n"
            },
            {
              "text": "`0`",
              "correct": false,
              "feedback": "Erreur : le bloc ne s'exécute qu'une fois, un `if` n'est pas une\nboucle.\n"
            },
            {
              "text": "`-1`",
              "correct": false,
              "feedback": "Erreur : on retire 1 à 3, ce qui donne 2.\n"
            }
          ],
          "explanation": "Un `if` exécute son bloc au plus une fois. Pour répéter la\nsoustraction jusqu'à zéro, il faudrait une boucle."
        },
        {
          "statement": "```python\nstock = 7\nif stock > 0:\n    stock = stock - 1\nprint(stock)\n```\n\nQu'affiche ce programme ?",
          "options": [
            {
              "text": "`6`",
              "correct": true,
              "feedback": "Bonne réponse : la condition est vraie, le stock diminue de 1,\npuis la valeur 6 est affichée.\n"
            },
            {
              "text": "`7`",
              "correct": false,
              "feedback": "Erreur : `7 > 0` est vrai, la soustraction a lieu.\n"
            },
            {
              "text": "`0`",
              "correct": false,
              "feedback": "Erreur : le bloc ne s'exécute qu'une fois, un `if` n'est pas une\nboucle.\n"
            },
            {
              "text": "`-1`",
              "correct": false,
              "feedback": "Erreur : on retire 1 à 7, ce qui donne 6.\n"
            }
          ],
          "explanation": "Un `if` exécute son bloc au plus une fois. Pour répéter la\nsoustraction jusqu'à zéro, il faudrait une boucle."
        },
        {
          "statement": "```python\nstock = 12\nif stock > 0:\n    stock = stock - 1\nprint(stock)\n```\n\nQu'affiche ce programme ?",
          "options": [
            {
              "text": "`11`",
              "correct": true,
              "feedback": "Bonne réponse : la condition est vraie, le stock diminue de 1,\npuis la valeur 11 est affichée.\n"
            },
            {
              "text": "`12`",
              "correct": false,
              "feedback": "Erreur : `12 > 0` est vrai, la soustraction a lieu.\n"
            },
            {
              "text": "`0`",
              "correct": false,
              "feedback": "Erreur : le bloc ne s'exécute qu'une fois, un `if` n'est pas une\nboucle.\n"
            },
            {
              "text": "`-1`",
              "correct": false,
              "feedback": "Erreur : on retire 1 à 12, ce qui donne 11.\n"
            }
          ],
          "explanation": "Un `if` exécute son bloc au plus une fois. Pour répéter la\nsoustraction jusqu'à zéro, il faudrait une boucle."
        }
      ]
    },
    {
      "id": "q12",
      "difficulty": 3,
      "skills": [
        "elif",
        "condition"
      ],
      "title": "L'ordre des tests",
      "statement": "```python\nnote = 17\nif note >= 10:\n    mention = \"Admis\"\nelif note >= 16:\n    mention = \"Très bien\"\nelse:\n    mention = \"Refusé\"\nprint(mention)\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`Admis`",
          "correct": true,
          "feedback": "Bonne réponse : la première condition est vraie pour 17, elle\nprend la main et la branche `Très bien` n'est jamais atteinte.\n"
        },
        {
          "text": "`Très bien`",
          "correct": false,
          "feedback": "Erreur : `17 >= 16` est vrai, mais la condition `note >= 10`,\ntestée avant, l'est aussi et l'emporte.\n"
        },
        {
          "text": "`Admis` puis `Très bien`",
          "correct": false,
          "feedback": "Erreur : une seule branche s'exécute, et un seul `print` suit.\n"
        },
        {
          "text": "`Refusé`",
          "correct": false,
          "feedback": "Erreur : `else` ne s'exécute que si toutes les conditions sont\nfausses.\n"
        }
      ],
      "explanation": "Dans une chaîne `if`, `elif`, l'ordre des tests compte : la\ncondition la plus restrictive doit venir en premier. Ici, il fallait\ntester `note >= 16` avant `note >= 10`."
    },
    {
      "id": "q13",
      "difficulty": 2,
      "skills": [
        "imbrication",
        "condition"
      ],
      "title": "Une condition dans une autre",
      "statement": "```python\nconnecte = True\nadmin = False\nif connecte:\n    if admin:\n        print(\"Réglages\")\n    else:\n        print(\"Accueil\")\nelse:\n    print(\"Connexion\")\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`Accueil`",
          "correct": true,
          "feedback": "Bonne réponse : `connecte` est vrai, on entre dans le premier\nbloc ; `admin` est faux, c'est le `else` intérieur qui\ns'exécute.\n"
        },
        {
          "text": "`Réglages`",
          "correct": false,
          "feedback": "Erreur : `admin` vaut `False`, la condition intérieure est\nfausse.\n"
        },
        {
          "text": "`Connexion`",
          "correct": false,
          "feedback": "Erreur : le `else` extérieur correspond à `connecte` faux, ce\nqui n'est pas le cas.\n"
        },
        {
          "text": "`Accueil` puis `Connexion`",
          "correct": false,
          "feedback": "Erreur : les deux `else` appartiennent à des `if` différents,\nrepérés par l'indentation. Un seul s'exécute.\n"
        }
      ],
      "explanation": "L'indentation indique à quel `if` chaque `else` se rattache. Une\ncondition imbriquée n'est testée que si la condition extérieure est\nvraie."
    },
    {
      "id": "q14",
      "difficulty": 1,
      "skills": [
        "comparaison",
        "booleens"
      ],
      "title": "Différent de",
      "statement": "```python\nprint(4 != 4)\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`False`",
          "correct": true,
          "feedback": "Bonne réponse : `!=` signifie « différent de ». 4 n'est pas\ndifférent de 4, la comparaison est fausse.\n"
        },
        {
          "text": "`True`",
          "correct": false,
          "feedback": "Erreur : `!=` est vrai seulement quand les deux valeurs\ndiffèrent.\n"
        },
        {
          "text": "`4`",
          "correct": false,
          "feedback": "Erreur : une comparaison donne un booléen, pas un nombre.\n"
        },
        {
          "text": "Une erreur, l'opérateur `!=` n'existe pas",
          "correct": false,
          "feedback": "Erreur : `!=` est l'opérateur de différence, l'inverse de `==`.\n"
        }
      ],
      "explanation": "Les six comparaisons sont `==`, `!=`, `<`, `<=`, `>` et `>=`. Chacune\nrenvoie `True` ou `False`."
    },
    {
      "id": "q15",
      "difficulty": 2,
      "skills": [
        "indentation",
        "condition"
      ],
      "title": "Une ligne hors du bloc",
      "statement": "```python\nsolde = 5\nif solde >= 10:\n    print(\"Achat possible\")\nprint(\"Fin\")\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`Fin` seulement",
          "correct": true,
          "feedback": "Bonne réponse : la condition est fausse, le bloc indenté est\nsauté. `print(\"Fin\")` n'est pas indenté et s'exécute toujours.\n"
        },
        {
          "text": "`Achat possible` puis `Fin`",
          "correct": false,
          "feedback": "Erreur : 5 n'est pas supérieur ou égal à 10, le premier\naffichage n'a pas lieu.\n"
        },
        {
          "text": "Rien",
          "correct": false,
          "feedback": "Erreur : la dernière ligne ne dépend pas de la condition.\n"
        },
        {
          "text": "`Achat possible` seulement",
          "correct": false,
          "feedback": "Erreur : c'est l'inverse, seul `Fin` est affiché.\n"
        }
      ],
      "explanation": "Seules les lignes indentées sous `if` dépendent de la condition. Une\nligne revenue au niveau du `if` s'exécute dans tous les cas."
    },
    {
      "id": "q16",
      "difficulty": 3,
      "skills": [
        "indentation",
        "condition"
      ],
      "title": "Deux lignes dans le bloc",
      "statement": "```python\nbatterie = 15\nif batterie < 10:\n    print(\"Batterie faible\")\n    print(\"Brancher le chargeur\")\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "Rien, les deux affichages dépendent de la condition",
          "correct": true,
          "feedback": "Bonne réponse : les deux lignes sont indentées sous `if`, et la\ncondition `15 < 10` est fausse.\n"
        },
        {
          "text": "`Brancher le chargeur` seulement",
          "correct": false,
          "feedback": "Erreur : cette ligne est indentée comme la précédente, elle fait\npartie du même bloc.\n"
        },
        {
          "text": "`Batterie faible` puis `Brancher le chargeur`",
          "correct": false,
          "feedback": "Erreur : la condition est fausse, aucune des deux lignes ne\ns'exécute.\n"
        },
        {
          "text": "`Batterie faible` seulement",
          "correct": false,
          "feedback": "Erreur : la première ligne dépend aussi de la condition, qui\nest fausse.\n"
        }
      ],
      "explanation": "Un bloc contient toutes les lignes indentées au même niveau sous le\n`if`. Elles s'exécutent toutes ou aucune, selon la condition."
    },
    {
      "id": "q17",
      "difficulty": 3,
      "skills": [
        "booleens",
        "and-or-not",
        "trace"
      ],
      "title": "Des booléens mémorisés",
      "statement": "```python\nx = 7\npair = x % 2 == 0\npetit = x < 10\nprint(pair, petit, pair or petit)\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`False True True`",
          "correct": true,
          "feedback": "Bonne réponse : 7 est impair, donc `pair` vaut `False` ; 7 est\ninférieur à 10, donc `petit` vaut `True` ; un seul vrai suffit\nau `or`.\n"
        },
        {
          "text": "`True True True`",
          "correct": false,
          "feedback": "Erreur : 7 % 2 vaut 1, `pair` est faux.\n"
        },
        {
          "text": "`False True False`",
          "correct": false,
          "feedback": "Erreur : `or` est vrai dès qu'un des deux booléens est vrai.\n"
        },
        {
          "text": "`False False False`",
          "correct": false,
          "feedback": "Erreur : `x < 10` est vrai pour 7.\n"
        }
      ],
      "explanation": "Un booléen se range dans une variable comme n'importe quelle valeur.\nOn peut ensuite le combiner avec `and`, `or` et `not`, ce qui rend\nles conditions lisibles."
    },
    {
      "id": "q18",
      "difficulty": 2,
      "skills": [
        "condition",
        "completer-code"
      ],
      "title": "Compléter une condition",
      "statement": "Un arrosage automatique se déclenche si l'humidité du sol est\ninférieure à 30 et qu'il ne pleut pas. `pluie` est un booléen.\nQuelle ligne convient ?",
      "options": [
        {
          "text": "`if humidite < 30 and not pluie:`",
          "correct": true,
          "feedback": "Bonne réponse : les deux conditions doivent être vraies à la\nfois, et « il ne pleut pas » se traduit par `not pluie`.\n"
        },
        {
          "text": "`if humidite < 30 or not pluie:`",
          "correct": false,
          "feedback": "Erreur : avec `or`, l'arrosage partirait dès qu'il ne pleut pas,\nmême sur un sol humide.\n"
        },
        {
          "text": "`if humidite > 30 and pluie:`",
          "correct": false,
          "feedback": "Erreur : c'est presque l'inverse : sol humide et pluie.\n"
        },
        {
          "text": "`if humidite < 30 and pluie:`",
          "correct": false,
          "feedback": "Erreur : cette condition arrose quand il pleut, il manque le\n`not`.\n"
        }
      ],
      "explanation": "Traduire une phrase en condition demande de repérer le connecteur,\n« et » devient `and`, et les négations, « ne … pas » devient `not`."
    },
    {
      "id": "q19",
      "difficulty": 3,
      "skills": [
        "elif",
        "trace"
      ],
      "title": "Deux conditions vraies, une seule branche",
      "statement": "```python\nn = 12\nif n % 2 == 0:\n    print(\"Pair\")\nelif n % 3 == 0:\n    print(\"Multiple de 3\")\nelse:\n    print(\"Autre\")\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`Pair`",
          "correct": true,
          "feedback": "Bonne réponse : 12 est pair, la première branche s'exécute, et\nle `elif` n'est pas testé même si 12 est aussi multiple de 3.\n"
        },
        {
          "text": "`Pair` puis `Multiple de 3`",
          "correct": false,
          "feedback": "Erreur : avec `elif`, une seule branche s'exécute. Deux `if`\nséparés afficheraient les deux.\n"
        },
        {
          "text": "`Multiple de 3`",
          "correct": false,
          "feedback": "Erreur : la première condition, testée avant, est vraie.\n"
        },
        {
          "text": "`Autre`",
          "correct": false,
          "feedback": "Erreur : `else` n'est atteint que si toutes les conditions sont\nfausses.\n"
        }
      ],
      "explanation": "`elif` signifie « sinon, si » : il n'est testé que si les conditions\nprécédentes sont fausses. Pour afficher toutes les propriétés vraies,\non utilise des `if` indépendants."
    },
    {
      "id": "q20",
      "difficulty": 1,
      "skills": [
        "comparaison"
      ],
      "title": "Supérieur ou égal",
      "statement": "```python\na = 8\nprint(a >= 8, a > 8)\n```\n\nQu'affiche ce programme ?",
      "options": [
        {
          "text": "`True False`",
          "correct": true,
          "feedback": "Bonne réponse : 8 est supérieur ou égal à 8, mais pas\nstrictement supérieur.\n"
        },
        {
          "text": "`True True`",
          "correct": false,
          "feedback": "Erreur : `>` est strict, 8 n'est pas plus grand que 8.\n"
        },
        {
          "text": "`False False`",
          "correct": false,
          "feedback": "Erreur : `>=` accepte l'égalité, la première comparaison est\nvraie.\n"
        },
        {
          "text": "`False True`",
          "correct": false,
          "feedback": "Erreur : c'est l'inverse.\n"
        }
      ],
      "explanation": "`>=` et `<=` acceptent l'égalité, `>` et `<` sont stricts. Le choix\nentre les deux décide du sort de la valeur limite."
    },
    {
      "id": "q21",
      "difficulty": 1,
      "skills": [
        "if-else",
        "comparaison"
      ],
      "title": "Majeur ou mineur",
      "statement": "Qu'affiche ce programme ?\n```python\nage = 20\nif age >= 18:\n    print(\"majeur\")\nelse:\n    print(\"mineur\")\n```",
      "options": [
        {
          "text": "`majeur`",
          "correct": true,
          "feedback": "Bonne réponse : avec `age` égal à 20, la condition `age >= 18`\ndésigne la branche exécutée, qui affiche `majeur`.\n"
        },
        {
          "text": "`mineur`",
          "correct": false,
          "feedback": "Erreur : compare 20 à 18 pour savoir si la condition est vraie.\n"
        },
        {
          "text": "`majeur` puis `mineur`",
          "correct": false,
          "feedback": "Erreur : une seule des deux branches est exécutée.\n"
        },
        {
          "text": "`20`",
          "correct": false,
          "feedback": "Erreur : le programme affiche un texte, pas la valeur de `age`.\n"
        }
      ],
      "explanation": "`if` choisit la branche selon la condition, `else` prend le relais\nquand elle est fausse.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\nage = 20\nif age >= 18:\n    print(\"majeur\")\nelse:\n    print(\"mineur\")\n```",
          "options": [
            {
              "text": "`majeur`",
              "correct": true,
              "feedback": "Bonne réponse : avec `age` égal à 20, la condition `age >= 18`\ndésigne la branche exécutée, qui affiche `majeur`.\n"
            },
            {
              "text": "`mineur`",
              "correct": false,
              "feedback": "Erreur : compare 20 à 18 pour savoir si la condition est vraie.\n"
            },
            {
              "text": "`majeur` puis `mineur`",
              "correct": false,
              "feedback": "Erreur : une seule des deux branches est exécutée.\n"
            },
            {
              "text": "`20`",
              "correct": false,
              "feedback": "Erreur : le programme affiche un texte, pas la valeur de `age`.\n"
            }
          ],
          "explanation": "`if` choisit la branche selon la condition, `else` prend le relais\nquand elle est fausse."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nage = 15\nif age >= 18:\n    print(\"majeur\")\nelse:\n    print(\"mineur\")\n```",
          "options": [
            {
              "text": "`mineur`",
              "correct": true,
              "feedback": "Bonne réponse : avec `age` égal à 15, la condition `age >= 18`\ndésigne la branche exécutée, qui affiche `mineur`.\n"
            },
            {
              "text": "`majeur`",
              "correct": false,
              "feedback": "Erreur : compare 15 à 18 pour savoir si la condition est vraie.\n"
            },
            {
              "text": "`majeur` puis `mineur`",
              "correct": false,
              "feedback": "Erreur : une seule des deux branches est exécutée.\n"
            },
            {
              "text": "`15`",
              "correct": false,
              "feedback": "Erreur : le programme affiche un texte, pas la valeur de `age`.\n"
            }
          ],
          "explanation": "`if` choisit la branche selon la condition, `else` prend le relais\nquand elle est fausse."
        }
      ]
    },
    {
      "id": "q22",
      "difficulty": 1,
      "skills": [
        "modulo",
        "if-else",
        "parite"
      ],
      "title": "Pair ou impair",
      "statement": "Qu'affiche ce programme ?\n```python\nn = 4\nif n % 2 == 0:\n    print(\"pair\")\nelse:\n    print(\"impair\")\n```",
      "options": [
        {
          "text": "`pair`",
          "correct": true,
          "feedback": "Bonne réponse : `n % 2` est le reste de la division de 4 par\n2. Il vaut 0 pour un nombre pair.\n"
        },
        {
          "text": "`impair`",
          "correct": false,
          "feedback": "Erreur : calcule le reste de 4 divisé par 2 avant de choisir la\nbranche.\n"
        },
        {
          "text": "`0`",
          "correct": false,
          "feedback": "Erreur : le reste n'est pas affiché, il sert seulement au test.\n"
        },
        {
          "text": "Une erreur, `%` ne pouvant être comparé à 0",
          "correct": false,
          "feedback": "Erreur : `n % 2 == 0` est la façon habituelle de tester la\nparité.\n"
        }
      ],
      "explanation": "Tester `n % 2 == 0` est le réflexe pour reconnaître un nombre pair.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\nn = 4\nif n % 2 == 0:\n    print(\"pair\")\nelse:\n    print(\"impair\")\n```",
          "options": [
            {
              "text": "`pair`",
              "correct": true,
              "feedback": "Bonne réponse : `n % 2` est le reste de la division de 4 par\n2. Il vaut 0 pour un nombre pair.\n"
            },
            {
              "text": "`impair`",
              "correct": false,
              "feedback": "Erreur : calcule le reste de 4 divisé par 2 avant de choisir la\nbranche.\n"
            },
            {
              "text": "`0`",
              "correct": false,
              "feedback": "Erreur : le reste n'est pas affiché, il sert seulement au test.\n"
            },
            {
              "text": "Une erreur, `%` ne pouvant être comparé à 0",
              "correct": false,
              "feedback": "Erreur : `n % 2 == 0` est la façon habituelle de tester la\nparité.\n"
            }
          ],
          "explanation": "Tester `n % 2 == 0` est le réflexe pour reconnaître un nombre pair."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nn = 7\nif n % 2 == 0:\n    print(\"pair\")\nelse:\n    print(\"impair\")\n```",
          "options": [
            {
              "text": "`impair`",
              "correct": true,
              "feedback": "Bonne réponse : `n % 2` est le reste de la division de 7 par\n2. Il vaut 0 pour un nombre pair.\n"
            },
            {
              "text": "`pair`",
              "correct": false,
              "feedback": "Erreur : calcule le reste de 7 divisé par 2 avant de choisir la\nbranche.\n"
            },
            {
              "text": "`1`",
              "correct": false,
              "feedback": "Erreur : le reste n'est pas affiché, il sert seulement au test.\n"
            },
            {
              "text": "Une erreur, `%` ne pouvant être comparé à 0",
              "correct": false,
              "feedback": "Erreur : `n % 2 == 0` est la façon habituelle de tester la\nparité.\n"
            }
          ],
          "explanation": "Tester `n % 2 == 0` est le réflexe pour reconnaître un nombre pair."
        }
      ]
    },
    {
      "id": "q23",
      "difficulty": 1,
      "skills": [
        "if",
        "suite-du-programme"
      ],
      "title": "Ce qui s'affiche après le if",
      "statement": "Qu'affiche ce programme ?\n```python\ntemperature = 30\nif temperature > 25:\n    print(\"chaud\")\nprint(\"fin\")\n```",
      "options": [
        {
          "text": "`chaud` puis `fin`",
          "correct": true,
          "feedback": "Bonne réponse : seul `print(\"chaud\")` dépend de la condition.\n`print(\"fin\")`, non indenté, s'exécute dans tous les cas.\n"
        },
        {
          "text": "`fin` seulement",
          "correct": false,
          "feedback": "Erreur : vérifie si 30 dépasse 25, et souviens-toi que la\ndernière ligne n'est pas dans le bloc.\n"
        },
        {
          "text": "`chaud` seulement",
          "correct": false,
          "feedback": "Erreur : `print(\"fin\")` est hors du bloc `if`, il s'affiche\ntoujours.\n"
        },
        {
          "text": "Rien, le programme n'ayant pas de `else`",
          "correct": false,
          "feedback": "Erreur : `else` est facultatif, et la dernière ligne s'exécute de\ntoute façon.\n"
        }
      ],
      "explanation": "L'indentation délimite le bloc conditionnel. Ce qui revient à la\nmarge est exécuté quoi qu'il arrive.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\ntemperature = 30\nif temperature > 25:\n    print(\"chaud\")\nprint(\"fin\")\n```",
          "options": [
            {
              "text": "`chaud` puis `fin`",
              "correct": true,
              "feedback": "Bonne réponse : seul `print(\"chaud\")` dépend de la condition.\n`print(\"fin\")`, non indenté, s'exécute dans tous les cas.\n"
            },
            {
              "text": "`fin` seulement",
              "correct": false,
              "feedback": "Erreur : vérifie si 30 dépasse 25, et souviens-toi que la\ndernière ligne n'est pas dans le bloc.\n"
            },
            {
              "text": "`chaud` seulement",
              "correct": false,
              "feedback": "Erreur : `print(\"fin\")` est hors du bloc `if`, il s'affiche\ntoujours.\n"
            },
            {
              "text": "Rien, le programme n'ayant pas de `else`",
              "correct": false,
              "feedback": "Erreur : `else` est facultatif, et la dernière ligne s'exécute de\ntoute façon.\n"
            }
          ],
          "explanation": "L'indentation délimite le bloc conditionnel. Ce qui revient à la\nmarge est exécuté quoi qu'il arrive."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\ntemperature = 20\nif temperature > 25:\n    print(\"chaud\")\nprint(\"fin\")\n```",
          "options": [
            {
              "text": "`fin` seulement",
              "correct": true,
              "feedback": "Bonne réponse : seul `print(\"chaud\")` dépend de la condition.\n`print(\"fin\")`, non indenté, s'exécute dans tous les cas.\n"
            },
            {
              "text": "`chaud` puis `fin`",
              "correct": false,
              "feedback": "Erreur : vérifie si 20 dépasse 25, et souviens-toi que la\ndernière ligne n'est pas dans le bloc.\n"
            },
            {
              "text": "`chaud` seulement",
              "correct": false,
              "feedback": "Erreur : `print(\"fin\")` est hors du bloc `if`, il s'affiche\ntoujours.\n"
            },
            {
              "text": "Rien, le programme n'ayant pas de `else`",
              "correct": false,
              "feedback": "Erreur : `else` est facultatif, et la dernière ligne s'exécute de\ntoute façon.\n"
            }
          ],
          "explanation": "L'indentation délimite le bloc conditionnel. Ce qui revient à la\nmarge est exécuté quoi qu'il arrive."
        }
      ]
    },
    {
      "id": "q24",
      "difficulty": 2,
      "skills": [
        "if-else",
        "maximum"
      ],
      "title": "Le plus grand de deux nombres",
      "statement": "Qu'affiche ce programme ?\n```python\na = 3\nb = 5\nif a > b:\n    print(a)\nelse:\n    print(b)\n```",
      "options": [
        {
          "text": "`5`",
          "correct": true,
          "feedback": "Bonne réponse : si `a > b`, c'est `a` qui est affiché, sinon\n`b`. Dans tous les cas, le plus grand des deux apparaît.\n"
        },
        {
          "text": "`3`",
          "correct": false,
          "feedback": "Erreur : la condition `a > b` conduit à afficher le plus grand,\npas le plus petit.\n"
        },
        {
          "text": "`3 5`",
          "correct": false,
          "feedback": "Erreur : une seule branche s'exécute, donc une seule valeur.\n"
        },
        {
          "text": "`8`",
          "correct": false,
          "feedback": "Erreur : aucune addition n'est faite.\n"
        }
      ],
      "explanation": "Ce programme calcule un maximum. Si `a` et `b` étaient égaux, la\nbranche `else` afficherait `b`, ce qui reviendrait au même.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\na = 3\nb = 5\nif a > b:\n    print(a)\nelse:\n    print(b)\n```",
          "options": [
            {
              "text": "`5`",
              "correct": true,
              "feedback": "Bonne réponse : si `a > b`, c'est `a` qui est affiché, sinon\n`b`. Dans tous les cas, le plus grand des deux apparaît.\n"
            },
            {
              "text": "`3`",
              "correct": false,
              "feedback": "Erreur : la condition `a > b` conduit à afficher le plus grand,\npas le plus petit.\n"
            },
            {
              "text": "`3 5`",
              "correct": false,
              "feedback": "Erreur : une seule branche s'exécute, donc une seule valeur.\n"
            },
            {
              "text": "`8`",
              "correct": false,
              "feedback": "Erreur : aucune addition n'est faite.\n"
            }
          ],
          "explanation": "Ce programme calcule un maximum. Si `a` et `b` étaient égaux, la\nbranche `else` afficherait `b`, ce qui reviendrait au même."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\na = 9\nb = 4\nif a > b:\n    print(a)\nelse:\n    print(b)\n```",
          "options": [
            {
              "text": "`9`",
              "correct": true,
              "feedback": "Bonne réponse : si `a > b`, c'est `a` qui est affiché, sinon\n`b`. Dans tous les cas, le plus grand des deux apparaît.\n"
            },
            {
              "text": "`4`",
              "correct": false,
              "feedback": "Erreur : la condition `a > b` conduit à afficher le plus grand,\npas le plus petit.\n"
            },
            {
              "text": "`9 4`",
              "correct": false,
              "feedback": "Erreur : une seule branche s'exécute, donc une seule valeur.\n"
            },
            {
              "text": "`13`",
              "correct": false,
              "feedback": "Erreur : aucune addition n'est faite.\n"
            }
          ],
          "explanation": "Ce programme calcule un maximum. Si `a` et `b` étaient égaux, la\nbranche `else` afficherait `b`, ce qui reviendrait au même."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\na = 7\nb = 2\nif a > b:\n    print(a)\nelse:\n    print(b)\n```",
          "options": [
            {
              "text": "`7`",
              "correct": true,
              "feedback": "Bonne réponse : si `a > b`, c'est `a` qui est affiché, sinon\n`b`. Dans tous les cas, le plus grand des deux apparaît.\n"
            },
            {
              "text": "`2`",
              "correct": false,
              "feedback": "Erreur : la condition `a > b` conduit à afficher le plus grand,\npas le plus petit.\n"
            },
            {
              "text": "`7 2`",
              "correct": false,
              "feedback": "Erreur : une seule branche s'exécute, donc une seule valeur.\n"
            },
            {
              "text": "`9`",
              "correct": false,
              "feedback": "Erreur : aucune addition n'est faite.\n"
            }
          ],
          "explanation": "Ce programme calcule un maximum. Si `a` et `b` étaient égaux, la\nbranche `else` afficherait `b`, ce qui reviendrait au même."
        }
      ]
    },
    {
      "id": "q25",
      "difficulty": 2,
      "skills": [
        "if-successifs",
        "trace"
      ],
      "title": "Deux retraits successifs",
      "statement": "Qu'affiche ce programme ?\n```python\nx = 8\nif x > 10:\n    x = x - 10\nif x > 5:\n    x = x - 5\nprint(x)\n```",
      "options": [
        {
          "text": "`3`",
          "correct": true,
          "feedback": "Bonne réponse : 8 n'est pas supérieur à 10, le premier bloc\nest sauté ; 8 est supérieur à 5, le second retire 5.\n"
        },
        {
          "text": "`-7`",
          "correct": false,
          "feedback": "Erreur : les deux retraits ne sont pas automatiques. Le premier\nexige `x > 10`, ce qui est faux pour 8.\n"
        },
        {
          "text": "`8`",
          "correct": false,
          "feedback": "Erreur : au moins une condition est vraie et modifie `x`.\n"
        },
        {
          "text": "`-2`",
          "correct": false,
          "feedback": "Erreur : -2 correspondrait au premier retrait seul, or sa\ncondition `x > 10` est fausse pour 8.\n"
        }
      ],
      "explanation": "Deux `if` à la suite sont indépendants : le second voit les\nmodifications faites par le premier.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\nx = 8\nif x > 10:\n    x = x - 10\nif x > 5:\n    x = x - 5\nprint(x)\n```",
          "options": [
            {
              "text": "`3`",
              "correct": true,
              "feedback": "Bonne réponse : 8 n'est pas supérieur à 10, le premier bloc\nest sauté ; 8 est supérieur à 5, le second retire 5.\n"
            },
            {
              "text": "`-7`",
              "correct": false,
              "feedback": "Erreur : les deux retraits ne sont pas automatiques. Le premier\nexige `x > 10`, ce qui est faux pour 8.\n"
            },
            {
              "text": "`8`",
              "correct": false,
              "feedback": "Erreur : au moins une condition est vraie et modifie `x`.\n"
            },
            {
              "text": "`-2`",
              "correct": false,
              "feedback": "Erreur : -2 correspondrait au premier retrait seul, or sa\ncondition `x > 10` est fausse pour 8.\n"
            }
          ],
          "explanation": "Deux `if` à la suite sont indépendants : le second voit les\nmodifications faites par le premier."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nx = 9\nif x > 10:\n    x = x - 10\nif x > 5:\n    x = x - 5\nprint(x)\n```",
          "options": [
            {
              "text": "`4`",
              "correct": true,
              "feedback": "Bonne réponse : 9 n'est pas supérieur à 10, le premier bloc\nest sauté ; 9 est supérieur à 5, le second retire 5.\n"
            },
            {
              "text": "`-6`",
              "correct": false,
              "feedback": "Erreur : les deux retraits ne sont pas automatiques. Le premier\nexige `x > 10`, ce qui est faux pour 9.\n"
            },
            {
              "text": "`9`",
              "correct": false,
              "feedback": "Erreur : au moins une condition est vraie et modifie `x`.\n"
            },
            {
              "text": "`-1`",
              "correct": false,
              "feedback": "Erreur : -1 correspondrait au premier retrait seul, or sa\ncondition `x > 10` est fausse pour 9.\n"
            }
          ],
          "explanation": "Deux `if` à la suite sont indépendants : le second voit les\nmodifications faites par le premier."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nx = 7\nif x > 10:\n    x = x - 10\nif x > 5:\n    x = x - 5\nprint(x)\n```",
          "options": [
            {
              "text": "`2`",
              "correct": true,
              "feedback": "Bonne réponse : 7 n'est pas supérieur à 10, le premier bloc\nest sauté ; 7 est supérieur à 5, le second retire 5.\n"
            },
            {
              "text": "`-8`",
              "correct": false,
              "feedback": "Erreur : les deux retraits ne sont pas automatiques. Le premier\nexige `x > 10`, ce qui est faux pour 7.\n"
            },
            {
              "text": "`7`",
              "correct": false,
              "feedback": "Erreur : au moins une condition est vraie et modifie `x`.\n"
            },
            {
              "text": "`-3`",
              "correct": false,
              "feedback": "Erreur : -3 correspondrait au premier retrait seul, or sa\ncondition `x > 10` est fausse pour 7.\n"
            }
          ],
          "explanation": "Deux `if` à la suite sont indépendants : le second voit les\nmodifications faites par le premier."
        }
      ]
    },
    {
      "id": "q26",
      "difficulty": 2,
      "skills": [
        "elif",
        "ordre"
      ],
      "title": "Le tarif selon l'âge",
      "statement": "Qu'affiche ce programme ?\n```python\nage = 10\nif age < 12:\n    prix = 3\nelif age < 18:\n    prix = 5\nelse:\n    prix = 8\nprint(prix)\n```",
      "options": [
        {
          "text": "`3`",
          "correct": true,
          "feedback": "Bonne réponse : les conditions sont testées dans l'ordre, et la\npremière vraie fixe le prix. Avec 10 ans, c'est 3.\n"
        },
        {
          "text": "`5`",
          "correct": false,
          "feedback": "Erreur : relis les conditions dans l'ordre avec `age` égal à\n10.\n"
        },
        {
          "text": "`8`",
          "correct": false,
          "feedback": "Erreur : une seule branche de la chaîne s'exécute, la première\ndont la condition est vraie.\n"
        },
        {
          "text": "`3 5 8`",
          "correct": false,
          "feedback": "Erreur : une chaîne `if`, `elif`, `else` ne retient qu'une\nvaleur.\n"
        }
      ],
      "explanation": "`elif` enchaîne les tests sans les cumuler : dès qu'une condition\nest vraie, les suivantes sont ignorées.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\nage = 10\nif age < 12:\n    prix = 3\nelif age < 18:\n    prix = 5\nelse:\n    prix = 8\nprint(prix)\n```",
          "options": [
            {
              "text": "`3`",
              "correct": true,
              "feedback": "Bonne réponse : les conditions sont testées dans l'ordre, et la\npremière vraie fixe le prix. Avec 10 ans, c'est 3.\n"
            },
            {
              "text": "`5`",
              "correct": false,
              "feedback": "Erreur : relis les conditions dans l'ordre avec `age` égal à\n10.\n"
            },
            {
              "text": "`8`",
              "correct": false,
              "feedback": "Erreur : une seule branche de la chaîne s'exécute, la première\ndont la condition est vraie.\n"
            },
            {
              "text": "`3 5 8`",
              "correct": false,
              "feedback": "Erreur : une chaîne `if`, `elif`, `else` ne retient qu'une\nvaleur.\n"
            }
          ],
          "explanation": "`elif` enchaîne les tests sans les cumuler : dès qu'une condition\nest vraie, les suivantes sont ignorées."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nage = 15\nif age < 12:\n    prix = 3\nelif age < 18:\n    prix = 5\nelse:\n    prix = 8\nprint(prix)\n```",
          "options": [
            {
              "text": "`5`",
              "correct": true,
              "feedback": "Bonne réponse : les conditions sont testées dans l'ordre, et la\npremière vraie fixe le prix. Avec 15 ans, c'est 5.\n"
            },
            {
              "text": "`3`",
              "correct": false,
              "feedback": "Erreur : relis les conditions dans l'ordre avec `age` égal à\n15.\n"
            },
            {
              "text": "`8`",
              "correct": false,
              "feedback": "Erreur : une seule branche de la chaîne s'exécute, la première\ndont la condition est vraie.\n"
            },
            {
              "text": "`3 5 8`",
              "correct": false,
              "feedback": "Erreur : une chaîne `if`, `elif`, `else` ne retient qu'une\nvaleur.\n"
            }
          ],
          "explanation": "`elif` enchaîne les tests sans les cumuler : dès qu'une condition\nest vraie, les suivantes sont ignorées."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nage = 30\nif age < 12:\n    prix = 3\nelif age < 18:\n    prix = 5\nelse:\n    prix = 8\nprint(prix)\n```",
          "options": [
            {
              "text": "`8`",
              "correct": true,
              "feedback": "Bonne réponse : les conditions sont testées dans l'ordre, et la\npremière vraie fixe le prix. Avec 30 ans, c'est 8.\n"
            },
            {
              "text": "`5`",
              "correct": false,
              "feedback": "Erreur : relis les conditions dans l'ordre avec `age` égal à\n30.\n"
            },
            {
              "text": "`3`",
              "correct": false,
              "feedback": "Erreur : une seule branche de la chaîne s'exécute, la première\ndont la condition est vraie.\n"
            },
            {
              "text": "`3 5 8`",
              "correct": false,
              "feedback": "Erreur : une chaîne `if`, `elif`, `else` ne retient qu'une\nvaleur.\n"
            }
          ],
          "explanation": "`elif` enchaîne les tests sans les cumuler : dès qu'une condition\nest vraie, les suivantes sont ignorées."
        }
      ]
    },
    {
      "id": "q27",
      "difficulty": 2,
      "skills": [
        "not",
        "booleen"
      ],
      "title": "Un état inversé par not",
      "statement": "Qu'affiche ce programme ?\n```python\nactif = False\nif not actif:\n    print(\"inactif\")\n```",
      "options": [
        {
          "text": "`inactif`",
          "correct": true,
          "feedback": "Bonne réponse : `not` inverse le booléen. Avec `actif` à False,\n`not actif` vaut l'inverse, ce qui décide de l'affichage.\n"
        },
        {
          "text": "Rien, la condition étant fausse",
          "correct": false,
          "feedback": "Erreur : `not False` vaut l'inverse de False. Reprends le test avec\ncette valeur.\n"
        },
        {
          "text": "`actif`",
          "correct": false,
          "feedback": "Erreur : le programme ne peut afficher que `inactif`, ou rien.\n"
        },
        {
          "text": "Une erreur, `not` ne s'appliquant qu'aux nombres",
          "correct": false,
          "feedback": "Erreur : `not` s'applique justement aux booléens.\n"
        }
      ],
      "explanation": "`not` transforme `True` en `False` et inversement. `if not actif`\nse lit « si l'objet n'est pas actif ».",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\nactif = False\nif not actif:\n    print(\"inactif\")\n```",
          "options": [
            {
              "text": "`inactif`",
              "correct": true,
              "feedback": "Bonne réponse : `not` inverse le booléen. Avec `actif` à False,\n`not actif` vaut l'inverse, ce qui décide de l'affichage.\n"
            },
            {
              "text": "Rien, la condition étant fausse",
              "correct": false,
              "feedback": "Erreur : `not False` vaut l'inverse de False. Reprends le test avec\ncette valeur.\n"
            },
            {
              "text": "`actif`",
              "correct": false,
              "feedback": "Erreur : le programme ne peut afficher que `inactif`, ou rien.\n"
            },
            {
              "text": "Une erreur, `not` ne s'appliquant qu'aux nombres",
              "correct": false,
              "feedback": "Erreur : `not` s'applique justement aux booléens.\n"
            }
          ],
          "explanation": "`not` transforme `True` en `False` et inversement. `if not actif`\nse lit « si l'objet n'est pas actif »."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nactif = True\nif not actif:\n    print(\"inactif\")\n```",
          "options": [
            {
              "text": "Rien, la condition étant fausse",
              "correct": true,
              "feedback": "Bonne réponse : `not` inverse le booléen. Avec `actif` à True,\n`not actif` vaut l'inverse, ce qui décide de l'affichage.\n"
            },
            {
              "text": "`inactif`",
              "correct": false,
              "feedback": "Erreur : `not True` vaut l'inverse de True. Reprends le test avec\ncette valeur.\n"
            },
            {
              "text": "`actif`",
              "correct": false,
              "feedback": "Erreur : le programme ne peut afficher que `inactif`, ou rien.\n"
            },
            {
              "text": "Une erreur, `not` ne s'appliquant qu'aux nombres",
              "correct": false,
              "feedback": "Erreur : `not` s'applique justement aux booléens.\n"
            }
          ],
          "explanation": "`not` transforme `True` en `False` et inversement. `if not actif`\nse lit « si l'objet n'est pas actif »."
        }
      ]
    },
    {
      "id": "q28",
      "difficulty": 3,
      "skills": [
        "or",
        "booleen",
        "trace"
      ],
      "title": "Un ou entre deux comparaisons",
      "statement": "Qu'affiche ce programme ?\n```python\nx = 3\ny = 9\nprint(x > 5 or y > 5)\n```",
      "options": [
        {
          "text": "`True`",
          "correct": true,
          "feedback": "Bonne réponse : `x > 5` est faux ; `y > 5` décide donc du\nrésultat, et `or` vaut `True` dès qu'une comparaison est vraie.\n"
        },
        {
          "text": "`False`",
          "correct": false,
          "feedback": "Erreur : évalue chaque comparaison séparément, puis applique la\nrègle du `or`.\n"
        },
        {
          "text": "`9`",
          "correct": false,
          "feedback": "Erreur : une expression avec `or` renvoie un booléen, pas un\nnombre.\n"
        },
        {
          "text": "Une erreur, `print` ne pouvant afficher une comparaison",
          "correct": false,
          "feedback": "Erreur : `print` affiche le résultat de l'expression, ici un\nbooléen.\n"
        }
      ],
      "explanation": "`or` est vrai si au moins une des conditions l'est, faux seulement\nsi toutes sont fausses.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\nx = 3\ny = 9\nprint(x > 5 or y > 5)\n```",
          "options": [
            {
              "text": "`True`",
              "correct": true,
              "feedback": "Bonne réponse : `x > 5` est faux ; `y > 5` décide donc du\nrésultat, et `or` vaut `True` dès qu'une comparaison est vraie.\n"
            },
            {
              "text": "`False`",
              "correct": false,
              "feedback": "Erreur : évalue chaque comparaison séparément, puis applique la\nrègle du `or`.\n"
            },
            {
              "text": "`9`",
              "correct": false,
              "feedback": "Erreur : une expression avec `or` renvoie un booléen, pas un\nnombre.\n"
            },
            {
              "text": "Une erreur, `print` ne pouvant afficher une comparaison",
              "correct": false,
              "feedback": "Erreur : `print` affiche le résultat de l'expression, ici un\nbooléen.\n"
            }
          ],
          "explanation": "`or` est vrai si au moins une des conditions l'est, faux seulement\nsi toutes sont fausses."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nx = 3\ny = 2\nprint(x > 5 or y > 5)\n```",
          "options": [
            {
              "text": "`False`",
              "correct": true,
              "feedback": "Bonne réponse : `x > 5` est faux ; `y > 5` décide donc du\nrésultat, et `or` vaut `True` dès qu'une comparaison est vraie.\n"
            },
            {
              "text": "`True`",
              "correct": false,
              "feedback": "Erreur : évalue chaque comparaison séparément, puis applique la\nrègle du `or`.\n"
            },
            {
              "text": "`2`",
              "correct": false,
              "feedback": "Erreur : une expression avec `or` renvoie un booléen, pas un\nnombre.\n"
            },
            {
              "text": "Une erreur, `print` ne pouvant afficher une comparaison",
              "correct": false,
              "feedback": "Erreur : `print` affiche le résultat de l'expression, ici un\nbooléen.\n"
            }
          ],
          "explanation": "`or` est vrai si au moins une des conditions l'est, faux seulement\nsi toutes sont fausses."
        }
      ]
    },
    {
      "id": "q29",
      "difficulty": 3,
      "skills": [
        "conditions-imbriquees",
        "trace"
      ],
      "title": "Petit, grand ou négatif",
      "statement": "Qu'affiche ce programme ?\n```python\na = 5\nif a > 0:\n    if a > 10:\n        print(\"grand\")\n    else:\n        print(\"petit\")\nelse:\n    print(\"négatif\")\n```",
      "options": [
        {
          "text": "`petit`",
          "correct": true,
          "feedback": "Bonne réponse : le premier test sépare positifs et négatifs ; le\nsecond, à l'intérieur, sépare les positifs en grands et petits.\nAvec 5, on obtient `petit`.\n"
        },
        {
          "text": "`grand`",
          "correct": false,
          "feedback": "Erreur : suis les tests dans l'ordre, en respectant\nl'indentation.\n"
        },
        {
          "text": "`négatif`",
          "correct": false,
          "feedback": "Erreur : chaque `else` est lié au `if` de même indentation.\n"
        },
        {
          "text": "Rien, aucune branche ne convenant",
          "correct": false,
          "feedback": "Erreur : tout nombre tombe dans une des trois branches.\n"
        }
      ],
      "explanation": "Un `if` dans un `if` affine le tri. L'indentation indique à quel\n`if` appartient chaque `else`.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\na = 5\nif a > 0:\n    if a > 10:\n        print(\"grand\")\n    else:\n        print(\"petit\")\nelse:\n    print(\"négatif\")\n```",
          "options": [
            {
              "text": "`petit`",
              "correct": true,
              "feedback": "Bonne réponse : le premier test sépare positifs et négatifs ; le\nsecond, à l'intérieur, sépare les positifs en grands et petits.\nAvec 5, on obtient `petit`.\n"
            },
            {
              "text": "`grand`",
              "correct": false,
              "feedback": "Erreur : suis les tests dans l'ordre, en respectant\nl'indentation.\n"
            },
            {
              "text": "`négatif`",
              "correct": false,
              "feedback": "Erreur : chaque `else` est lié au `if` de même indentation.\n"
            },
            {
              "text": "Rien, aucune branche ne convenant",
              "correct": false,
              "feedback": "Erreur : tout nombre tombe dans une des trois branches.\n"
            }
          ],
          "explanation": "Un `if` dans un `if` affine le tri. L'indentation indique à quel\n`if` appartient chaque `else`."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\na = 15\nif a > 0:\n    if a > 10:\n        print(\"grand\")\n    else:\n        print(\"petit\")\nelse:\n    print(\"négatif\")\n```",
          "options": [
            {
              "text": "`grand`",
              "correct": true,
              "feedback": "Bonne réponse : le premier test sépare positifs et négatifs ; le\nsecond, à l'intérieur, sépare les positifs en grands et petits.\nAvec 15, on obtient `grand`.\n"
            },
            {
              "text": "`petit`",
              "correct": false,
              "feedback": "Erreur : suis les tests dans l'ordre, en respectant\nl'indentation.\n"
            },
            {
              "text": "`négatif`",
              "correct": false,
              "feedback": "Erreur : chaque `else` est lié au `if` de même indentation.\n"
            },
            {
              "text": "Rien, aucune branche ne convenant",
              "correct": false,
              "feedback": "Erreur : tout nombre tombe dans une des trois branches.\n"
            }
          ],
          "explanation": "Un `if` dans un `if` affine le tri. L'indentation indique à quel\n`if` appartient chaque `else`."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\na = -2\nif a > 0:\n    if a > 10:\n        print(\"grand\")\n    else:\n        print(\"petit\")\nelse:\n    print(\"négatif\")\n```",
          "options": [
            {
              "text": "`négatif`",
              "correct": true,
              "feedback": "Bonne réponse : le premier test sépare positifs et négatifs ; le\nsecond, à l'intérieur, sépare les positifs en grands et petits.\nAvec -2, on obtient `négatif`.\n"
            },
            {
              "text": "`petit`",
              "correct": false,
              "feedback": "Erreur : suis les tests dans l'ordre, en respectant\nl'indentation.\n"
            },
            {
              "text": "`grand`",
              "correct": false,
              "feedback": "Erreur : chaque `else` est lié au `if` de même indentation.\n"
            },
            {
              "text": "Rien, aucune branche ne convenant",
              "correct": false,
              "feedback": "Erreur : tout nombre tombe dans une des trois branches.\n"
            }
          ],
          "explanation": "Un `if` dans un `if` affine le tri. L'indentation indique à quel\n`if` appartient chaque `else`."
        }
      ]
    },
    {
      "id": "q30",
      "difficulty": 3,
      "skills": [
        "comparaison",
        "frontiere"
      ],
      "title": "La note à la frontière",
      "statement": "Qu'affiche ce programme ?\n```python\nnote = 10\nif note >= 10:\n    print(\"reçu\")\nelse:\n    print(\"recalé\")\n```",
      "options": [
        {
          "text": "`reçu`",
          "correct": true,
          "feedback": "Bonne réponse : `>=` inclut la valeur 10. Avec 10, la\ncondition `note >= 10` donne `reçu`.\n"
        },
        {
          "text": "`recalé`",
          "correct": false,
          "feedback": "Erreur : regarde si 10 est supérieur ou égal à 10, le signe\n`>=` incluant l'égalité.\n"
        },
        {
          "text": "`10`",
          "correct": false,
          "feedback": "Erreur : le programme affiche un texte, pas la note.\n"
        },
        {
          "text": "Une erreur, une note ne pouvant être comparée à un entier",
          "correct": false,
          "feedback": "Erreur : entiers et flottants se comparent sans difficulté.\n"
        }
      ],
      "explanation": "La valeur frontière décide tout : `>=` l'accepte, `>` la rejette.\nChoisir le bon signe est une question de précision.",
      "variants": [
        {
          "statement": "Qu'affiche ce programme ?\n```python\nnote = 10\nif note >= 10:\n    print(\"reçu\")\nelse:\n    print(\"recalé\")\n```",
          "options": [
            {
              "text": "`reçu`",
              "correct": true,
              "feedback": "Bonne réponse : `>=` inclut la valeur 10. Avec 10, la\ncondition `note >= 10` donne `reçu`.\n"
            },
            {
              "text": "`recalé`",
              "correct": false,
              "feedback": "Erreur : regarde si 10 est supérieur ou égal à 10, le signe\n`>=` incluant l'égalité.\n"
            },
            {
              "text": "`10`",
              "correct": false,
              "feedback": "Erreur : le programme affiche un texte, pas la note.\n"
            },
            {
              "text": "Une erreur, une note ne pouvant être comparée à un entier",
              "correct": false,
              "feedback": "Erreur : entiers et flottants se comparent sans difficulté.\n"
            }
          ],
          "explanation": "La valeur frontière décide tout : `>=` l'accepte, `>` la rejette.\nChoisir le bon signe est une question de précision."
        },
        {
          "statement": "Qu'affiche ce programme ?\n```python\nnote = 9.5\nif note >= 10:\n    print(\"reçu\")\nelse:\n    print(\"recalé\")\n```",
          "options": [
            {
              "text": "`recalé`",
              "correct": true,
              "feedback": "Bonne réponse : `>=` inclut la valeur 10. Avec 9.5, la\ncondition `note >= 10` donne `recalé`.\n"
            },
            {
              "text": "`reçu`",
              "correct": false,
              "feedback": "Erreur : regarde si 9.5 est supérieur ou égal à 10, le signe\n`>=` incluant l'égalité.\n"
            },
            {
              "text": "`9.5`",
              "correct": false,
              "feedback": "Erreur : le programme affiche un texte, pas la note.\n"
            },
            {
              "text": "Une erreur, une note ne pouvant être comparée à un entier",
              "correct": false,
              "feedback": "Erreur : entiers et flottants se comparent sans difficulté.\n"
            }
          ],
          "explanation": "La valeur frontière décide tout : `>=` l'accepte, `>` la rejette.\nChoisir le bon signe est une question de précision."
        }
      ]
    }
  ]
}