NSI (première) · Chapitre 11 · Exercice de TD
Voici la fonction gagnant rendue par un groupe
Conduire un projet · Tester pour de vrai · niveau 3 (difficile)
Énoncé
Voici la fonction gagnant rendue par un groupe. Elle a été « testée : ça marche ».
def gagnant(g):
"""Renvoie 'X', 'O' ou None."""
for i in range(3):
if g[i][0] == g[i][1] == g[i][2] != ".":
return g[i][0]
for j in range(3):
if g[0][j] == g[1][j] == g[2][j] != ".":
return g[0][j]
return None
- Écrire une grille sur laquelle cette fonction se trompe, et dire ce qu'elle renvoie.
- Écrire le test qui révèle le défaut, avec son message.
- Corriger la fonction. On demande une version où les huit alignements sont écrits une seule fois.
- Pourquoi ce défaut a-t-il pu traverser une séance entière de parties d'essai ?
Corrigé
1. Les diagonales ne sont pas examinées. Sur la grille
diag = [["X", ".", "."],
[".", "X", "."],
[".", ".", "X"]]
la fonction renvoie None : elle ne trouve aucune ligne complète, aucune colonne complète, et s'arrête. Le programme continuerait donc la partie alors qu'elle est gagnée — et le joueur suivant pourrait, en théorie, gagner à son tour.
2.
def test_diagonales():
diag = [["X", ".", "."], [".", "X", "."], [".", ".", "X"]]
anti = [[".", ".", "O"], [".", "O", "."], ["O", ".", "."]]
assert gagnant(diag) == "X", "la diagonale n'est pas detectee"
assert gagnant(anti) == "O", "l'antidiagonale n'est pas detectee"
Le message compte autant que l'assertion : AssertionError sans texte oblige à relire le test pour comprendre ce qui a échoué.
3. Plutôt que d'ajouter deux if de plus — ce qui donnerait quatre morceaux de code presque identiques —, on énumère les huit alignements une fois pour toutes :
def gagnant(g):
"""Renvoie 'X', 'O' ou None si personne n'a encore gagne."""
lignes = [[(i, 0), (i, 1), (i, 2)] for i in range(3)]
colonnes = [[(0, j), (1, j), (2, j)] for j in range(3)]
diagonales = [[(0, 0), (1, 1), (2, 2)], [(0, 2), (1, 1), (2, 0)]]
for trio in lignes + colonnes + diagonales:
a, b, c = [g[i][j] for i, j in trio]
if a == b == c != ".":
return a
return None
Huit trios, un seul test. Le jour où la grille passe en , une seule liste est à changer.
Contrôle : sur les cinq grilles du jeu de tests — ligne, colonne, diagonale, antidiagonale, grille vide — la fonction rend respectivement X, O, X, O, None.
4. Parce qu'une partie d'essai ne se termine presque jamais par une diagonale. Deux joueurs qui découvrent leur propre programme jouent lentement, au milieu, se bloquent, et finissent le plus souvent sur une ligne ou une colonne — ou en match nul. Le cas manquant est précisément celui qu'on ne rencontre pas par hasard.
C'est l'argument central du chapitre : « on a joué toute la séance, ça marche » n'est pas un jeu de tests. Un jeu de tests énumère les cas délibérément, y compris — surtout — ceux qui ne se présentent pas spontanément. Ici, la seule question « de combien de façons peut-on gagner ? » aurait suffi : la réponse est huit, et le code n'en traitait que six.
100 % gratuit
Essaie le suivant avec le tuteur
- L'exercice suivant avec le tuteur, sans compte : il guide pas à pas, sans donner la réponse
- 16 autres exercices corrigés dans ce chapitre, et 20 à chercher avec le tuteur
- Le podcast et la vidéo du chapitre et la correction filmée du TD : 2 minutes sans compte
Sans compte : le cours, 2 minutes de podcast et de vidéo et un exercice avec le tuteur. Pour tout le reste : inscription gratuite en 30 secondes, sans carte bancaire.