2010-11-13 4 views
4

Je veux choisir des coordonnées aléatoires sur une carte 8x8. Les coordonnées x et y ne peuvent être que -8. -6, -4, -2, 0, 2, 4, 6 et 8. Je veux choisir des coordonnées aléatoires pour 20 objets mais je ne veux pas que 2 objets aient les mêmes coordonnées. Programmez loin en C++!Cueillir des coordonnées aléatoires sans doublons?

+1

Il est donc en fait un 9x9. – starblue

Répondre

4

Vous ne disposez que de 9 valeurs possibles pour chaque coordonnée, soit 81 points possibles au total. La solution la plus simple consisterait simplement à énumérer tous les points possibles (par exemple: dans un tableau ou un vecteur), puis sélectionner au hasard 20.

Vous pouvez sélectionner au hasard 20 en sélectionnant un index de 0 à 80, en échangeant cet élément du tableau avec l'index 80, puis en choisissant au hasard un index de 0 à 79, permutant cela avec l'index 79, et ainsi de suite 20 fois. Ensuite, les 20 derniers éléments de votre tableau seront 20 points aléatoires distincts.

+0

Note de côté: Ce que vous expliquez il y a [Réservoir d'échantillonnage] (http://en.wikipedia.org/wiki/Reservoir_sampling) (Juste pour mettre un nom là-dessus pour les personnes qui pourraient ne pas le savoir). Et en fait, vous pouvez arrêter l'échange une fois que vous avez 20 valeurs, car celles-ci ne changeront pas à nouveau. – Joey

+0

@Joey: "vous pouvez arrêter l'échange une fois que vous avez 20 valeurs" c'est pourquoi j'ai dit "... et ainsi de suite 20 fois". –

0

Mettre l'algorithme de Laurence dans le programme. Cela fonctionne bien.

#include <iostream> 
#include <vector> 
#include <ctime> 
using namespace std; 

//To store x and y coordinate of a point 
struct Point 
{ 
    int x, y; 
}; 

int main() 
{ 
    vector<Point> v; 
    Point p; 
    //Populate vector with 81 combinations. 
    for(int i = -8; i < 10; i += 2) 
    { 
     for(int j = -8; j < 10; j += 2) 
     { 
      p.x = i; 
      p.y = j; 
      v.push_back(p); 
     } 
    } 
    srand(time(NULL)); 

    int lastIndex = 80; 
    for(int i = 0; i < 20; i++) 
    { 
     int randNum = rand() % (81-i); 
     //Swap to isolate chosen points. 
     std::swap(v[randNum], v[lastIndex-i]); 
    } 

    //Print chosen random coordinates 
    cout<<"Random points chosen are "<<endl; 
    for(int i = 61; i < 81; i++) 
    { 
     Point p = v[i]; 
     cout<<p.x<<"\t"<<p.y<<endl; 
    } 
} 
+1

Si vous allez utiliser la STL, pourquoi ne pas utiliser aussi std :: random_shuffle()? – Blastfurnace

+0

@Blastfurnace: Oui, mais ce n'est pas disponible dans mon édition vc express. – bjskishore123

+0

J'ai MSVC++ Express 2010 et j'utilise le STL inclus tout le temps. Si vous avez std :: vector et std :: swap, vous devriez avoir le reste de la STL disponible. – Blastfurnace

1

Prenez toutes les paires de coordonnées dans votre jeu, et les jeter dans une liste, et générer une permutation aléatoire de la liste (des algorithmes standards existent pour cela, tel que l'algorithme Laurence suggère). Prenez les 20 premiers éléments de la permutation.

+0

C'est une bonne solution, mais elle nécessite une mémoire proportionnelle à la taille de l'ensemble.Je me suis parfois demandé s'il y avait un moyen de résoudre ce problème lorsque le nombre de coordonnées possibles est astronomique. Comment pourrait-on gérer cela s'il y avait un billion de paires de coordonnées dans l'ensemble, et nous voulions visiter chacun d'eux exactement une fois, mais dans un ordre aléatoire? –

+0

Tant que vous pouvez énumérer vos points et calculer efficacement la position d'un point arbitraire directement à partir de son numéro de séquence, vous pouvez utiliser n'importe quel algorithme d'échantillonnage 1D efficace, tel que l'algorithme de Floyd - voir ma réponse pour plus de détails. –

1

Si vous pouvez énumérer toutes les coordonnées sur la carte, vous pouvez utiliser n'importe quel algorithme d'échantillonnage. Vous êtes sur une grille de 9x9; il suffit de choisir 20 des valeurs de la plage [0,80], puis les traduire en coordonnées de grille:

// Say the number picked is "n" 
int x = ((n % 9) - 4) * 2; 
int y = ((n/9) - 4) * 2; 

Vous pouvez utiliser un algorithme d'échantillonnage pour générer les n s; Découvrez les réponses à this question, par exemple. L'avantage de cette approche par rapport à la génération explicite des points est que vous pouvez économiser un peu de mémoire (et de temps de traitement) sur les grandes grilles. S'ils sont vraiment grands et que vous choisissez un petit simple, l'algorithme évident fonctionne bien aussi: choisissez un point aléatoire et réessayez si vous l'avez déjà choisi. Le seul problème avec cet algorithme est qu'il peut finir par faire assez de tentatives si vous sélectionnez une grande partie d'un ensemble.

0

Vous pouvez utiliser std :: random_shuffle par exemple, puisque vous avez un nombre fini de coordonnées entières. Il suffit donc de mélanger cet ensemble de vecteurs/positions autour. Vous pouvez également passer votre propre RNG à random_shuffle en tant qu'objet de fonction.

Exemple:

#include <algorithm> //for copy and random_shuffle 
#include <utility> //for pair and make_pair 
#include <vector> 

... 

std::vector<std::pair<int, int> > coords; 
std::vector<std::pair<int, int> > coords20(20); 
for(int y=-8; y<=8; y+=2) 
    for(int x=-8; x<=8; x+=2) 
     coords.push_back(std::make_pair(x,y)); 

std::random_shuffle(coords.begin(), coords.end());  
std::copy(coords.begin(), coords.begin() + 20, coords20.begin()); 
Questions connexes