IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Macros et VBA Excel Discussion :

Optimisation compte est bon


Sujet :

Macros et VBA Excel

  1. #21
    Invité
    Invité(e)
    Par défaut
    Ok

    Le + additionne les numérique et concatène les string donc java voila 3 et 1 comme de string???

    Puisque qu'il il multiplie divise et soustrait je penses que (3 * 1) +(1 * 1) = 4???

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if(op == '+'){" & vbCrLfJv = Jv & "  res = parseFloat(n1) + parseFloat(n2);" & vbCrLf
    Jv = Jv & "  operations_encours.push(n1+ op + n2 + '=' + res);" & vbCrLf
    Jv = Jv & "  return res;" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Code Complet : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
     
    Function Jv()
    Jv = Jv & "var nb_a_tirer = 6; // combien de nombres à tirer aléatoirement" & vbCrLf
    Jv = Jv & "var cible = 2;var nbalea='';var nbcible=0; // valeur cible" & vbCrLf
    Jv = Jv & "var nbres_dispos = new Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 25, 50, 75, 100); // nombres dispos pour tirage aléatoire" & vbCrLf
    Jv = Jv & "var operations_encours = new Array();" & vbCrLf
    Jv = Jv & "var best_operations = new Array();" & vbCrLf
    Jv = Jv & "var best_distance;" & vbCrLf
    Jv = Jv & "var best_nb_op;" & vbCrLf
    Jv = Jv & "var nbres_aleas = new Array(6,3,50,50,50,500); // tableau des nombres tirés pour calcul" & vbCrLf
    Jv = Jv & "var operateurs = new Array('+','*','-','/');" & vbCrLf
    Jv = Jv & "var compteur = 0;" & vbCrLf
    Jv = Jv & "var resultat = '';" & vbCrLf
    Jv = Jv & "" & vbCrLf
    Jv = Jv & "" & vbCrLf
    Jv = Jv & "// tirage d'un nombre cible aléatoirement" & vbCrLf
    Jv = Jv & "function nombre_cible_aleatoire() {" & vbCrLf
    Jv = Jv & " cible = 100 + Math.floor(900*Math.random());" & vbCrLf
    Jv = Jv & "nbcible= cible;" & vbCrLf
    Jv = Jv & "return nbcible;}" & vbCrLf
    Jv = Jv & "// tirage des nombres pour le calcul" & vbCrLf
    Jv = Jv & "function nombres_aleatoires() {" & vbCrLf
    Jv = Jv & " var texte = '';" & vbCrLf
    Jv = Jv & " for(i=0;i<nb_a_tirer;i++)" & vbCrLf
    Jv = Jv & " {" & vbCrLf
    Jv = Jv & " b = 1 + Math.floor((nbres_dispos.length)*Math.random());" & vbCrLf
    Jv = Jv & " texte = texte + ';' + nbres_dispos[b-1];" & vbCrLf
    Jv = Jv & " nbres_aleas[i] = nbres_dispos[b-1];" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & " nbalea = texte;" & vbCrLf
    Jv = Jv & "return texte;}" & vbCrLf
    Jv = Jv & "// calcule de 2 nombres n1 et n2 avec 1 des 4 opérateurs" & vbCrLf
    Jv = Jv & "function calcule(n1, n2, op){" & vbCrLf
    Jv = Jv & " compteur = compteur + 1;" & vbCrLf
    Jv = Jv & " var res;" & vbCrLf
    Jv = Jv & " if(op == '+'){" & vbCrLf
    Jv = Jv & " res = parseFloat(n1) + parseFloat(n2);" & vbCrLf
    Jv = Jv & " operations_encours.push(n1+ op + n2 + '=' + res);" & vbCrLf
    Jv = Jv & " return res;" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & " if(op == '-') {" & vbCrLf
    Jv = Jv & " if(n1 > n2)" & vbCrLf
    Jv = Jv & " {" & vbCrLf
    Jv = Jv & " res = n1 - n2;" & vbCrLf
    Jv = Jv & " operations_encours.push(n1 + op + n2 + '=' + res);" & vbCrLf
    Jv = Jv & " return res;" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & " else" & vbCrLf
    Jv = Jv & " {" & vbCrLf
    Jv = Jv & " res = n2 - n1;" & vbCrLf
    Jv = Jv & " operations_encours.push(n2 + op + n1 + '=' + res);" & vbCrLf
    Jv = Jv & " return res;" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & " if(op == '*')" & vbCrLf
    Jv = Jv & " {" & vbCrLf
    Jv = Jv & " res = n1 * n2;" & vbCrLf
    Jv = Jv & " operations_encours.push(n1 + op + n2 + '=' + res);" & vbCrLf
    Jv = Jv & " return res;" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & " if(op == '/')" & vbCrLf
    Jv = Jv & " {" & vbCrLf
    Jv = Jv & " if(n1 >= n2){" & vbCrLf
    Jv = Jv & " res = Math.floor(n1 / n2);" & vbCrLf
    Jv = Jv & " if(res * n2 != n1) res = 0;" & vbCrLf
    Jv = Jv & " operations_encours.push(n1 + op + n2 + '=' + res);" & vbCrLf
    Jv = Jv & " return res;" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & " else" & vbCrLf
    Jv = Jv & " {" & vbCrLf
    Jv = Jv & " res = Math.floor(n2 / n1);" & vbCrLf
    Jv = Jv & " if(res * n1 != n2) res = 0;" & vbCrLf
    Jv = Jv & " operations_encours.push(n2 + op + n1 + '=' + res);" & vbCrLf
    Jv = Jv & " return res;" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & "}" & vbCrLf
    Jv = Jv & "function go(Tin,Vin){" & vbCrLf
    Jv = Jv & "nbres_aleas=Tin.split(',');cible=Vin; // réinitialisation des variables" & vbCrLf
    Jv = Jv & " compteur = 0;" & vbCrLf
    Jv = Jv & " best_distance = cible;" & vbCrLf
    Jv = Jv & " best_nb_op = nb_a_tirer;" & vbCrLf
    Jv = Jv & " operations_encours = new Array();" & vbCrLf
    Jv = Jv & " best_operations = new Array();" & vbCrLf
    Jv = Jv & " resultat = '';" & vbCrLf
    Jv = Jv & " recherche_arbre(nbres_aleas); // recherche récursive" & vbCrLf
    Jv = Jv & " if(best_distance ==0) resultat = resultat + 'Le compte est bon ! \n';" & vbCrLf
    Jv = Jv & " else resultat = resultat + 'Le compte n est pas bon ! \n';" & vbCrLf
    Jv = Jv & " affiche(compteur,best_operations);" & vbCrLf
    Jv = Jv & "return resultat;" & vbCrLf
    Jv = Jv & "}" & vbCrLf
    Jv = Jv & "function recherche_arbre(tab){" & vbCrLf
    Jv = Jv & " var nb_nombres = tab.length;" & vbCrLf
    Jv = Jv & " var i,j,p;" & vbCrLf
    Jv = Jv & " //if(nb_nombres<=best_nb_op){" & vbCrLf
    Jv = Jv & " for(i=0;i<nb_nombres-1;i++) {" & vbCrLf
    Jv = Jv & " for(j=i+1;j<nb_nombres;j++){" & vbCrLf
    Jv = Jv & " for(p=0;p<4;p++){" & vbCrLf
    Jv = Jv & " res = calcule(tab[i],tab[j],operateurs[p]); // on calcule et on empile" & vbCrLf
    Jv = Jv & " if(res!=0){" & vbCrLf
    Jv = Jv & " compare(res);" & vbCrLf
    Jv = Jv & " var tab2 = new Array();" & vbCrLf
    Jv = Jv & " tab2.push(res);" & vbCrLf
    Jv = Jv & " for(k=0;k<nb_nombres;k++) if(k!=i && k!=j) tab2.push(tab[k]);" & vbCrLf
    Jv = Jv & " if(tab2.length>1 && operations_encours.length<best_nb_op-1) recherche_arbre(tab2);" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & " operations_encours.pop(); // on dépile" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & "}" & vbCrLf
    Jv = Jv & "" & vbCrLf
    Jv = Jv & "" & vbCrLf
    Jv = Jv & "function compare(n){" & vbCrLf
    Jv = Jv & " if(n==cible && operations_encours.length<best_nb_op){" & vbCrLf
    Jv = Jv & " best_distance = 0;" & vbCrLf
    Jv = Jv & " best_nb_op = operations_encours.length;" & vbCrLf
    Jv = Jv & " copie_vers_best_operations();" & vbCrLf
    Jv = Jv & " //resultat = 'Le compte est bon ! \n';" & vbCrLf
    Jv = Jv & " //affiche(compteur,operations_encours);" & vbCrLf
    Jv = Jv & " //break;" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & " else{" & vbCrLf
    Jv = Jv & " if(best_distance !=0){" & vbCrLf
    Jv = Jv & " var distance = Math.abs(n-cible);" & vbCrLf
    Jv = Jv & " if(distance < best_distance){" & vbCrLf
    Jv = Jv & " best_distance = distance;" & vbCrLf
    Jv = Jv & " copie_vers_best_operations();" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & "}" & vbCrLf
    Jv = Jv & "function copie_vers_best_operations(){" & vbCrLf
    Jv = Jv & " for(i=0;i<operations_encours.length;i++) best_operations[i] = operations_encours[i];" & vbCrLf
    Jv = Jv & " for(i=operations_encours.length;i<nb_a_tirer-1;i++) best_operations[i] = '';" & vbCrLf
    Jv = Jv & "}" & vbCrLf
    Jv = Jv & "function affiche(nb_operations, tab_operations){" & vbCrLf
    'Jv = Jv & " resultat = resultat + 'Profondeur de recherche : ' + nb_operations + '\n';" & vbCrLf
    Jv = Jv & " var i;" & vbCrLf
    Jv = Jv & " for(i=0;i<tab_operations.length;i++){" & vbCrLf
    Jv = Jv & " resultat = resultat + tab_operations[i] + '\n';" & vbCrLf
    Jv = Jv & " }" & vbCrLf
    Jv = Jv & " return resultat;;" & vbCrLf
    Jv = Jv & "}"
    End Function
    Dernière modification par Invité ; 18/01/2018 à 21h20.

  2. #22
    Invité
    Invité(e)
    Par défaut
    Bonjour,
    Notes que nous avons extrait ce script d'une page web. Que JavaScript à l'habitude de cohabiter avec des formulaires HTLM!

    Adapté pour adapté adaptons nous!
    "3" + "1" = "31" ; 3+1=4

  3. #23
    Nouveau candidat au Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2022
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2022
    Messages : 3
    Par défaut Le Compte Est Bon en Excel 2016 VBA
    Voici ma version du Compte est bon.

    J'ai utilisé une "worksheet" d'Excel comme interface utilisateur. L'interface ne permet pas de jouer, elle permet de spécifier ou générer une suite de 6 nombres (parmi les 24 plaques) et une cible entre 101 et 999 ainsi qu'un bouton "Solutionner".

    L'algorithme lui peut résoudre n'importe quel problème. Plus ou moins de 6 nombres (entre 1 et 2000000000) et une cible entre 1 et 2000000000. Attention si vous voulez solutionner un problème ayant plus de 6 nombres, l'algorithme étant récursif, vous pourriez dépasser la capacité de la plie. Aucune vérification n'a été faite en ce sens.

    Avec les restrictions de l'émission : 6 nombres (parmi les 24 plaques) et une cible entre 101 et 999, ça plante jamais sur un PC avec 10 Gb de RAM et les solutions trouvées sortent en moins de 40 secondes avec un CPU i7 d'Intel.

    Dites-moi ce que vous en pensez...
    Fichiers attachés Fichiers attachés

  4. #24
    Rédacteur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2013
    Messages
    995
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Finance

    Informations forums :
    Inscription : Août 2013
    Messages : 995
    Par défaut
    Bonjour,
    Merci pour votre application.
    D'ailleurs vous pouvez la déposer dans la rubrique "Contribuez" du site.

    Concernant le code, ne connaissant pas la Programmation Orientée Objet je n'ai rien compris (normal), donc j'aurais aimé, si possible, une explication de l'algorithme utilisé.

    Un plus : la possibilité de choisir manuellement les plaques (liste déroulante) et le nombre à trouver.

    Cordialement.

  5. #25
    Expert confirmé
    Avatar de jurassic pork
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Décembre 2008
    Messages
    4 157
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2008
    Messages : 4 157
    Par défaut
    Hello,
    Citation Envoyé par laurent_ott Voir le message
    Un plus : la possibilité de choisir manuellement les plaques (liste déroulante) et le nombre à trouver.
    Pour la demande de Laurent, voici ce que je propose :
    1 - Ajout d'une case à cocher pour choisir la saisie manuelle
    2 - Ajout de 6 Listes déroulantes Activex correspondant aux 6 plaques
    Le bouton Générer devient un bouton Effacer lorsqu'on choisit la saisie manuelle. Dans ce cas le bouton Effacer, efface les plaques et le nombre à trouver.
    Les listes déroulantes sont masquées lorsque l'on est pas en saisie manuelle ou lorsque la solution apparaît.
    Procédures ajoutées :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    'Initialisation des listes déroulantes pour saisie manuelle
     
    Private Sub InitCbPlaques()
    Dim ValPlaques As Variant: ValPlaques = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 25, 50, 75, 100)
    Dim ValPlaque
    Dim Ctrl
    For Each Ctrl In Me.OLEObjects
       If InStr(Ctrl.Name, "CbPlaque") Then
          Ctrl.Object.Clear
          For Each ValPlaque In ValPlaques
              Ctrl.Object.AddItem ValPlaque
          Next
          Ctrl.Visible = True
       End If
    Next
    End Sub
     
     
    'Masquage des listes déroulantes
    Private Sub CacherCbPlaques()
    Dim Ctrl
    For Each Ctrl In Me.OLEObjects
       If InStr(Ctrl.Name, "CbPlaque") Then
          Ctrl.Visible = False
       End If
    Next
    End Sub
    Voici ce que cela donne :

    Nom : CompteEstBon.gif
Affichages : 123
Taille : 207,1 Ko

    Le classeur est en pièce jointe. Il y a peut-être des bugs car je n'ai pas tout testé. Et Merci à Jacques pour son excellent code de départ.

    Ami calmant, J.P
    Fichiers attachés Fichiers attachés

  6. #26
    Nouveau candidat au Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2022
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2022
    Messages : 3
    Par défaut Le Compte Est Bon en Excel 2016 VBA Version 2
    Je viens de terminer une version 2 afin d'améliorer et d'étendre l'interface utilisateur. J'ai aussi documenté l'algorithme (en commentaire dans le module de la "WorkSheet").

    CompteEstBonV2.xlsm

    Merci à jurasisc pork pour son intérêt et ses judicieuses suggestions. Tellement judicieuses qu'elles sont déjà dans ma version 2. Par contre, les nombres sont saisissables manuellement dans des cellule Excel plutôt que via une DropdownList mais l'utilisateur peut saisir n'importe quel nombre (amusez-vous).

    Les commentaires reçus à ce moment font presque tous référence à l'interface utilisateur. J'avoue que, pour moi, l'interface utilisateur n'est qu'un accessoire afin d'exécuter un algorithme qui solutionne un problème. C'est sur cet algorithme que j'aimerais avoir des commentaires.

    Merci encore.

  7. #27
    Expert confirmé
    Avatar de jurassic pork
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Décembre 2008
    Messages
    4 157
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2008
    Messages : 4 157
    Par défaut
    Hello,
    Pour accélérer le calcul des solutions, j'ai récupéré le code source d'un programme dotnet C# que j'ai transformé en assemblage dotnet compatible VBA contenant une classe qui effectue le calcul de solutions. J'ai ajouté par rapport au programme original l'affichage du compte approchant s'il n'y a pas de solution. Voici des informations concernant le programme original :
    Le programme est écrit en C#. Il permet de trouver n'importe quel chiffre dans la limite d'un Int32 avec un ensemble de 2 à 10 plaquettes.
    Il intègre en outre en option une table de Hashage afin d'éviter les redondances dans les calculs et d'accélérer par moment de façon drastique la résolution.
    Avec un nombre de plaquettes de 2 à 10 contenants des nombres, il fait trouver un chiffre.
    Le programme applique la récursivité en appliquant toutes les opérations possibles entre deux plaquettes et se ramenant au même problème avec les n-2 plaquettes restantes et la nouvelle créée par l'opération.
    Le programme est très puissant et avec 2Go de mémoire, la table de hashage peut contenir plus 20 millions d'entrées.
    Un compte à 7 plaquettes est trouvé en moins d'une seconde.
    En activant la table on évite les redondances dans les solutions.
    Attention la solution affichée avec le calcul dotnet est la première trouvée qui n'est pas forcément celle en moins de plaque.


    Voici le code en VBA qui fait appel à la classe Calcul de l'assemblage Dotnet :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Public Sub CalculDotnet()
        Dim ArrSolutions() As String
        Dim CalcSol As ClassesDotnetJP.Calcul
        Dim i As Integer
        Dim plaques(0 To 5) As Variant
        Dim iNbr As Long
        If Not Valider(plaques, iNbr) Then Exit Sub
        Set CalcSol = New ClassesDotnetJP.Calcul
        CalcSol.Cherche plaques, iNbr, ChkHashage.Value
        ArrSolutions = Split(CalcSol.Solutions, ",")
        Me.Cells(miRowStatus, miColStatus) = Format(CalcSol.lblNbCombi, "#,###,##0") & " opération(s) vérifiée(s) en " & CalcSol.lblSecondes & " seconde(s)"
        If CalcSol.Dif = 0 Then
                Me.Cells(miRowSolution, miColSolution) = ArrSolutions(0)
        Else
                Me.Cells(miRowSolution, miColSolution) = CalcSol.SoluApproch
        End If
        Me.Cells(miRowStatus, miColNbOper) = CalcSol.NbSol
        If CalcSol.NbSol > 0 Then Me.Range(Me.Cells(miRowAllSolutions, 1), Me.Cells(miRowAllSolutions, CalcSol.NbSol)) = ArrSolutions
    End Sub

    En pièce jointe un zip contenant le classeur avec le code VBA et dans un répertoire l'assemblage dotnet, son tbl et un script d'installation et un script de désinstallation de l'assemblage.
    Pour intégrer l'assemblage dotnet dans les Références de VBA
    1 - Enregistrer l'assemblage en lançant le script RegClassesDotnetJP.cmd en tant qu'administrateur.
    2 - Ouvrir le classeur et dans l'éditeur VBA choisir Outils/Références et cocher la case ClassesDotnetJP.
    Et voilà vous pouvez maintenant utiliser les nouvelles options du classeur.
    1 - Calcul Dotnet : pour utiliser le calcul en Dotnet au lieu du calcul en VBA
    2 - Table de Hashage : option qui permet au calcul dotnet d'éviter les redondances dans les solutions.

    Nom : CompteEstBonDotnet.PNG
Affichages : 106
Taille : 38,6 Ko




    Résultats des performances pour un tirage 5,10,3,50,4,9 avec 743 à trouver :
    1 - en VBA : 1 114 046 opérations pour 84 solutions trouvées en 13,156 secondes
    2 - en Dotnet : 1 114 061 opérations pour 84 solutions trouvées en 0,030 secondes
    2 - en Dotnet avec table de hashage : 586 993 opérations pour 55 solutions trouvées en 0,017 secondes


    en Dotnet le résultat est instantané.


    Ami calmant, J.P
    Fichiers attachés Fichiers attachés

  8. #28
    Rédacteur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Août 2013
    Messages
    995
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Finance

    Informations forums :
    Inscription : Août 2013
    Messages : 995
    Par défaut
    Bonjour,
    Merci jurassic pork pour la source et la version Dotnet.
    De mon coté j'ai trouvé une source en C que j'ai converti en VBA traditionnel pour ceux que cela intéresse.
    Actuellement le code ne donne que le premier résultat trouvé, mais est un peu plus rapide que la version de inetjack.

    Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    'Sources: https://codes-sources.commentcamarche.net/source/22392-le-compte-est-bon
    Option Explicit
     
    Private Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long
    Private Declare PtrSafe Function GetFrequency Lib "kernel32" Alias "QueryPerformanceFrequency" (cyFrequency As Currency) As Long
     
    Private Const Operateur As String = "+*/-"
    Private PlusProche As Integer
    Private Ecart As Integer
    Private Compteur As Long
     
    '---------------------------------------------------------------------------------------
    Sub main()
    '---------------------------------------------------------------------------------------
    Dim Plaque(0 To 5)
    Dim Nombre As Integer
    Dim ATrouver As Integer
    Dim iSec As Long, iFreq As Currency
     
    Plaque(0) = 5
    Plaque(1) = 10
    Plaque(2) = 3
    Plaque(3) = 50
    Plaque(4) = 4
    Plaque(5) = 9
    Nombre = 743
     
    Ecart = Nombre
    ATrouver = Nombre
    iSec = GetTickCount()
    GetFrequency iFreq
    Compteur = 0
     
    If Compte(Plaque, 6, Nombre) = True Then
        iSec = GetTickCount() - iSec
        Debug.Print "Le compte est bon ! en " & Compteur & " tests en " & Format(iSec / iFreq, "##0.000") & " seconde(s)"
    Else
        Compteur = -1000
        Call Compte(Plaque, 6, PlusProche)
        Debug.Print "Meilleure solution: (écart " & Abs(PlusProche - ATrouver) & ")"
    End If
    Debug.Print "------------------------------------------------"
     
    End Sub
     
    '---------------------------------------------------------------------------------------
    Function Compte(Plaque As Variant, Nombre As Integer, Total As Integer) As Boolean
    '---------------------------------------------------------------------------------------
    Dim i, j, k, T(5), l
     
    Compteur = Compteur + 1
    If Compteur > 999999 Then Exit Function
     
    For i = 0 To Nombre - 2
        For j = i + 1 To Nombre - 1
            For k = 1 To 4
     
            For l = 0 To 5: T(l) = Plaque(l): Next l
     
            Select Case k
     
            Case 1:
            T(i) = T(i) + T(j)
            If T(i) = Total Then
                Debug.Print Plaque(i), Mid(Operateur, k, 1), Plaque(j), "=", T(i)
                Compte = True: Exit Function
            End If
            If Abs(T(i) - Total) < Ecart Then PlusProche = T(i): Ecart = Abs(T(i) - Total)
            If Nombre > 0 Then T(j) = T(Nombre - 1)
            If (Compte(T, Nombre - 1, Total)) = True Then
                Debug.Print Plaque(i), Mid(Operateur, k, 1), Plaque(j), "==", T(i)
                Compte = True: Exit Function
            End If
     
            Case 2:
            T(i) = T(i) * T(j)
            If T(i) = Total Then
                Debug.Print Plaque(i), Mid(Operateur, k, 1), Plaque(j), "=", T(i)
                Compte = True: Exit Function
            End If
            If Abs(T(i) - Total) < Ecart Then PlusProche = T(i): Ecart = Abs(T(i) - Total)
            If Nombre > 0 Then T(j) = T(Nombre - 1)
            If (Compte(T, Nombre - 1, Total)) = True Then
                Debug.Print Plaque(i), Mid(Operateur, k, 1), Plaque(j), "==", T(i)
                Compte = True: Exit Function
            End If
     
            Case 3:
            If T(i) > T(j) And T(i) > 0 And T(j) > 0 Then
                If CDec(T(i) / T(j)) = CDec(T(i) \ T(j)) Then
                    T(i) = T(i) / T(j)
                    If T(i) = Total Then
                        Debug.Print Plaque(i), Mid(Operateur, k, 1), Plaque(j), "=", T(i)
                        Compte = True: Exit Function
                    End If
                    If Abs(T(i) - Total) < Ecart Then PlusProche = T(i): Ecart = Abs(T(i) - Total)
                    If Nombre > 0 Then T(j) = T(Nombre - 1)
                    If (Compte(T, Nombre - 1, Total)) = True Then
                        Debug.Print Plaque(i), Mid(Operateur, k, 1), Plaque(j), "==", T(i)
                        Compte = True: Exit Function
                    End If
                End If
            End If
     
            Case 4:
            If T(i) < T(j) Then
                T(i) = T(j) - T(i)
            Else
                T(i) = T(i) - T(j)
            End If
            If T(i) = Total Then
                If Plaque(i) > Plaque(j) Then
                    Debug.Print Plaque(i), Mid(Operateur, k, 1), Plaque(j), "=", T(i)
                Else
                    Debug.Print Plaque(j), Mid(Operateur, k, 1), Plaque(i), "=", T(i)
                End If
                Compte = True: Exit Function
            End If
            If Abs(T(i) - Total) < Ecart Then PlusProche = T(i): Ecart = Abs(T(i) - Total)
            If Nombre > 0 Then T(j) = T(Nombre - 1)
            If (Compte(T, Nombre - 1, Total)) = True Then
                If Plaque(i) > Plaque(j) Then
                    Debug.Print Plaque(i), Mid(Operateur, k, 1), Plaque(j), "==", T(i)
                Else
                    Debug.Print Plaque(j), Mid(Operateur, k, 1), Plaque(i), "==", T(i)
                End If
                Compte = True: Exit Function
            End If
     
            End Select
     
            Next k
        Next j
    Next i
     
    End Function

    @inetjack
    Vous écrivez "C'est sur cet algorithme que j'aimerais avoir des commentaires".
    Je vous invite à écrire le pseudo-code de l'algorithme et le présenter sur le forum dédié à l'algorithmie : https://www.developpez.net/forums/f6...tures-donnees/

    Bonne programmation.

  9. #29
    Expert confirmé
    Avatar de jurassic pork
    Homme Profil pro
    Bidouilleur
    Inscrit en
    Décembre 2008
    Messages
    4 157
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Bidouilleur
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2008
    Messages : 4 157
    Par défaut
    Hello,
    j'ai trouvé une méthode plus simple et plus pratique pour utiliser du code dotnet que celle que j'ai utilisée dans mon message précédent ( assemblage dotnet). Pour pouvoir utiliser mon assemblage dans la méthode précédente, cela obligeait à installer l'assemblage dans le système ( en étant administrateur). La nouvelle méthode qui s'appelle "unmanaged exports" crée une seule dll qu'il suffit de déclarer dans un module VBA.
    Un exemple est fourni ici . Attention la dll générée est soit en version 32 bits ou soit en version 64 bits. La version d'Excel doit correspondre. Le principe de la méthode : Dans le code C# dotnet on définit une méthode de création de classe. Cette classe sera visible par VBA en tant qu'objet. Les éléments accessibles depuis VBA doivent être définis dans le code C# en type "Unmanaged".
    Je rappelle quelques avantages potentiels en utilisant une bibliothèque de classes dotnet.
    1 - Il existe un très grand nombre de bibliothèques de classes dotnet avec sources dans tous les domaines (il faudra modifier légèrement le code pour l'utiliser dans VBA).
    2 - Exécution Multitâche – Excel VBA est limité à 1 tâche tandis que C#.NET peut être multitâche.
    3 - Vitesse de calcul.
    4 - Protection de code et d'algorithmes en les compilant en dll.
    Le problème majeur c'est qu'il faut utiliser Visual Studio et savoir programmer en C#.


    J'ai créé un nouveau classeur pour utiliser une dll (ClassCalculLibJP.dll) issue de la nouvelle méthode :
    1 - Voici le code :
    Dans un module de classe Déclaration de la méthode de création de classe avec le chemin de la Dll :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Declare Function CreateCalculClass Lib "D:\Tmp\ClassCalculLibJP.dll" () As Object
    2 - Code d'utilisation de la classe.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Public Sub CalculDotnet()
        Dim CalcSol As Object
        Dim ArrSolutions() As String
        Dim i As Integer
        Dim plaques(0 To 5) As Variant
        Dim iNbr As Long
        If Not Valider(plaques, iNbr) Then Exit Sub
        Set CalcSol = CreateCalculClass()
        CalcSol.Cherche plaques, iNbr, ChkHashage.Value
        ArrSolutions = Split(CalcSol.Solutions, ",")
        Me.Cells(miRowStatus, miColStatus) = Format(CalcSol.lblNbCombi, "#,###,##0") & " opération(s) vérifiée(s) en " & CalcSol.lblSecondes & " seconde(s)"
        If CalcSol.Dif = 0 Then
                Me.Cells(miRowSolution, miColSolution) = ArrSolutions(0)
        Else
                Me.Cells(miRowSolution, miColSolution) = CalcSol.SoluApproch
        End If
        Me.Cells(miRowStatus, miColNbOper) = CalcSol.NbSol
        If CalcSol.NbSol > 0 Then Me.Range(Me.Cells(miRowAllSolutions, 1), Me.Cells(miRowAllSolutions, CalcSol.NbSol)) = ArrSolutions
    End Sub
    Comme on peut le constater le code VBA est presque identique à celui de la première méthode.


    En pièce jointe, le classeur accompagnée de la dll ClassCalculLibJP.dll (en version 32 bits).


    Ami calmant, J.P
    Fichiers attachés Fichiers attachés

  10. #30
    Nouveau candidat au Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2022
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2022
    Messages : 3
    Par défaut Version c#
    J'ai réécrit en c#. Je savais que VBA n'était pas très rapide, mais à ce point...
    Juste la réécriture a optimisé le traitement de près de 5000%
    J'ai en plus utilisé quelques truc dans la version c# proposée par Jurassic Pork
    Liste triée et utilisation d'un array déjà créé ont optimisé l'algorithme de près de 25%
    La solution que je vous partage a 2 projets
    LeCompteEstBon :
    Contient les fichiers :
    LeBonCompte.cs qui contient une partie de la classe LeBonCompte contenant l'algorithme principal
    LeBonCompteUtil.cs qui contient des classes utilitaires utilisées par l'algorithme principal
    DOC_LeBonCompte.txt qui contient la documentation complète et le pseudo code de l'algorithme principal
    TestLeCompteEstBon :
    Contient l'interface utilisateur (non documentée)

    Merci à Jurassic Pork

    Et si vous connaissez une façon d'optimiser encore, ne vous gênez pas pour m'en faire part.

    Merci
    Fichiers attachés Fichiers attachés

Discussions similaires

  1. Jeu "Le compte est bon" avec récursivité
    Par elvis54 dans le forum Général Java
    Réponses: 1
    Dernier message: 19/11/2008, 08h50
  2. [Jeu "Le Compte est Bon"] Recherche algorithme
    Par Chriss21 dans le forum Algorithmes et structures de données
    Réponses: 3
    Dernier message: 29/10/2005, 17h10

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo