Optimiser 4 "if" dansune boucle

Signaler
Messages postés
218
Date d'inscription
dimanche 1 mai 2005
Statut
Membre
Dernière intervention
15 novembre 2009
-
 cs_caramelmou -
Bonjour, voila jaurai voulu savoire si c pas possible d'optimiser ce code pour reduire le nombre de "if" ? je suis sur que sa doit etre possible lol, jai essaye une autre boucle dans la boucle mais sa change rien etant donner quil va faire 4 fois la boucle et donc 4 fois le test "if"...

Bon je suis consciente que je viens pas ici pour me faire servire sur un plateau le nouveau code ! sa minteresserai de voire les possibilitées ou si il ya dautre moyen de pouvoire optimiser ca :

For T = 1 To 50

Rem Haut ( = 1 )
If JMove(T) = 1 Then
Joueur(T).Top = Joueur(T).Top - JMoveSpeed(T) If Joueur(T).Top <JTop(T) Then JMove(T) 0: Joueur(T).Top = JTop(T)
End If

Rem Bas ( = 2 )
If JMove(T) = 2 Then
Joueur(T).Top = Joueur(T).Top + JMoveSpeed(T) If Joueur(T).Top >JTop(T) Then JMove(T) 0: Joueur(T).Top = JTop(T)
End If

Rem Gauche ( = 3 )
If JMove(T) = 3 Then
Joueur(T).Left = Joueur(T).Left - JMoveSpeed(T) If Joueur(T).Left <JLeft(T) Then JMove(T) 0: Joueur(T).Left = JLeft(T)
End If

Rem Droite ( = 4 )
If JMove(T) = 4 Then
Joueur(T).Left = Joueur(T).Left + JMoveSpeed(T) If Joueur(T).Left >JLeft(T) Then JMove(T) 0: Joueur(T).Left = JLeft(T)
End If

Next T

Merci! kakenette

31 réponses

Messages postés
1263
Date d'inscription
mardi 11 novembre 2003
Statut
Membre
Dernière intervention
24 juillet 2013
6
Salut kakenette

Essaie ceci et dis-moi si cela te convient

For T = 1 To 50
Select case JMove(T)
case 1 ' Haut
Joueur(T).Top = Joueur(T).Top - JMoveSpeed(T) If Joueur(T).Top <JTop(T) Then JMove(T) 0: Joueur(T).Top = JTop(T)
case 2 ' Bas
Joueur(T).Top = Joueur(T).Top + JMoveSpeed(T) If Joueur(T).Top >JTop(T) Then JMove(T) 0: Joueur(T).Top = JTop(T)
case 3 ' Gauche
Joueur(T).Left = Joueur(T).Left - JMoveSpeed(T) If Joueur(T).Left <JLeft(T) Then JMove(T) 0: Joueur(T).Left = JLeft(T)
case 4 ' Droite
Joueur(T).Left = Joueur(T).Left + JMoveSpeed(T) If Joueur(T).Left >JLeft(T) Then JMove(T) 0: Joueur(T).Left = JLeft(T)
End Select

Next T

GRENIER Alain
Messages postés
218
Date d'inscription
dimanche 1 mai 2005
Statut
Membre
Dernière intervention
15 novembre 2009
1
c se que javais pensée faire mais on ma dit que sa va pas changer le problem car les case il va les faire 1 par 1 comme meme

kakenette
Messages postés
1263
Date d'inscription
mardi 11 novembre 2003
Statut
Membre
Dernière intervention
24 juillet 2013
6
Salut Kakenette

Avec les 4 If le programme va les tester un par un jusqu'à trouver le bon bloc à traiter
Avec select case le programme va directement au bon bloc à traiter ans les tester un par un

Dans le second cas tu gagnes du temps
GRENIER Alain
Messages postés
1263
Date d'inscription
mardi 11 novembre 2003
Statut
Membre
Dernière intervention
24 juillet 2013
6
Salut Kakenette

Faute de frappe : sans les tester un par un

Avec les 4 If le programme va les tester un par un jusqu'à trouver le bon bloc à traiter
Avec select case le programme va directement au bon bloc à traiter sans les tester un par un

Dans le second cas tu gagnes du temps

GRENIER Alain
Messages postés
218
Date d'inscription
dimanche 1 mai 2005
Statut
Membre
Dernière intervention
15 novembre 2009
1
na jai un amis "BurNews" il dit que sa les test un par un car il dit que le compilateur n'est pas devaint enfin voila en attendant jutilise ta solution, celle que je voulais faire.

mais je suis sur que je peut enlever le select case et les if en treiton direcement la valeur de JMove(T)

kakenette
Messages postés
1263
Date d'inscription
mardi 11 novembre 2003
Statut
Membre
Dernière intervention
24 juillet 2013
6
Brunews a raison : dans les 2 cas on les teste un par un et je reconnais m'être trompé
Désolé

GRENIER Alain
Messages postés
1488
Date d'inscription
mercredi 5 février 2003
Statut
Membre
Dernière intervention
3 décembre 2007
24
Dis donc, toi tu sais choisir tes amis !!! Si BruNews le dit c'est que c'est vrai et on se doit donc de s'incliner.

Cependant, je pense quand même qu'un Select Case reste plus "pratique" dans ce genre de cas.
Mais je ne vois pas ce qu'ici on pourrait réduire si ce n'est le nombre de joueurs!

Enjoy

<hr size="2" width="100%">
( Si une réponse vous convient, cliquez sur le bouton "Réponse acceptée". )
Messages postés
3140
Date d'inscription
vendredi 14 mai 2004
Statut
Membre
Dernière intervention
11 mars 2019
31
Salut,

ça les teste un par un jusqu'au moment où il trouve
c'est à dire que pour le cas 1 les autres cas sont pas traités, pour le cas 2 on gagne le test 3 et 4, etc...

tout ceci pouvant être remplacé par des ElseIf.



pour utiliser JMove(T) il faudrait l'utiliser en tant qu'opérateur

Top et Left

JMove(1) --> -1 et 0

JMove(2) --> +1 et 0

JMove(1) --> 0 et -1


JMove(2) --> 0 et +1

traiter Left et Top en même temps, mais ça n'empêchera pas les
autres tests qui sont différents à chaque fois donc gain de temps ???



NB:


ce qui semble bizarre c'est qu'il n'y a pas de valeurs mini et maxi pour JTop et JLeft

If Joueur(T).Top <= JTopMin(T) Then ...

If Joueur(T).Top >= JTopMax(T) Then ...


Daniel
Messages postés
809
Date d'inscription
mercredi 11 octobre 2000
Statut
Membre
Dernière intervention
29 septembre 2010
9
Salut kakenette,

Le cas des ElseIf est pas mal vu qu'on arrete de tester des qu'on trouve un test à True.

If JMove(T) = 1 Then
' Haut ( = 1 )
ElseIf JMove(T) = 2 Then
' Bas ( = 2 )
ElseIf JMove(T) = 3 Then
'Gauche ( = 3 )
Else
' Droite ( = 4 )
End If

Mais pas top, je m'explique avec deux cas extremes :

- si JMove(T) = 1 alors on fait 1 test (nickel)
- si JMove(T) = 4 alors on aura fait 3 tests (pas top, mais mieux que tes 4)

Tout dépend de la répartition des tes valeurs. Si tu as plus de cas 4 que de cas 1 c'est pas génial.

Tu peux réduire le nombre de test en
orientant la recherche de façon dichotomique. En gros, c'est la
stratégie visant à diviser pour mieux regner.



Je te propose donc de réduire de moitié les tests effectués à chaque tour.
L'idée c'est de derterminer :

1) si on est dans le couple (droite,gauche) ou dans le couple (haut,bas)
2) puis afiner pour trouver le bon cas

Const HAUT = 1
Const BAS = 2
Const GAUCHE = 3
Const DROITE = 4

Sub test()

For T = 1 To 50
If JMove(T) < GAUCHE Then
If JMove(T) = HAUT Then
' Haut
Joueur(T).Top = Joueur(T).Top - JMoveSpeed(T) If Joueur(T).Top <JTop(T) Then JMove(T) 0: _
Joueur(T).Top = JTop(T)
Else
' Bas
Joueur(T).Top = Joueur(T).Top + JMoveSpeed(T) If Joueur(T).Top >JTop(T) Then JMove(T) 0: _
Joueur(T).Top = JTop(T)

End If

Else
If JMove(T) = GAUCHE Then
'Gauche
Joueur(T).Left = Joueur(T).Left - JMoveSpeed(T) If Joueur(T).Left <JLeft(T) Then JMove(T) 0: _
Joueur(T).Left = JLeft(T)
Else
' Droite
Joueur(T).Left = Joueur(T).Left + JMoveSpeed(T) If Joueur(T).Left >JLeft(T) Then JMove(T) 0: _
Joueur(T).Left = JLeft(T)
End If

End If
Next i

End Sub




Ainsi à chaque tour de boucle, il ne sera fait que deux tests au lieu
des quatre que l'on avait tant avec la méthode des If que celle des
Select




On passe donc dans le pire des cas



de 50 * 4 = 200 tests (If - Select)
à 50 * 3 = 150 tests (ElseIf)

à 50 * 2 = 100 tests



En stockant dans une variable en début de boucle, le contenu de JMove(T) et en utilisant cette variable dans les tests, c'est possibles que tu gagnes un peux de temps.



NB: tu devrais utiliser des constantes pour aider à la lisibilitée de ton code et également à la maintenance. Ecrire en dur dans le code des valeurs, c'est souvent pas une bonne idées.

A toi de selectionner le code qui convient en fonction de la répartition de tes données dans le tableau.

Bon dev,

++

Zlub
Messages postés
256
Date d'inscription
jeudi 17 avril 2003
Statut
Membre
Dernière intervention
20 février 2008
1
For T = 1 To 50
a (iif (Jmove(T) mod 21,-1,1))

If JMove(T) <= 2 Then
Joueur(T).Top = Joueur(T).Top + JMoveSpeed(T) *a If (Joueur(T).Top - JTop(T)) * a >0 Then JMove(T) 0: Joueur(T).Top = JTop(T)

else

Joueur(T).Left = Joueur(T).Left + JMoveSpeed(T) * a If (Joueur(T).Left - JLeft(T))*a >0 Then JMove(T) 0: Joueur(T).Left = JLeft(T)
End If

Next T

A+.
Thomas.
Messages postés
3140
Date d'inscription
vendredi 14 mai 2004
Statut
Membre
Dernière intervention
11 mars 2019
31
mélangeons les deux méthodes, avec une table d'opérateurs:

Table(1) = -1

Table(2) = +1

Table(3) = -1


Table(4) = +1



Const HAUT = 1

Const BAS = 2

Const GAUCHE = 3

Const DROITE = 4



Sub test()



For T = 1 To 50



J = JMove(T)

If J < GAUCHE Then

Joueur(T).Top = Joueur(T).Top + Table(J))* JMoveSpeed(T)

If Abs(Joueur(T).Top - JTop(T)) > 0 Then JMove(T) 0: Joueur(T).Top JTop(T)

End If

Else

Joueur(T).Left = Joueur(T).Left + Table(J)) * JMoveSpeed(T)

If Abs(Joueur(T).Left - JLeft(T)) > 0 Then JMove(T) 0: Joueur(T).Left JLeft(T)

End If



Next i



End Sub



et toujours ce test de limite qui me gêne

il semblerait que JTop() et JLeft() soit les seuls valeurs possible.

est-ce que chaque joueur évolue dans un environnement différent ?

et comment sont déterminées ces limites ?

si c'est dans une autre boucle, il faudrait aussi optimiser en mélangeant les deux boucles ...



Daniel
Messages postés
809
Date d'inscription
mercredi 11 octobre 2000
Statut
Membre
Dernière intervention
29 septembre 2010
9
Salut,


Je me suis arrété en cours de route ... c'est vrai que j'ai pas pensé à simplifier les calcul par la suite.

Le IIF ce n'est ni plus ni moi qu'un If déguisé ... donc ça ne fait pas gagner un test.


Par contre, la solution de Gobillot permet en effet de supprimer un
if. Petit oublie de ) et next T au lieu de next i + déclarations des
variables



donc





Option Explicit

Const HAUT = 1
Const BAS = 2
Const GAUCHE = 3
Const DROITE = 4
Const MAXVAL = 50

Sub test()

Dim sens(HAUT To DROITE) As Integer
sens(HAUT) = -1
sens(BAS) = 1
sens(GAUCHE) = -1
sens(DROITE) = 1

Dim this As Integer

For T = 1 To MAXVAL

this = JMove(T)
If this < GAUCHE Then
Joueur(T).Top = Joueur(T).Top + (sens(this) * JMoveSpeed(T)) If (Joueur(T).Top - JTop(T)) * sens(this) >0 Then JMove(T) 0: Joueur(T).Top = JTop(T)
Else
Joueur(T).Left = Joueur(T).Left + (sens(this) * JMoveSpeed(T)) If (Joueur(T).Left - JLeft(T)) * sens(this) >0 Then JMove(T) 0: Joueur(T).Left = JLeft(T)
End If

Next T



Erase sens

End Sub





pour le coups en reprenant les comptes



On passe donc dans le pire des cas

de 50 * 4 = 200 tests (If - Select)
à 50 * 3 = 150 tests (ElseIf et v1 du code)
à 50 * 2 = 100 tests





++

Zlub
Messages postés
3140
Date d'inscription
vendredi 14 mai 2004
Statut
Membre
Dernière intervention
11 mars 2019
31
bien vu

le Next i m'avait complétement échappé







le Select Case devrait être en meilleur position je pense

en supposant que les 4 cas sont partagés équilibrement:

cas 1: 1/4 pour 1 text

cas 2: 2/4 pour 2 tests

cas 3: 3/4 pour 3 tests

cas 4: 4/4 pour 4 tests
soit 10/4 * 50 = 125 tests


Daniel
Messages postés
809
Date d'inscription
mercredi 11 octobre 2000
Statut
Membre
Dernière intervention
29 septembre 2010
9
Salut,

B'hein non,
puisque le Select Case permet juste de trouver dans quel cas on
est... reste en plus à tester pour placer ou non JMove(T) = 0





Nb: avec le Select Case, tu peux encore réduire, d'un poil,


Case 1:
'1 test + 1 (pour JMove(T) = 0) donc 2


Case 2:
'2 tests + 1 (pour JMove(T) = 0 donc 3


Case 3:
'3 tests + 1 (pour JMove(T) = 0) donc 4


Case
Else:
'3 tests + 1 (pour JMove(T) = 0) donc 4




Donc, je persiste dans l'idée que l'algo que "je" propose est le plus compact pour l'instant



++

Zlub
Messages postés
3140
Date d'inscription
vendredi 14 mai 2004
Statut
Membre
Dernière intervention
11 mars 2019
31
pour les Ifs à l'origine:


5 * 50 = 250 tests




pour les ElseIF:

je sais plus



pour le Case Select:

Case 1:
'2 tests

Case 2:
'3 tests

Case 3:
'4 tests

Case 4
:
'5 tests

------------

14/4 * 50 = 175



pour la dernière méthode:


2 * 50 = 100
tests
*** gagnant ***



Daniel
Messages postés
218
Date d'inscription
dimanche 1 mai 2005
Statut
Membre
Dernière intervention
15 novembre 2009
1
Merci Merci Woaw! jen eprend plein je suis comptente!

Aufaite JMove() est une abréviation qui veut dire a la base JoueurMove.

DOnc en effet yen a le nombre de joueur donc si ya 50 joueur sa ferra JMove(50) au max et chacun peuve etre soit de 1(Avence) soit de 0(Avence pas)

lol Maintenant jai ajouter un autre timer a 1 aussi avec ce dode dedans (C'est pour l'Attaque d'un joueur)

<hr>
Rem ITEM SHOW
For T = 0 To 20

Rem Droite frappe
If ActalItem(T, 1) >= 1 Then
ActalItem(T, 1) = ActalItem(T, 1) + 1
Item(T).Left = Item(T).Left + 10
If ActalItem(T, 1) > 10 Then
ActalItem(T, 1) = 0
Item(T).Visible = False
Item(T).Top = 100000
Item(T).Left = 100000
End If
End If

Rem Gauche frappe
If ActalItem(T, 2) >= 1 Then
ActalItem(T, 2) = ActalItem(T, 2) + 1
Item(T).Left = Item(T).Left - 10
If ActalItem(T, 2) > 10 Then
ActalItem(T, 2) = 0
Item(T).Visible = False
Item(T).Top = 100000
Item(T).Left = 100000
End If
End If

Rem Haut frappe
If ActalItem(T, 3) >= 1 Then
ActalItem(T, 3) = ActalItem(T, 3) + 1
Item(T).Top = Item(T).Top - 10
If ActalItem(T, 3) > 10 Then
ActalItem(T, 3) = 0
Item(T).Visible = False
Item(T).Top = 100000
Item(T).Left = 100000
End If
End If

Rem Bas frappe
If ActalItem(T, 4) >= 1 Then
ActalItem(T, 4) = ActalItem(T, 4) + 1
Item(T).Top = Item(T).Top + 10
If ActalItem(T, 4) > 10 Then
ActalItem(T, 4) = 0
Item(T).Visible = False
Item(T).Top = 100000
Item(T).Left = 100000
End If
End If

DoEvents
Next T

<hr>
Mais alor une fois le timer True alor la quand javence avec mon perso, le perso est bcp moin fluide sa fait des acoup par acoups...

Et je vois pas comment faire par exemple un select case avec "ActalItem(T, 1)" pour savoire si il est plus grand que 1 le prob c que comme vous avez pu le voire, ya 4 test avec (T,1) (T,2) (T,3) (T,4)...

La je cherche une solution pour optimise ca! Un jour jai fait une visite dans une école d'informatique et on ma dit Que on ne programme jamais une chose 2 fois... ce que je voulais dire c que par exemple avec mon code si dessus ya 4 fois :

Item(T).Top = 100000

Item(T).Left = 100000

et normalement il devrait pour etre bien coder selon lui etre ecrit que une seul fois!

Enfin bon deja merci pour tous, je vais me relire ce topic encore ca il est très interessant merci a tous!

kakenette
Messages postés
3140
Date d'inscription
vendredi 14 mai 2004
Statut
Membre
Dernière intervention
11 mars 2019
31
Bonjour,

peut on avoir les 4 en même temps ?

(T,1) et (T,2) s'annulent ainsi que (T,3) et (T,4)







première approche,

un Booleen évitera de faire 4 fois Item(T).Top 100000 et Item(T).Left 100000

une zone temp pour éviter de calculer plusieurs fois les mêmes indices.

Dim temp As ???

Dim Bool As Boolean



Rem Droite frappe

temp = ActalItem(T, 1)

If temp >= 1 Then

temp = temp + 1

ActalItem(T, 1) = temp

Item(T).Left = Item(T).Left + 10

If temp > 10 Then

ActalItem(T, 1) = 0

Bool = True

End If

End If


etc ...



If Bool Then

Item(T).Visible = False

Item(T).Top = 100000

Item(T).Left = 100000

Bol = False

End If


Daniel
Messages postés
3140
Date d'inscription
vendredi 14 mai 2004
Statut
Membre
Dernière intervention
11 mars 2019
31
Re salut,

optimiser (en temps) ne veut pas dire regrouper ...

bien au contraire, il faut parfois écrire plusieurs fois les mêmes instructions pour éviter les boucles et les calculs d'indices

écrire 20 fois les mêmes instructions rien ne sera plus rapide

c'est pas de la très jolie programmation mais question rapidité ...



refaire les 4 tests * 20 fois avec les indices en dur



Rem Droite frappe

If ActalItem(1, 1) >= 1 Then

ActalItem(1, 1) = ActalItem(1, 1) + 1

Item(1).Left = Item(1).Left + 10

If ActalItem(1, 1) > 10 Then

ActalItem(1, 1) = 0

Item(1).Visible = False

Item(1).Top = 100000

Item(1).Left = 100000

End If

End If




Daniel
Messages postés
3140
Date d'inscription
vendredi 14 mai 2004
Statut
Membre
Dernière intervention
11 mars 2019
31
re re Salut,

une autre chose (importante)

Item(T).Top = 100000

Item(T).Left = 100000


en travaillant en Twips tu perds 15 fois trop de temps

met tout en Pixels déjà

déclare tes variables en Long

et n'oublie pas de tester en compilé


Daniel
Messages postés
809
Date d'inscription
mercredi 11 octobre 2000
Statut
Membre
Dernière intervention
29 septembre 2010
9
Salut,


En effet, Gobillot



de 50 * (4+1) = 250 tests (If)
à 50 * 3 = 150 tests (ElseIf et v1 du code)
à 50 * 2 = 100 tests



Pour le Select, vu que j'ai pris dans le pire des cas à chaque fois, ça revient à choisir le cas 4 (donc le plus long)

soit équivalent aux If à la suite (ou au ElseIf si on utilise Case Else encor que je sais pas s'il teste le Else)







kakenette
>




Pour éviter de copier/coller du code identique, fais des fonction ou des methodes:



Option Explicit

Const HAUT = 1
Const BAS = 2
Const GAUCHE = 3
Const DROITE = 4
Const MAXVAL = 50

Sub test()

Dim sens(HAUT To DROITE) As Integer
sens(HAUT) = -1
sens(BAS) = 1
sens(GAUCHE) = -1
sens(DROITE) = 1

Dim this As Integer

For T = 1 To MAXVAL

this = JMove(T)
If this < GAUCHE Then
Joueur(T).Top = Joueur(T).Top + (sens(this) * JMoveSpeed(T)) If (Joueur(T).Top - JTop(T)) * sens(this) >0 Then JMove(T) 0: Joueur(T).Top = JTop(T)
Else
Joueur(T).Left = Joueur(T).Left + (sens(this) * JMoveSpeed(T)) If (Joueur(T).Left - JLeft(T)) * sens(this) >0 Then JMove(T) 0: Joueur(T).Left = JLeft(T)
End If

Next T

Erase sens
End Sub

Private Sub ajuster(index As Integer, cas As Integer)

Dim valeur As Integer ' pour eviter d'affecter une valeur,
valeur = ActalItem(index, cas) + 1 ' pour la changer par la suite si > 10

If valeur <= 10 Then
ActalItem(index, cas) = valeur
Item(index).Left = Item(index).Left + 10 'idem autant stocker la bonne valeur directement
' sauf si c'était voulu pour l'affichage
Else
ActalItem(index, cas) = 0
Item(T).Visible = False
Item(T).Top = 100000
Item(T).Left = 100000
End If
End Sub

Private Sub Timer1_Timer()
Dim T As Integer ' i serait plus simple mais bon bourquoi pas T
Dim cas As Integer
For T 0 To 20 'Utiliser Const MAXTIMER 20 au lieu de coder en dur
For cas = HAUT To DROITE
If ActalItem(T, cas) >= 1 Then Call ajuster(T, cas)
Next cas
Next T

End Sub



Essais de faire des Const XXX = ... le plus souvent possible au lieu de marquer un chiffre dans ton code.

C'est d'une part plus lisible et si jamais tu dois changer la valeurs,
ça evite de chercher dans tout le code se qu'il faut modifier.



Et si tu pouvais indenter un minimun ça serait nickel. Dernier point, perso, je suis aps Fan du Rem

et je te coneil d'utiliser le simple quote qui revient au même...


++

Zlub