Entrainement architectures en fonctions
Sous problème et spécifications
Exercice : max3
Ecrivez en Python la spécification d'une fonction qui prends en entrée trois entiers positifs, et retourne le plus grand des trois.
Rappel de la spécification :
def nom_de_la_fonction(argument, argument, ...):
"""une chaine qui complete
la spécification de la fonction
"""
pass ## ligne pas obligatoire ici mais mieux pour que le prog. soit valide
n'oubliez pas de fournir : la précondition, la postcondition, et eventuellement un exemple ou deux
il n'est pas demandé d'implanter la fonction, seulement de la spécifier
Exercice : somme et produit
Proposez une décomposition en sous problèmes du problème suivant :
On utilise souvent les mots "puis" et "et" comme des séparateurs de sous problèmes, sans nous en rendre compte.
Il y a de nombreuses solutions possibles, en voici une :
- demander deux nombres à l'utilisateur, puis afficher leur somme et leur produit sur des lignes différentes
- afficher la somme des deux nombres
- afficher le produit des deux nombres
- afficher une nouvelle ligne
la décomposition en sous problèmes n'est pas toujours aussi évidente.
Une autre solution peut-être : - demander deux nombres à l'utilisateur, puis afficher leur somme et leur produit sur des lignes différentes - calculer la somme de deux nombres - calculer le produit de deux nombres - Afficher deux chaines de caractères sur des lignes différentes
Exercice : somme et produit, suite
A partir de la décomposition en sous problème de l'exercice précédent, spécifiez les fonctions qui résolvent chacun des sous problèmes.
Rappel de la décomposition :
- demander deux nombres à l'utilisateur, puis afficher leur somme et leur produit sur des lignes différentes
- afficher la somme des deux nombres
- afficher le produit des deux nombres
- afficher une nouvelle ligne
Ensuite, dites quelle fonction appelera quelles autres fonctions, sans pour autant implanter les fonctions en question.
Il y a une fonction par sous problème.
def afficher_somme_produit():
"""Demande deux nombres à l'utilisateur puis affiche leur somme et leur produit sur deux lignes différentes"""
def afficher_somme(a, b):
"""a, b des nombres,
affiche la valeur de a + b
"""
pass
def afficher_produit(a, b):
"""a, b des nombres,
affiche la valeur de a * b
"""
pass
def nouvelle_ligne():
"""affiche une ligne vide"""
pass
Cette solution n'est pas la seule possible. Entre autres, on pourrait par exemple considérer que le problème d'affichage d'une nouvelle ligne est déjà résolu par print
, qui fait automatiquement un retour à la ligne à chaque affichage.
Assertions
Exercice : minimum
Ajoutez des assertions dans la fonction suivante pour vérifier que sa précondition est bien respectée.
Le corps de la fonction n'a pas d'importance dans notre cas, concentrez vous sur la chaîne de spécification.
"""a, b, c des nombres entiers strictement supérieurs à zéro
retourne la valeur du plus petit d'entre eux
"""
Remarque : appliquez la spécification MEME SI DES POINTS SEMBLENT INUTILES
On ajoute des assertions pour vérifier le type et la valeur des arguments a
, b
et c
. Les messages d'erreurs sont optionnels, ici, on a pas vraiment besoin d'en mettre parce que les assertions sont claires sur ce qu'elles testent.
On ne vérifie qu'une seule valeur par condition pour que les erreurs soient plus précises.
def minimum(a, b, c):
"""a, b, c des nombres entiers strictement supérieurs à zéro
retourne la valeur du plus petit d'entre eux
"""
assert type(a) == int
assert type(b) == int
assert type(d) == int
assert a > 0
assert b > 0
assert c > 0
if a <= b and a <= c:
return a
elif b <= c:
return b
else:
return c
Remarque : quand on a ajouté des assertions, les aspects de la spécifications qu'elles expriment peuvent généralement être retirés de la docstring :
Alternativement, on aurait pu grouper les vérifications par argument ou par thème (type ou valeur) pour garder le bloc des assertions plus compact, mais cela rends les erreurs moins lisibles, vu qu'on ne sait pas quelle vérification d'une même assertion a levé l'erreur
Exercice : reconstituer la spec
A partir des assertions dans la fonction suivante, reconstituez les parties manquantes de la docstring, marquées par des ... :
Il faut simplement lire les assertions et les retranscrire en français dans la docstring.
Lire un rapport de tests
Exercice : rapport de tests
Observez le rapport de tests ci-dessous et répondez aux questions :
Le but de cet exercice est de comprendre le rapport de test sans se préocuper du code qu'il teste.
Quelle fonction n'a pas passé les tests (= un de ses tests a échoué) ?
La ligne 3 comporte des informations sur le test.
linenums=3
FAIL: test_soir (__main__.Test_bonjour)
__main__.Test_bonjour
__main__.Test_nom_de_la_fonction
Cette convention est propre à ce cours, nous la conserveront jusqu'à ce que nous ayons vu les tests plus en détail.
Quel est le nom du cas qui a échoué ?
La ligne 3 comporte des informations sur le test.
linenums=3
FAIL: test_soir (__main__.Test_bonjour)
test_soir
nous indique le cas qui a échoué : ici, soir.
Le cas d'un test ne sera pas toujours explicite, mais il peut résumer rapidement ce qui a été testé dans un test et donc permettre une compréhension plus rapide du problème.
Quel appel a effectivement été effectué par le test ? Quelle valeur l'appel a-t-il renvoyé ? Quelle valeur était attendue ?
La ligne 5 nous renseigne sur ce que le test a essayé de faire et qui a échoué :
L'appel
a été testé. On voulait qu'il renvoie la valeur "bonsoir"
, mais il a retourné bonne nuit
.
TP : Turtle
La plupart des exercices de ce TP utilisent le module turtle
. Le principe de ce module est de déplacer une tortue dans une fenêtre.
A chaque fois que la tortue se déplace, elle va tracer une ligne le long de son chemin. On peut donc la piloter et tracer des formes relativement
complexes.
La tortue se déplace dans un repère en 2D, qui utilise donc deux coordonnées, x (axe horizontal) et y (axe vertical). Elle est toujours positionnée en (0,0) au démarrage du programme.
Il existe deux manières de diriger la tortue :
- En lui indiquant, un déplacement relatif, sous forme d'une orientation et une direction à suivre à partir de sa position: tourne de 70 degrés sur la gauche et avance de 100.
- En lui indiquand une position absolue que la tortue doit atteindre. va en (100,100). Elle s'y rends alors en ligne droite.
On peut bien entendu combiner les deux modes de pilotage. Déplacer la tortue en un point précis est beaucoup plus facile avec une position absolue. Créer des polygones réguliers comme des pentagones est en général beaucoup plus simple avec une orientation et une direction.
Voici un exemple de pilotage de tortue :
from turtle import setpos
setpos(200, 0) ## la tortue va en (200,0) setpos(200, 200) setpos(0, 200) setpos(0, 0)
Dans les deux cas, il est difficile de voir ce que fait le code en un coup d'oeil. On va donc utiliser des fonctions pour simplifier et expliciter le code.
Partie 1 : Rectangle relatif
Implémentez la fonction suivante :
Le code de la fonction sera très similaire à l'exemple de pilotage relatif proposé plus haut.
N'oubliez pas de réorienter une dernière fois la tortue.
N'oubliez pas, si ce n'est pas déjà fait, d'importer le module et les fonctions dans votre code.
Appelez votre fonction pour la tester.
La tortue est orientée vers la droite de l'écran, elle va donc se déplacer dans la largeur de l'écran, puis tourner de 90 degrés à sa gauche pour se déplacer vers le haut, et donc la hauteur de l'écran.
from turtle import forward, left
def rectangle(l, h):
"""l, h des entiers.
Utilise le pilotage relatif (orientation et direction) pour tracer un rectangle de largueur l et de hauteur h.
A la fin du tracé, la tortue est de retour a sa position et son orientation d'origine.
"""
forward(l) ## Avancer de l
left(90)
forward(h) ## avancer de h
left(90)
forward(l)
left(90)
forward(h)
left(90) #on remet la tortue en orientation initiale !
if __name__ == "__main__":
rectangle(300, 120)
rectangle(130, 200)
On aimerait bien dessiner des rectangles un peu partout sur la surface, et pas seulement avec l'angle inférieur gauche sur (0,0).
Pour ça, on peut déplacer la tortue en utilisant setpos
. Importez setpos
de turtle
et modifiez votre main pour ajouter un appel à setpos
entre les deux rectangles :
from turtle import forward, left, setpos
## ... Ici la fonction Rectangle
if __name__ == "__main__":
rectangle(300, 120)
setpos(-100, -300)
rectangle(130, 200)
C'est pas mal, mais il y a un soucis. Quand on fait setpos
, la tortue continue de tracer. On voudrait :
- Dire à la tortue d'arrêter de tracer. On utilisera la fonction
penup
("lever le stylo"), qui ne prends aucun argument. - Deplacer la tortue
- Dire à la tortue de reprendre le tracé. On utilisera la fonction
pendown
("baisser le stylo"), qui ne prends aucun argument.
Partie 2 : Déplacer la tortue
Implémentez la fonction suivante, et ajoutez là à votre code :
def deplacer(x, y):
"""x, y des entiers
deplace la tortue aux coordonnées (x,y) sans tracer de trait, et sans
changer son oritentation
"""
pass
N'oubliez pas d'importer les fonctions nécessaires !
Dans le main, appelez la fonction deplacer
au lieu de la fonction setpos
.
Importez les fonctions penup
et pendown
.
Vous n'avez simplement que 3 appels de fonction à faire, ils sont plus ou moins décrits dans les explications juste avant l'exercice.
from turtle import forward, left, setpos, penup, pendown
##... ICI la fonction Rectangle
def deplacer(x, y):
"""x, y des entiers
deplace la tortue aux coordonnées (x,y) sans tracer de trait, et sans
changer son oritentation
"""
penup()
setpos(x,y)
pendown()
if __name__ == "__main__":
rectangle(300, 120)
deplacer(-100, -300)
rectangle(130, 200)
Code complet
from turtle import forward, left, setpos, penup, pendown
def rectangle(l, h):
"""l, h des entiers.
Utilise le pilotage relatif (orientation et direction) pour tracer un rectangle de largueur l et de hauteur h.
A la fin du tracé, la tortue est de retour a sa position et son orientation d'origine.
"""
forward(l) ## Avancer de l
left(90)
forward(h) ## avancer de h
left(90)
forward(l)
left(90)
forward(h)
left(90) #on remet la tortue en orientation initiale !
def deplacer(x, y):
"""x, y des entiers
deplace la tortue aux coordonnées (x,y) sans tracer de trait, et sans
changer son oritentation
"""
penup()
setpos(x,y)
pendown()
if __name__ == "__main__":
rectangle(300, 120)
deplacer(-100, -300)
rectangle(130, 200)
On veut pouvoir dessiner des rectangles alignés sur les axes (leurs bords sont parallèles aux axes) de la manière la plus pratique possible pour un humain (c'est à dire qu'on veut faire peu de calculs).
Pour ça, on va tracer des rectangles à partir d'un début et d'une fin. Le début sera le point avec les coordonnées x et y les plus petites, et la fin sera le point avec les coordonnées x et y les plus grandes.
On a pas besoin de plus de points que ça, on peut déduire les deux autres coordonnées.
Partie 3 : un peu de dessin
Soit un rectangle \(ABCD\), dans un repère orthonormé, tel que \((AB)\) est parallèle à l'axe des abscisses \((x)\).
On pose \(A = (0,0)\) et \(C = (100,50)\). Que valent \(B\) et \(D\) ?
N'hésitez pas à tracer \(ABCD\) sur une feuille (à carreaux ça peut aider) ! On fait est en train de faire du dessin, pas de la géométrie !
\(B = (100, 0)\) et \(D = (0, 50)\)
Explications.
On sait que \((AB)\) est parallèle à \((x)\), donc \(B\) a la même ordonnée que \(A\), soit \(0\). Aussi, parce que le rectangle n'a que des angles droits et que le repère est orthonormé, \((BC)\) est parallèle à l'axe des abscisses \((y)\), et a donc \(B\) à la même abscisse que \(C\), soit \(100\).
Même raisonnement pour \(D\).
Une petite vue graphique peut aider à comprendre:
On pose \(A = (50,50)\) et \(C = (200,75)\). Que valent \(AB\) et \(CD\), respectivement les longueurs des segments \([AB]\) et \([CD]\) ? Et \(BC\) et \(AD\) ?
Rappel, ce n'est pas de la géométrie mais du dessin ! N'hésitez pas à dessiner et à mesurer !
Pour ceux qui veulent absolument calculer, la formule de distance entre deux points \((x_1, y_1)\) et \((x_2, y_2)\) est
Et on en a pas besoin ici, une simple soustraction suffit !
\(AB = CD = 150\) et \(BC = AD = 25\) On sait que \(A\) et \(B\) ont la même ordonnée, donc seule leur abscisse compte. Alors on a \(200 - 50 = 150\). Comme \(ABCD\) est un rectangle, \(AB = CD\).
Même raisonnement pour \(BC\) et \(AD\).
On fait beaucoup trop de calcul pour une activité de dessin ! Pourquoi ne pas implémenter une fonction pour ne pas avoir à refaire ces calculs à chaque fois ?
Partie 4 : Rectangle Aligné aux Axes
Implémentez la fonction suivante. Ajoutez là bien sûr au reste du code. N'oubliez pas de renseigner les assertions qui correspondent à la spécification !
Servez-vous des fonctions rectangle
et deplacer
que nous avons fait précédemment, ainsi que
de ce que nous avons vu à l'exercice précédent !
Deplacez la tortue sur le point d'origine du rectangle, puis calculez la longueur et largeur du rectangle. Finalement, tracez le rectangle.
def rectangle_aa(xd, yd, xf, yf):
"""xd, yd, xf, yf des entiers. xd <= xf, yd <= yf
Dessine un rectangle ayant pour début (xd, yd) et pour fin (xf, yf)
"""
deplacer(xd, yd)
rectangle(xf - xd, yf - yd)
Code complet
from turtle import forward, left, setpos, penup, pendown
def rectangle(l, h):
"""l, h des entiers.
Utilise le pilotage relatif (orientation et direction) pour tracer un rectangle de largueur l et de hauteur h.
A la fin du tracé, la tortue est de retour a sa position et son orientation d'origine.
"""
forward(l) ## Avancer de l
left(90)
forward(h) ## avancer de h
left(90)
forward(l)
left(90)
forward(h)
left(90) #on remet la tortue en orientation initiale !
def deplacer(x, y):
"""x, y des entiers
deplace la tortue aux coordonnées (x,y) sans tracer de trait, et sans
changer son oritentation
"""
penup()
setpos(x,y)
pendown()
def rectangle_aa(xd, yd, xf, yf):
"""xd, yd, xf, yf des entiers. xd <= xf, yd <= yf
Dessine un rectangle ayant pour début (xd, yd) et pour fin (xf, yf)
"""
deplacer(xd, yd)
rectangle(xf - xd, yf - yd)
if __name__ == "__main__":
rectangle_aa(50, 50, 200, 200)
Finalement, pour dessiner un rectangle coloré, on va s'y prendre comme ça :
- On appelle la fonction
color
, qui prends un paramètre, et qui définit à la fois la couleur de trait et la couleur de remplissage. La couleur est une chaîne de caractère qui représente la couleur en anglais, par exemple"red"
pour rouge. Alternativement, on peut l'appeler avec trois paramètres entiers de 0 à 255 qui définissent les composantes RVB de la couleur. - On appelle la fonction
begin_fill
qui ne prends aucun paramètre, pour dire qu'on va tracer une forme qu'il faudra remplir. - On trace le rectangle
- On appelle la fonction
end_fill
qui ne prends aucun paramètre, pour dire qu'on a fini de tracer la forme à remplir.
from turtle import forward, left, setpos, penup, pendown, color, begin_fill, end_fill
## ... reste de notre code ici
if __name__ == "__main__":
color("red")
begin_fill()
rectangle_aa(50, 50, 200, 200)
end_fill()
Partie 5 : Rectangle coloré
Implementer la fonction suivante et ajoutez-la à votre code. N'oubliez pas d'importer les fonctions nécessaires.
C'est exactement le même principe que l'exemple juste au dessus.
def remplir_rect_aa(xd, yd, xf, yf, couleur):
"""xd, yd, xf, yf des entiers. xd <= xf, yd <= yf, couleur une chaine
Remplit un rectangle ayant pour début (xd, yd) et pour fin (xf, yf)
avec la couleur couleur
"""
color(couleur)
begin_fill()
rectangle_aa(xd, yd, xf, yf)
end_fill()
Code complet
from turtle import forward, left, setpos, penup, pendown, color, begin_fill, end_fill
def rectangle(l, h):
"""l, h des entiers.
Utilise le pilotage relatif (orientation et direction) pour tracer un rectangle de largueur l et de hauteur h.
A la fin du tracé, la tortue est de retour a sa position et son orientation d'origine.
"""
forward(l) ## Avancer de l
left(90)
forward(h) ## avancer de h
left(90)
forward(l)
left(90)
forward(h)
left(90) #on remet la tortue en orientation initiale !
def deplacer(x, y):
"""x, y des entiers
deplace la tortue aux coordonnées (x,y) sans tracer de trait, et sans
changer son oritentation
"""
penup()
setpos(x,y)
pendown()
def rectangle_aa(xd, yd, xf, yf):
"""xd, yd, xf, yf des entiers. xd <= xf, yd <= yf
Dessine un rectangle ayant pour début (xd, yd) et pour fin (xf, yf)
"""
deplacer(xd, yd)
rectangle(xf - xd, yf - yd)
def remplir_rect_aa(xd, yd, xf, yf, couleur):
"""xd, yd, xf, yf des entiers. xd <= xf, yd <= yf, couleur une chaine
Remplit un rectangle ayant pour début (xd, yd) et pour fin (xf, yf)
avec la couleur couleur
"""
color(couleur)
begin_fill()
rectangle_aa(xd, yd, xf, yf)
end_fill()
if __name__ == "__main__":
remplir_rect_aa(50, 100, 200, 300, "red")
Partie 6 : Fonction mystère
Observez la fonction suivante, et essayez de prédire ce qu'elle dessine sans l'executer:
def dessiner(x, y, couleur):
remplir_rect_aa(x + 0, y + 0, x + 250, y + 400, "black")
remplir_rect_aa(x + 240, y + 25, x + 330, y + 300, "black")
remplir_rect_aa(x + 10, y + 10, x + 240, y + 390, couleur)
remplir_rect_aa(x + 0, y + 0, x + 100, y - 100, "black")
remplir_rect_aa(x + 150, y + 0, x + 250, y - 100, "black")
remplir_rect_aa(x + 10, y + 10, x + 90, y - 90, couleur)
remplir_rect_aa(x + 160, y + 10, x + 240, y - 90, couleur)
remplir_rect_aa(x + 250, y + 35, x + 320, y + 290, couleur)
remplir_rect_aa(x - 15, y + 225, x + 175, y + 325, "black")
remplir_rect_aa(x - 5, y + 235, x + 165, y + 315, "lightgrey")
Remarque : n'y passez pas trop de temps et n'oubliez pas que l'aide est là !
Peut-être qu'avec un nom plus explicite ce sera plus facile. Après tout, c'est un des intérêts des fonctions...
def dessiner_crewmate(x, y, couleur):
remplir_rect_aa(x + 0, y + 0, x + 250, y + 400, "black")
remplir_rect_aa(x + 240, y + 25, x + 330, y + 300, "black")
remplir_rect_aa(x + 10, y + 10, x + 240, y + 390, couleur)
remplir_rect_aa(x + 0, y + 0, x + 100, y - 100, "black")
remplir_rect_aa(x + 150, y + 0, x + 250, y - 100, "black")
remplir_rect_aa(x + 10, y + 10, x + 90, y - 90, couleur)
remplir_rect_aa(x + 160, y + 10, x + 240, y - 90, couleur)
remplir_rect_aa(x + 250, y + 35, x + 320, y + 290, couleur)
remplir_rect_aa(x - 15, y + 225, x + 175, y + 325, "black")
remplir_rect_aa(x - 5, y + 235, x + 165, y + 315, "lightgrey")
Si ce n'est pas déjà fait, essayez d'appeler la fonction avec une position et un paramètre de couleur, par exemple de la manière suivante :
Cette fonction trace un crewmate, personnage d'un jeu bien connu de traîtrise spatiale1.
Code complet si besoin
from turtle import forward, left, setpos, penup, pendown, color, begin_fill, end_fill
def rectangle(l, h):
"""l, h des entiers.
Utilise le pilotage relatif (orientation et direction) pour tracer un rectangle de largueur l et de hauteur h.
A la fin du tracé, la tortue est de retour a sa position et son orientation d'origine.
"""
forward(l) ## Avancer de l
left(90)
forward(h) ## avancer de h
left(90)
forward(l)
left(90)
forward(h)
left(90) #on remet la tortue en orientation initiale !
def deplacer(x, y):
"""x, y des entiers
deplace la tortue aux coordonnées (x,y) sans tracer de trait, et sans
changer son oritentation
"""
penup()
setpos(x,y)
pendown()
def rectangle_aa(xd, yd, xf, yf):
"""xd, yd, xf, yf des entiers. xd <= xf, yd <= yf
Dessine un rectangle ayant pour début (xd, yd) et pour fin (xf, yf)
"""
deplacer(xd, yd)
rectangle(xf - xd, yf - yd)
def remplir_rect_aa(xd, yd, xf, yf, couleur):
"""xd, yd, xf, yf des entiers. xd <= xf, yd <= yf, couleur une chaine
Remplit un rectangle ayant pour début (xd, yd) et pour fin (xf, yf)
avec la couleur couleur
"""
color(couleur)
begin_fill()
rectangle_aa(xd, yd, xf, yf)
end_fill()
def dessiner_crewmate(x, y, couleur):
remplir_rect_aa(x + 0, y + 0, x + 250, y + 400, "black")
remplir_rect_aa(x + 240, y + 25, x + 330, y + 300, "black")
remplir_rect_aa(x + 10, y + 10, x + 240, y + 390, couleur)
remplir_rect_aa(x + 0, y + 0, x + 100, y - 100, "black")
remplir_rect_aa(x + 150, y + 0, x + 250, y - 100, "black")
remplir_rect_aa(x + 10, y + 10, x + 90, y - 90, couleur)
remplir_rect_aa(x + 160, y + 10, x + 240, y - 90, couleur)
remplir_rect_aa(x + 250, y + 35, x + 320, y + 290, couleur)
remplir_rect_aa(x - 15, y + 225, x + 175, y + 325, "black")
remplir_rect_aa(x - 5, y + 235, x + 165, y + 315, "lightgrey")
if __name__ == "__main__":
dessiner_crewmate(0,0,"green")
Avec uniquement des fonctions relativement simples, on a donc réussi à créer un programme qui dessine des formes compliquée !
Partie 7 : réflexions
Le corps de la fonction que nous avons vue dans l'exercice précédent est relativement compliqué à lire.
Est-ce un problème si l'on veut utiliser cette fonction pour dessiner plusieurs crewmates ?
L'abstraction y est peut-être pour quelque chose ...
La fonction dessiner_crewmate
agit comme une abstraction du code utilisé pour dessiner un crewmate, on peut donc facilement l'utiliser même sans comprendre son code !
Quelque chose manque dans cette fonction pour qu'elle exprime bien le fait qu'elle dessine un crewmate. Proposez et justifiez une amélioration de la fonction, sans forcément la mettre en oeuvre et sans toucher à son corps, pour la rendre plus simple à utiliser.
Ca a peut-être à voir avec la spécification ...
Le nom dessiner_crewmate
est beaucoup trop flou : un crewmate peut être beaucoup de choses, d'autant que le lecteur n'aura pas forcément la référence ...
- On pourrait préciser la fonction avec une docstring expliquant en détail ce qu'elle dessin. Une telle docstring pourrait faire explicitement référence à Among Us. Il faudrait alors que le lecteur aille voir la docstring de la fonction pour comprendre le code l'utilisant.
- On pourraît sinon (ou en plus) modifier le nom de la fonction, par exemple en `dessiner_crewmate_among_us". Le lecteur n'aurait alors plus à aller lire la docstring, mais le nom allongé de la fonction pourrait gêner la lecture du code utilisant la fonction.
En pratique ces deux solutions sont valides, et dépendent beaucoup du contexte, et des conventions de présentation du code choisies.
Partie 8 : réflexion difficile
Le code de la fonction dessiner_crewmate
est diffile à lire en partie parce que chaque élément du corps est dessiné deux fois :
- une fois en noir pour faire des contours de type *dessin animé*.
- une fois en couleur, un peu moins large, pour dessiner l'élément en lui-même.
Imaginons que l'on veuille alléger le code de la fonction dessiner_crewmate
, pour le rendre un peu plus simple à lire. Que pourrait-on faire pour simplifier le code ?
Il n'est pas attendu une réponse détaillée, mais une plutôt une idée.
Essayez de voir si vous pouvez "découper" le processus de dessin d'un crewmate en plusieurs étapes, des sous-problèmes, que l'on pourrait donc écrire dans des fonctions séparées.
Remarque : il y a plusieurs découpages possibles.
On a trois possibilités de découpages que l'on peut combiner entre elles :
- Dessiner d'abord les contours, puis dessiner les éléments. On aurait alors deux fonctions comme
dessiner_contours_crewmate
etdessiner_couleur_crewmate
. - Dessiner chaque élément du crewmate l'un après l'autre : jambes, corps, visière, sac à dos. On aurait alors
dessiner_jambe_crewmate
,dessiner_corps_crewmate
,dessiner_visiere_crewmate
,dessiner_sac_crewmate
- Dessiner chaque rectangle avec ses contours. On aurait alors, au lieu de
remplir_rect_aa
, une fonctionremplir_rect_aa_contours
.
TP : Jeu des allumettes
Pour illustrer le chapitre, implémentons un jeu des allumettes avec une intelligence artificielle basique. Le jeu des allumettes consiste en un jeu à deux joueurs. On pose n
allumettes côte à côte sur une table. Les joueurs tirent entre 1 et 3 allumettes à tour de rôle. Le joueur qui tire la dernière allumette perds la partie2
On va dans un premier temps faire en sorte que le PC tire toujours une et une seule allumette. Une partie ressemblera donc à ça :
Choisissez un nombre d'allumettes pour cette partie : 10
|||||||||| (10)
Combien d'allumettes (1-3)? 3
||||||| (7)
PC : 1
|||||| (6)
Combien d'allumettes (1-3)? 3
||| (3)
PC : 1
|| (2)
Combien d'allumettes (1-3)? 1
| (1)
PC : 1
### victoire du Joueur ###
Partie 1 : sous problèmes
Essayez d'identifier les principaux problèmes (et eventuellement leurs sous problèmes) que nous devons résoudre pour implanter ce jeu.
Essayez de dessiner cette structure de problèmes sur une feuille ou dans un logiciel de dessin, comme drawio, inkscape, ...
Ne passez pas trop de temps sur cette partie, identifier les problèmes dans un programme peut-être difficile. Celà viendra avec la pratique, et c'est en plus du programme de terminale.
On peut aussi voir les problèmes comme des roles ou des responsabilité que doivent remplir les différentes fonctions et autres composants du logiciel :
- Affichage
- Calculs
- ...
On peut identifier quelques problèmes et sous problèmes :
- Conduire la partie
- Formatter le plateau du jeu
- Dessiner des allumettes
- Gérer la prise de décision du PC
- Demander son action à l'utilisateur
- Afficher la victoire
- Demander le nombre d'allumettes pour la partie
- Alterner les tours des joueurs
- Formatter le plateau du jeu
Cette solution n'est pas absolue, de nombreuses autres configurations sont valides. Par exemple, on pourrait considérer que détecter la victoire constitue un sous problème de conduire la partie qui serait digne d'être mis à part.
Si vous êtes confiants, vous pouvez utiliser vos propres problèmes et sous problèmes. A noter que dans ce cas là, vous ne bénéficierez pas des tests automatiques, et vous ne pourrez que vous inspirer des solutions données pour chaque parties.
On va maintenant pour chaque problème implanter une fonction qui le résouds. Dans cette partie, les specifications des fonctions vous sont fournies dans un fichier jeu_des_allumettes.py
. Vous pouvez le télécharger en cliquant sur ce lien. Alternativement, si le téléchargement n'est pas supporté par votre navigateur ou bloqué par votre établissement, pouvez le copier à partir du dépliant ci-dessous :
Code de base du TP
lancer_tests_automatiques = False ##Mettez à False pour ne pas lancer les tests
lancer_tests_interface = False ##Mettez à True pour lancer les tests semi-automatiques
afficher_traces = False ##Mettez a True pour afficher la trace complète des erreurs dans les tests
def allumettes(n):
"""
n un entier > 0
retourne une chaîne composée de n barres |
allumettes(5) vaut '|||||'
"""
pass
def plateau(n):
"""
n un entier > 0
retourne une chaîne composée de n barres | , suivi de n entre ()
plateau(5) vaut `||||| (5)`
"""
pass
def coup_basique_pc(a):
"""
a un entier > 0, représente le nombre d'allumettes
retourne toujours 1
coup_basique_pc(10000) vaut 1
"""
pass
def autre_joueur(joueur):
"""
joueur une chaine qui contient de nom "Joueur" ou "PC".
retourne l'autre chaine
autre_joueur("Joueur") vaut "PC"
"""
pass
def afficher_victoire(joueur):
"""
joueur une chaine qui contient le nom ("Joueur" ou "PC") du vainqueur.
Affiche une chaîne qui annonce la victoire de ce joueur !
"""
pass
def demander_coup_joueur():
"""
Demande au joueur combien d'allumettes il veut retirer (entier de 1 a 3)
retourne la valeur saisie par le joueur (type int).
"""
pass
def derouler_tour(joueur, al):
"""
joueur une chaine qui contient le nom ("Joueur" ou "PC") du joueur en cours.
al un entier, le nombre d'allumettes au debut du tour
Affiche le nombre d'allumettes, s'enquiert du coup du joueur en cours,
puis retourne le nouveau nombre d'allumettes
"""
pass
############################################
############# PARTIE TESTS #############
############################################
import unittest
if not afficher_traces:
__unittest = True
def checktype(expr, res, exp):
assert type(res) == exp, expr + " doit retourner une valeur de type " + exp.__name__ + ", mais a retourné une valeur de type " + type(res).__name__
def checkval_equal(expr, res, exp):
str_exp = "'" +exp+ "'" if type(exp) == str else str(exp)
str_res = "'" +res+ "'" if type(res) == str else str(res)
assert res == exp, expr + " doit retourner " + str_exp + ", mais a retourné " + str_res
class Test_allumettes(unittest.TestCase):
def test_1(self):
res = allumettes(1)
checktype("allumettes(1)", res, str)
checkval_equal("allumettes(1)", res, "|")
def test_10(self):
res = allumettes(10)
checktype("allumettes(10)", res, str)
checkval_equal("allumettes(10)", res, "||||||||||")
class Test_plateau(unittest.TestCase):
def test_1(self):
res = plateau(1)
checktype("plateau(1)", res, str)
checkval_equal("plateau(1)", res, "| (1)")
def test_10(self):
res = plateau(10)
checktype("plateau(10)", res, str)
checkval_equal("plateau(10)", res, "|||||||||| (10)")
class Test_coup_basique_pc(unittest.TestCase):
def test_1(self):
res = coup_basique_pc(1)
checktype("coup_basique_pc(1)", res, int)
checkval_equal("coup_basique_pc(1)", res, 1)
def test_10(self):
res = coup_basique_pc(10)
checktype("coup_basique_pc(10)", res, int)
checkval_equal("coup_basique_pc(10)", res, 1)
def test_10934(self):
res = coup_basique_pc(10934)
checktype("coup_basique_pc(10934)", res, int)
checkval_equal("coup_basique_pc(10934)", res, 1)
class Test_autre_joueur(unittest.TestCase):
def test_Joueur(self):
res = autre_joueur("Joueur")
checktype("autre_joueur('Joueur')", res, str)
checkval_equal("autre_joueur('Joueur')", res, "PC")
def test_PC(self):
res = autre_joueur("PC")
checktype("autre_joueur('PC')", res, str)
checkval_equal("autre_joueur('PC')", res, "Joueur")
if __name__ == '__main__' and lancer_tests_automatiques:
s = unittest.TestSuite()
s.addTests(unittest.TestLoader().loadTestsFromTestCase(Test_allumettes))
s.addTests(unittest.TestLoader().loadTestsFromTestCase(Test_plateau))
s.addTests(unittest.TestLoader().loadTestsFromTestCase(Test_coup_basique_pc))
s.addTests(unittest.TestLoader().loadTestsFromTestCase(Test_autre_joueur))
unittest.TextTestRunner().run(s)
def check_interface_afficher_victoire():
print("\nTEST INTERFACE : afficher_victoire")
afficher_victoire("PC")
res = input("TEST INTERFACE : la victoire du PC est-elle correctement affichée (oui/non) ? ")
if(res != "oui"):
assert False, "ECHEC"
def check_interface_demander_coup_joueur():
print("\nTEST INTERFACE : demander_coup_joueur")
print("TEST INTERFACE : A la prochaine question, répondez 3 !")
res = demander_coup_joueur()
checktype("demander_coup_joueur()", res, int)
checkval_equal("demander_coup_joueur()", res, 3)
res = input("TEST INTERFACE : la question affichait que la réponse était entre 1 et 3 (oui/non) ? ")
if(res != "oui"):
assert False, "ECHEC"
def check_interface_derouler_tour_PC():
print("\nTEST INTERFACE : derouler_tour('PC')")
r = derouler_tour("PC", 4)
checktype("derouler_tour('PC', 4)", r, int)
checkval_equal("derouler_tour('PC', 4)", r, 3)
res = input("TEST INTERFACE : C'est le PC qui a joué (oui/non) ? ")
if(res != "oui"):
assert False, "ECHEC"
res = input("TEST INTERFACE : Il y avait 4 allumettes à la base (oui/non) ? ")
if(res != "oui"):
assert False, "ECHEC"
res = input("TEST INTERFACE : Il a retiré 1 allumette, celà a été affiché (oui/non) ? ")
if(res != "oui"):
assert False, "ECHEC"
def check_interface_derouler_tour_Joueur():
print("\nTEST INTERFACE : derouler_tour('Joueur')")
print("TEST INTERFACE : A la prochaine question, répondez 2 !")
r = derouler_tour("Joueur", 5)
checktype("derouler_tour('Joueur', 5)", r, int)
checkval_equal("derouler_tour('Joueur', 5)", r, 3)
res = input("TEST INTERFACE : C'est le Joueur qui a joué (oui/non) ? ")
if(res != "oui"):
assert False, "ECHEC"
res = input("TEST INTERFACE : Il y avait 5 allumettes à la base (oui/non) ? ")
if(res != "oui"):
assert False, "ECHEC"
if __name__ == '__main__' and lancer_tests_interface:
print("LES TESTS D'INTERFACE COMMENCENT")
check_interface_afficher_victoire()
check_interface_demander_coup_joueur()
check_interface_derouler_tour_PC()
check_interface_derouler_tour_Joueur()
print("\nSUCCES")
Partie 2 : fonctions pures
En premier lieu, on va implanter les fonctions pures, qui peuvent être testées automatiquement.
Implantez les fonctions `suivantes à partir de leurs spécifications :
allumettes
(1 ligne)plateau
(1 ligne)- coup_basique_pc (1 ligne)
- autre joueur (4 lignes)
Votre code peut être différent de ces solutions. L'important est que les test automatiquent passent.
def allumettes(n):
"""
n un entier > 0
retourne une chaîne composée de n barres |
allumettes(5) vaut '|||||'
"""
return "|" * n
def plateau(n):
"""
n un entier > 0
retourne une chaîne composée de n barres | , suivi de n entre ()
plateau(5) vaut `||||| (5)`
"""
return allumettes(n) + " (" + str(n) + ")"
def coup_basique_pc(a):
"""
a un entier > 0, représente le nombre d'allumettes
retourne toujours 1
coup_basique_pc(10000) vaut 1
"""
return 1
def autre_joueur(joueur):
"""
joueur une chaine qui contient de nom "Joueur" ou "PC".
retourne l'autre chaine
autre_joueur("Joueur") vaut "PC"
"""
if joueur == "PC":
return "Joueur"
else :
return "PC"
Les fonctions d'interface, qui demandent des entrées et sorties à l'utilisateur sont plus difficiles à tester automatiquement. On se contentera donc de tests semi-automatiques, dans lesquels le programme vous guidera dans les vérifications à effectuer. Vous pouvez activer ces tests en mettant lancer_tests_interface
à True
.
Une bonne pratique en programmation est d'essayer d'"isoler" les entrées et sorties du reste du code, et de privilégier les fonctions pures. C'est pour ça que allumettes
et plateau
retournent une valeur au lieu d'afficher directement.
Partie 3 : fonctions d'interface
Implantez les fonction d'interfaces suivantes en considérant que l'utilisateur ne fera pas d'erreur de saisie. Respectez l'ordre d'implémentation, les tests bloquent à la première fonction qui ne marche pas !
demander_coup_joueur
(1 ligne)afficher_victoire
(2 lignes)derouler_tour
(10 lignes)
On considèrera que l'utilisateur ne fait pas d'erreur de saisie.
Les deux premières fonctions sont normalement simples à implémenter.
La troisième vous demandera
- d'utiliser une structure if else
pour choisir si le joueur ou le PC joue.
- d'appeler la fonction qui corresponds
- demander_coup_joueur
pour le joueur
- coup_basique_pc
pour le PC
Votre code sera probablement différent. Tant que les tests d'interface, effectués avec grande attention, passent, c'est normalement bon.
def afficher_victoire(joueur):
"""
joueur une chaine qui contient le nom ("Joueur" ou "PC") du vainqueur.
Affiche une chaîne qui annonce la victoire de ce joueur !
"""
print("\n### Victoire du " + joueur + " ###")
def demander_coup_joueur():
"""
Demande au joueur combien d'allumettes il veut retirer (entier de 1 a 3)
retourne la valeur saisie par le joueur (type int).
"""
coup = input("Combien d'allumettes (1-3)? ")
return int(coup)
def derouler_tour(joueur, al):
"""
joueur une chaine qui contient le nom ("Joueur" ou "PC") du joueur en cours.
al une chaine qui contient le nombre d'allumettes au debut du tour
Affiche le nombre d'allumettes, s'enquiert du coup du joueur en cours,
puis retourne le nouveau nombre d'allumettes
"""
print() #les prints vides sont là pour sauter une lignes de formattage
print(plateau(al))
if joueur == "Joueur":
print()
coup = demander_coup_joueur()
else:
coup = coup_basique_pc(al)
print()
print("PC : " + str(coup))
return al - coup
Partie 4 : test système
Jusqu'à maintenant, nos tests ont testé une seule fonction à la fois. Ce sont des tests unitaires. On est donc presque assurés que les fonctions marchent bien.
Mais ce n'est pas suffisant, il nous faut aussi tester notre programme tout entier. Pour ça, on va faire un test à la main, mais pour être rigoureux, on va écrire le scénario du test quelque part, comme ça on pourra le suivre à la lettre quand on testera.
Proposez un tel scénario, il doit comporter :
- chaque action que le testeur doit faire à chaque étape de l'execution du programme qui demande une action (par exemple, la valeur du nombre à entrer)
- A chaque étape, le comportement attendu du programme, et les points importants que le testeur doit véfifier.
Ecrivez votre scénario lisiblement sur une feuille ou dans un fichier txt ou markdown.
Remarque : on suppose que l'utilisateur ne peut pas se tromper en faisant une saisie, sinon celà pourrait énormément compliquer le scénario.
Vous pouvez partir de la trace d'execution qui a été présentée juste avant la partie 1, et rajouter des éléments entre [[]]
pour la préciser.
Remarque : il y a peut-être des points supplémentaires sur lequel il faut faire attention.
[[Scénario de test du jeu des allumettes]]
[[A la fin de ce scénario, le programme doit terminer sans erreur.]]
[[Action testeur : entrer 10]]
Choisissez un nombre d'allumettes pour cette partie : 10
|||||||||| (10)
[[Vérifier qu'il y a bien 10 allumettes]]
[[Action testeur : entrer 3]]
Combien d'allumettes (1-3)? 3
[[Vérifier que le nombre d'allumettes autorisées est bien affiché]]
||||||| (7)
PC : 1
[[Vérifier que le PC a bien tiré une allumette]]
|||||| (6)
[[Action testeur : entrer 3]]
Combien d'allumettes (1-3)? 3
||| (3)
PC : 1
|| (2)
[[Action testeur : entrer 1]]
Combien d'allumettes (1-3)? 1
| (1)
PC : 1
### victoire du Joueur ###
[[Vérifier que c'est bien le Joueur et non le PC qui est victorieux]]
Partie 5 : fonction main
Implantez la fonction main
et un bloc if
pour la lancer, comme vu précédemment dans le cours.
La fonction main
doit demander un nombre d'allumettes initial au joueur, désigner le joueur comme celui qui commence, puis enchainer les tours tant qu'il reste des allumettes, et finalement afficher le joueur victorieux.
Utilisez votre scénario de test pour tester votre programme.
Il y a probablement une boucle while
quelque part.
Utilisez les fonctions que l'on a déjà implantées !
N'hésitez pas à mettre des commentaires.
def main():
"""
demande un nombre d'allumettes au joueur, puis lance la partie avec ce nombre d'allumettes,
jusqu'à qu'un joueur gagne. Ensuite, affiche la victoire.
"""
al = int(input("Choisissez un nombre d'allumettes pour cette partie : "))
joueur = "Joueur"
while al > 0:
al = derouler_tour(joueur, al)
joueur = autre_joueur(joueur)
afficher_victoire(joueur)
if __name__=="__main__":
main()
La solution complète peut être téléchargée en cliquant sur ce lien, ou alternativement par le biais du dépliant :
Solution complète du TP
lancer_tests_automatiques = False ##Mettez à False pour ne pas lancer les tests
lancer_tests_interface = False ##Mettez à True pour lancer les tests semi-automatiques
afficher_traces = False ##Mettez a True pour afficher la trace complète des erreurs dans les tests
def allumettes(n):
"""
n un entier > 0
retourne une chaîne composée de n barres |
allumettes(5) vaut '|||||'
"""
return "|" * n
def plateau(n):
"""
n un entier > 0
retourne une chaîne composée de n barres | , suivi de n entre ()
plateau(5) vaut `||||| (5)`
"""
return allumettes(n) + " (" + str(n) + ")"
def coup_basique_pc(a):
"""
a un entier > 0, représente le nombre d'allumettes
retourne toujours 1
coup_basique_pc(10000) vaut 1
"""
return 1
def autre_joueur(joueur):
"""
joueur une chaine qui contient de nom "Joueur" ou "PC".
retourne l'autre chaine
autre_joueur("Joueur") vaut "PC"
"""
if joueur == "PC":
return "Joueur"
else :
return "PC"
def afficher_victoire(joueur):
"""
joueur une chaine qui contient le nom ("Joueur" ou "PC") du vainqueur.
Affiche une chaîne qui annonce la victoire de ce joueur !
"""
print("\n### VICTOIRE DU " + joueur + " ###")
def demander_coup_joueur():
"""
Demande au joueur combien d'allumettes il veut retirer (entier de 1 a 3)
retourne la valeur saisie par le joueur (type int).
"""
coup = input("Combien d'allumettes (1-3)? ")
return int(coup)
def derouler_tour(joueur, al):
"""
joueur une chaine qui contient le nom ("Joueur" ou "PC") du joueur en cours.
al un entier, le nombre d'allumettes au debut du tour
Affiche le nombre d'allumettes, s'enquiert du coup du joueur en cours,
puis retourne le nouveau nombre d'allumettes
"""
print() #les prints vides sont là pour sauter une lignes de formattage
print(plateau(al))
if joueur == "Joueur":
print()
coup = demander_coup_joueur()
else:
coup = coup_basique_pc(al)
print()
print("PC : " + str(coup))
return al - coup
def main():
"""
demande un nombre d'allumettes au joueur, puis lance la partie avec ce nombre d'allumettes,
jusqu'à qu'un joueur gagne. Ensuite, affiche la victoire.
"""
al = int(input("Choisissez un nombre d'allumettes pour cette partie : "))
joueur = "Joueur"
while al > 0:
al = derouler_tour(joueur, al)
joueur = autre_joueur(joueur)
afficher_victoire(joueur)
if __name__=="__main__":
main()
############################################
############# PARTIE TESTS #############
############################################
import unittest
if not afficher_traces:
__unittest = True
def checktype(expr, res, exp):
assert type(res) == exp, expr + " doit retourner une valeur de type " + exp.__name__ + ", mais a retourné une valeur de type " + type(res).__name__
def checkval_equal(expr, res, exp):
str_exp = "'" +exp+ "'" if type(exp) == str else str(exp)
str_res = "'" +res+ "'" if type(res) == str else str(res)
assert res == exp, expr + " doit retourner " + str_exp + ", mais a retourné " + str_res
class Test_allumettes(unittest.TestCase):
def test_1(self):
res = allumettes(1)
checktype("allumettes(1)", res, str)
checkval_equal("allumettes(1)", res, "|")
def test_10(self):
res = allumettes(10)
checktype("allumettes(10)", res, str)
checkval_equal("allumettes(10)", res, "||||||||||")
class Test_plateau(unittest.TestCase):
def test_1(self):
res = plateau(1)
checktype("plateau(1)", res, str)
checkval_equal("plateau(1)", res, "| (1)")
def test_10(self):
res = plateau(10)
checktype("plateau(10)", res, str)
checkval_equal("plateau(10)", res, "|||||||||| (10)")
class Test_coup_basique_pc(unittest.TestCase):
def test_1(self):
res = coup_basique_pc(1)
checktype("coup_basique_pc(1)", res, int)
checkval_equal("coup_basique_pc(1)", res, 1)
def test_10(self):
res = coup_basique_pc(10)
checktype("coup_basique_pc(10)", res, int)
checkval_equal("coup_basique_pc(10)", res, 1)
def test_10934(self):
res = coup_basique_pc(10934)
checktype("coup_basique_pc(10934)", res, int)
checkval_equal("coup_basique_pc(10934)", res, 1)
class Test_autre_joueur(unittest.TestCase):
def test_Joueur(self):
res = autre_joueur("Joueur")
checktype("autre_joueur('Joueur')", res, str)
checkval_equal("autre_joueur('Joueur')", res, "PC")
def test_PC(self):
res = autre_joueur("PC")
checktype("autre_joueur('PC')", res, str)
checkval_equal("autre_joueur('PC')", res, "Joueur")
if __name__ == '__main__' and lancer_tests_automatiques:
s = unittest.TestSuite()
s.addTests(unittest.TestLoader().loadTestsFromTestCase(Test_allumettes))
s.addTests(unittest.TestLoader().loadTestsFromTestCase(Test_plateau))
s.addTests(unittest.TestLoader().loadTestsFromTestCase(Test_coup_basique_pc))
s.addTests(unittest.TestLoader().loadTestsFromTestCase(Test_autre_joueur))
unittest.TextTestRunner().run(s)
def check_interface_afficher_victoire():
print("\nTEST INTERFACE : afficher_victoire")
afficher_victoire("PC")
res = input("TEST INTERFACE : la victoire du PC est-elle correctement affichée (oui/non) ? ")
if(res != "oui"):
assert False, "ECHEC"
def check_interface_demander_coup_joueur():
print("\nTEST INTERFACE : demander_coup_joueur")
print("TEST INTERFACE : A la prochaine question, répondez 3 !")
res = demander_coup_joueur()
checktype("demander_coup_joueur()", res, int)
checkval_equal("demander_coup_joueur()", res, 3)
res = input("TEST INTERFACE : la question affichait que la réponse était entre 1 et 3 (oui/non) ? ")
if(res != "oui"):
assert False, "ECHEC"
def check_interface_derouler_tour_PC():
print("\nTEST INTERFACE : derouler_tour('PC')")
r = derouler_tour("PC", 4)
checktype("derouler_tour('PC', 4)", r, int)
checkval_equal("derouler_tour('PC', 4)", r, 3)
res = input("TEST INTERFACE : C'est le PC qui a joué (oui/non) ? ")
if(res != "oui"):
assert False, "ECHEC"
res = input("TEST INTERFACE : Il y avait 4 allumettes à la base (oui/non) ? ")
if(res != "oui"):
assert False, "ECHEC"
res = input("TEST INTERFACE : Il a retiré 1 allumette, celà a été affiché (oui/non) ? ")
if(res != "oui"):
assert False, "ECHEC"
def check_interface_derouler_tour_Joueur():
print("\nTEST INTERFACE : derouler_tour('Joueur')")
print("TEST INTERFACE : A la prochaine question, répondez 2 !")
r = derouler_tour("Joueur", 5)
checktype("derouler_tour('Joueur', 5)", r, int)
checkval_equal("derouler_tour('Joueur', 5)", r, 3)
res = input("TEST INTERFACE : C'est le Joueur qui a joué (oui/non) ? ")
if(res != "oui"):
assert False, "ECHEC"
res = input("TEST INTERFACE : Il y avait 5 allumettes à la base (oui/non) ? ")
if(res != "oui"):
assert False, "ECHEC"
if __name__ == '__main__' and lancer_tests_interface:
print("LES TESTS D'INTERFACE COMMENCENT")
check_interface_afficher_victoire()
check_interface_demander_coup_joueur()
check_interface_derouler_tour_PC()
check_interface_derouler_tour_Joueur()
print("\nSUCCES")
Partie 6 : ouverture
Pour cette partie, vous pouvez repartir du code fourni dans le dépliant juste au dessus. Il ne vous est pas demandé de répondre forcément juste (la plupart des questions n'ont pas qu'une seule "bonne réponse"), mais de rendre compte de votre démarche et de votre réflexion !
Donnez une représentation grapique du programme, qui montre : Les fonction et les appels qu'elles font à d'autres fonctions du programme.
On veut ameliorer la stratégie du PC. Combien de fonctions faut-il modifier au minimum ? Expliquez en quelques lignes votre raisonnement.. Remarque : vous avez le droit de partir du code de la solution complète.
Proposez une idée pour améliorer la stratégie du PC. Expliquez comment vous l'avez trouvée (raisonnement, recherche sur Internet, utilisation d'un module ou d'une bibliothèque comme le module random, ...).
Implantez votre stratégie dans le programme, ou expliquez comment vous l'implanteriez si vous ne savez pas exactement comment faire : la structure du problème, du programme (les fonctions et leurs spécifications).