Programme plante au bout d'un certain nombre de lancements
RésoluNabi -
Bonsoir,
Je suis un débutant en code et je fais des programmes pour le fun ou pour les cours. J'ai un petit problème avec une histoire de boucle for mais probablement pas aussi facile à régler qu'au premier abord. J'ai mis toutes les explications détaillées dans mon programme en commentaire (ce qui explique l'absence d'accents)
'''
Je ne sais pas si vous connaissez le jeu des batons de Fort Boyard. Dans le doute le but est simple :
2 joueurs s'affrontent et sont face a face devant 20 batons. Chaque joueur chacun son tour peut decider de prendre 1, 2 ou
3 batons (il est oblige d'en prendre). La partie s'arrete lorsqu'il n'y a plus de batons et le but est de ne pas etre le
dernier a jouer, donc le dernier a retirer un baton.
Il se trouve qu'il existe une strategie imparable qui permet au 1er joueur de gagner dans 100 % des cas s'il la connait :
- Commencer par prendre 3 batons
Puis durant toute la partie :
- Si l'adversaire en prend 3 prennez en 1
- S'il en prend 2 prennez en 2 aussi
- S'il en prend 1 prennez en 3
Il est donc impossible de gagner pour le 2e joueur si le premier connait cette strategie. Mais en jouant avec ma famille
j'ai vite remarque qu'ils ne la connaissaient pas et j'ai eu envie de creer un programme qui obeit a cette règle et s'il
joue en premier gagne tout le temps. Après avoir fait cela je l'ai ameliorer pour maximiser selon moi ses chances de gagner
en etant 2e en lui apprenant a profiter de chaque erreur du premier joueur qui lui serait fatale.
J'ai ensuite voulu tester le pourcentage de fois sur lesquels mon programme gagnerai en etant 2e a jouer. Pour ce faire
j'ai simule les coups d'un joueur par des coups aléatoires (effectivement ce n'est pas la meilleure manière car un joueur
réfléchit mais qu'importe).
C'est la que vient mon problème, j'ai lancé ce programme d'abord 100 ou 200 fois avec un boucle for mais j'ai remarqué
qu'au dela d'environ 230 le programme ne se lançait plus. J'ai d'abord pensé qu'il mettait du temps et j'ai donc ajouté
une barre de progression et attendu mais rien ni fait la barre au dela de 230 essais (environ) n'avance pas d'un iota.
'''
# IMPORTS
import random
from time import sleep
from tqdm import tqdm
# INITIALISATION DES VARIABLES
J1 = []
J2 = []
J1_victories = []
J2_victories = []
R3 = [True]
# DEF DU TOUR FAIT PAR LE PROGRAMME (COMMENT IL DOIT REAGIR)
def tour(Nb_batons, Joueur):
verification = False
if Joueur == 1 :
Liste = J1
if Nb_batons == (20-J1[0]):
R2 = True
else :
R2 = R3[0]
else :
Liste = J2
if Nb_batons != 0 :
while verification == False :
R2 = R3[0]
if Liste == J2 or R2 == False :
if len(list(Liste)) == 0:
batons = 3
else :
if Liste[-1] == 1 :
batons = 3
elif Liste[-1] == 2:
batons = 2
elif Liste[-1] == 3:
batons = 1
if batons <= Nb_batons :
verification = True
else :
right_move = True
if len(J2) == 0 and J1[0] != 3:
right_move = False
if J1[-1] == 2 :
batons = 1
else :
batons = 2
elif len(J2) > 0 :
Nb_test = Nb_batons
V3 = False
while (Nb_test-1) % 4 != 0 :
V3 = True
Nb_test = Nb_batons
if J2[-1] == 1 and J1[-1] != 3:
right_move = False
batons = random.randint(1,3)
Nb_test -= batons
elif J2[-1] == 2 and J1[-1] != 2:
right_move = False
batons = random.randint(1,3)
Nb_test -= batons
elif J2[-1] == 3 and J1[-1] != 1:
right_move = False
batons = random.randint(1,3)
Nb_test -= batons
else :
batons = 2
break
if (Nb_test-1) % 4 == 0 and V3 == False:
batons = 2
else :
batons = 2
if right_move == False :
R3.clear()
R3.append(False)
if batons <= Nb_batons :
verification = True
else :
R3.clear()
R3.append(True)
return batons
# DEF DU TOUR D'UN UTILISATEUR, ICI SIMULE PAR DES COUPS ALEATOIRES ENTRE 1 ET 3
def tour_utilisateur(Nb_batons):
verification = False
if Nb_batons != 0 :
while verification == False :
batons = random.randint(1,3)
if batons <= Nb_batons:
verification = True
return batons
# DEF DU JEU EN FONCTION DE QUI COMMENCE
def game():
Nb_batons = 20
Tour_joueur = 1
Joueur = 1
while Nb_batons > 0 :
if Joueur == 1 :
if Tour_joueur % 2 != 0 :
batons = tour_utilisateur(Nb_batons)
J1.append(batons)
Nb_batons -= batons
Tour_joueur += 1
if Nb_batons == 0 :
J2_victories.append(1)
else :
batons = tour(Nb_batons, Joueur)
J2.append(batons)
Nb_batons -= batons
Tour_joueur += 1
if Nb_batons == 0 :
J1_victories.append(1)
else :
if Tour_joueur % 2 != 0 :
batons = tour(Nb_batons, Joueur)
J1.append(batons)
Nb_batons -= batons
Tour_joueur += 1
if Nb_batons == 0 :
J1_victories.append(1)
else :
batons = tour_utilisateur(Nb_batons)
J2.append(batons)
Nb_batons -= batons
Tour_joueur += 1
if Nb_batons == 0 :
J2_victories.append(1)
# LAUNCH
for i in tqdm(range(300)):
J1.clear()
J2.clear()
J1_win = False
J2_win = False
R3.clear()
R3.append(True)
game()
Nb_victoires_J1 = sum(J1_victories)
Nb_victoires_J2 = sum(J2_victories)
print('J1 a gagne',Nb_victoires_J1,'fois et J2,',Nb_victoires_J2,'fois')
Si quelqu'un à la patience et la gentillesse d'y rejeter un oeil je le remerci d'avance.
Windows / Chrome 110.0.0.0
- Programme plante au bout d'un certain nombre de lancements
- Qu'est ce qui se lance au démarrage de l'ordinateur - Guide
- Lancer un programme au démarrage windows 10 - Guide
- Nombre de jours entre deux dates excel - Guide
- Mettre en veille un programme - Guide
- Nombre facile - Télécharger - Outils professionnels
7 réponses
Pas évident de trouver l'erreur et je n'avais pas envie de m'essayer ...
Tu peux éliminer une cause de boucle infinie en modifiant la fonction suivante:
# DEF DU TOUR D'UN UTILISATEUR, ICI SIMULE PAR DES COUPS ALEATOIRES ENTRE 1 ET 3
def tour_utilisateur(Nb_batons):
verification = False
if Nb_batons != 0 :
essais = 0
while verification == False and essais < 1000:
essais += 1
batons = random.randint(1,3)
if batons <= Nb_batons:
verification = True
return batons if essais < 1000 else Nb_batons
J'ai modifié cette boucle pour la simplifier:
while (Nb_test-1) % 4 != 0 :
V3 = True
Nb_test = Nb_batons
if J1[-1] + J2[-1] != 4: # Tu ne veux pas que la somme soit 4 ?
right_move = False
batons = random.randint(1,3)
Nb_test -= batons
else :
batons = 2
break
J'ai fini par faire un copier-coller de ton code. :)
Avec la modification donnée au début, j'ai pu me rendre au moins une fois jusqu'à 300 et c'est l'ordi qui a gagné. :)
Il se peut qu'on soit malchanceux avec randint() et qu'on ne trouve jamais la bonne réponse.
Il faut se parer contre ce côté aléatoire.
edit: quand on entre dans cette boucle, il est impossible d'en sortir.
Dans tour_utilisateur, je retourne le nombre de batons restants. Ce n'est pas correct.
Et pour donner une chance à l'utilisateur, ce serait mieux de retourner 1 à la place.
J'ai remplacé la boucle ci-haut par ceci:
if (Nb_test-1) % 4 != 0 :
V3 = True
Nb_test = Nb_batons
if J1[-1] + J2[-1] != 4: # Tu ne veux pas que la somme soit 4 ?
right_move = False
batons = [3, 0, 1, 2][Nb_test%4]
Nb_test -= batons
else :
batons = 2
Je n'ai pas trouvé où ça boucle, mais je me rend plus souvent jusqu'à 300.
Il y a sans doute encore un bug dans la stratégie qui fait boucler le programme.
Et cela dépend des choix aléatoires de l'utilisateur.
bonjour,
quand tu partages du code, merci de préciser le langage,comme expliqué ici: https://codes-sources.commentcamarche.net/faq/11288-poster-un-extrait-de-code
Le programme boucle parfois dans tour(), sans jamais sortir de "while verification == False :" Tu peux facilement déterminer où il boucle en ajoutant des print().
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre questionJ'ai fait dans mon propre code les modifications que j'ai suggérées.
Et effectivement, je boucle toujours dans la fonction tour() et dans la boucle mentionnée par yg_be.
Je crois que j'étais fatigué pour le dernier code. Ceci est plus simple:
if (Nb_test-1) % 4 != 0 :
V3 = True
Nb_test = Nb_batons
if J1[-1] + J2[-1] != 4: # Tu ne veux pas que la somme soit 4 ?
right_move = False
batons = (Nb_test + 3) % 4
Nb_test -= batons
else :
batons = 2
On peut simplifier encore:
if Liste[-1] == 1 :
batons = 3
... les deux autres tests
batons = 4 - Liste[-1]
Plus tu vas simplifier, plus le bug finira par devenir évident.