Jouez contre l'ordinateur... Le but est d'essayer de comprendre quelles sont les règles de ce jeu et comment l'ordinateur choisit de jouer. Les parties suivantes reviennent en détail sur ces questions.
from random import randint
def verif(n):
"""
n est un entier > 1
"""
for k in range(2,n):
if n % k == 0:
return False
return True
def autorise(tas, k):
"""
tas est un entier naturel, c'est le nombre d'allumettes se trouvant devant les joueurs.
k est un entier naturel, c'est le nombre d'allumettes que veut enlever le joueur dont c'est le tour.
La fonction renvoie True si le coup est permis et renvoie False si le coup n'est pas permis.
"""
return 0 < k <= tas and (verif(k) or k==1)
def jeu_ordi(tas):
"""
tas est le nombre d'allumettes au moment de jouer.
"""
if tas % 4 == 0:
return 1
else:
return tas % 4
def tas_actuel(n):
print("Le tas compte ", n, "allumettes.\n")
def choix_joueur1():
choix = randint(0, 1)
if choix == 0:
print("Je commence.")
return 0
else:
print("Vous commencez.")
return 1
def une_partie():
nb_allumettes = randint(20,40)
tas_actuel(nb_allumettes)
joueur = choix_joueur1()
while nb_allumettes >= 0:
if nb_allumettes == 0:
if joueur == 0:
print("J'ai perdu.\n")
else:
print("Vous avez perdu.\n")
break # sortie de boucle quand la partie est finie
else:
if joueur == 0:
nb_pris = jeu_ordi(nb_allumettes)
nb_allumettes = nb_allumettes - nb_pris
if nb_pris == 1:
print("Je prends ", nb_pris, "allumette.\n")
else:
print("Je prends ", nb_pris, "allumettes.\n")
tas_actuel(nb_allumettes)
joueur = 1
else:
print("A vous de jouer.\n")
nb_pris = 0
while not(autorise(nb_allumettes, nb_pris)):
nb_pris = int(input("Combien d'allumettes prenez-vous ?\n"))
if not(autorise(nb_allumettes, nb_pris)):
print("Ce nombre n'est pas autorisé.\n")
nb_allumettes = nb_allumettes - nb_pris
if nb_pris == 1:
print("Vous avez pris ", nb_pris, "allumette.\n")
else:
print("Vous avez pris ", nb_pris, "allumettes.\n")
tas_actuel(nb_allumettes)
joueur = 0
une_partie()
Un bon usage en programmation est de donner aux fonctions des noms explicites permettant de saisir l'essentiel de leur rôle.
Ce n'est pas ce qui a été fait avec le code ci-dessous.
def f(n):
"""
n est un entier > 1
"""
for k in range(2,n):
if n % k == 0:
return False
return True
Anissa affirme que la fonction suivante a le même rôle que f. Est-ce vrai?
from math import sqrt, floor
def g(n):
"""
n est un entier > 1
"""
for k in range(2,floor(sqrt(n))+1):
if n % k == 0:
return False
return True
On joue à un jeu à deux joueurs.
La fonction python ci-dessous permet de contrôler si le coup proposé par un joueur est valide: il a devant lui un nombre d'allumettes appelé ici tas et il veut enlever k allumettes.
Explicitez les règles du jeu en lisant le code de la fonction.
def coup_autorisé(tas, k):
"""
tas est un entier naturel, c'est le nombre d'allumettes se trouvant devant les joueurs.
k est un entier naturel, c'est le nombre d'allumettes que veut enlever le joueur dont c'est le tour.
La fonction renvoie True si le coup est permis et renvoie False si le coup n'est pas permis.
"""
if not(0 < k <= tas):
return False
elif not(g(k) or k==1):
return False
else:
return True
(la fonction g utilisée est celle de la partie précédente.)
Léna, qui a bien étudié le jeu, a programmé une stratégie. Sa fonction stratégie est donnée ci-dessous:
def stratégie(tas):
"""
tas est le nombre d'allumettes au moment de jouer.
La fonction renvoie le nombre d'allumettes enlevées par Léna.
"""
if tas % 4 == 0:
return 1
else:
return tas % 4
Explicitez en français la stratégie de Léna en lisant le code de la fonction.
Justifiez que lorsque le tas présent devant Léna n'est pas multiple de 4, alors Léna offre systématiquement à son adversaire un nombre d'allumettes multiple de 4.
Justifier que lorsque Léna a pu offrir un multiple de 4 à son adversaire, alors son adversaire ne pourra pas lui offrir un tas dont le nombre d'allumettes est multiple de 4.
Justifiez que si Léna arrive à offrir un tas multiple de 4 à son adversaire alors elle a la garantie de gagner.
Léna et Victor jouent au jeu précédent. Ils décident de commencer avec un tas dont le nombre d'allumettes est égal à l'année en cours.
Victor, galant, laisse Léna décider qui commence la partie.
Quelle sera la décision de Léna (sachant qu'elle aime gagner!) ?
Léna a une stratégie gagnante, mais il lui arrive de faire des erreurs de calcul pour calculer les restes des divisions par 4 avec des entiers de plus de deux chiffres.
Anissa lui propose de procéder suivant la méthode suivante:
Exemple: pour calculer le reste dans la division de 2019 par 4, on calcule à la place le reste de 19 par 4.
def reste_par_4(n):
deux_chiffres = n%100
return deux_chiffres % 4
Le programme de stratégie de Léna peut être amélioré pour accélérer la victoire. Comment ? Proposer une modification du code Python de la fonction stratégie.
def stratégie_plus_rapide(tas):
"""
tas est le nombre d'allumettes au moment de jouer.
La fonction renvoie le nombre d'allumettes enlevées par Léna.
"""
if tas % 4 == 0:
return 1
else:
reste = tas % 4
for k in range(tas, 0, -1):
if g(k) and k%4 == reste: # si k est premier et a même reste modulo 4 que tas
return k # on renvoie le plus grand nombre premier de même reste que tas
return reste # cas où un tel nombre premier n'est pas trouvé
Dans la proposition de modification du code de la fonction stratégie de la question précédente, pouvez citer un cas où la recherche d'un entier premier de même reste que tas (dans la division par 4) est inutile?
def stratégie_plus_rapide(tas):
"""
tas est le nombre d'allumettes au moment de jouer.
La fonction renvoie le nombre d'allumettes enlevées par Léna.
"""
if tas % 4 == 0:
return 1
else:
reste = tas % 4
if reste == 2:
return 2
else:
for k in range(tas, 0, -1):
if g(k) and k%4 == reste: # si k est premier et a même reste modulo 4 que tas
return k # on renvoie le plus grand nombre premier de même reste que tas
return reste # cas où un tel nombre premier n'est pas trouvé