Le chasseur de bombes

Pour partager vos applications (Excel, Calc et Google Sheets) avec les autres membres
Avatar du membre
LouReeD
Contributeur
Contributeur
Messages : 5'916
Appréciations reçues : 249
Inscrit le : 14 octobre 2014
Version d'Excel : 2013 FR, 2016 FR
Contact :
Téléchargements : Mes applications

Message par LouReeD » 20 septembre 2019, 00:15

Bonsoir,
Pourquoi tester si une feuille existe à chaque fois?
C'est un exemple d'application où il y a ajout d'une feuille dont l'utilisateur choisi son nom, et donc dans le code pour éviter un message d'erreur il faut "gérer" ceci en vérifiant que le nom donné pour la création de la nouvelle feuille n'est pas déjà utilisé.
Par contre je ne vois pas en quoi une gestion d'erreur est nécessaire, l'instruction "exit for" sert exactement à faire ça nan?
Si la grille est représentée sous VBA par un tableau, une dimension de 20 colonnes sur 20 lignes, cela se représente par DIM Tableau(1 to 20, 1 to 20) où chaque "intersections" représente une cellule aux même coordonnées : cellule A1 en Tableau(1,1).
La gestion d'erreur vient au niveau du test des cellules autour de celle cliquée : si c'est en A1, alors la référence du tableau X-1 et Y-1 n'existe pas est engendre une erreur. Pour éviter cela j'avais mis en place 8 tests afin de m'assurer qu'il y avait bien une position "existante" dans le tableau pour faire le test de la cellule vide pour l'ajouter à la zone blanche... Mais avec la gestion d'erreur, plus de test, si ça passe c'est que la cellule existe dans le tableau, si ça passe pas alors le code continue...
Du coup moins de test et plus de rapidité !
Le mieux est de modifier la police clairement ou directement de faire dans les MFC
Dans les MFC en effet la liste des polices est visible mais chez moi elle est grisée, je n'arrive pas à les sélectionner ! Y a t il une astuce de ce coté ?
Car en effet la gestion des polices en directe "est simple" mais elle est lourde sur un gros tableau.

Je suis pour le moment "très" satisfait du code de blanchiment, mais avec cette histoire de police, la "construction" des grandes grilles est un peu longue...

@ bientôt

LouReeD
Contributeur depuis peu ! 8-)
Quelques règles à lire ICI ;;)
______________________________________________________Vous pouvez allez faire un tour sur : Index de "Mes applications" ;;)
E
ExcelCoreGame
Membre fidèle
Membre fidèle
Messages : 392
Appréciations reçues : 13
Inscrit le : 24 octobre 2017
Version d'Excel : 2007FR

Message par ExcelCoreGame » 20 septembre 2019, 19:11

je viens de faire une boucle sur un classeur avec 30 feuilles, la macro est tellement rapide que quand je calcule le temps d’exécution avec 2 timers la différence vaut 0 donc j'avoue que le gain de temps me semble dérisoire surtout que l'on ne va pas demander au joueur de faire une nouvelle feuille tous les 3 matins nan? ^^

cela fait que 4 tests à faire nan? si X est >= mini et <= maxi et idem pour Y, pourquoi 8 tests?
En tout cas c'est une bonne idée dans le sens ou en effet cela va beaucoup plus vite (il fallait y penser! bien joué) mais je ne pense pas que ce soit une bonne pratique d'utiliser les gestions d'erreur de cette façon car s'il y a un souci lambda alors la macro peut faire n'importe quoi sans le signaler du coup ^^
Quand je verrais le code je comprendrais mieux surement :D

Je n'avais jamais testé plus que ça mais chez moi aussi au final c'est grisé! c'est emmerdant LOL
Avatar du membre
LouReeD
Contributeur
Contributeur
Messages : 5'916
Appréciations reçues : 249
Inscrit le : 14 octobre 2014
Version d'Excel : 2013 FR, 2016 FR
Contact :
Téléchargements : Mes applications

Message par LouReeD » 20 septembre 2019, 20:50

Bonsoir,

juste pour vous en téléchargement la version "sans cosmétique" du chasseur de bombes : Effacé par LouReeD
Attention le lien ne restera pas longtemps, donc merci de laisser un message dès qu'il sera téléchargé.
Sa taille n'est pas grande car j'ai enlevé des MFC qui prennent beaucoup de place, par contre avant de cliquer sur "Allons-y", il faut faire une copie de la cellule A1 sur la zone "visible" de la feuille à savoir A1:BER1500. En effet le code est prévu pour 1500 ligne et colonnes.
Il y a 10% de bombes par rapport à ce nombre de cases possibles.
Numérotation et mise en couleur du nombre de bombes adjacentes aux cellule, fond violet pour les zones blanches sans le quadrillage.
Il manque la gestion du clic droit, du score et l'emballage ! ;-)

@ bientôt

LouReeD
Modifié en dernier par LouReeD le 20 septembre 2019, 21:09, modifié 2 fois.
Contributeur depuis peu ! 8-)
Quelques règles à lire ICI ;;)
______________________________________________________Vous pouvez allez faire un tour sur : Index de "Mes applications" ;;)
E
ExcelCoreGame
Membre fidèle
Membre fidèle
Messages : 392
Appréciations reçues : 13
Inscrit le : 24 octobre 2017
Version d'Excel : 2007FR

Message par ExcelCoreGame » 20 septembre 2019, 20:51

je l'ai c'est bon :)
merci
Avatar du membre
LouReeD
Contributeur
Contributeur
Messages : 5'916
Appréciations reçues : 249
Inscrit le : 14 octobre 2014
Version d'Excel : 2013 FR, 2016 FR
Contact :
Téléchargements : Mes applications

Message par LouReeD » 20 septembre 2019, 22:04

Un exemple de "rapidité" par la gestion des erreurs :
Si le code de détermination des chiffres à coté des bombes suivant :
Tempo = Timer
For I = 1 To NB_Bombes
  For J = -1 To 1
    For k = -1 To 1
      ' test que la cellule testée (référence dans le tableau) existe
      If Bombes(1, I) + J > 0 And Bombes(1, I) + J <= Tx And Bombes(2, I) + k > 0 And Bombes(2, I) + k <= Ty Then
        ' test si numérique pour éviter une erreur
        If Grille(Bombes(1, I) + J, Bombes(2, I) + k) <> "B" Then
          Grille(Bombes(1, I) + J, Bombes(2, I) + k) = Grille(Bombes(1, I) + J, Bombes(2, I) + k) + 1
        End If
      End If
    Next k
  Next J
Next I
MsgBox (Timer - Tempo)
est modifié par celui ci-dessous :
    Tempo = Timer
    On Error Resume Next
    ' ici une gestion d'erreur afin de ne pas avoir à faire le test du "numérique" pour faire l'addition
    ' on fait l'addition et si c'est une erreur le code continue
    ' et on zappe également en cas de test "hors grille"
    For I = 1 To NB_Bombes
        For J = -1 To 1
            For k = -1 To 1
                Grille(Bombes(1, I) + J, Bombes(2, I) + k) = Grille(Bombes(1, I) + J, Bombes(2, I) + k) + 1
            Next k
        Next J
    Next I
    MsgBox (Timer - Tempo)

on passe d'environ de 4,5 à 5.2 secondes à de 2.20 à 2.4 secondes pour faire la même chose.
Suivant la disposition des bombes sur la grille on gagne de 2 à 3 secondes !
Alors sur une recherche de zone blanche où il y a énormément de teste avec mon principe de recherche, cela m'a permis de gagner beaucoup de temps.
C'est un exemple, il est vrai que celui des feuilles de classeurs est moins parlant... ;-)
Mais le principe est là, VBA détecte une erreur, on zappe l'erreur et on continue le code, cette erreur équivaut au résultat de plusieurs tests pour ne pas provoquer l'erreur, et ces tests cumulés ralentissent le code.

Voilà, alors ? Le code ? J'ai essayé de le simplifier au maximum, mais du coup pour une "accélération" j'ai du l'étoffé, comme la création d'un sous tableau pour l'affichage de la zone blanche calculée...

@ bientôt

LouReeD
Contributeur depuis peu ! 8-)
Quelques règles à lire ICI ;;)
______________________________________________________Vous pouvez allez faire un tour sur : Index de "Mes applications" ;;)
E
ExcelCoreGame
Membre fidèle
Membre fidèle
Messages : 392
Appréciations reçues : 13
Inscrit le : 24 octobre 2017
Version d'Excel : 2007FR

Message par ExcelCoreGame » 21 septembre 2019, 16:45

L'idée d'utiliser les erreurs pour gagner du temps est vraiment très bonne sur la papier et le gain est très concret mais ce n'est pas une bonne pratique à avoir je dirais
Tout comme "normalement" les bonnes méthodologie pour utiliser une variable passe par des Get/Set mais je n'ai jamais vu une telle chose dans un code sur ce forum ^^

Quoi qu'il en soit c'est très tentant d'utiliser cette méthode pour gagner du temps en effet ou au moins voir ce que je pourrais gagner aussi de mon coté car je viens de regarder à nouveau mon code (j'ai déjà tout oublié de comment j'avais fait LOL) et je fais pas mal de check

Par contre quand on clique sur une case, mon code pour faire l'extension et le calcule de bombe (les commentaires sont peu être faux ou pas très compréhensif car je n'ai pas fait de mise à jour de ce coté la) :
'si on tombe sur une case vide alors on fait une extension
            If Sheets(SHEET_JEU).Cells(LIGNE, COLONNE).Value = 0 Then

                'pas de usedrange le usedrange car les Bombes ne sont pas placé forcément au bon endroit pour délimiter la zone
                Sheets(SHEET_PARAMETRE).Visible = True
                Sheets(SHEET_PARAMETRE).Select
                TABLEAU_GRILLE_PARAMETRE = Sheets(SHEET_PARAMETRE).Range(Cells(LIMITE_INF_LIGNE, LIMITE_INF_COL), 	Cells(LIMITE_SUP_LIGNE, LIMITE_SUP_COL)).Value
                Sheets(SHEET_JEU).Select
                TABLEAU_GRILLE_JEU = Sheets(SHEET_JEU).Range(Cells(LIMITE_INF_LIGNE, LIMITE_INF_COL), Cells(LIMITE_SUP_LIGNE, LIMITE_SUP_COL)).Value
                ReDim TABLEAU_RESTANT_A_CHECKER(2, 1000000)
                            
                'on reprend les valeurs pour être en ligne avec les tableaux
                LIGNE = LIGNE - LIMITE_INF_LIGNE + 1
                COLONNE = COLONNE - LIMITE_INF_COL + 1

                
                BALAYAGE_TABLEAU_RESTANT_A_CHECKER = 1
                BALAYAGE_CREATION_TABLEAU_RESTANT_A_CHECKER = 1
                
                'on entre la case en cours
                TABLEAU_RESTANT_A_CHECKER(1, BALAYAGE_TABLEAU_RESTANT_A_CHECKER) = LIGNE
                TABLEAU_RESTANT_A_CHECKER(2, BALAYAGE_TABLEAU_RESTANT_A_CHECKER) = COLONNE


                'tant qu'on aura pas regarder toute les cases en "cercle" concentrique et qu'elle ne seront pas vide alors on continue
                ' ???
                ' ?X?
                ' ???
                
                Do
                
                   
                    'on reprend les coordonnées de la cellule à checker, pour la première itération c'est une opération inutile mais voulu
                    'car on va reprendre celle que l'on vient de renseigner juste avant
                    LIGNE_CLIQUE = TABLEAU_RESTANT_A_CHECKER(1, BALAYAGE_TABLEAU_RESTANT_A_CHECKER)
                    COLONNE_CLIQUE = TABLEAU_RESTANT_A_CHECKER(2, BALAYAGE_TABLEAU_RESTANT_A_CHECKER)


                    
                    For BALAYAGE_LIGNE = -1 To 1
                        For BALAYAGE_COLONNE = -1 To 1

                            'si regarde la case qui si on est bien dans les limites de la grille
                            If (LIGNE_CLIQUE + BALAYAGE_LIGNE >= 1) And (LIGNE_CLIQUE + BALAYAGE_LIGNE <= UBound(TABLEAU_GRILLE_PARAMETRE(), 1)) And _
                            (COLONNE_CLIQUE + BALAYAGE_COLONNE >= 1) And (COLONNE_CLIQUE + BALAYAGE_COLONNE <= UBound(TABLEAU_GRILLE_PARAMETRE(), 2)) Then
                                                       
                                                       
                                'ligne  = 0 et col = 0 est la case en cours donc déja traité
                                'on vérifie que la case est bien vide pour ne pas retraiter une case déja prise en compte
                                If ((BALAYAGE_LIGNE = 0) And (BALAYAGE_COLONNE = 0)) Or _
                                    TABLEAU_GRILLE_PARAMETRE(LIGNE_CLIQUE + BALAYAGE_LIGNE, COLONNE_CLIQUE + BALAYAGE_COLONNE) <> "" Then
                                
                                    'on ne fait rien
                                Else

                                        NB_BOMBE = 0
                                        For BALAYAGE_LIGNE_EXPENSION = -1 To 1
                                            For BALAYAGE_COLONNE_EXPENSION = -1 To 1
                                            
                                                'si regarde la case qui si on est bien dans les limites de la grille
                                                If (LIGNE_CLIQUE + BALAYAGE_LIGNE + BALAYAGE_LIGNE_EXPENSION >= 1) And (LIGNE_CLIQUE + BALAYAGE_LIGNE + BALAYAGE_LIGNE_EXPENSION <= UBound(TABLEAU_GRILLE_PARAMETRE(), 1)) And _
                                                (COLONNE_CLIQUE + BALAYAGE_COLONNE + BALAYAGE_COLONNE_EXPENSION >= 1) And (COLONNE_CLIQUE + BALAYAGE_COLONNE + BALAYAGE_COLONNE_EXPENSION <= UBound(TABLEAU_GRILLE_PARAMETRE(), 2)) Then
                                                
                                                        'si c'est une bombe on le prends en compte
                                                        If TABLEAU_GRILLE_PARAMETRE(LIGNE_CLIQUE + BALAYAGE_LIGNE + BALAYAGE_LIGNE_EXPENSION, COLONNE_CLIQUE + BALAYAGE_COLONNE + BALAYAGE_COLONNE_EXPENSION) = "X" Then
                                                            NB_BOMBE = NB_BOMBE + 1
                                                        End If
                                                        
                                                End If
    
                                                
                                            Next
                                        Next
                                        
                                        'on renseigner les 2 tableaux, parametre comme quoi la case est checké avec un C et la valeur de la bombe en jeu
                                        TABLEAU_GRILLE_PARAMETRE(LIGNE_CLIQUE + BALAYAGE_LIGNE, COLONNE_CLIQUE + BALAYAGE_COLONNE) = "C"
                                                                              
                                        
                                        'le joueur ne voit pas 0 mais une case vide par choix
                                        If NB_BOMBE = 0 Then
                                            TABLEAU_GRILLE_JEU(LIGNE_CLIQUE + BALAYAGE_LIGNE, COLONNE_CLIQUE + BALAYAGE_COLONNE) = 0
                                            'on décale d'une ligne pour reprendre la case à checker
                                            BALAYAGE_CREATION_TABLEAU_RESTANT_A_CHECKER = BALAYAGE_CREATION_TABLEAU_RESTANT_A_CHECKER + 1
                                            TABLEAU_RESTANT_A_CHECKER(1, BALAYAGE_CREATION_TABLEAU_RESTANT_A_CHECKER) = LIGNE_CLIQUE + BALAYAGE_LIGNE
                                            TABLEAU_RESTANT_A_CHECKER(2, BALAYAGE_CREATION_TABLEAU_RESTANT_A_CHECKER) = COLONNE_CLIQUE + BALAYAGE_COLONNE
                                        Else
                                            TABLEAU_GRILLE_JEU(LIGNE_CLIQUE + BALAYAGE_LIGNE, COLONNE_CLIQUE + BALAYAGE_COLONNE) = NB_BOMBE
                                        End If
                                End If
                            End If
                        Next
                    Next

                    'on va voir la prochaine ligne du tableau à tester
                    BALAYAGE_TABLEAU_RESTANT_A_CHECKER = BALAYAGE_TABLEAU_RESTANT_A_CHECKER + 1
                    
                'tant qu'on a renseigner des nouvelles case vide à expendre alors on continue
                Loop Until BALAYAGE_TABLEAU_RESTANT_A_CHECKER > BALAYAGE_CREATION_TABLEAU_RESTANT_A_CHECKER
        
                'on recopie les tableaux sur les feuilles
                Sheets(SHEET_PARAMETRE).Select
                Sheets(SHEET_PARAMETRE).Range(Cells(LIMITE_INF_LIGNE, LIMITE_INF_COL), Cells(LIMITE_SUP_LIGNE, LIMITE_SUP_COL)).Value = TABLEAU_GRILLE_PARAMETRE
                    
                Sheets(SHEET_JEU).Select
                Sheets(SHEET_JEU).Range(Cells(LIMITE_INF_LIGNE, LIMITE_INF_COL), Cells(LIMITE_SUP_LIGNE, LIMITE_SUP_COL)).Value = TABLEAU_GRILLE_JEU

            End If
Avatar du membre
LouReeD
Contributeur
Contributeur
Messages : 5'916
Appréciations reçues : 249
Inscrit le : 14 octobre 2014
Version d'Excel : 2013 FR, 2016 FR
Contact :
Téléchargements : Mes applications

Message par LouReeD » 21 septembre 2019, 17:09

Bonjour,

sur le papier cela fonctionne de faire les test par la gestion d'erreur, mais comme cela est indiqué il faut "gérer" cette gestion et de savoir quand l'utiliser. Dans mon cas le risque d'erreur et le fait de "sortir" du tableau pour les test ou bien de faire une addition entre un M et un chiffre, le risque est donc limité ;-)

Pour ce qui est de votre code, j'ai du mal à percevoir le fonctionnement, je vois bien les -1 to +1 x2 pour scanner les cellules adjacentes à celles cliquée, mais pour le reste, l'histoire des tableaux... :(
Tout comme "normalement" les bonnes méthodologie
N'y a t il pas trop de Select dans votre code ? Cela est gourmant en temps... Et je ne pense pas qu'il soit utile de "montrer" une feuille pour écrire dessus tout comme pour la lire.
Le Select sous VBA est très superflue si ce n'est pour réellement sélectionner une cellule et rendre la main à l'utilisateur dans une configuration particulière...

@ bientôt

LouReeD
Contributeur depuis peu ! 8-)
Quelques règles à lire ICI ;;)
______________________________________________________Vous pouvez allez faire un tour sur : Index de "Mes applications" ;;)
E
ExcelCoreGame
Membre fidèle
Membre fidèle
Messages : 392
Appréciations reçues : 13
Inscrit le : 24 octobre 2017
Version d'Excel : 2007FR

Message par ExcelCoreGame » 21 septembre 2019, 18:59

Je fais 2 select au début de la macro et 2 à la fin en effet mais de toute façon sous un Application.ScreenUpdating =False cela ne se voit pas du tout et prends beaucoup moins de temps
Mais surtout sur ma version, Excel ne me permet pas de faire un .range sur une feuille qui n'est pas sélectionné sinon j'ai l’erreur
Erreur d'éxécution '1004': Erreur définie par l'application ou par l'objet
d’où les .select

Et pour écrire dessus vu qu'elles sont cachés en .veryhidden en plus il faut que je les rendent visible à chaque fois que le joueur clique sinon on ne peut pas y accéder et forcément que je refassent en veryhidden à la fin, du moins j'ai choisi cette solution technique et malgré tout cela le temps de calcule reste correcte donc j'ai pas cherché plus loin faut avouer ^^

Pour faire simple je passe tout simplement par des tableaux car je calcule à la volée le nombre de bombe autour d'une case et comme tu le sais, c'est plus rapide que de calculer sur les feuilles.

Je redim une fois pour toute au début de la macro un TABLEAU_RESTANT_A_CHECKER(2, 1000000), car au maximum en 1000x1000 on aura en gros au max ce nombre de case "blanche à traiter" (bon techniquement -2 car j'ai au mini 2 bombes sur ma grilles mais bon)
Par contre cela prends genre quand même 0.5-1 seconde à excel pour la créer à chaque fois mais encore une fois c'est un choix technique plutôt que de le redimensionner à la volée ou de le garder "en vie" et de le nettoyer avant chaque réutilisation.

Puis en gros je regarde tout autour de la case blanche, si je tombe sur une case non découverte par le joueur alors je calcule et j'y inscrit le nombre de bombe autour, s'il y a 0 bombes alors je stock la case dans mon TABLEAU_RESTANT_A_CHECKER
Puis comme tu imagines bien je fais la même chose pour chaque case répertorié dans ce Tableau
La façon de la construction de ce tableau m'assure que je ne prendrais jamais en compte plusieurs fois une case
E
ExcelCoreGame
Membre fidèle
Membre fidèle
Messages : 392
Appréciations reçues : 13
Inscrit le : 24 octobre 2017
Version d'Excel : 2007FR

Message par ExcelCoreGame » 21 septembre 2019, 21:40

Pareil de la même façon c'est une feature au final MUST HAVE sur des grilles 1500x1500, après chaque clique il faut scanner (ou juste une formule excel surement possible) toute la grille pour vérifier si le joueur à trouver toute les cases "blanches" et si c'est le cas alors il gagne instantanément.
En effet si on part sur une grille 1500x1500 avec 2 249 980 bombes soit 10 cases blanches et qu'au hasard de la construction en 2 cliques le joueur découvres ces 10 cases blanches .... il ne faudrait pas qu'il ai à faire 2 249 980 cliques droits pour "identifier" toutes les bombes et gagner !
Avatar du membre
LouReeD
Contributeur
Contributeur
Messages : 5'916
Appréciations reçues : 249
Inscrit le : 14 octobre 2014
Version d'Excel : 2013 FR, 2016 FR
Contact :
Téléchargements : Mes applications

Message par LouReeD » 29 septembre 2019, 23:41

Bonsoir @ tous ! :-)

Bon je prend mon temps pour le sortir ce "Démineur" ! :lol:
Grâce à ExcelCoreGame, je suis arrivé à descendre aux alentour des 13 secondes pour un clic sur une zone "blanche" pour une grille de 1000 x 1000 avec 66 666 bombes !
Comment ? En reprenant son idée de tableau "déjà" dimensionné au maximum ce qui évite le ralentissement de mon code avec les "ReDim Preserve" qu'il y avait "à chaque tour" !

Merci à lui.

Pour ce qui est du "Skin", je suis parti sur une nouvelle idée qui me rapproche encore un peu plus de l'original : le forme des "briques", en effet maintenant elles ressemblent vraiment à des boutons !
Pour le reste, je reste sur l'idée du USF Modal 0 qui permet d'avoir une zone de jeu maximum par la suppression d'une zone de menu, et le fait de mettre m'application en "maxi grand écran" ! Et toujours l'affichage des chiffres en couleur, par contre j'ai abandonné l'idée de la police "Wingdings" pour l'affichage des bombes et têtes de mort... Cela ralenti trop l'affichage de fin de jeu, mais qui sait, avec un message "d'avertissement" il pourrait y avoir une version de cette forme...
Voici donc une nouvelle capture d'écran :
Aperçu.png
Il me reste à ajouter la gestion du temps et du classement des meilleurs scores.
Donc cela ne devrait pas durer longtemps ! Enfin j'espère !

@ bientôt

LouReeD
1 membre du forum aime ce message.
Contributeur depuis peu ! 8-)
Quelques règles à lire ICI ;;)
______________________________________________________Vous pouvez allez faire un tour sur : Index de "Mes applications" ;;)
Répondre Sujet précédentSujet suivant