Logique/structure programme

Python est le langage de prédilection du Raspberry Pi

Modérateurs : Francois, Manfraid

salade
Messages : 26
Enregistré le : dim. 19 oct. 2014 20:36

Logique/structure programme

Message par salade » mer. 20 mars 2019 16:09

Bonjour,

j'essaie de réaliser un jeu en python avec un raspberry Pi mais je bloque à un certain niveau.
C'est un jeu de réflexe : on allume une led qui s'éteint apres un laps de temps aléatoire, le joueur qui réagi le plus rapidement a l'extinction de la led en appuyant sur son bouton marque 1 point.
Le programme fonctionne bien mais je n'arrive pas à mettre en oeuvre une fonctionnalité importante : si un joueur appuie sur son bouton avant l'extinction de la led, il gagnera à coup sur car je ne sais pas comment tester l'état des boutons durant le la phase du timer aléatoire.

Que faut-il utiliser pour verifier l'état de ces boutons pendant le déroulement du timer ?
Une interruption ?

Par ailleurs, si les 2 joueurs décident de tricher en appuyant sur leur bouton respectif, le joueur A gagnera à coup sur car c'est par lui que la première boucle if commence.
De la même manière, si les 2 joueurs réagissent exactement en même temps (sans tricher), le joueur A l'emportera car c'est par lui que la première boucle if commence (ce n'est pas juste !)
Cela soulève donc un autre problème structurel à corriger.

Je ne code pas souvent mais j'aimerais passer un cap ;-)

Merci pour votre aide.

Code : Tout sélectionner

#!/usr/bin/python
# coding: utf-8
from time import sleep
import RPi.GPIO as GPIO
import sys
import os
import time
from random import uniform
def cls():
    os.system('cls' if os.name=='nt' else 'clear')
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(6, GPIO.IN, pull_up_down=GPIO.PUD_UP) #start button, pin 6
GPIO.setup(27,GPIO.OUT) # led bouton start, pin 27 
GPIO.setup(14, GPIO.IN, pull_up_down=GPIO.PUD_UP) #button A joueur A, pin 14
GPIO.setup(17,GPIO.OUT) #led joueur 1, pin 17
GPIO.setup(15, GPIO.IN, pull_up_down=GPIO.PUD_UP) #button D joueur D, pin 15
GPIO.setup(5,GPIO.OUT) #led joueur 2, pin 5
GPIO.setup(4,GPIO.OUT) #led depart, pin 14 output 
a = 0 # initialisation des scores
d = 0 # initialisation des scores
while True:
	sleep(0.3) #une pause
	button_start = GPIO.input(6) #on affecte le bouton A à la pin 6 
	if button_start == True: #si le bouton start n'est pas presse
		os.system('clear')   # on nettoie l'ecran
		print "Score A :", str(a) #on affiche le score du joueur  A
		print "Score D :", str(d) #on affiche le score du joueur  D
		print ('presser le bouton blanc pour commencer le jeu')
		GPIO.output(27,GPIO.HIGH) # on fait clignoter la led du bouton demarrer
		sleep (0.07)			  # on fait clignoter la led du bouton demarrer
		GPIO.output(27,GPIO.LOW)  # on fait clignoter la led du bouton demarrer		
	buttonA_state = GPIO.input(14)
	buttonD_state = GPIO.input(15)
	if buttonA_state == False: # on verifie que le bouton A n'est presse avant l'allumage de la led
		print('A est trop rapide') #on dit au joueur A qu'il triche
		sleep(1) #on affiche le message 1 sec.	
	if buttonD_state == False:  # on verifie que le bouton D n'est presse avant l'allumage de la led
		print('D est trop rapide') #on dit au joueur D qu'il triche
		sleep(1) #on affiche le message 1 sec.	 	
	if button_start == False: # Quand on presse le bouton 			
		GPIO.output(4,GPIO.HIGH) #on allume la led
		sleep(uniform(3, 5)) #on demarre le timer aleatoire
#test des 2 boutons ici 		
		GPIO.output(4,GPIO.LOW) #on eteint la led
		print ('On attends la reaction des joueurs') #pour savoir ou on en est si peronne n'a reagi
		while True: #on demarre une boucle sans fin 
			buttonA_state = GPIO.input(14) # on affecte le bouton A à la pin 14  
			buttonD_state = GPIO.input(15) # on affecte le bouton D à la pin 15
			if buttonA_state == False: 	# Joueur A vainqueur 
				a = a + 1 					 #on ajoute 1 au score du joueur A
				print('A est vainqueur !')        #on affiche que le joueur A est vainqueur            
				x = 1                             #on fait clignoter 5 fois le bouton du vainqueur
				while x < 5:                      #on fait clignoter 5 fois le bouton du vainqueur
					GPIO.output(17,GPIO.HIGH)     #on fait clignoter 5 fois le bouton du vainqueur
					sleep (0.07)                  #on fait clignoter 5 fois le bouton du vainqueur
					GPIO.output(17,GPIO.LOW)      #on fait clignoter 5 fois le bouton du vainqueur       
					sleep (0.07)                  #on fait clignoter 5 fois le bouton du vainqueur
					x = x + 1                     #on fait clignoter 5 fois le bouton du vainqueur
				break
			if buttonD_state == False: 	#Joueur D vainqueur
				d = d + 1 					 #on ajoute 1 au score du joueur D
				print('D est vainqueur !')      #on affiche que le joueur A est vainqueur 
				x = 1								#on fait clignoter 5 fois le bouton du vainqueur
				while x < 5:                    	#on fait clignoter 5 fois le bouton du vainqueur
					GPIO.output(5,GPIO.HIGH)    	#on fait clignoter 5 fois le bouton du vainqueur
					sleep (0.07)                	#on fait clignoter 5 fois le bouton du vainqueur
					GPIO.output(5,GPIO.LOW)     	#on fait clignoter 5 fois le bouton du vainqueur
					sleep (0.07)                	#on fait clignoter 5 fois le bouton du vainqueur
					x = x + 1                  		#on fait clignoter 5 fois le bouton du vainqueur  
				break

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: Logique/structure programme

Message par Bud Spencer » ven. 22 mars 2019 10:35

salade a écrit :
mer. 20 mars 2019 16:09
Je ne code pas souvent mais j'aimerais passer un cap ;-)
Pour ça, il faut oublier tout ce que tu crois savoir et tu dois apprendre comment on DOIT utiliser un langage structuré (quel qu’il soit).

Cette méthode que tu as utilisé et qui consiste à enfermer des successions d’évaluation dans des boucles sans fin non contrôlées ne te mènera a rien et c’est la pire façon de faire (et malheureusement la plus répandue pour ce qui est des exemples pour le PI). Si tu regardes bien ton code, la moitié des instructions que tu as saisie servent à faire clignoter des leds. Une procédure unique à laquelle tu passerais en paramètre le n° de la led et le nombre de blink désiré suffirait. Idem pour l’action de désignation du gagnant. Tu réécrits 2 fois la même chose alors qu’une seule procédure à laquelle tu passerais le gagnant suffirait aussi. Chacun de tes joueurs est défini par plusieurs propriétés (sa led, son score, son bouton ….), c’est très largement suffisant pour les définir en tant que structure ou objet plutôt qu’en variables isolées (que tu redéclares plusieurs fois pour rien …). Ainsi tu pourrais aussi bien avoir 2 ou 1000 joueurs simultanés avec exactement le même code (en supposant que tu trouves suffisamment de GPIO pour tout le monde :lol: …)

Comme tu t’y prend tu ne pourras pas surveiller d’éventuels appuis pendant ce que tu appels le timer. Tout simplement parce que ce n’est justement pas un timer mais un simple sleep qui met le programme en attente pour une durée aléatoire. Pour lever ce sommeil avant la fin, il faut initialiser et être abonné à des events (évènements) avant l’instruction sleep. Le module GPIO te permet de faire ca avec les fonctions add_event_detect() et add_event_callback() .

Dans ta règle du jeu, il faut gérer le fait qu’un joueurs appuis avant le départ. Dans ce cas, tu pourrais soit lui retirer un point directement ou lui mettre un avertissement qui lui supprimerait à la prochaine triche et pourquoi pas l’éliminer à la troisième triche successive. Ça, cela fait partie de la réflexion que tu dois avoir AVANT de commencer ton programme. Pour ça, il faut faire la synthèse de tous les cas d’interaction possible de facon à tous les gérer.

Autre chose : perd définitivement cette habitude de vouloir commenter chacune des lignes de ton code, ça ne sert absolument à rien et ça le rend complétement illisible.
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

salade
Messages : 26
Enregistré le : dim. 19 oct. 2014 20:36

Re: Logique/structure programme

Message par salade » mer. 27 mars 2019 16:01

Bonjour et merci pour la réponse,
salade a écrit :
mer. 20 mars 2019 16:09
Je ne code pas souvent mais j'aimerais passer un cap ;-)
Bud Spencer a écrit :
ven. 22 mars 2019 10:35
Pour ça, il faut oublier tout ce que tu crois savoir et tu dois apprendre comment on DOIT utiliser un langage structuré (quel qu’il soit).
ça tomble plutôt bien car je ne sais pas grand chose, ou suffisament pour mal commencer et me retrouver rapidement dans l'impasse.
Bud Spencer a écrit :
ven. 22 mars 2019 10:35
Si tu regardes bien ton code, la moitié des instructions que tu as saisie servent à faire clignoter des leds. Une procédure unique à laquelle tu passerais en paramètre le n° de la led et le nombre de blink désiré suffirait.
Voilà, c'est la petite explication que j'attendais !
Je m'exécute et ça fonctionne parfaitement :

Code : Tout sélectionner

#blink sequence
def blink(pin_number,blink_repeat,blink_delay):
    for i in range(0,blink_repeat):
	GPIO.output(pin_number,GPIO.HIGH)
        sleep (blink_delay)
	GPIO.output(pin_number,GPIO.LOW)
        sleep (blink_delay)
que j'appelle ensuite la procedure ainsi :

Code : Tout sélectionner

blink(5,5,0.1)
Bud Spencer a écrit :
ven. 22 mars 2019 10:35
Comme tu t’y prend tu ne pourras pas surveiller d’éventuels appuis pendant ce que tu appels le timer. Tout simplement parce que ce n’est justement pas un timer mais un simple sleep qui met le programme en attente pour une durée aléatoire. Pour lever ce sommeil avant la fin, il faut initialiser et être abonné à des events (évènements) avant l’instruction sleep.
On m'a glissé à l'oreille que je pouvais décomposer mon sleep tout en vérifiant que les joueurs ne trichaient pas en appuyant sur les boutons, j'ai donc écris une procédure qui "semble" fonctionnelle mais qui va certainement m'attirer les foudres de Bud :

Code : Tout sélectionner

#timer 
def timer():
	global x
	x = 0
	while x < signal_off_delay:
		x = x + 0.1
		sleep(x)
		global A, B
		player_A_button = GPIO.input(14)
		if player_A_button == False: 	# if button A pressed
			print "Player A is cheating" 
			A = A - 1 
			print A
		player_B_button = GPIO.input(15)	
		if player_B_button == False: 	# if button B pressed
			print "Player B is cheating"
			B = B - 1
que j'appelle ainsi :

Code : Tout sélectionner

signal_off_delay = uniform(0,2)
timer()
J'ai ensuite écrit une autre procedure pour déterminer le gagnant mais peut-être devrais-je écrire une fonction (qui retournerait le gagnant en paramètre).
Bud à mainte fois raison car quand j'essaie d'agencer/imbriquer toutes ces procedures je me perds lamentablement dans mes propres boucles (j'ose plus mettre le code de peur de me faire retourner ;-)
Je vais creuser les fonctions add_event_detect() et add_event_callback() et reviendrais vers vous quand j'aurais eu le temps de potasser/experimenter.

Cordialement,

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: Logique/structure programme

Message par Bud Spencer » mer. 27 mars 2019 21:41

salade a écrit :
mer. 27 mars 2019 16:01
...une procédure qui "semble" fonctionnelle mais qui va certainement m'attirer les foudres de Bud :
Rassures toi, je ne t'engueule pas, ce sont juste des conseils pour t'aider à avancer un peu :lol:

La procédure blink démontre que tu as fait un pas en avant et c’est un bon exemple. Plus besoin d’écrire tout un tas d’instructions à chaque fois que tu voudras faire clignoter une led, il suffira juste d’appeler ta procédure en lui passant les paramètres voulus.

Le principe est le meme pour ton timer. Ici, il ne sagit pas d’une boucle infernale puisque nombre d’itération est conditionné. Là où ça coince c’est au niveau du code qui est dedans … Déjà, Il faut absolument que tu te documentes sur les bases fondamentales de la programmation en ce qui concerne la declaration et la portée des variables.


global x : pourquoi global ?
global A, B : pourquoi global ? Si elles ont besoin de l’etre pour par exemple comptabilisé le nombre de triche des joueurs sur toutes la partie, elles sont alors très mal nommées et auraient dut etre définies comme global bien avant de les utiliser dans le timer et en tout cas, surtout pas à l’interieur d'une boucle.
player_X_button = GPIO.input(xx) : tu vas déclarer les boutons de chaque joueur combien de fois dans ton programme ? Ça, ça pourrait etre des variables déclarées et définies comme global dès le début de ton programme puisque que tu vas les utiliser partout. Là aussi, tu redéfinis ces variables à chaque tours de boucle alors que leur valeur ne change pas.

Le timer par lui-même est faux. Explication :

Premier tours de boucle, x est = 0
x = x + 0.1
sleep(x) <- donc sleep pendant 0.1 seconde : sleep total de la boucle 0.1 sec.

Seconde tours de boucle, x est = 0.1
x = x + 0.1
sleep(x) <- donc sleep pendant 0.2 seconde : sleep total de la boucle 0.3 sec.

troisième tours de boucle, x est = 0.2
x = x + 0.1
sleep(x) <- donc sleep pendant 0.3 seconde : sleep total de la boucle 0.6 sec.

Ect ….

Tu incrémentes ta valeur x à chaque tour, c’est bien, mais dans cas, il ne faut pas utiliser x comme valeur de sommeil. Il aurait été plus juste d’ecrire
x = x +0.1
sleep(0.1)

Meme remarque que dans mon post précédent, imagine que tu veuilles pouvoir avoir beaucoup plus de joueurs simultanés … le code de ton timer ne tiens plus. C’est encore un peu tôt pour aborder ce genre de truc, mais tu verras que tu y arriveras très vite …

;)
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

salade
Messages : 26
Enregistré le : dim. 19 oct. 2014 20:36

Re: Logique/structure programme

Message par salade » ven. 29 mars 2019 18:43

Bonjour,

Tout d'abord merci Bud pour tes conseils.

J'ai enfin réussi à pondre un oeuf (c'est bientôt Pâques), non sans quelques noeuds au cerveau, je dirais que plus j'avance plus je me noie, j'ai parfois l'impression que même les concepts des blocs et des boucles m'échappent.
Je fais beaucoup d'erreurs d'étourderies (la gestion du timer en est un bel exemple, ce n'est malheureusement pas la seule).
Les variables me posent problème : elles sont ignorées si déclarées avant la boucle while, global ou pas, c'est pourquoi je les répète.
c'est le cas pour chaque vérification de l'état des boutons. Par exemple "if button_start == True:" est sans effet si je ne mets pas "button_start = GPIO.input(6)" directement au dessus.
Cela fonctionne en revanche pour les scores : "print "Score du joueur A =", score_A" alors que je déclare ces variables en début de script.
A ce niveau là je ne suis plus étanche, je doute des boucles, du câblage, je câble même un autre bouton pour voir, et puis pour enfoncer le clou, comme j'édite le script via notepad++ sous Windows en SFTP je me retrouve avec des fins de lignes pas catholiques, et si c'était la version de Python, ou la dernière mise à jour ? bref, c'est sport, mais c'est vendredi, et vendredi on est haaappy :D

J'essaie d'expliquer ici ce que je voudrais faire, de manière séquentielle et logique (enfin, selon moi):

1 - tant que l'utilisateur n'a pas appuyé sur le bouton start il clignote
2 - si le bouton démarrer est pressé alors :
2.1on allume la led
2.2 on lance le timer
3 - quand le timer est terminé
3.1 on vérifie l'état des boutons A et B pour connaître le vainqueur
3.2 on affecte le score

J'explique mes tentatives infructueuses:

1 - en première approche je tente une boucle while :
tant que le button_start n'est pas pressé:
je clignote
je t'invite à démarrer le jeu
Je me dis c'est bien ça mais comment je passe à l'étape 2 avec tout ça ?
Je transforme donc le while en if mais au final je me retrouve vite coincé dans cette logique et j'en reviens toujours aux boucles infernales.

Donc, question : Est-il possible/censé de réaliser ce bout de code en utilisant uniquement des fonctions, une pour le "timer/triche" et une pour déterminer le gagnant avec un retour en sortie de fonction, style gagnant = A ou B. ?
J'ai zieuté les add_event_detect() et add_event_callback(), mais il faut que je plonge et j'ai l'impression que l'eau est froide, et trouble :roll:

Le code limité mais néanmoins fonctionnel ci-dessous. Pour la gestion des scores : un point est retranché à chaque pression avant l'extinction de la led, ça peut faire très mal pour celui qui à la main lourde, faut pas tricher, un point c'est tout ! et puis pour être honnête je ne sais pas (encore) comment faire, mais j'imagine qu'il y a multe solutions.

Code : Tout sélectionner

#!/usr/bin/python
# coding: utf-8
from time import sleep
import RPi.GPIO as GPIO
import sys
import os
import time
from random import uniform
def cls():
    os.system('cls' if os.name=='nt' else 'clear')
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
#start button
GPIO.setup(6, GPIO.IN, pull_up_down=GPIO.PUD_UP) 
GPIO.setup(27,GPIO.OUT) 
#start led  
GPIO.setup(4,GPIO.OUT)  
#joueur A
GPIO.setup(14, GPIO.IN, pull_up_down=GPIO.PUD_UP) #button A joueur A, pin 14
GPIO.setup(17,GPIO.OUT) #led joueur 1, pin 17
#joueur B
GPIO.setup(15, GPIO.IN, pull_up_down=GPIO.PUD_UP) #button D joueur D, pin 15
GPIO.setup(5,GPIO.OUT) #led joueur 2, pin 5
#scores
score_A = 0 
score_B = 0 
#blink sequence
def blink(pin_number,blink_number,blink_delay):
	for i in range(0,blink_number):
		GPIO.output(pin_number,GPIO.HIGH)
		sleep (blink_delay)
		GPIO.output(pin_number,GPIO.LOW)
		sleep (blink_delay)
while True:
	button_start = GPIO.input(6)
	if button_start == True: #True => button NOT pressed due to PUD_UP
		os.system('clear')   
		print ""
		print "======================"
		print "Score du joueur A =", score_A		
		print "Score du joueur B =", score_B
		print "======================"
		print ""
		print ('Presser le bouton blanc pour commencer le jeu')
		print ""
		blink(27,1,0.07) 	
	if button_start == False: #False => if button pressed  			
		GPIO.output(4,GPIO.HIGH) 
		signal_delay_off = uniform(0,1)
		x = 0
		while x < signal_delay_off:
			x = x + 0.1
			sleep(0.1)
			player_A_button = GPIO.input(14)
			player_B_button = GPIO.input(15)
			if player_A_button == False: 
				print "Player A is cheating" 
				score_A = score_A - 1 
				print score_A
			if player_B_button == False: 
					print "Player B is cheating"
					score_B = score_B - 1 
					print score_B
		GPIO.output(4,GPIO.LOW) 
		print ('On attends la reaction des joueurs endormis')
		while True: 
			player_A_button = GPIO.input(14)   
			player_B_button = GPIO.input(15) 
			if player_A_button == False: 	
				score_A = score_A + 1 					
				print('A est vainqueur !')               
				blink(17,5,0.07)
				break
			if player_B_button == False: 	
				score_B = score_B + 1 					 
				print('B est vainqueur !')      
				blink(5,5,0.07)                 		
				break
GPIO.cleanup()
PS : le petit "Lab" que j'ai réalisé pour faire mumuse avec le Pi, à base d'acrylique translucide de 8 mm d'épaisseur, découpé au sabre laser.
PiLab_01.jpg
PiLab_01.jpg (359.25 Kio) Vu 6294 fois
PiLab_02.jpg
PiLab_02.jpg (288.14 Kio) Vu 6294 fois

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: Logique/structure programme

Message par Bud Spencer » dim. 31 mars 2019 20:48

Sympa le PiLab :D

Pour le reste ce n’est pas gagné … Tiens, kado (attention au n° de gpio à redéfinir dans la proc main suivant ton PiLab):

Code : Tout sélectionner


#!/usr/bin/python
# coding: utf-8
from time import sleep
from random import uniform
import RPi.GPIO as GPIO
import sys
import os

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

class Joueur:

    def __init__(self, nom,bouton):
        self._nom = nom
        self._bouton = bouton
        self._score = 0
        self._triche = 0

        GPIO.setup(bouton, GPIO.IN, pull_up_down=GPIO.PUD_UP) 

    def get_nom(self) : return self._nom
    
    def get_bouton(self) : return self._bouton   
    
    def set_score(self,value): self._score = value
    def get_score(self):  return self._score
    
    def set_triche(self,value): self._triche = value
    def get_triche(self):  return self._triche

    nom = property (get_nom)
    bouton = property (get_bouton)
    score = property (get_score,set_score)
    triche = property (get_triche,set_triche)
     

class Partie:
    
    def __init__(self,bouton_start,led,joueurs):
        self._bouton_start = bouton_start
        self._led = led
        self._joueurs = joueurs
        self._round = 1

        GPIO.setup(self._bouton_start, GPIO.IN, pull_up_down=GPIO.PUD_UP) 
        GPIO.setup(self._led,GPIO.OUT)

    def start(self):
        c = self._round
        self.scores()
        self.wait_start()
        for j in self._joueurs:
            GPIO.add_event_detect(j.bouton, GPIO.FALLING, callback=self.joueur_event, bouncetime=100)
        t = 0
        tt = uniform(2.,10.)
        while self._round == c: 
            t += 0.1
            GPIO.output(self._led, t <= tt)
            sleep(0.1)
        self.start()

    def scores(self):
        os.system('clear')
        print ("Round " + str(self._round))
        for j in self._joueurs:
            print (j.nom + "  Score:" + str(j.score) + "  Triche:" +  str(j.triche))

    def wait_start(self):
        print ("\r\nAppuyer sur start pour demarrer le timer")
        while GPIO.input(self._bouton_start):            
            GPIO.output(self._led, not GPIO.input(self._led))
            sleep(0.25)            
        self.scores()
        GPIO.output(self._led,True)

    def joueur_event(self,input):
        res = GPIO.input(self._led)
        self._round += 1
        for j in self._joueurs:
            GPIO.remove_event_detect(j.bouton)
        for j in self._joueurs:
            if res and input == j.bouton: 
                j.triche += 1
                break
            elif not res and input == j.bouton: 
                j.score += 1
                break

def main(): 

    gpio_bouton_joueur_a = 14
    gpio_bouton_joueur_b = 17
    gpio_bouton_start = 22
    gpio_led = 18
    
    Joueurs = [] 
    
    Joueurs.append(Joueur("Bud Spencer",gpio_bouton_joueur_a))
    Joueurs.append(Joueur("Terence Hill",gpio_bouton_joueur_b))
    partie = Partie(gpio_bouton_start,gpio_led,Joueurs);

    try:
        partie.start()
    except KeyboardInterrupt:
        pass

    GPIO.cleanup() 
   
if __name__ == '__main__':
    main()    


Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

salade
Messages : 26
Enregistré le : dim. 19 oct. 2014 20:36

Re: Logique/structure programme

Message par salade » lun. 1 avr. 2019 17:06

Tout fonctionne bien du premier coup, chapeau.
Reste plus qu'à comprendre ou tenter de comprendre comment ça fonctionne mais j'avoue que de prime abord ça ne fait pas "tilt" mais plutôt "self" :roll:
En tout cas c'est super sympa de ta part, merci.

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: Logique/structure programme

Message par Bud Spencer » mar. 2 avr. 2019 14:07

La méthode de programmation peut sembler déroutante pour un débutant puisque c’est ce que l’on appelle de la poo (programmation orientée objets). Mais je te rassure même des développeurs plus aguerris qui ne sont pas familiariser avec ce paradigme ont tendance à galérer un peu avec ça. La notion de poo est très simpliste en python comparé à des langages comme Java ou C#, mais elle est suffisante pour permettre de structurer correctement ses programmes et devient quasi indispensable pour des projets conséquents. Je ne veux pas te faire un cours complet là-dessus, mais je te recommande vivement de te pencher sur cette façon de programmer.

Si j’ai le temps ce soir ou un autre soir de la semaine, je te ferais une autre version un peu plus évoluée notamment en portant l’initialisation des évènements de bouton et les comptages de score là ou tout ça devrait être, à savoir dans la classe Joueur. Cela te permettra de comparer et de voir que ce paradigme permet une très grande flexibilité du code avec beaucoup moins de contrainte qu’avec de la programmation impérative procédurale comme tu le fais.
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

salade
Messages : 26
Enregistré le : dim. 19 oct. 2014 20:36

Re: Logique/structure programme

Message par salade » mer. 3 avr. 2019 13:07

Merci Bud, j'aurais pourtant suivant ton cours avec plaisir car j'ai de plus en plus de d'élèves qui souhaitent intégrer des Arduino ou RaspBerryPi et depuis peu micro:bit dans leurs projets afin de les rendre plus interactifs, plus attractifs. Je les comprends parfaitement et les encourage même à le faire mais ça devient vite compliqué voir très compliqué quand ils veulent sortir des sentiers battus afin de devenir vraiment créatif. Je me retrouve alors un peu (beaucoup) frustré car je ne sais pas "comment faire" alors que je me rends compte que le code nous apporte des perspectives géniales en terme de créativité. (j'enseigne le design, pas la programmation et apprendre à programmer demande du temps ...)

Le petit jeu de réaction en est l'exemple type, je pensais déjà aux évolutions possible (ce n'est pas une demande): on allume et on éteint de manière aléatoire les boutons des joueurs et à un instant donné on s'arrête (position allumé) sur le bouton d'un des joueurs, il doit réagir et presser le bouton à ce moment là. On mesurerait la rapidité des temps de réaction propre à chaque joueur, la triche, chaque joueur devrait avoir un nombre de run identique mais déclenché de manière aléatoire pour ne pas voir venir, à la fin on fait les comptes ... matériellement on peut imaginer le jeu integré à une table avec des boutons massifs ou une version de poche ...

Pour les cours j'ai été bluffé par ton tutoriel concernant les applications web dynamique
J'ai depuis longtemps l'idée d'automatiser une petite centrale hydroélectrique que j'ai fabriqué pour alimenter un chalet d'alpage isolé et là ça devient carrément possible ! c'est une autre histoire sur laquelle je reviendrai bientôt dans la section appropriée du forum.

Bud Spencer
Raspinaute
Messages : 1089
Enregistré le : lun. 15 août 2016 21:38

Re: Logique/structure programme

Message par Bud Spencer » sam. 6 avr. 2019 12:11

On peut imaginer toutes sortes de jeux qui reposent juste sur l’appui d’un bouton par les joueurs. Y compris reproduire tous ceux que l’on voit à la tv ou les concurrents n’ont que pour seul accessoire un gros champignon sur un pupitre. Tu pourrais meme reproduire un Monopoly ou un jeu de petits chevaux ou le bouton serait la modélisation du lancer de dé. Matériellement, il faut juste des boutons et des leds et te voilà partie avec des milliers de possibilités de jeux différents.

Le tuto des ‘app web dynamique’, c’était au départ une petite claque aux préjugés qui ne juraient que par des méthodes lourding et complétement obsolètes. Je pense qu’Il suffit de voir ce que j’ai réalisé sur ce tuto avec si peu de code pour etre convaincu que c’est une excellente solution pour le PI. Pour exemple, essais de modifier ton jeux pour lui ajouter une vraie interface graphique et la, crois-moi, tu vas vite en vouloir à ceux qui t’ont vendu python comme langage de prédilection.

Ici, je réponds à ta demande en python, tout simplement parce qu’elle ne porte pas sur le code lui-même mais sur la façon de le structurer. Je t’oriente vers de la poo parce que c’est une très bonne façon de le faire et que c’est un paradigme qui touche les langages les plus utilisés. Généralement cette méthode est plutôt critiquée ici, mais quand tu creuses un peu, tu te rends compte que ceux qui la critique ne la maitrise pas.

Comme promis voilà une autre version pour ton jeu. La première grosse différence, c’est que j’ai fractionné le programme en 3 fichiers. J’ai aussi ajouter un peu de broderie, comme le démarrage d’une nouvelle partie et des règles du jeu.

Le premier (jeux.py) est le programme principal (c’est lui qui doit etre démarré par une commande python jeux.py). Il ne fait qu’initialiser une partie, lui ajoute des joueurs et une règle du jeu, puis la demarre. C’est aussi dans ce fichier que l’on définit et initialise en une seule fois GPIO et on passe ensuite sa variable aux objets qui en ont besoin.

Le second (joueur.py) est le fichier qui contient l’objet joueur. Contrairement à ta façon de programmer ou les joueurs n’existent pas, ici ils existent et ont des attributs (score, nom, bouton …). Ainsi, tu peux instancier autant de joueur que tu veux sans modifier la moindre ligne de code dans le jeu lui-même. Tu noteras par exemple que dans la première version, c’est la partie qui hébergeait le code pour ajouter ou annuler les évènements des boutons des joueurs. Dans cette version, la partie appelle juste la fonction joueur[].add_bouton_event en lui passant en paramètre sa propre procédure qui sera levée quand un joueur appuiera sur un bouton. La partie ne sais pas comment joueur detecte un évènement sur la gpio de son bouton et elle n’a pas à le savoir. Idem pour supprimer l’évènement. Elle demande juste au joueur d’arrêter la détection d’évènement en appelant joueur[].rem_bouton_event . Comment l’objet joueur le fait, la partie s’en fout, l’important c’est qu’il le fasse. Si je voulais ajouter une led à chaque joueur, il suffirait d’enrichir la classe joueur et lui ajouter une procédure led_off et une led_on. Ainsi, pour allumer la led d’un joueur, le code dans la partie serait juste un truc du genre joueur[].led_on(). Dans l’absolu, on pourrait définir la gpio qui correspond à chaque led de chaque joueur et l’offusquer. La partie aurait ainsi accès aux méthodes pour allumer ou éteindre les leds des joueurs mais n’aurait pas accès au code utilisé pour le faire et ne connaitrait meme pas la gpio utilisé puisque tout ça ne la regarde pas. C’est la base meme de la poo. On appelle ce concept ‘encapsulation’ et c’est valable aussi bien pour les données que pour les fonctions de l’objet.

Le troisième fichier est le jeu lui-même (fastman.py). C’est cet objet qui exécute la partie. Pour le fun, j’ai ajouté 2 règles du jeu différent ou la méthode de comptabilisation des scores diffère. La notion d’encapsulation est très explicite ici. Quand un joueur réagi sur son bouton, c’est la fonction regle.comptage qui est appelée. La partie ne sait pas comment sont comptabilisés les points et s’en fout. C’est la règle du jeu qui gère ça. Idem pour la désignation du gagnant ou du perdant.

Voilà, Tout est dans le zip et tu as de quoi t’amuser. Si tu as d’autres boutons de dispo sur ton super PiLAb, tu peux ajouter un troisième, un quatrième …. Joueur à la partie et changer de règle du jeu en modifiant juste la ligne Partie.set_regle(fastman.regle…). Tout ça dans le code du programme principal jeux.py et sans rien toucher d’autre.


Note que tout ca est purement didactique donc n'en profites pas pour passer tes journées à jouer a FastMan :lol: ;)

PS : Pour le fun aussi, j’ai durcie un peu la syntaxe par endroit. Tu vas me dire que ce n’est pas très sympa de ma part pour du code qui s’adresse à un débutant, mais tu vas voir que si tu prends le temps d’analyser chacune des instructions, c’est très instructif et tu vas apprendre beaucoup de chose. Au besoin, s’il y a des trucs que vraiment tu n’arrives pas à saisir, n’hésite pas à demander.
Fichiers joints
jeu_salade.zip
(2.53 Kio) Téléchargé 196 fois
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).

Répondre

Retourner vers « Python »