Nous allons tenter d'écrire pas à pas un programme qui reproduit le jeu "pierre feuilles ciseaux" ou chifoumi. Ce sera également l'occasion de se familiariser avec les notebooks.
Le jeu comporte deux joueurs : "Heckel" et "Jeckel". Le programme leur attribue un coup de façon aléatoire et indique qui est le gagnant. Nous commencerons en décomposant le problème en trois parties : les coups, les règles, le résultat
Dans une partie, Heckel et Jeckel ont chacun un coup. Nous allons utiliser des variables pour conserver en mémoire le coup joué par chacun des joueurs. Nous ferons varier les coups par la suite.
heckel = "feuille"
jeckel = "pierre"
print(heckel) # En python3 print est une fonction, parenthèses obligatoires
Vous pouvez éxecuter la cellule ci-dessus, elle sera interprétée par Python (clic sur bouton "play" ou shift+return). Vous pouvez également modifier les valeurs possibles ou les noms de variable et éxecuter à nouveau.
Il n'y a pas de norme pour les noms de variable. Python donne des conseils dans la PEP 8 (Python Enhancement Proposal) : Style Guide for Python Code. Ici nous écrirons les noms de variables en minuscule avec des underscores au besoin.
Ensuite nous devons implémenter les règles du jeu pour déterminer le vainqueur. Dans un premier temps nous allons le faire naïvement à l'aide de disjonctions imbriquées 'si pierre et ciseaux alors pierre gagne, sinon etc...'. Pour cela nous utiliserons les instructions if
, else
et elif
.
if heckel == jeckel:
result = "Égalité"
else:
if heckel == "pierre":
if jeckel == "ciseaux":
result = "Heckel a gagné"
elif jeckel == "feuille":
result = "Jeckel a gagné"
elif heckel == "feuille":
if jeckel == "pierre":
result = "Heckel a gagné"
else:
# Jeckel joue forcément ciseaux (enfin s'il respecte les règles)
result = "Jeckel a gagné"
# Heckel joue ciseaux
# A vous d'écrire la suite ici
Ce n'est ni élégant ni optimisé mais c'est simple à comprendre et à écrire.
Prenez garde aux niveaux d'indentation, c'est une erreur commune quand on débute en Python. La PEP 8 recommande l'utilisation des espaces pour l'indentation. Je recommande le visionnage de cet extrait de la série "Silicon Valley".
Une fois que le vainqueur a été déterminé par nos règles il faut afficher le résultat à l'utilisateur. L'affichage devra rappeler le coup de chaque joueur et le résulat.
Nous utiliserons pour cela la fonction print
. Par défaut print
affiche ses arguments sur STDOUT (la sortie standard).
# Les variables sont séparées par des virgules
# L'affichage n'est pas très satisfaisant
print(heckel, jeckel, result)
# Construction d'une longue chaîne de caractères
# à l'aide de l'opérateur de concaténation +
print("Heckel : " + heckel + ", Jeckel : " + jeckel + ", " + result)
Pour le moment Hekcel et Jeckel jouent toujours le même coup, c'est un peu nul. Nous allons ajouter un peu d'incertitude en choisissant un coup de façon aléatoire.
Pour cela nous allons utiliser une liste des coups possible associé au module random
qui permet de générer des nombres aléatoires.
import random
coups = ["pierre", "feuille", "ciseaux"] # la liste des coups possibles
rand = random.randint(0,2) # fonction randint renvoie un entier, ici entre 0 et 2, bornes incluses
print(rand, coups[rand]) # on accède à l'élément d'indice 'rand' de la liste 'coups'
heckel = coups[rand]
jeckel = coups[random.randint(0,2)] # on peut s'épargner la variable rand
print(heckel, jeckel)
Exécutez la cellule ci-dessus plusieurs fois et vous verrez que les coups varient.
Plutôt que d'appeler deux fois une suite d'instructions nous allons en faire une fonction.
Nous l'appelerons draw
, elle ne reçoit pas d'arguments et renvoie un des coups possibles.
def draw():
"""
Coup aléatoire au chifoumi
pas d'arguments
"""
coups = ["pierre", "feuille", "ciseaux"]
coup = coups[random.randint(0,2)]
return coup
Pensez à éxécuter la cellule ci-dessus pour que la fonction soit connue par l'interpréteur
heckel = draw()
jeckel = draw()
print(heckel, jeckel)
Les règles n'ont pas changé mais nous allons essayer de les regrouper dans une fonction pour pouvoir les appeler plus aisément
def rules(heckel, jeckel):
"""
implémentation naïve des règles du chifoumi
args : heckel (str), jeckel (str)
"""
if heckel == jeckel:
return "Égalité"
else:
if heckel == "pierre":
if jeckel == "ciseaux":
return "Heckel a gagné"
else:
return "Jeckel a gagné"
elif heckel == "feuille":
if jeckel == "pierre":
return "Heckel a gagné"
else:
return "Jeckel a gagné"
else:
if jeckel == "feuille":
return "Heckel a gagné"
else:
return "Jeckel a gagné"
heckel = draw()
jeckel = draw()
result = rules(heckel, jeckel)
print(result)
Nous utiliserons pour cela les fonctions print
et format
.
# Une chaîne plus facile à modifier avec format() (existe depuis Python 2.6)
print("Heckel : {}, Jeckel : {}, {}".format(heckel, jeckel, result))
# Pour les old-timers, un printf like. Risque de disparaître au profit de format()
print("heckel : %s, jeckel : %s, %s" %(heckel, jeckel, result))
Au final pour cette deuxième version, on a le code suivant (sans les fonctions) :
heckel = draw()
jeckel = draw()
result = rules(heckel, jeckel)
print("Heckel : {}, Jeckel : {}, {}".format(heckel, jeckel, result))
jeckel = input("À vous de jouer [pierre, feuille, ciseaux]")
print("Jeckel joue : {}".format(jeckel))
En modifiant uniquement la deuxième instruction de notre code vous pouvez commencer à jouer contre Heckel.
heckel = draw()
jeckel = input("À vous de jouer [pierre, feuille, ciseaux]")
result = rules(heckel, jeckel)
print("Heckel : {}, Jeckel : {}, {}".format(heckel, jeckel, result))
Il y a une faille dans notre implémentation des règles qui peut permettre de gagner à tous les coups. Essayez de la trouver.
Vous incarnez Jeckel n'oubliez pas. C'est un sacré filou, s'il y a une faille il va en profiter.
Pour éviter la triche il faut vérifier que la valeur soumise par l'utilisateur est bien conforme à ce qui est attendu. Il y a plusieurs manières de faire cette vérification.
import sys
jeckel = input("À vous de jouer [pierre, feuille, ciseaux]")
if not(jeckel in coups):
sys.exit("Tricheur !")
jeckel = input("À vous de jouer [pierre, feuille, ciseaux]")
try:
coups.index(jeckel)
except:
print('Tricheur !')
raise
jeckel = input("À vous de jouer [pierre, feuille, ciseaux]")
if not(jeckel in coups):
raise ValueError("Tricheur ! {} ne fait pas partie des coups permis".format(jeckel))
Vous pouvez ajouter une fonction de vérification de la valeur du coup soumis puis ajoutez cette fonction dans la fonction rules
.
Il est également possible d'implémenter les règles avec un dictionnaire. Exemple :
winners = {'ciseaux': 'feuille', 'feuille': 'pierre', 'pierre':'ciseaux'}
if jeckel == heckel:
print("Égalité")
elif jeckel in winners.keys() and heckel == winners[jeckel]:
print("Jeckel a gagné")
else:
print("heckel a gagné")
Vous n'avez plus qu'à modifier la fonction rules()
def rules(heckel, jeckel):
"""
implémentation naïve des règles du chifoumi
args : heckel (str), jeckel (str)
"""
winners = {'ciseaux': 'feuille', 'feuille': 'pierre', 'pierre':'ciseaux'}
if jeckel == heckel:
return "Égalité"
elif heckel == winners[jeckel]:
return "Jeckel a gagné"
else:
return "Heckel a gagné"
Comment améliorer l'affichage du résultat ? Avec des emojis !
Vous pouvez récupérer le code Unicode des émojis sur emojipedia.
Pour afficher un caractère d'après son code hexadécimal utilisez \u
suivi du code hexa sur 16 bits ou \U
suivi du code sur 32 bits ou \N
suivi du nom du caractère entre accolades. Exemple :
print("\U0001F43C")
print("\N{PANDA FACE}")
Evidemment ça ne fonctionne que si le glyphe existe dans la police sélectionnée. Sur le navigateur ça devrait aller, dans la console il faut veiller à choisir une police adaptée.
pierre = "\u270A"
feuille = "\u270B"
ciseaux = "\u270C"
print(pierre)
print(feuille)
print(ciseaux)
Essayons de modifier l'affichage pour que les coups soit aussi affichées en emojis.
emojis = {'pierre': "\u270A", 'feuille': "\u270B", 'ciseaux': "\u270C"}
print("Heckel : {}, Jeckel : {}, {}".format(emojis[heckel], emojis[jeckel], result))
On récapitule cette troisième version :
coups = ["pierre", "feuille", "ciseaux"]
emojis = {'pierre': "\u270A", 'feuille': "\u270B", 'ciseaux': "\u270C"}
heckel = draw()
jeckel = input("À vous de jouer [pierre, feuille, ciseaux]")
if not(jeckel in coups):
raise ValueError("Tricheur ! {} ne fait pas partie des coups permis".format(jeckel))
result = rules(heckel, jeckel)
print("Heckel : {}, Jeckel : {}, {}".format(emojis[heckel], emojis[jeckel], result))
Une chance ne suffit, nous allons jouer 3 fois, celui qui a le plus de victoires gagne.
Pour cela nous aurons besoin d'utiliser une boucle.