Microsoft 365 Fonction Rnd

jireu

XLDnaute Nouveau
Bonjour à tous,

Je me suis lancé le défi de réaliser un démineur en VBA sur Excel. Je sais que ce jeu existe déjà sur Excel mais je me suis dit que ca pourrait être un bon exercice pour découvrir des fonctionnalités que je ne connais pas encore.

J'en arrive à un point ou je génère une grille de "mine" de manière aléatoire via la fonction Rnd et là, c'est la surprise !
En effet, pour une grille de 9x9 cellule avec 10 mines , le positionnement des mines semblent aléatoire.

J'ai par contre tenté une grille de 100 x 100 cellules avec 2000 mines, et c'est là que la surprise apparait . Je me retrouve avec un positionnement qui semble répéter un pattern :
pattern  2000.JPG


J'imagine que ma façon d'utiliser la fonction Rnd n'est pas la bonne et c'est donc pour ça que je viens vous demander de l'aide.
Si cela peut vous être utile, vous trouverez en PJ le fichier en cours de construction que j'utilise.

Le code se trouve dans le module 1 - Sub FillGrid() et Function Roulette()

Bonne soirée !
Jireu
 

Pièces jointes

  • Mon_Demineur.xlsm
    27.7 KB · Affichages: 9

mapomme

XLDnaute Barbatruc
Supporter XLD
Bonsoir @jireu :)

Le phénomène que vous décrivez ne semble pas se produire sur ma bécane (je continue les tests).

En attendant et pour le fun, un p'tit code qui devrait faire la même chose. Le phénomène que vous avez décrit se produit-il aussi ?

Le code :
VB:
Sub FillGrid(nbLigne As Integer, nbColonne As Integer, nbMine As Integer)
Dim i&, j&, aux, t
   ReDim t(1 To nbLigne * nbColonne)
   For i = 1 To nbLigne: For j = 1 To nbColonne: t(nbColonne * (i - 1) + j) = i & " " & j: Next j, i
   Randomize
   For k = 1 To 10: For i = 1 To UBound(t): j = 1 + Int(Rnd * UBound(t)): aux = t(i): t(i) = t(j): t(j) = aux: Next i: Next k
   ReDim res(1 To nbLigne, 1 To nbColonne)
   For i = 1 To nbMine: aux = Split(t(i)): res(CLng(aux(0)), CLng(aux(1))) = "x": Next i
   Range("b4").Resize(UBound(res), UBound(res, 2)) = res
End Sub

Le même avec quelques commentaires:
VB:
Sub FillGridComm(nbLigne As Integer, nbColonne As Integer, nbMine As Integer)
Dim i&, j&, aux, t
   'tableau t à une seule dimension représentant toutes les cellules du tableau final
   ReDim t(1 To nbLigne * nbColonne)
   'on remplit le tableau avec la concaténation du numéro de ligne, d'un espace et ensuite le numéro de colonne
   For i = 1 To nbLigne: For j = 1 To nbColonne: t(nbColonne * (i - 1) + j) = i & " " & j: Next j, i
   Randomize
   ' on va mélanger 10 fois tout le tableau t (boucle indice k)
   '     un mélange est une boucle (indice i) sur tous les éléments de t
   '        pour chaque i on tire au hasard un nombre j (entre 1 et le nombre d'élément de t)
   '        puis on intervertit les éléments t(i) et t(j)
   '        et on passe à l'élément i suivant
   For k = 1 To 10: For i = 1 To UBound(t): j = 1 + Int(Rnd * UBound(t)): aux = t(i): t(i) = t(j): t(j) = aux: Next i: Next k
   ' on déclare le tableau résultat
   ReDim res(1 To nbLigne, 1 To nbColonne)
   'on va choisir les nbMine premiers éléments du tableau 't mélangé' t (boucle indice i)
   'et à partir de la valeur de t(i), on reconstruit la ligne et la colonne pour laquelle
   'le résultat doit être égal à "x"
   For i = 1 To nbMine: aux = Split(t(i)): res(CLng(aux(0)), CLng(aux(1))) = "x": Next i
   'enfin, on transfère le tableau résultat res en B4
   Range("b4").Resize(UBound(res), UBound(res, 2)) = res
End Sub
 
Dernière édition:

jireu

XLDnaute Nouveau
Bonjour et merci pour la réponse.
Le code proposé semble fournir une répartition plus aléatoire, je ne vois plus de "pattern" sur le positionnement.

Egalement, ce code est beaucoup plus rapide à exécuter que celui que j'ai proposé :) Je vais donc maintenant passer un peu de temps pour bien tout comprendre ^^

Merci pour cette proposition. Je vais essayer de trouver d'où peut venir la répartition régulière de mon premier code.

Bonne journée :)
Jireu
 

jireu

XLDnaute Nouveau
Merci @mapomme pour ta disponibilité. Je pense que j'ai compris la majorité du code proposé.
Voici ce que j'ai pu voir sur ce code que je ne connaissais pas :
  • La notation raccourci pour la déclaration des variables
  • La possibilité de dimensionner un tableau en écrivant "1 to Valeur"
    • Le fait que cette notation fait commencer le tableau à 1 et non pas à 0. J'en déduit donc que la notation "1 to valeur" ne se contente pas de juste compter de 1 à valeur mais définit les adresse du tableau
  • L'écriture de plusieurs ligne de code sur une seule ligne : il va falloir que j'étudie ce point
  • La fonction resize()
  • La possibilité de remplir une plage avec un tableau juste en faisant plage=tableau

Concernant le protocole de "mélange", c'est toi qui instaure cette façon de faire ou c'est une méthode répandue?

je continue sur mon projet.

Si toi ou quelqu'un a une idée pour cette histoire de pattern, je reste preneur.

Belle journée :)
 

mapomme

XLDnaute Barbatruc
Supporter XLD
Bonjour @jireu ;)

  • La notation raccourci pour la déclaration des variables
Quand on utilise des numéro de lignes, il vaut mieux utiliser le type Long (suffixe &) car un numéro de lignes peut être un entier plus grand que le plus grand des entiers (32 767). Personnellement, pour les entiers, j'utilise toujours le type Long.
  • La possibilité de dimensionner un tableau en écrivant "1 to Valeur"
    • Le fait que cette notation fait commencer le tableau à 1 et non pas à 0. J'en déduit donc que la notation "1 to valeur" ne se contente pas de juste compter de 1 à valeur mais définit les adresse du tableau
Oui, on pourrait écrire Dim t(-10 to -5, -5 to 5, 0 to 1) (tableau à trois dimensions avec indices personnalisés)

  • L'écriture de plusieurs ligne de code sur une seule ligne : il va falloir que j'étudie ce point
Attention !
Si on utilise des instructions "un tout petit compliquées" (exemple boucle avec un IF dans le corps de la boucle), l'écriture sur une seule ligne peut devenir incohérent par rapport à la logique recherchée.
Je n'utilise plusieurs instructions sur une seule ligne que dans le cas où toutes les instructions sont des instruction d'affectation.
Cependant, écrire une instruction par ligne rend le code quand même bien plus lisible.

  • La possibilité de remplir une plage avec un tableau juste en faisant plage=tableau
C'est un classique tant en lecture qu'en écriture.

Si on veut transférer les valeurs d'une plage dans un tableau : t=range("a1:g8") ( ou range("a1:g8").value )
Si on veut transférer les formules d'une plage dans un tableau : t=range("a1:g8").formula
Les indices des tableaux t à partir d'une plage d'une feuille de calcul commencent toujours à 1 (même si Option Base = 0 est présent dans le code)

Si on veut transférer le tableau t sur la feuille Excel à partir de la cellule B11 : Range("B11").Resize(ubound(t),ubound(t,2))=t
Si on veut se limiter aux 3 premières lignes de t et 5 premières colonnes: Range("B11").Resize(3,5))=t

Concernant le protocole de "mélange", c'est toi qui instaure cette façon de faire ou c'est une méthode répandue?
Pour l'instant, je ne l'ai vu que dans mes codes mais ça doit exister déjà ailleurs (presque tout existe déjà en VBA 😜 )
 
Dernière édition:

Statistiques des forums

Discussions
315 051
Messages
2 115 752
Membres
112 571
dernier inscrit
Pascaldeboissieu