Mes questions sur Python

Mes questions sur Python - Python - Programmation

Marsh Posté le 15-03-2011 à 16:21:00    

Bonjour,
 
En ce moment, j'apprends Python 3 avec le livre de G. Swinnen, et comme tous les exercices ne sont pas corrigés ou commentés en détail, j'ai des questions.
 
Je vais commencer par le 8.21. Le but de l'exo est de simuler un passage piéton avec 4 feux dont on inverse les couleurs en cliquant sur un bouton. Mon code fonctionne, mais j'aimerais savoir si j'ai bien fait ou si j'aurais pu faire plus simple, notamment au niveau de la fonction changecoul.
 

Code :
  1. from tkinter import *
  2. def changecoul():
  3.     global c
  4.     if c==0:
  5.         feu1= can.create_oval(35, 45, 45, 55, fill=coul[0])
  6.         feu2= can.create_oval(155, 45, 165, 55, fill=coul[1])
  7.         feu1= can.create_oval(155, 145, 165, 155, fill=coul[0])
  8.         feu1= can.create_oval(35, 145, 45, 155, fill=coul[1])
  9.         c=1
  10.     else:
  11.         feu1= can.create_oval(35, 45, 45, 55, fill=coul[1])
  12.         feu2= can.create_oval(155, 45, 165, 55, fill=coul[0])
  13.         feu1= can.create_oval(155, 145, 165, 155, fill=coul[1])
  14.         feu1= can.create_oval(35, 145, 45, 155, fill=coul[0])
  15.         c=0
  16. #variables
  17. coul=['red', 'green']       #liste des couleurs
  18. c= 0                        #variable d'inversion
  19. #programme
  20. fen=Tk()
  21. can= Canvas(fen, width=200, height=200, bg='light grey')
  22. can.pack()
  23. can.create_rectangle(50, 0, 150, 200, fill="grey" )
  24. can.grid(rowspan=3, column=2)
  25. #on crée le passage piéton
  26. i, x=0, 52.5
  27. while i<7:
  28.     can.create_rectangle(x, 60, x+10, 140, fill="white" )
  29.     i+=1
  30.     x+=14
  31.    
  32. #les feux
  33. feu1= can.create_oval(35, 45, 45, 55, fill=coul[1])
  34. feu2= can.create_oval(155, 45, 165, 55, fill=coul[0])
  35. feu1= can.create_oval(155, 145, 165, 155, fill=coul[1])
  36. feu1= can.create_oval(35, 145, 45, 155, fill=coul[0])
  37. bou= Button(fen, text="Changer", command=changecoul)
  38. bou.grid(row=4, column=2, sticky=E)
  39. fen.mainloop()


 
 :jap:


---------------
Des piafs en photo
Reply

Marsh Posté le 15-03-2011 à 16:21:00   

Reply

Marsh Posté le 15-03-2011 à 20:47:34    

Bonsoir carrion crow,
je n'ai rien d'un expert mais il me semble :

 

* que ta ligne 33 pourrait s'écrire plus simplement :

Code :
  1. for i in range(0,7): (voir edit)


* qu'il vaut mieux éviter d'utiliser des variables globales dans ta fonction changecoul(); je ne vois pas comment simplement résoudre ce problème si ce n'est en créant une classe regroupant ta fonction changecoul et une variable self.c
* qu'il faut éviter les import * qui neutralisent l'intérêt des namespaces. Je pense qu'il vaut mieux écrire :

Code :
  1. import tkinter
  2. tkinter.Canvas (...)
 

*edit : et non range(0,6) comme je l'avais écrit mais Masklinn a mieux encore (uide infra)

Message cité 1 fois
Message édité par suizokukan le 15-03-2011 à 23:11:51

---------------
rule #1 : trust the python
Reply

Marsh Posté le 15-03-2011 à 20:57:23    

Quant au contenu de la fonction changecoul on pouvait aussi le faire ainsi, mais de manière plus abstraite et moins lisible (et en gardant le global) :

Code :
  1. def changecoul():
  2.     global c
  3.     choix = {
  4.                   0: ( (35,45,45,55,0),
  5.                         (155,45,165,55,1),
  6.                         ...manquent deux lignes de données)
  7.                   1: ( (35,45,45,55,1),
  8.                         (155,45,165,55,0),
  9.                         ...manquent deux lignes de données)
  10.                 }
  11.     feu1 = can.create_oval( choix[c][0][0], choix[c][0][1], choix[c][0][2], choix[c][0][3], fill=coul[ choix[c][0][4] )
  12.     feu2 = can.create_oval( choix[c][1][0], choix[c][1][1], choix[c][1][2], choix[c][1][3], fill=coul[ choix[c][1][4] )
  13.     feu3 =
  14.     feu4 =
  15.     (...)
  16.     # pour faire alterne les valeurs de c :
  17.     c = (c+1)%2
 

Encore une fois, je n'ai rien d'un expert; attendons les gurus !


Message édité par suizokukan le 15-03-2011 à 21:16:49

---------------
rule #1 : trust the python
Reply

Marsh Posté le 15-03-2011 à 22:14:25    

Pour améliorer encore sur ce que suggère suizokukan, le `0` est optionnel dans range. Par contre, la borne supérieure n'est pas include donc il faut écrire `for i in range(7)` (sinon il manque une raie du passage), et retirer le x += 1 naturellement:

Code :
  1. diff -r 3ce560a26ab2 swinnen.py
  2. --- a/swinnen.py    Tue Mar 15 21:35:09 2011 +0100
  3. +++ b/swinnen.py    Tue Mar 15 21:37:36 2011 +0100
  4. @@ -23,10 +23,9 @@
  5. can.create_rectangle(50, 0, 150, 200, fill="grey" )
  6. can.grid(rowspan=3, column=2)
  7. #on cree le passage pieton
  8. -i, x=0, 52.5
  9. -while i<7:
  10. +x = 52.5
  11. +for i in range(7):
  12.     can.create_rectangle(x, 60, x+10, 140, fill="white" )
  13. -    i+=1
  14.     x+=14
  15.  
  16. #les feux


À partir de là, tu peux renommer x en "offset" et ne plus l'altérer, mais utiliser i à la place:

Code :
  1. diff -r be63091caa07 swinnen.py
  2. --- a/swinnen.py    Tue Mar 15 21:38:27 2011 +0100
  3. +++ b/swinnen.py    Tue Mar 15 21:39:39 2011 +0100
  4. @@ -23,10 +23,11 @@
  5. can.create_rectangle(50, 0, 150, 200, fill="grey" )
  6. can.grid(rowspan=3, column=2)
  7. #on cree le passage pieton
  8. -x = 52.5
  9. +OFFSET = 52.5
  10. for i in range(7):
  11. -    can.create_rectangle(x, 60, x+10, 140, fill="white" )
  12. -    x+=14
  13. +    can.create_rectangle(OFFSET + 14*i, 60,
  14. +                         OFFSET+14*i+10, 140,
  15. +                         fill="white" )
  16.  
  17. #les feux
  18. feu1= can.create_oval(35, 45, 45, 55, fill=coul[1])


En python, False et True font parallèle à 0 et 1, et tant qu'on ne vérifie pas explicitement les types ils sont interchangeables, je suggérerais donc de remplacer 0/1 par un booléen:

diff -r dc7be27b08f2 swinnen.py
--- a/swinnen.py Tue Mar 15 21:39:48 2011 +0100
+++ b/swinnen.py Tue Mar 15 21:43:12 2011 +0100
@@ -1,21 +1,21 @@
 from tkinter import *
 def changecoul():
     global c
-    if c==0:
+    if not c:
         feu1= can.create_oval(35, 45, 45, 55, fill=coul[0])
         feu2= can.create_oval(155, 45, 165, 55, fill=coul[1])
         feu1= can.create_oval(155, 145, 165, 155, fill=coul[0])
         feu1= can.create_oval(35, 145, 45, 155, fill=coul[1])
-        c=1
+        c = not c
     else:
         feu1= can.create_oval(35, 45, 45, 55, fill=coul[1])
         feu2= can.create_oval(155, 45, 165, 55, fill=coul[0])
         feu1= can.create_oval(155, 145, 165, 155, fill=coul[1])
         feu1= can.create_oval(35, 145, 45, 155, fill=coul[0])
-        c=0
+        c = not c
 #variables
 coul=['red', 'green']       #liste des couleurs
-c= 0                        #variable d'inversion
+c = False
 #programme
 fen=Tk()
 can= Canvas(fen, width=200, height=200, bg='light grey')


On peut remarquer que l'inversion est redondante entre les deux clauses de changecoul. Je vais en profiter pour renommer c:

diff -r d38abb78fdab swinnen.py
--- a/swinnen.py Tue Mar 15 21:43:47 2011 +0100
+++ b/swinnen.py Tue Mar 15 21:45:49 2011 +0100
@@ -1,21 +1,20 @@
 from tkinter import *
 def changecoul():
-    global c
-    if not c:
+    global toggle
+    if not toggle:
         feu1= can.create_oval(35, 45, 45, 55, fill=coul[0])
         feu2= can.create_oval(155, 45, 165, 55, fill=coul[1])
         feu1= can.create_oval(155, 145, 165, 155, fill=coul[0])
         feu1= can.create_oval(35, 145, 45, 155, fill=coul[1])
-        c = not c
     else:
         feu1= can.create_oval(35, 45, 45, 55, fill=coul[1])
         feu2= can.create_oval(155, 45, 165, 55, fill=coul[0])
         feu1= can.create_oval(155, 145, 165, 155, fill=coul[1])
         feu1= can.create_oval(35, 145, 45, 155, fill=coul[0])
-        c = not c
+    toggle = not toggle
 #variables
-coul=['red', 'green']       #liste des couleurs
-c = False
+coul = ['red', 'green']       #liste des couleurs
+toggle = False
 #programme
 fen=Tk()
 can= Canvas(fen, width=200, height=200, bg='light grey')

 

Bon. Maintenant on peut remarquer une chose: ton initialisation des feux dans le corps du script est identique au 2e cas de changecoul. Donc si on appellait changecoul pour qu'il exécute son 2e cas, paf pastèque.

 

Ce 2e cas arrive quand "not (not toggle)", donc toggle = True. Donc on inverse notre initialisation de toggle et on appelle changecoul:

diff -r 78ce1213a04f swinnen.py
--- a/swinnen.py Tue Mar 15 21:48:31 2011 +0100
+++ b/swinnen.py Tue Mar 15 21:48:43 2011 +0100
@@ -14,7 +14,7 @@
     toggle = not toggle
 #variables
 coul = ['red', 'green']       #liste des couleurs
-toggle = False
+toggle = True
 #programme
 fen=Tk()
 can= Canvas(fen, width=200, height=200, bg='light grey')
@@ -29,10 +29,7 @@
                          fill="white" )
 
 #les feux
-feu1= can.create_oval(35, 45, 45, 55, fill=coul[1])
-feu2= can.create_oval(155, 45, 165, 55, fill=coul[0])
-feu1= can.create_oval(155, 145, 165, 155, fill=coul[1])
-feu1= can.create_oval(35, 145, 45, 155, fill=coul[0])
+changecoul()
 bou= Button(fen, text="Changer", command=changecoul)
 bou.grid(row=4, column=2, sticky=E)
 fen.mainloop()


Au passage, les variables feu1 et feu2 sont settées n'importe comment, autant les dégager aussi dans changecoul:

diff -r 0d0cd1263a8d swinnen.py
--- a/swinnen.py Tue Mar 15 21:49:03 2011 +0100
+++ b/swinnen.py Tue Mar 15 21:49:43 2011 +0100
@@ -2,15 +2,15 @@
 def changecoul():
     global toggle
     if not toggle:
-        feu1= can.create_oval(35, 45, 45, 55, fill=coul[0])
-        feu2= can.create_oval(155, 45, 165, 55, fill=coul[1])
-        feu1= can.create_oval(155, 145, 165, 155, fill=coul[0])
-        feu1= can.create_oval(35, 145, 45, 155, fill=coul[1])
+        can.create_oval(35, 45, 45, 55, fill=coul[0])
+        can.create_oval(155, 45, 165, 55, fill=coul[1])
+        can.create_oval(155, 145, 165, 155, fill=coul[0])
+        can.create_oval(35, 145, 45, 155, fill=coul[1])
     else:
-        feu1= can.create_oval(35, 45, 45, 55, fill=coul[1])
-        feu2= can.create_oval(155, 45, 165, 55, fill=coul[0])
-        feu1= can.create_oval(155, 145, 165, 155, fill=coul[1])
-        feu1= can.create_oval(35, 145, 45, 155, fill=coul[0])
+        can.create_oval(35, 45, 45, 55, fill=coul[1])
+        can.create_oval(155, 45, 165, 55, fill=coul[0])
+        can.create_oval(155, 145, 165, 155, fill=coul[1])
+        can.create_oval(35, 145, 45, 155, fill=coul[0])
     toggle = not toggle
 #variables
 coul = ['red', 'green']       #liste des couleurs


Bon. Le packing c'est bon, concentrons nous sur changecoul.

 

On voit que les deux cas sont le même code, la seule différence étant l'indice pour le tableau de couleurs.

 

Je vais commencer par inverser les clauses histoire d'arrêter de tester sur un not sans besoin:

diff -r f5e00b9d0311 swinnen.py
--- a/swinnen.py Tue Mar 15 21:50:11 2011 +0100
+++ b/swinnen.py Tue Mar 15 21:52:11 2011 +0100
@@ -1,16 +1,17 @@
 from tkinter import *
 def changecoul():
     global toggle
-    if not toggle:
+    if toggle:
+        can.create_oval(35, 45, 45, 55, fill=coul[1])
+        can.create_oval(155, 45, 165, 55, fill=coul[0])
+        can.create_oval(155, 145, 165, 155, fill=coul[1])
+        can.create_oval(35, 145, 45, 155, fill=coul[0])
+    else:
         can.create_oval(35, 45, 45, 55, fill=coul[0])
         can.create_oval(155, 45, 165, 55, fill=coul[1])
         can.create_oval(155, 145, 165, 155, fill=coul[0])
         can.create_oval(35, 145, 45, 155, fill=coul[1])
-    else:
-        can.create_oval(35, 45, 45, 55, fill=coul[1])
-        can.create_oval(155, 45, 165, 55, fill=coul[0])
-        can.create_oval(155, 145, 165, 155, fill=coul[1])
-        can.create_oval(35, 145, 45, 155, fill=coul[0])
+
     toggle = not toggle
 #variables
 coul = ['red', 'green']       #liste des couleurs


puis, en virtue de ce que j'ai dit au dessus, remplacer les 0/1 par False/True:

diff -r dcbc754f32ef swinnen.py
--- a/swinnen.py Tue Mar 15 21:52:32 2011 +0100
+++ b/swinnen.py Tue Mar 15 21:53:27 2011 +0100
@@ -2,15 +2,15 @@
 def changecoul():
     global toggle
     if toggle:
-        can.create_oval(35, 45, 45, 55, fill=coul[1])
-        can.create_oval(155, 45, 165, 55, fill=coul[0])
-        can.create_oval(155, 145, 165, 155, fill=coul[1])
-        can.create_oval(35, 145, 45, 155, fill=coul[0])
+        can.create_oval(35, 45, 45, 55, fill=coul[True])
+        can.create_oval(155, 45, 165, 55, fill=coul[False])
+        can.create_oval(155, 145, 165, 155, fill=coul[True])
+        can.create_oval(35, 145, 45, 155, fill=coul[False])
     else:
-        can.create_oval(35, 45, 45, 55, fill=coul[0])
-        can.create_oval(155, 45, 165, 55, fill=coul[1])
-        can.create_oval(155, 145, 165, 155, fill=coul[0])
-        can.create_oval(35, 145, 45, 155, fill=coul[1])
+        can.create_oval(35, 45, 45, 55, fill=coul[False])
+        can.create_oval(155, 45, 165, 55, fill=coul[True])
+        can.create_oval(155, 145, 165, 155, fill=coul[False])
+        can.create_oval(35, 145, 45, 155, fill=coul[True])
 
     toggle = not toggle
 #variables


Maintenant, dans le premier cas "toggle" est trues donc on peut remplacer les "true" par "toggle" et les "false" par "not toggle".

 

Et on fait l'inverse dans le 2e cas (toggle est false, donc on remplace false par toggle et true par not toggle):

diff -r a9646c4fdfc9 swinnen.py
--- a/swinnen.py Tue Mar 15 21:53:58 2011 +0100
+++ b/swinnen.py Tue Mar 15 21:55:08 2011 +0100
@@ -2,15 +2,15 @@
 def changecoul():
     global toggle
     if toggle:
-        can.create_oval(35, 45, 45, 55, fill=coul[True])
-        can.create_oval(155, 45, 165, 55, fill=coul[False])
-        can.create_oval(155, 145, 165, 155, fill=coul[True])
-        can.create_oval(35, 145, 45, 155, fill=coul[False])
+        can.create_oval(35, 45, 45, 55, fill=coul[toggle])
+        can.create_oval(155, 45, 165, 55, fill=coul[not toggle])
+        can.create_oval(155, 145, 165, 155, fill=coul[toggle])
+        can.create_oval(35, 145, 45, 155, fill=coul[not toggle])
     else:
-        can.create_oval(35, 45, 45, 55, fill=coul[False])
-        can.create_oval(155, 45, 165, 55, fill=coul[True])
-        can.create_oval(155, 145, 165, 155, fill=coul[False])
-        can.create_oval(35, 145, 45, 155, fill=coul[True])
+        can.create_oval(35, 45, 45, 55, fill=coul[toggle])
+        can.create_oval(155, 45, 165, 55, fill=coul[not toggle])
+        can.create_oval(155, 145, 165, 155, fill=coul[toggle])
+        can.create_oval(35, 145, 45, 155, fill=coul[not toggle])
 
     toggle = not toggle
 #variables


Tiens c'est marrant, on aurait pas le même code dans les deux branches du "if", un peu? On va donc dégager la première branche:

diff -r a9646c4fdfc9 -r 4e1e38520db5 swinnen.py
--- a/swinnen.py Tue Mar 15 21:53:58 2011 +0100
+++ b/swinnen.py Tue Mar 15 21:56:13 2011 +0100
@@ -1,16 +1,11 @@
 from tkinter import *
 def changecoul():
     global toggle
-    if toggle:
-        can.create_oval(35, 45, 45, 55, fill=coul[True])
-        can.create_oval(155, 45, 165, 55, fill=coul[False])
-        can.create_oval(155, 145, 165, 155, fill=coul[True])
-        can.create_oval(35, 145, 45, 155, fill=coul[False])
-    else:
-        can.create_oval(35, 45, 45, 55, fill=coul[False])
-        can.create_oval(155, 45, 165, 55, fill=coul[True])
-        can.create_oval(155, 145, 165, 155, fill=coul[False])
-        can.create_oval(35, 145, 45, 155, fill=coul[True])
+
+    can.create_oval(35, 45, 45, 55, fill=coul[toggle])
+    can.create_oval(155, 45, 165, 55, fill=coul[not toggle])
+    can.create_oval(155, 145, 165, 155, fill=coul[toggle])
+    can.create_oval(35, 145, 45, 155, fill=coul[not toggle])
 
     toggle = not toggle
 #variables


Bon après faire un peu de nettoyage: stylistiquement, les constantes sont en majuscules et au sommet du fichier avec les globales, les noms en anglais, les assignation (et plus généralement les opérateurs) ont des espaces sur les deux côtés (mais pas les paramètres nommés), on a aucun besoin de garder le bouton final (donc pas besoin de l'assigner à une variable):

diff -r 4e1e38520db5 swinnen.py
--- a/swinnen.py Tue Mar 15 21:56:13 2011 +0100
+++ b/swinnen.py Tue Mar 15 22:11:44 2011 +0100
@@ -1,31 +1,34 @@
 from tkinter import *
-def changecoul():
+
+COLORS = ['red', 'green']       #liste des couleurs
+OFFSET = 52.5
+
+toggle = True
+
+def toggle_lights():
     global toggle
 
-    can.create_oval(35, 45, 45, 55, fill=coul[toggle])
-    can.create_oval(155, 45, 165, 55, fill=coul[not toggle])
-    can.create_oval(155, 145, 165, 155, fill=coul[toggle])
-    can.create_oval(35, 145, 45, 155, fill=coul[not toggle])
+    can.create_oval(35, 45, 45, 55, fill=COLORS[toggle])
+    can.create_oval(155, 45, 165, 55, fill=COLORS[not toggle])
+    can.create_oval(155, 145, 165, 155, fill=COLORS[toggle])
+    can.create_oval(35, 145, 45, 155, fill=COLORS[not toggle])
 
     toggle = not toggle
-#variables
-coul = ['red', 'green']       #liste des couleurs
-toggle = True
+
 #programme
-fen=Tk()
-can= Canvas(fen, width=200, height=200, bg='light grey')
+window = Tk()
+can = Canvas(window, width=200, height=200, bg='light grey')
 can.pack()
 can.create_rectangle(50, 0, 150, 200, fill="grey" )
 can.grid(rowspan=3, column=2)
 #on cree le passage pieton
-OFFSET = 52.5
 for i in range(7):
-    can.create_rectangle(OFFSET + 14*i, 60,
-                         OFFSET+14*i+10, 140,
+    can.create_rectangle(OFFSET + 14 * i, 60,
+                         OFFSET + 14 * i + 10, 140,
                          fill="white" )
 
 #les feux
-changecoul()
-bou= Button(fen, text="Changer", command=changecoul)
-bou.grid(row=4, column=2, sticky=E)
-fen.mainloop()
+toggle_lights()
+Button(window, text="Changer", command=toggle_lights)\
+    .grid(row=4, column=2, sticky=E)
+window.mainloop()

 

On en arrive à ce programme "final":

Code :
  1. from tkinter import *
  2.  
  3. COLORS = ['red', 'green']       #liste des couleurs
  4. OFFSET = 52.5
  5.  
  6. toggle = True
  7.  
  8. def toggle_lights():
  9.    global toggle
  10.  
  11.    can.create_oval(35, 45, 45, 55, fill=COLORS[toggle])
  12.    can.create_oval(155, 45, 165, 55, fill=COLORS[not toggle])
  13.    can.create_oval(155, 145, 165, 155, fill=COLORS[toggle])
  14.    can.create_oval(35, 145, 45, 155, fill=COLORS[not toggle])
  15.  
  16.    toggle = not toggle
  17.  
  18. #programme
  19. window = Tk()
  20. can = Canvas(window, width=200, height=200, bg='light grey')
  21. can.pack()
  22. can.create_rectangle(50, 0, 150, 200, fill="grey" )
  23. can.grid(rowspan=3, column=2)
  24. #on cree le passage pieton
  25. for i in range(7):
  26.    can.create_rectangle(OFFSET + 14 * i, 60,
  27.                         OFFSET + 14 * i + 10, 140,
  28.                         fill="white" )
  29.  
  30. #les feux
  31. toggle_lights()
  32. Button(window, text="Changer", command=toggle_lights)\
  33.    .grid(row=4, column=2, sticky=E)
  34. window.mainloop()


Il y a encore des choses qu'on peut améliorer:

  • la création du passage piéton utilise des valeurs magiques, surtout dans la partie avec des offsets, il faudrait probablement extraire ça dans des constantes et peut-être même une fonction (bien nommée): 14 est la largeur d'une bande et 10 est la séparation.
  • on pourrait se débarasser de la variable globale (globales = caca) en utilisant un objet callable, mais je ne sais pas si tu en est déjà à ce genre de trucs.
  • pour la seconde idée de suizokukan (stocker les coordonnées des feux), j'utiliserais *args, mais c'est un peu bof parce qu'on a encore à mettre en place le fill.

mais bon je vais aller me pieuter.


Message édité par masklinn le 15-03-2011 à 22:15:51

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 16-03-2011 à 13:45:29    

suizokukan  :jap:  
 
Masklinn  :jap:  pour ta correction très détaillée. J'ai compris le principe, je vais essayer d'appliquer cette méthode aux prochains exo, mais j'ai encore du boulot pour apprendre à penser comme ça  :D  
 
Par contre, le "for i in range", il me semble que je ne l'ai pas encore vu dans le livre.
 
edit: en parlant de trucs qu'on n'a pas vu dans le livre et qui sert pour les exos, ça arrive et ça m'énerve au plus haut point de bloquer alors que c'est un truc que je ne sais pas  :fou:  [:toad666]  
Par exemple, je suis sur le 8.24, on doit faire changer de couleur une balle à chaque virage, il me faut donc la méthode .itemconfigure(), sauf que je ne l'ai pas encore vu dans le livre (merci internet du coup)


Message édité par carrion crow le 16-03-2011 à 14:33:11

---------------
Des piafs en photo
Reply

Marsh Posté le 17-03-2011 à 12:12:44    

Put***, j'ai l'impression d'être un débile mental:
exercice 8.27: il faut simuler une balle qui tombe et rebondi en prenant en compte la vitesse de la chute.

 

Avec ce que j'ai fait, la balle tombe, rebondit, de moins en moins haut, de façon naturelle quoi, par contre après, elle roule (c'est pas grave à la limite)
Dans sa correction, l'auteur a une balle qui tombe et rebondit sans jamais perdre de hauteur. J'essaie de modifier mon code pour faire pareil mais je ne comprends pas la différence entre les deux, ils me semblent "pareil" (même fonctions, incrémentations...) sans être identiques bien sur.

 

Mon code:

Code :
  1. #Simulation du mouvement d'une balle qui tombe
  2. from tkinter import *
  3. def move():
  4.     "déplacement de la balle"
  5.     global x1, y1, dx, v, flag
  6.    
  7.     xp, yp = x1, y1
  8.     x1, y1 = x1+dx, y1+v
  9.    
  10.     if x1>280 or x1<5:       #à gauche et à droite
  11.         dx = -dx     #on inverse le sens de déplacement
  12.        
  13.     if y1<50:      #montée
  14.         v = -v
  15.        
  16.     if y1>=180:      #descente
  17.         y1=180      #pas plus loin
  18.         v = -v
  19.     can1.coords(oval1, x1-10, y1-10, x1+10, y1+10)
  20.    
  21.     #on trace
  22.     can1.create_line(x1, y1, xp, yp)
  23.    
  24.     v=v+dv
  25.    
  26.     if flag>0:
  27.         fen1.after(50, move)        #boucler après 50 millisecondes
  28.        
  29. def stop_it():
  30.     "arrêt de l'animation"
  31.     global flag
  32.     flag=0
  33. def start_it():
  34.     "démarrage de l'animation"
  35.     global flag
  36.     if flag==0:     #pour ne lancer qu'une seule boucle
  37.         flag=1
  38.         move()
  39.        
  40. #programme
  41. #variables
  42. x1, y1= 10, 45          #coordonnées initiales
  43. dx = 5           #'pas' de déplacement
  44. v, dv = 0, 6                   #vitesse et sa variable
  45. flag=0                  #commutateur
  46. #widget principal
  47. fen1=Tk()
  48. fen1.title("Exercice d'animation avec tkinter" )
  49. #widgets enfants
  50. can1= Canvas(fen1, bg='dark grey', height=200, width=300)
  51. can1.pack(side=LEFT, padx=5, pady=5)
  52. #Création de la balle
  53. oval1= can1.create_oval(x1-10, y1-10, x1+10, y1+10, width=2, fill='red')
  54. #Bouton quitter
  55. bou1= Button(fen1, text='Quitter', width=8, command=fen1.quit)
  56. bou1.pack(side=BOTTOM)
  57. #Bouton démarrer
  58. bou2= Button(fen1, text='Démarrer', width=8, command=start_it)
  59. bou2.pack()
  60. #Bouton arrêter
  61. bou3= Button(fen1, text='Arrêter', width=8, command=stop_it)
  62. bou3.pack()
  63. #on lance
  64. fen1.mainloop()
 

La correction:

Code :
  1. #Simulation du mouvement d'une balle qui tombe
  2. #correction pour comprendre car je capte pas pourquoi mon code ne fonctionne pas. En apparence c'est la même chose.
  3. from tkinter import *
  4. def move():
  5.     "déplacement de la balle"
  6.     global x, y, v, flag, dv, dx
  7.    
  8.     xp, yp = x, y   #mémorisation des anciennes coordonnées
  9.    
  10.     if x>385 or x<15:       #à gauche et à droite
  11.         dx = -dx     #on inverse le sens de déplacement
  12.     x=x+dx
  13.    
  14.     #variation de la vitesse
  15.     v = v+dv
  16.    
  17.     #déplacement vertical proportionnel à la vitesse
  18.     y= y + v
  19.     if y>240:      #niveau du sol
  20.         y=240      #pas plus loin
  21.         v = -v
  22.     can.coords(balle, x-10, y-10, x+10, y+10)
  23.    
  24.     #on trace
  25.     can.create_line(xp, yp, x, y, fill='light grey')
  26.    
  27.     if flag>0:
  28.         fen1.after(50, move)        #boucler après 50 millisecondes
  29.        
  30. def stop_it():
  31.     "arrêt de l'animation"
  32.     global flag
  33.     flag=0
  34. def start_it():
  35.     "démarrage de l'animation"
  36.     global flag
  37.     if flag==0:     #pour ne lancer qu'une seule boucle
  38.         flag=1
  39.         move()
  40.        
  41. #programme
  42. #variables
  43. x, y= 15, 15          #coordonnées initiales
  44. dx = 6           #'pas' de déplacement
  45. v, dv = 0, 5                   #vitesse et sa variable
  46. flag=0                  #commutateur
  47. #widget principal
  48. fen1=Tk()
  49. fen1.title("Exercice d'animation avec tkinter" )
  50. #widgets enfants
  51. can= Canvas(fen1, bg='dark grey', height=250, width=400)
  52. can.pack(side=LEFT, padx=5, pady=5)
  53. #Création de la balle
  54. balle= can.create_oval(x-10, y-10, x+10, y+10, width=2, fill='red')
  55. #Bouton quitter
  56. bou1= Button(fen1, text='Quitter', width=8, command=fen1.quit)
  57. bou1.pack(side=BOTTOM)
  58. #Bouton démarrer
  59. bou2= Button(fen1, text='Démarrer', width=8, command=start_it)
  60. bou2.pack()
  61. #Bouton arrêter
  62. bou3= Button(fen1, text='Arrêter', width=8, command=stop_it)
  63. bou3.pack()
  64. #on lance
  65. fen1.mainloop()
 

Qu'est-ce qui diffère? Pourquoi mon code ne fonctionne pas pareil?

 

Edit: quand avez un programme à faire, quelle méthode appliquez-vous? Vous faites une liste des différents paramètres dont vous aurez besoin, des différentes fonctions???


Message édité par carrion crow le 17-03-2011 à 12:16:36

---------------
Des piafs en photo
Reply

Marsh Posté le 18-03-2011 à 16:36:27    

Rraaaahhh!!! Je vais péter un câble  [:gunblade]  
 
Exercice 8.33: créer un jeu du serpent. Cet exercice m'a bien chauffé mais le 8.34: si le serpent se recoupe, la partie s'arrête, me prend la tête.
 
Le serpent est constitué de carrés. Une liste "snake" contient les coordonnées de ces carrés. Le dernier de la liste est celui de la tête.
J'ai écrit ce code, en gros si le x du nouveau carré (newx) est entre le x et le x+t d'un autre carré du serpent et le y du nouveau carré (newy) est entre le y et le y+t d'un autre carré

Code :
  1. #si le serpent se recoupe, on perd
  2.     for u in range(h-1):
  3.         old=snake[u]    #old est la liste contenant les coordonnées d'un carré autre que celui de tête
  4.         oldx=old[1]     #coordonnée x du carré
  5.         oldy=old[2]     #coordonnée y du carré
  6.         if newx>=oldx and newx<=oldx+t and newy>=oldy and newy<=oldy+t:
  7.             loose()


 
Ça me semble logique mais ça ne fonctionne pas  :fou:  
 
Voici le code entier:

Code :
  1. #Jeu du serpent
  2. from tkinter import *
  3. from random import randrange
  4. #procédure générale de déplacement
  5. def move():
  6.     #Déplacement du serpent
  7.     global flag, points
  8.    
  9.     tail = snake[0]     #on prend les coords de la queue
  10.     c = tail[0]         #mémorisation du nom du carré
  11.    
  12.     h=len(snake)-1      #on prend l'indice de la tête dans la liste
  13.     head=snake[h]       #on prend les coords de la tête
  14.    
  15.     newx = head[1]+dx*t
  16.     newy = head[2]+dy*t
  17.    
  18.     #si on mange une boulette de bouffe
  19.     if newx+t>meatx-meatr and newx+t<meatx+meatr:
  20.         if newy>meaty-meatr and newy<meaty+meatr:
  21.             points+=1       #on gagne un point
  22.             meatgen()       #on génère une nouvelle boulette de bouffe
  23.             growsnake()     #on grossi le serpent
  24.     if newy+t>meaty-meatr and newy+t<meaty+meatr:
  25.         if newx>meatx-meatr and newx<meatx+meatr:
  26.             points+=1       #on gagne un point
  27.             meatgen()       #on génère une nouvelle boulette de bouffe
  28.             growsnake()     #on grossit le serpent#on grossit le serpent
  29.     displayPoints.configure(text= "Points = " + str(points))
  30.    
  31.     #si le serpent se recoupe, on perd
  32.     for u in range(h-1):
  33.         old=snake[u]    #old est la liste contenant les coordonnées d'un carré autre que celui de tête
  34.         oldx=old[1]     #coordonnée x du carré
  35.         oldy=old[2]     #coordonnée y du carré
  36.         if newx>=oldx and newx<=oldx+t and newy>=oldy and newy<=oldy+t:
  37.             loose()
  38.    
  39.     #si on sort du cadre on a perdu
  40.     if newx<0 or newy<0 or newx>canx-t or newy>cany-t:
  41.         loose()
  42.    
  43.     can.coords(c, newx, newy, newx+t, newy+t)   #on déplace
  44.    
  45.     del(snake[0])
  46.    
  47.     snake.append([c, newx, newy])       #nouvelle tête
  48.    
  49.     if flag>0:
  50.         fen.after(80, move)        #boucler après 50 millisecondes
  51. def meatgen():
  52.     global meatx, meaty
  53.    
  54.     meatx=randrange(meatr, canx-meatr)    #choix d'une coord au hasard sur x
  55.     meaty=randrange(meatr, cany-meatr)    #choix d'une coord au hasard sur y
  56.    
  57.     #on déplace la boulette de bouffe   
  58.     can.coords(meat, meatx-meatr, meaty-meatr, meatx+meatr, meaty+meatr)
  59. #fonction pour faire grandir le serpent à chaque boulette mangée   
  60. def growsnake():
  61.     global snake
  62.     h=len(snake)-1      #on prend l'indice de la tête dans la liste
  63.     head=snake[h]       #on prend les coords de la tête
  64.     newx = head[1]+dx*t
  65.     newy = head[2]+dy*t
  66.     carre=can.create_rectangle(newx, newy, newx+t, newy+t, fill='green')
  67.     snake.append([carre, newx, newy])
  68. def loose():
  69.     stop_it()
  70.     can.create_text(canx/2, 20, anchor=CENTER, text='Perdu !!!', fill='red', font='Arial 14 bold')  #affichage d'un message dans le canvas
  71.    
  72. #Animation
  73. def stop_it():
  74.     "arrêt de l'animation"
  75.     global flag
  76.     flag=0
  77. def start_it():
  78.     "démarrage de l'animation"
  79.     global flag, points
  80.     if flag==0:     #pour ne lancer qu'une seule boucle
  81.         points=0
  82.         flag=1
  83.         move()   
  84. #gestionnaire d'évènements
  85. def depl_gauche(event=None):
  86.     global dx, dy
  87.     dx, dy = -1, 0
  88. def depl_droite(event=None):
  89.     global dx, dy
  90.     dx, dy = 1, 0
  91.    
  92. def depl_haut(event=None):
  93.     global dx, dy
  94.     dx, dy = 0, -1
  95.    
  96. def depl_bas(event=None):
  97.     global dx, dy
  98.     dx, dy = 0, 1
  99. #Variables   
  100. x, y= 50, 50        #coordonnées initiales du serpent
  101. t=15                #taille d'un coté de carré du serpent
  102. snake=[]            #liste avec les coordonnées du serpent
  103. flag=0
  104. canx, cany = 400, 400   #dimensions du canvas
  105. dx, dy = 1, 0       #sens de déplacement
  106. meatx, meaty, meatr = 10, 10, 10   #coords et rayon de la bouffe
  107. points=0
  108. #widget principal
  109. fen=Tk()
  110. fen.title("exercice d'animation avec tkinter" )
  111. #widgets esclaves
  112. can= Canvas(fen, bg='dark grey', height=canx, width=cany)
  113. can.grid(row=0, columnspan=3)
  114. #création du serpent
  115. for i in range(4):          #on crée un serpent de 4 carré de long
  116.     carre=can.create_rectangle(x, y, x+t, y+t, fill='green')
  117.     snake.append([carre, x, y])
  118.     x=x+t
  119. #première bouffe
  120. meat=can.create_oval(meatx-meatr, meaty-meatr, meatx+meatr, meaty+meatr, fill='red')
  121. meatgen()
  122. Button(fen, text='quitter', command=fen.quit).grid(row=2, column=2)
  123. bou2= Button(fen, text='Play', width=8, command=start_it)
  124. bou2.grid(row=2, column=1)
  125. bou3= Button(fen, text='Stop', width=8, command=stop_it)
  126. bou3.grid(row=2, column=0)
  127. #Boutons de déplacement, associés aux touches fléchées du clavier
  128. fen.bind("<Left>", depl_gauche)
  129. fen.bind("<Right>", depl_droite)
  130. fen.bind("<Up>", depl_haut)
  131. fen.bind("<Down>", depl_bas)
  132. #affichage perdu
  133. displayPoints = Label(fen)
  134. displayPoints.grid(row=1, columnspan=3)
  135. #démarrage du programme
  136. fen.mainloop()


 
Qu'est-ce qui ne va pas? (j'ai eu le même genre de problème pour faire manger les boules au serpent et j'ai écrit le code que je trouve bancal ligne 20 à 30)


---------------
Des piafs en photo
Reply

Marsh Posté le 07-04-2011 à 12:15:01    

Bonjour,
 
C'est encore moi  :whistle: . J'ai laissé un peu de coté python ces temps-ci mais j'essaie de m'y remettre, donc j'ai encore des questions de gros n00b  :D  
 
J'en suis au chapitre 9 "manipuler des fichiers"
 
Exercice 9.2: je dois écrire un script qui trouve et affiche la phrase la plus longue dans un fichier texte à disposition.
 
J'ai écrit ça, mais ça ne m'affiche rien  :??:  
 

Code :
  1. #la phrase la plus longue
  2. #on ouvre le fichier en lecture
  3. fichier = open('coco', 'r')
  4. t, n = fichier.readlines(), 0       #t est la liste des phrases, n est le compteur
  5. while n<len(t):
  6.     max, phrase=0, ''               #on retient la longueur maxi et la phrase
  7.     if len(t[n])>max:
  8.         max = len(t[n])
  9.         phrase = t[n]
  10.     n+=1
  11.        
  12. print(phrase)
  13. fichier.close()


 
En tapant des lignes de commandes indépendamment, les différentes instructions fonctionnent mais pas ensemble dans un script.


---------------
Des piafs en photo
Reply

Marsh Posté le 07-04-2011 à 13:27:45    

Le scope de phrase est pas limité au while? Je fais pas de python justement à cause de cette convention que j’exècre sur les tabs remplaçant un scope bien explicite avec des {}, donc je sais pas comment marchent les scopes des variables en python, mais si c'est comme dans les langages usuels...
A+,

Message cité 2 fois
Message édité par gilou le 07-04-2011 à 13:29:57

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 07-04-2011 à 13:47:12    

gilou a écrit :

Le scope de phrase est pas limité au while?


non.

gilou a écrit :

Je fais pas de python justement à cause de cette convention que j’exècre sur les tabs remplaçant un scope bien explicite avec des {}


{} c'est pas un indicateur de scoping mais de blocs.

gilou a écrit :

donc je sais pas comment marchent les scopes des variables en python


Function scope.

gilou a écrit :

mais si c'est comme dans les langages usuels...


Cette phrase ne veut rien dire, ya pas deux personnes qui ont les mêmes "langages usuels".

Message cité 1 fois
Message édité par masklinn le 07-04-2011 à 13:48:53

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 07-04-2011 à 13:47:12   

Reply

Marsh Posté le 07-04-2011 à 14:12:24    

OK, c'est ce que je me demandais.
 

masklinn a écrit :


{} c'est pas un indicateur de scoping mais de blocs.

Tout a fait, mais dans de nombreux langages, une variable déclarée dans un bloc a pour scope ce bloc.
 

masklinn a écrit :


Function scope.


 

masklinn a écrit :


Cette phrase ne veut rien dire, ya pas deux personnes qui ont les mêmes "langages usuels".

A part que c'est juste ainsi dans les langages dont la syntaxe dérive du C, et donc au moins 95% du code écrit dans un cadre autre que le recherche universitaire (et le HTML/XML, si tant est qu'on considère que l'écriture de données balisées relève de la catégorie langage de programmation).
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 07-04-2011 à 15:02:31    

gilou a écrit :

A part que c'est juste ainsi dans les langages dont la syntaxe dérive du C


non, c'est pas le cas en JS par exemple.


Message édité par masklinn le 07-04-2011 à 15:02:48

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 07-04-2011 à 15:37:15    

gilou a écrit :

Le scope de phrase est pas limité au while? Je fais pas de python justement à cause de cette convention que j’exècre sur les tabs remplaçant un scope bien explicite avec des {}, donc je sais pas comment marchent les scopes des variables en python, mais si c'est comme dans les langages usuels...
A+,


 
Alors gogole pour savoir ce qu'est "scope" parce-que j'en sais rien :D  
Donc je pense que tu me demandais si ma variable "phrase" n'existait pas seulement à dans "while". Donc non, c'est juste quand on défini une fonction que, par défaut, la variable est "captive" de celle-ci (il y a peut-être d'autres cas mais je ne les ai pas encore abordés)
 
Sinon, une autre idée du pourquoi du comment ça ne fonctionne pas? Et s'il y a une méthode plus élégante (et pourquoi) je suis preneur aussi  :)


---------------
Des piafs en photo
Reply

Marsh Posté le 07-04-2011 à 15:56:21    

carrion crow a écrit :

Et s'il y a une méthode plus élégante (et pourquoi) je suis preneur aussi  :)


functools.reduce:

Code :
  1. functools.reduce(lambda current, candidate: candidate if len(candidate) > len(current) else current, phrases, '')


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 07-04-2011 à 16:37:26    

masklinn a écrit :


functools.reduce:

Code :
  1. functools.reduce(lambda current, candidate: candidate if len(candidate) > len(current) else current, phrases, '')



 
 :jap:  Par contre, je n'ai pas encore vu cette fonction dans le cours. Pour l'instant, je n'utilise que des while, if, elif, else


---------------
Des piafs en photo
Reply

Marsh Posté le 21-04-2011 à 15:53:48    

Bonjour, c'est encore moi  [:anathema]  
 
Dans l'exercice 10.14, il faut afficher les caractères ascii. Pas de soucis là dessus, mais dans le 10.15, il faut modifier le script pour afficher les caractères entre 128 et 256, et là ça me met une erreur:

Code :
  1. 129  =  Traceback (most recent call last):
  2.   File "C:\Users\Romain\exo_10.15.py", line 5, in <module>
  3.     print (i, " = ", chr(i))
  4.   File "C:\Python31\lib\encodings\cp850.py", line 19, in encode
  5.     return codecs.charmap_encode(input,self.errors,encoding_map)[0]
  6. UnicodeEncodeError: 'charmap' codec can't encode character '\x81' in position 0:
  7. character maps to <undefined>


 
Mon script:

Code :
  1. i = 128
  2. while i<=256:
  3.     print (i, " = ", chr(i))
  4.     i+=1


 
Je ne comprends pas trop pourquoi ça ne fonctionne pas. Mon script est enregistré en Utf-8


---------------
Des piafs en photo
Reply

Marsh Posté le 21-04-2011 à 16:28:36    

carrion crow a écrit :

Je ne comprends pas trop pourquoi ça ne fonctionne pas. Mon script est enregistré en Utf-8


Ce qui n'a aucun rapport avec la sortie du script, les encodages sont indépendants.
 
Apparemment ici il a décidé d'encoder ta sortie en cp850, je sais pas trop d'où il tire ça mais bon...


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 21-04-2011 à 21:03:54    

masklinn a écrit :


Ce qui n'a aucun rapport avec la sortie du script, les encodages sont indépendants.
 
Apparemment ici il a décidé d'encoder ta sortie en cp850, je sais pas trop d'où il tire ça mais bon...


 
 :jap:  
 
J'ai vu que cp850 est utilisé par la console windows (http://fr.wikipedia.org/wiki/Page_de_code_850)
 
Mais ça me met pareil avec un terminal python


---------------
Des piafs en photo
Reply

Marsh Posté le 26-05-2011 à 18:51:19    

Bonjour,
 
Encore un soucis avec un exercice. En gros, il faut faire une classe avec des méthodes :

Code :
  1. class Satellite(object):
  2.     "Simulation de satellites artificiels"
  3.    
  4.     def __init__(self, nom,masse = 100, vitesse = 0):
  5.         self.masse = masse
  6.         self.vitesse = vitesse
  7.         self.nom = nom
  8.        
  9.     def impulsion(self, force, duree):
  10.         "Pour faire varier la vitesse du satellite"
  11.         self.vitesse = self.vitesse + ((force*duree)/self.masse)
  12.        
  13.     def affiche_vitesse(self):
  14.         print("Vitesse du satellite {} : {} m/s" .format(self.nom, self.vitesse))
  15.        
  16.     def energie(self):
  17.         "Affichage de l'énergie cinétique"
  18.         return self.masse * self.vitesse**2 / 2
  19.        
  20. s1 = Satellite('Zoé', masse = 250, vitesse = 10)
  21. s1.impulsion(500, 15)
  22. s1.affiche_vitesse()
  23. print(s1.energie)
  24. s1.impulsion(500, 15)
  25. s1.affiche_vitesse()
  26. print(s1.energie())


 
Mon code est quasi le même que la solution, mais quand je le lance, il ne met :

Code :
  1. Vitesse du satellite Zoé : 40.0 m/s
  2. <bound method Satellite.energie of <__main__.Satellite object at 0x0000000002537
  3. 940>>
  4. Vitesse du satellite Zoé : 70.0 m/s
  5. 612500.0


 
Pourquoi il y a une "erreur" au milieu :??:


---------------
Des piafs en photo
Reply

Marsh Posté le 26-05-2011 à 18:59:48    

Si tu fais référence à ça :
<bound method Satellite.energie of <__main__.Satellite object at 0x0000000002537940>>
 
C'est parce que tu ne fais pas appel à la méthode :
print(s1.energie) à remplacer par print(s1.energie())
 
 
Tu as peut-être déjà fais du vb ont se genre de syntaxe est autorisé pour faire appel à une méthode ?
:)

Message cité 1 fois
Message édité par alien conspiracy le 26-05-2011 à 19:00:46
Reply

Marsh Posté le 26-05-2011 à 20:25:24    

alien conspiracy a écrit :

Si tu fais référence à ça :
<bound method Satellite.energie of <__main__.Satellite object at 0x0000000002537940>>
 
C'est parce que tu ne fais pas appel à la méthode :
print(s1.energie) à remplacer par print(s1.energie())
 
 
Tu as peut-être déjà fais du vb ont se genre de syntaxe est autorisé pour faire appel à une méthode ?
:)


 
Putai*, je suis un boulet  [:prozac]  Je me focalisais sur la dernière ligne en me disant "J'ai bien mis les parenthèses, pourquoi est-ce que ça ne fonctionne pas ?"  Sauf, que la faute était 5 lignes plus haut :whistle:  
 
Merci  :jap:


---------------
Des piafs en photo
Reply

Marsh Posté le 22-06-2011 à 23:23:32    

Bonjour,
 
Au détour d'une lien, je suis tombé sur cette vidéo et sa méthode de réduction de fraction m'a interpelé. Je me suis donc dit que j'allais faire un script pour décomposer un nombre en produit de facteurs premiers.
 
Le voici :

Code :
  1. # Script de décomposition en produit de facteurs premiers
  2. class ProduitFacteursPremiers(object):
  3.     """Théorème fondamental de l'arithmétique:
  4.     chaque entier strictement positif peut être écrit comme un produit de
  5.     nombres premiers d'une unique façon, à l'ordre près des facteurs
  6.     """
  7.     def __init__(self, nb):
  8.         self.nb = int(nb)    # int pour être sur que c'est un entier
  9.     def nombrePremier(self, n):
  10.         """Calcul du prochain nombre premier"""
  11.         n+=1
  12.         if n==3:  # on zappe 3 qui est premier et qui passerait le test qui suit
  13.             return n
  14.         while 1:
  15.             # un nombre premier est uniquement divisible par lui-même ou 1
  16.             if n%3==0 or n%2==0 or n%5==0:    # si oui pas premier
  17.                 n+=1
  18.             else:    # si premier on le renvoi
  19.                 return n
  20.     def decomp(self):
  21.         "Décomposition de nb en produit de facteurs premiers, renvoi une liste"
  22.         diviseur =2
  23.         facteur =[]    #liste pour stocker les facteurs premiers
  24.         while 1:
  25.         # on s'arrête si le nombre premier au carré est
  26.         # supérieur au nombre à tester
  27.             if self.nb<diviseur**2:
  28.                 facteur.append(int(self.nb))    # on ajoute le reste
  29.                 return facteur
  30.             elif self.nb%diviseur==0:
  31.                 self.nb = self.nb/diviseur
  32.                 facteur.append(diviseur)    #ajout d'un facteur à la liste
  33.             else:
  34.                 diviseur = self.nombrePremier(diviseur)# prochain nombre premier
  35. if __name__ == '__main__':
  36.     nb = input("Entre un nombre positif :" )
  37.     a = ProduitFacteursPremiers(nb)
  38.     liste = a.decomp()
  39.     print(liste)


 
C'est propre ? Il y a des endroits où je mérite des coups de pieds ?  :D  
 
Je vais peut-être continuer en faisant l'algorithme dont il parle dans la vidéo.
 
J'ai quasi fini le livre de Swinnen, mais j'ai du mal avec la POO, les self et l'héritage (ou les relations entre classes et méthodes plutôt), ça me perturbe. Je lis tous les tutos que je trouve qui traite de ça (enfin, j'ai commencé à lire celui du site du zéro  :sarcastic: )


---------------
Des piafs en photo
Reply

Marsh Posté le 23-06-2011 à 08:12:12    

Code :
  1. self.nb = int(nb)    # int pour être sur que c'est un entier
 

En python on ne vérifie que très rarement le type des variables, ce qui va à l'encontre de ce que l'on enseigne généralement en programmation.
Il faut pratiquer le Duck Typing, grosso modo l'idée est que l'on se fou de savoir le type de la variable du moment qu'elle présente toutes les méthodes et attributs que l'on utilise dans le code. Ca rejoint, en partie, l'idée d'interface que l'on retrouve dans d'autres langages.

 

Concrètement si je reçois ton code et que je créé, pour une raison X ou Y, une classe qui se comporte comme un entier alors le code fonctionnera avec cette classe, ce qui ne serait pas le cas si tu laisse la vérification du type.

Message cité 1 fois
Message édité par alien conspiracy le 23-06-2011 à 09:52:53
Reply

Marsh Posté le 23-06-2011 à 08:37:14    

alien conspiracy a écrit :

Code :
  1. self.nb = int(nb)    # int pour être sur que c'est un entier


 
En python on ne vérifie que très rarement le type des variables, ce qui va à l'encontre de ce que l'on enseigne généralement en programmation.  
Il faut pratiquer le Duck Typing, grosso modo l'idée et que l'on se fou de savoir le type de la variable du moment qu'elle présente toutes les méthodes et attributs que l'on utilise dans le code. Ca rejoint, en partie, l'idée d'interface que l'on retrouve dans d'autres langages.
 
Concrètement si je reçois ton code et que je créé, pour un raison X ou Y, une classe qui se comporte comme un entier alors le code fonctionnera avec cette classe, ce qui ne serait pas le cas si tu laisse la vérification du type.


 
Je suis obligé (?) de laissé le int, car input me crée un str et le code ne fonctionnerait pas avec (mon commentaire dans le code n'est pas vraiment approprié)


---------------
Des piafs en photo
Reply

Marsh Posté le 23-06-2011 à 09:41:22    

carrion crow a écrit :


 
Je suis obligé (?) de laissé le int, car input me crée un str et le code ne fonctionnerait pas avec (mon commentaire dans le code n'est pas vraiment approprié)


Effectivement mais dans ce cas la conversion de str() vers int() devrait se trouver en dehors de la classe (ie. dans le if __name__ == '__main__': ). Afin de ne pas contraindre le type que la classe peut accepter.    
 
C'est juste une bonne habitude à prendre quand on programme en python mais dans l'ensemble c'est du chipotage par rapport au but de l'exercice. :)

Message cité 1 fois
Message édité par alien conspiracy le 23-06-2011 à 09:41:43
Reply

Marsh Posté le 23-06-2011 à 09:46:02    

alien conspiracy a écrit :


Effectivement mais dans ce cas la conversion de str() vers int() devrait se trouver en dehors de la classe (ie. dans le if __name__ == '__main__': ). Afin de ne pas contraindre le type que la classe peut accepter.    
 
C'est juste une bonne habitude à prendre quand on programme en python mais dans l'ensemble c'est du chipotage par rapport au but de l'exercice. :)


 
Ok, au départ je l'avais mis dans le corps du programme, et c'est quand j'ai rajouté la classe que je me suis dit : "si je laisse le int dans if __name__ ... ça va poser problème si j'importe cette classe et que je ne me souviens pas qu'il faut lui donner du int à manger"


---------------
Des piafs en photo
Reply

Marsh Posté le 23-06-2011 à 13:14:16    

carrion crow a écrit :

Bonjour,
 
Au détour d'une lien, je suis tombé sur cette vidéo et sa méthode de réduction de fraction m'a interpelé. Je me suis donc dit que j'allais faire un script pour décomposer un nombre en produit de facteurs premiers.
 
Le voici :

Code :
  1. # Script de décomposition en produit de facteurs premiers
  2. class ProduitFacteursPremiers(object):
  3.     """Théorème fondamental de l'arithmétique:
  4.     chaque entier strictement positif peut être écrit comme un produit de
  5.     nombres premiers d'une unique façon, à l'ordre près des facteurs
  6.     """
  7.     def __init__(self, nb):
  8.         self.nb = int(nb)    # int pour être sur que c'est un entier
  9.     def nombrePremier(self, n):
  10.         """Calcul du prochain nombre premier"""
  11.         n+=1
  12.         if n==3:  # on zappe 3 qui est premier et qui passerait le test qui suit
  13.             return n
  14.         while 1:
  15.             # un nombre premier est uniquement divisible par lui-même ou 1
  16.             if n%3==0 or n%2==0 or n%5==0:    # si oui pas premier
  17.                 n+=1
  18.             else:    # si premier on le renvoi
  19.                 return n
  20.     def decomp(self):
  21.         "Décomposition de nb en produit de facteurs premiers, renvoi une liste"
  22.         diviseur =2
  23.         facteur =[]    #liste pour stocker les facteurs premiers
  24.         while 1:
  25.         # on s'arrête si le nombre premier au carré est
  26.         # supérieur au nombre à tester
  27.             if self.nb<diviseur**2:
  28.                 facteur.append(int(self.nb))    # on ajoute le reste
  29.                 return facteur
  30.             elif self.nb%diviseur==0:
  31.                 self.nb = self.nb/diviseur
  32.                 facteur.append(diviseur)    #ajout d'un facteur à la liste
  33.             else:
  34.                 diviseur = self.nombrePremier(diviseur)# prochain nombre premier
  35. if __name__ == '__main__':
  36.     nb = input("Entre un nombre positif :" )
  37.     a = ProduitFacteursPremiers(nb)
  38.     liste = a.decomp()
  39.     print(liste)


 
C'est propre ? Il y a des endroits où je mérite des coups de pieds ?  :D


1. Chuis vraiment pas persuadé de l'intérêt d'une classe pour un truc pareil
2. Ton calcul du prochain premier ne marche plus à partir de 7x7 (ou en dessous de 5) dans la mesure où les facteurs testés sont hardcodés, pourquoi ne pas implémenter un crible d'ératosthène?
3. Ne pas utiliser input, utiliser raw_input
4. les espacements autour des opérateurs & autres sont ne sont pas consistants, c'est désagréable à lire
5. nombrePremier est mal nommé
6. facteur.append(int(self.nb)) self.nb est déjà un entier, pas besoin de le re-convertir


---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 23-06-2011 à 16:40:09    

masklinn a écrit :

1. Chuis vraiment pas persuadé de l'intérêt d'une classe pour un truc pareil


C'était pour m'entrainer. Et là je suis en train d'écrire le code de la vidéo qui sert à réduire une fraction, je pense que c'est mieux d'avoir un objet qui me créer la liste. Cet objet peu peut-être me reservir plus tard pour autre chose  :??:  
 

masklinn a écrit :

2. Ton calcul du prochain premier ne marche plus à partir de 7x7 (ou en dessous de 5) dans la mesure où les facteurs testés sont hardcodés, pourquoi ne pas implémenter un crible d'ératosthène?


OK, je vais voir ça, je ne connaissais pas le crible d'èratosthène.
 

masklinn a écrit :

3. Ne pas utiliser input, utiliser raw_input


En python3, input() a remplacer raw_input non ?  
 

masklinn a écrit :

4. les espacements autour des opérateurs & autres sont ne sont pas consistants, c'est désagréable à lire


Tu veux dire "ne sont pas constants", non ? Car je ne mets pas des espaces partout pareil. J'y ferais attention à l'avenir.
 

masklinn a écrit :

5. nombrePremier est mal nommé


Ok
 

masklinn a écrit :

6. facteur.append(int(self.nb)) self.nb est déjà un entier, pas besoin de le re-convertir


C'est pour virer le .0. Il y a peut-être une méthode plus appropriée. Le .0 n'est pas bien gênant mais il me gênait  :D


---------------
Des piafs en photo
Reply

Marsh Posté le 23-06-2011 à 16:50:03    

carrion crow a écrit :

En python3, input() a remplacer raw_input non ?


Ah oui merde, j'oublie toujours que tu bosses en python 3 :D

carrion crow a écrit :


Tu veux dire "ne sont pas constants", non ? Car je ne mets pas des espaces partout pareil. J'y ferais attention à l'avenir.


Oui, me suis embrouyé avec l'anglais :o


Message édité par masklinn le 23-06-2011 à 16:50:11

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 23-06-2011 à 18:14:29    

Bon, soit je suis trop c*n, soit j'ai un énorme manque de connaissances en python (surement les deux  :o ). J'ai regardé ce qu'était le crible d'Eratosthène, et j'ai essayé de le coder sans regarder le script python fournis, ce qui m'a donné ce début :

Code :
  1. def eratosthene(limite):
  2.     """Calcule les nombres premiers entre 2 et limite"""
  3.     liste = []
  4.     for i in range(2, limite,1):
  5.         liste.append(i)
  6.     while len(liste) > 0:
  7.         L = liste des entiers de L non multiples du premier


Euh  :heink: , je fais ça comment. J'ai essayé des trucs mais voilà la catastrophe (et ça m'énerve de faire des trucs sans savoir ce que je fais  :fou: )

 

Je regarde donc l'exemple de script python. Déjà, il lui faut une ligne pour faire la liste, là où il m'en faut trois  [:mister mystere]  

Code :
  1. l = range(2, LIMIT)

(par contre, pour faire une liste, il faut mettre l = list(range(2, LIMIT)) non ?)

 

Donc après avoir tourné à chercher tous les trucs que je ne connaissais/comprenais pas (et en avoir trouvé d'autres au passage) comme filter et lambda (vu dans le livre, mais je ne m'en souvenais plus), j'ai décidé de garder mon code et de la modifier comme suit, ça fonctionne comme ça non ? :

 
Code :
  1. def prochainNombrePremier(self, n):
  2.         """Calcul du prochain nombre premier"""
  3.         n+= 1
  4.         if n == 3:  # on zappe 3 qui est premier et qui passerait le test qui suit
  5.             return n
  6.         if n == 7:    #pareil qu'au dessus
  7.             return n
  8.         while 1:
  9.             # un nombre premier est uniquement divisible par lui-même ou 1
  10.             if n%3 == 0 or n% 2== 0 or n%5 == 0 or n%7 == 0:    # si oui pas premier
  11.                 n+= 1
  12.             else:    # si premier on le renvoi
  13.                 return n
 


Sinon, dans un script sur cette page, il y a ce code que je ne comprends pas (et google ne doit pas comprendre les :: dans le champ de recherche), c'est quoi ces :: ?

Code :
  1. liste[ nombre*2 :: nombre ] = [0] * ((N // nombre) - 1)

Message cité 1 fois
Message édité par carrion crow le 23-06-2011 à 18:15:24

---------------
Des piafs en photo
Reply

Marsh Posté le 23-06-2011 à 18:25:57    

carrion crow a écrit :

Bon, soit je suis trop c*n, soit j'ai un énorme manque de connaissances en python (surement les deux  :o ). J'ai regardé ce qu'était le crible d'Eratosthène, et j'ai essayé de le coder sans regarder le script python fournis, ce qui m'a donné ce début :

Code :
  1. def eratosthene(limite):
  2.    """Calcule les nombres premiers entre 2 et limite"""
  3.    liste = []
  4.    for i in range(2, limite,1):
  5.        liste.append(i)
  6.    while len(liste) > 0:
  7.        [b]L = liste des entiers de L non multiples du premier[/b]


Euh  :heink: , je fais ça comment. J'ai essayé des trucs mais voilà la catastrophe (et ça m'énerve de faire des trucs sans savoir ce que je fais  :fou: )

 

Je regarde donc l'exemple de script python. Déjà, il lui faut une ligne pour faire la liste, là où il m'en faut trois  [:mister mystere]  

Code :
  1. l = range(2, LIMIT)

(par contre, pour faire une liste, il faut mettre l = list(range(2, LIMIT)) non ?)


Dans Python 3 oui; dans Python 2, range() renvoie une liste.

carrion crow a écrit :

Donc après avoir tourné à chercher tous les trucs que je ne connaissais/comprenais pas (et en avoir trouvé d'autres au passage) comme filter et lambda (vu dans le livre, mais je ne m'en souvenais plus), j'ai décidé de garder mon code et de la modifier comme suit, ça fonctionne comme ça non ? :

 
Code :
  1. def prochainNombrePremier(self, n):
  2.        """Calcul du prochain nombre premier"""
  3.        n+= 1
  4.        if n == 3:  # on zappe 3 qui est premier et qui passerait le test qui suit
  5.            return n
  6.        if n == 7:    #pareil qu'au dessus
  7.            return n
  8.        while 1:
  9.            # un nombre premier est uniquement divisible par lui-même ou 1
  10.            if n%3 == 0 or n% 2== 0 or n%5 == 0 or n%7 == 0:    # si oui pas premier
  11.                n+= 1
  12.            else:    # si premier on le renvoi
  13.                return n




Ça fonctionne jusqu'à 121 (11 * 11) :)

carrion crow a écrit :

Sinon, dans un script sur cette page, il y a ce code que je ne comprends pas (et google ne doit pas comprendre les :: dans le champ de recherche), c'est quoi ces :: ?

Code :
  1. liste[ nombre*2 :: nombre ] = [0] * ((N // nombre) - 1)



http://docs.python.org/dev/library [...] html#slice http://docs.python.org/dev/library [...] l#index-27

 

C'est une slice (lst[a:b:c]) avec l'élément du milieu (la limite haute) retiré

Message cité 1 fois
Message édité par masklinn le 23-06-2011 à 18:26:46

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 23-06-2011 à 18:51:44    

masklinn a écrit :


Dans Python 3 oui; dans Python 2, range() renvoie une liste.


 
 :jap:  
 

masklinn a écrit :


Ça fonctionne jusqu'à 121 (11 * 11) :)


 
ahhhhh, ça me fait chi**********. J'arrive pas à réfléchir et écrire direct un truc bien. Comment tu trouve que ça ne fonctionne que jusqu'à 11*11, il y a une formule ? (je viens de tester, effectivement après 113 (121), c'est plus bon, mais c'est un test et pas un raisonnement)
 

masklinn a écrit :


http://docs.python.org/dev/library [...] html#slice http://docs.python.org/dev/library [...] l#index-27
 
C'est une slice (lst[a:b:c]) avec l'élément du milieu (la limite haute) retiré


 
Ah merci, dans le livre, j'ai vu [start:stop] mais pas [start:stop:step] pour une liste


---------------
Des piafs en photo
Reply

Marsh Posté le 23-06-2011 à 19:33:57    

Alors, mon code devient ça :

Code :
  1. # Script de décomposition en produit de facteurs premiers
  2. class ProduitFacteursPremiers(object):
  3.     """Théorème fondamental de l'arithmétique:
  4.     chaque entier strictement positif peut être écrit comme un produit de
  5.     nombres premiers d'une unique façon, à l'ordre près des facteurs
  6.     """
  7.     def __init__(self, nb):
  8.         self.nb = int(nb)    # int pour être sur que c'est un entier
  9.         self.liste_premiers = self.eratosthene(nb)
  10.     def eratosthene(self, limite):
  11.         """Calcule les nombres premiers de 2 à limite"""
  12.         #liste des entiers de 2 à limite
  13.         liste = list(range(2, int(limite)+1))
  14.         # liste vide pour accueillir les nombres premiers
  15.         liste_premiers = []
  16.         #tant qu'il y a des éléments dans la liste
  17.         while liste:
  18.             liste_premiers.append(liste[0])    # on ajoute le premier élément
  19.             # on vire de la liste les multiples du premier élément
  20.             liste = list(filter(lambda x: x%liste[0], liste))
  21.         return liste_premiers
  22.     def decomp(self):
  23.         "Décomposition de nb en produit de facteurs premiers, renvoi une liste"
  24.         c = 0
  25.         diviseur = self.liste_premiers[c]
  26.         facteur = []    #liste pour stocker les facteurs premiers
  27.         while 1:
  28.         # on s'arrête si le nombre premier au carré est
  29.         # supérieur au nombre à tester
  30.             if self.nb < diviseur**2:
  31.                 facteur.append(int(self.nb))    # on ajoute le reste
  32.                 return facteur
  33.             elif self.nb%diviseur == 0:
  34.                 self.nb = self.nb/diviseur
  35.                 facteur.append(diviseur)    #ajout d'un facteur à la liste
  36.             else:
  37.                 c += 1
  38.                 diviseur = self.liste_premiers[c]
  39. if __name__ == '__main__':
  40.     nb = input("Entre un nombre positif :" )
  41.     a = ProduitFacteursPremiers(nb)
  42.     liste = a.decomp()
  43.     print(liste)
 

Ça fonctionne, enfin j'espère cette fois, mais ça ne me plait pas car je n'ai pas trouvé le crible d'ératosthène tout seul (je sais que je ne suis pas mathématicien  :( , mais s'il l'a trouvé tout seul, je veux aussi le trouver tout seul) et je sens que c'est d'une inélégance assez fantastique (et je ne tolèrerais uniquement du code élégant de ma part. Je veux être comme Jensen avec le "decimal print routine" qui a fait un code de 46 lignes, là où les autres hackers du MIT bloquaient à 50 (je lis "Hackers" de Steven Levy en ce moment  :) ), mais je ne suis pas un géni  :( )
J'ai encore du mal à comprendre pourquoi et où, il faut mettre self. J'ai modifié mon code sans problème (mis à part le int ligne 16), mais je mets des self sans trop savoir.

Message cité 1 fois
Message édité par carrion crow le 23-06-2011 à 19:34:08

---------------
Des piafs en photo
Reply

Marsh Posté le 23-06-2011 à 20:53:04    

carrion crow a écrit :

ahhhhh, ça me fait chi**********. J'arrive pas à réfléchir et écrire direct un truc bien. Comment tu trouve que ça ne fonctionne que jusqu'à 11*11, il y a une formule ? (je viens de tester, effectivement après 113 (121), c'est plus bon, mais c'est un test et pas un raisonnement)


Bah s'pas très compliqué, t'as une liste de premier que tu vérifies donc tous leurs multiples sont éliminés, mais comme cette liste est statique (2, 3, 5, 7) si on multiplie des premiers qui ne sont pas dans cette liste (11*11 ici) il ne peut plus les trouver.

 
carrion crow a écrit :

Ça fonctionne, enfin j'espère cette fois, mais ça ne me plait pas car je n'ai pas trouvé le crible d'ératosthène tout seul (je sais que je ne suis pas mathématicien  :( , mais s'il l'a trouvé tout seul, je veux aussi le trouver tout seul) et je sens que c'est d'une inélégance assez fantastique (et je ne tolèrerais uniquement du code élégant de ma part.


Tu n'as pas trouvé le crible tout seul, ou bien tu n'as pas trouvé comment coder un crible en python?

 

Le principe du crible est vraiment pas compliqué: tu prends une séquence d'entiers (à partir de 2) et une listes de nombres premiers (initialement vide).

 

Ensuite le processus est trivial (mais relativement coûteux, et le coût augmente au fur et à mesure que tu avances, c'est très naif comme méthode):

  • Pour chaque entier de ta séquence
  • Pour chaque premier de ta liste
  • Tu regardes si l'entier est divisible par le premier
  • Si oui, ce n'est pas un nombre premier
  • Si tu fais tous tes premiers sans en trouver un qui puisse diviser ton candidat, le candidat est un entier, tu l'ajoutes à ta liste d'entiers


En utilisant les générateurs et les bonnes fonctions des builtins et de la stdlib, ça tient en 6 lignes :)

Message cité 1 fois
Message édité par masklinn le 23-06-2011 à 20:53:19

---------------
Stick a parrot in a Call of Duty lobby, and you're gonna get a racist parrot. — Cody
Reply

Marsh Posté le 23-06-2011 à 21:24:47    

masklinn a écrit :


Bah s'pas très compliqué, t'as une liste de premier que tu vérifies donc tous leurs multiples sont éliminés, mais comme cette liste est statique (2, 3, 5, 7) si on multiplie des premiers qui ne sont pas dans cette liste (11*11 ici) il ne peut plus les trouver.
 


 

masklinn a écrit :


Tu n'as pas trouvé le crible tout seul, ou bien tu n'as pas trouvé comment coder un crible en python?
 
Le principe du crible est vraiment pas compliqué: tu prends une séquence d'entiers (à partir de 2) et une listes de nombres premiers (initialement vide).
 
Ensuite le processus est trivial (mais relativement coûteux, et le coût augmente au fur et à mesure que tu avances, c'est très naif comme méthode):

  • Pour chaque entier de ta séquence
  • Pour chaque premier de ta liste
  • Tu regardes si l'entier est divisible par le premier
  • Si oui, ce n'est pas un nombre premier
  • Si tu fais tous tes premiers sans en trouver un qui puisse diviser ton candidat, le candidat est un entier, tu l'ajoutes à ta liste d'entiers


En utilisant les générateurs et les bonnes fonctions des builtins et de la stdlib, ça tient en 6 lignes :)


 
J'ai compris le principe, mon problème c'est que je n'ai pas eut la même démarche que Ératosthène pour trouver ("découvrir" ) moi-même son crible.
 
Je viens de trouver ce que je voulais : le test de primalité. Avec ça, je pourrais refaire ma fonction prochainNombrePremier et qu'elle fonctionne  :)


---------------
Des piafs en photo
Reply

Marsh Posté le 24-06-2011 à 13:31:18    

Alors, voici le code pour réduire une fraction (j'ai virer les classes car ça m'embrouillait) :

Code :
  1. from math import sqrt
  2. def reduitFraction(fraction):
  3.     """Réduit une fraction"""
  4.     fraction = fraction.split("/" )    # transforme fraction en liste
  5.     fraction[1] = fraction[1].strip("\r" )    #vire le \r de la fin
  6.     numerateur = decomp(int(fraction[0]))
  7.     denominateur = decomp(int(fraction[1]))
  8.     new_num = 1
  9.     new_denom = 1
  10.     n = 0
  11.     d = 0
  12.     while 1:
  13.         if n >= len(numerateur)-1 or d >= len(denominateur)-1:
  14.             break
  15.         if numerateur[n] == denominateur[d]:
  16.             n += 1
  17.             d += 1
  18.         elif numerateur[n] > denominateur[d]:
  19.             new_denom = new_denom * denominateur[d]
  20.             d += 1
  21.         elif numerateur[n] < denominateur[d]:
  22.             new_num *= new_num * numerateur[d]
  23.             n += 1
  24.     while len(numerateur)-1>=n:
  25.         new_num *= numerateur[n]
  26.         n += 1
  27.     while len(denominateur)-1>=d:
  28.         new_denom *= denominateur[d]
  29.         d += 1
  30.     fractionReduite = ("{}/ {}" ).format(new_num, new_denom)
  31.     return fractionReduite
  32. def eratosthene(limite):
  33.     """Calcule les nombres premiers de 2 à limite"""
  34.         #liste des entiers de 2 à limite
  35.     liste = list(range(2, int(limite)+1))
  36.         # liste vide pour accueillir les nombres premiers
  37.     liste_premiers = []
  38.         #tant qu'il y a des éléments dans la liste
  39.     while liste:
  40.         liste_premiers.append(liste[0])    # on ajoute le premier élément
  41.             # on vire de la liste les multiples du premier élément
  42.         liste = list(filter(lambda x: x%liste[0], liste))
  43.     return liste_premiers
  44. def decomp(nb):
  45.     "Décomposition de nb en produit de facteurs premiers, renvoi une liste"
  46.     liste_premiers = eratosthene(sqrt(nb))    #liste des nombres premiers nécessaires
  47.     c = 0
  48.     diviseur = liste_premiers[c]
  49.     facteur = []    #liste pour stocker les facteurs premiers
  50.     while 1:
  51.         # on s'arrête si le nombre premier au carré est
  52.         # supérieur au nombre à tester
  53.         if nb < diviseur**2:
  54.             facteur.append(int(nb))    # on ajoute le reste
  55.             return facteur
  56.         elif nb%diviseur == 0:
  57.             nb = nb/diviseur
  58.             facteur.append(diviseur)    #ajout d'un facteur à la liste
  59.         else:
  60.             c += 1
  61.             diviseur = liste_premiers[c] #on change de nombre premier
  62. fraction = input("Entre une fraction : " )
  63. result = reduitFraction(fraction)
  64. print(result)
 

Par contre, ça ne fonctionne pas pour des grosses valeurs genre 54326452786/7423647326746, ça a l'air de tourner en boucle. J'ai isolé le problème, ça vient de mon crible d'Ératosthène, mais pourquoi ? Un truc avec la taille maxi d'un int ?
J'ai aussi constaté que sur certaines grosses valeur, ça renvoi n'importe quoi (genre 12345678/54325 renvoi 87791488/ 54325  [:tinostar] )

 

Ça existe un programme qui me renverrais toutes les étapes du déroulement du programme au fur et à mesure qu'il s’exécute ? (parce-que mettre des print() partout...)


Message édité par carrion crow le 24-06-2011 à 13:31:39

---------------
Des piafs en photo
Reply

Marsh Posté le 24-06-2011 à 13:35:48    

Reply

Marsh Posté le 24-06-2011 à 14:25:47    

Reply

Marsh Posté le 24-06-2011 à 16:59:07    

Je suis tombé sur mon problème de plus haut en cherchant à comprendre le code d'un type pour résoudre l'énigme d'algèbre de google. Je viens de me repencher dessus et malgré des dessins et des prints partout dans le code, je n'arrive pas à comprendre la permutation.
 

Code :
  1. def all_perms(str):
  2.     if len(str) <=1:
  3.         yield str
  4.     else:
  5.         for perm in all_perms(str[1:]):
  6.             for i in range(len(perm)+1):
  7.                 yield perm[:i] + str[0:1] + perm[i:]
  8. for p in all_perms(['a','b','c']):
  9.     print(p)


 
Ce que j'ai compris :
- Le if ne sert que si on envoi une liste d'un element
- yield est un return avec mémoire. Quand on rappel la fonction, on repart à partir du yield.
- on envoi une liste à all_perms
- dans le premier for, on rappel all_perms (c'est ça la récursivité ?) avec la liste amputée de son premier élément, dans cette appel, on rappel all_perms mais avec une liste d'un élément et donc le if renvoi la liste d'un élément ["c"]
-  ce qui fait :
for ["c"] in ["c"]:
    for 0 in range(2):
        yield ["c"]
    for 1 in range(2):
        yield [""]
???
 
Je comprends pas où ça va, les boucles sont imbriquées les unes dans les autres, j'arrive pas à suivre.


---------------
Des piafs en photo
Reply

Marsh Posté le 01-07-2011 à 16:53:16    

Bonjour,

 

Après avoir arrêté python quelques jours pour m'aérer la tête, je me suis dis que j'allais (essayer de) coder le célèbre jeu "Pong". Alors, j'ai réussi à faire un truc qui fonctionne  [:bodette]  mais j'ai galéré avec les self et les transmissions de variables entre fonctions/classe.

 

Il reste des soucis, genre :
- quand on ne peux pas contrôler les deux raquettes en même temps
- parfois il arrive que la balle se "coince" dans la raquette
- la balle a une trajectoire prévisible
- c'est pas très fluide

 

Et des manques :
- pas de jeux contre l'ordi (je n'ai aucune idée de comment faire une IA)
- manque de contrôles (genre commande start/pause/rejouer) ça je vois comment faire
- le bip/bip agaçant au bout de trois rebonds  :D

 

Voici mon code (attention les yeux) Si quelqu'un peut me faire une correction ou me donner quelques conseils pour l'améliorer ou pour que je fasse mieux la prochaine fois

 
Code :
  1. # Jeu Pong
  2. # Python 3
  3. from tkinter import *
  4. class Raquette(object):
  5.     """Créer un rectangle (la raquette) et inclus la méthode de déplacement
  6.     Il faut donner un parametre si on veut jouer à deux. Par défaut, le
  7.     jeu se fait contre un mur.
  8.     """
  9.     def __init__(self, boss, x, y):
  10.         self.boss = boss    # la ref de la fenêtre
  11.         #création d'une raquette
  12.         self.x = x
  13.         self.y = y
  14.         self.raq = boss.create_rectangle(self.x , self.y,
  15.                                          self.x+10, self.y+60, fill='white')
  16.         self.filet = boss.create_line(400, 0, 400, 480, fill='light grey',
  17.                                       dash=(20, 10))
  18.     def monter(self, depl):
  19.         self.y -=10
  20.         if self.y <=0:    # on contrôle que l'on ne sort pas du tableau
  21.             self.y =0
  22.         self.boss.coords(self.raq, self.x, self.y, self.x+10, self.y+60)
  23.     def descendre(self, depl):
  24.         self.y +=10
  25.         if self.y >=420:    # on contrôle que l'on ne sort pas du tableau
  26.             self.y =420
  27.         self.boss.coords(self.raq, self.x, self.y, self.x+10, self.y+60)
  28. class Balle(object):
  29.     """Créer la balle et sa méthode de déplacement"""
  30.     def __init__(self, boss, player1, player2,
  31.                  compteur, scorep1, scorep2):
  32.         self.boss = boss    #ref de la fenêtre
  33.         self.player1 = player1
  34.         self.player2 = player2
  35.         # coordonnées initiales
  36.         self.x, self.y = 400, 240
  37.         self.rayon = 10    # rayon de la balle
  38.         # création de la balle
  39.         self.balle = boss.create_oval(self.x-self.rayon,
  40.                                       self.y-self.rayon,
  41.                                       self.x+self.rayon,
  42.                                       self.y+self.rayon, fill='white')
  43.         # déplacement initial
  44.         self.dx, self.dy = 10, 10
  45.         #compteur
  46.         self.compteur = compteur
  47.         self.scorep1 = scorep1
  48.         self.scorep2 = scorep2
  49.     def move(self):
  50.         "Déplacement de la balle"
  51.         flag =1    # pour controler l'anim'
  52.         self.x += self.dx
  53.         self.y += self.dy
  54.         # On regarde si la balle tape à gauche où à droite
  55.         if self.x <= 0:
  56.             self.x =400    # balle au centre
  57.             self.dx = -self.dx    # renvoi de l'autre côté
  58.             self.scorep2 += 1    # on ajoute un point à p2
  59.             compt = str(self.scorep1) + "   " + str(self.scorep2)
  60.             self.boss.itemconfigure (self.compteur, text=compt)
  61.         if self.x >= 800:
  62.             self.x =400
  63.             self.dx = -self.dx
  64.             self.scorep1 += 1
  65.             compt = str(self.scorep1) + "   " + str(self.scorep2)
  66.             self.boss.itemconfigure (self.compteur, text=compt)
  67.         # contrôle pour mettre fin à la partie
  68.         if self.scorep1 ==5 or self.scorep2 ==5:
  69.             flag =0
  70.             self.boss.create_text(400, 240, text="Game over", fill='white',
  71.                                   font=("Arial", "22" ))
  72.         # Contrôles pour que la balle reste dans la zone (rebonds haut et bas)
  73.         if self.y+self.rayon >=480 or self.y-self.rayon <= 0:
  74.             self.dy = -self.dy
  75.         # pour le rebond sur la raquette de player1
  76.         if self.x-self.rayon <= 30:
  77.             if self.y-self.rayon >= self.player1.y and\
  78.             self.y+self.rayon <= self.player1.y+60:
  79.                 self.dx = -self.dx
  80.         # pour le rebond sur la raquette de player2
  81.         if self.x+self.rayon >= 770:
  82.             if self.y-self.rayon >= self.player2.y and\
  83.                     self.y+self.rayon <= self.player2.y+60:
  84.                 self.dx = -self.dx
  85.         self.boss.coords(self.balle,
  86.                          self.x-self.rayon,
  87.                          self.y-self.rayon,
  88.                          self.x+self.rayon,
  89.                          self.y+self.rayon)
  90.         # Récursivité pour animer la balle
  91.         if flag == 1:
  92.             self.boss.after(40, self.move)
  93. class Application(Frame):
  94.     """Fenêtre principale de l'application"""
  95.     def __init__(self):
  96.         Frame.__init__(self)
  97.         self.master.title(">>> Pong <<<" )
  98.         self.pack()
  99.         self.jeu = Canvas(self, width =800, height =480, background ='black')
  100.         self.jeu.pack()
  101.         self.compteur = self.jeu.create_text(400, 20, text="0   0", fill='white',
  102.                                              font=("Arial", "22" ))
  103.         self.y = 210
  104.         # score des joueurs
  105.         self.scorep1 = 0
  106.         self.scorep2 = 0
  107.         player1 = Raquette(self.jeu, 20, self.y)
  108.         player2 = Raquette(self.jeu, 770, self.y)
  109.         balle = Balle(self.jeu, player1, player2,
  110.                       self.compteur, self.scorep1, self.scorep2)
  111.         # animation de la balle
  112.         balle.move()
  113.         # on guette les touches a et z pour déplacer la raquette
  114.         self.bind_all("a", player1.monter)
  115.         self.bind_all("z", player1.descendre)
  116.         self.bind_all("k", player2.monter)
  117.         self.bind_all("m", player2.descendre)
  118. if __name__ == '__main__':
  119.     Application().mainloop()


Message édité par carrion crow le 01-07-2011 à 16:54:31

---------------
Des piafs en photo
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed