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

JavaScript Discussion :

Coordonnées systématiquement différentes


Sujet :

JavaScript

  1. #1
    Nouveau Candidat au Club
    Coordonnées systématiquement différentes
    Bonjour à vous je suis tout nouveau ici et je dois créer un jeu de plateau et générer toutes sortes d'éléments sur des cases qui contiennent donc des coordonnées (j'utilise canvas).

    Le problème c'est que ces éléments ne doivent logiquement pas apparaître sur la même case et donc les coordonnées doivent être systématiquement différentes.

    ça semble si simple mais je n'y arrive absolument pas.

    Je vous remercie pour votre aide.

  2. #2
    Modérateur

    Bonjour et bienvenue sur DVP.
    mais je n'y arrive absolument pas.
    Il serait bon que tu nous fournisses le code que tu as réalisé afin que l'on cerne mieux ton soucis.

  3. #3
    Nouveau Candidat au Club
    Pas de soucis

    je n'ai pas vraiment grand chose à proposer mais on m'a transmis cette solution fonctionnelle que j'ai encore beaucoup de mal à comprendre, vous pouvez la tester dans la console de votre navigateur:

    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
    const size = 10;
    const coord = [];
    const pas = 50;
    const canvas = 500;
     
    for (let i = 0; i < size; i++) {
     let x;
     let y;
     do
     {
       x = Math.floor(Math.random() * (canvas / pas)) * pas;
       y = Math.floor(Math.random() * (canvas / pas)) * pas;
       console.log(i, [x, y])
     } while (coord.filter(p => p[0] === x && p[1] === y).length)
     coord.push([x, y]);
    }
     
    console.log(coord);


    Encore merci

    [Edit] En gros , un nouveau jeu de coordonnées est créé lorsque qu'il y a duplication. Il est crée avec le même index que le tableau qui avait des coordonnées déjà utilisées.

  4. #4
    Modérateur

    mais on m'a transmis cette solution fonctionnelle
    elle fait le job, quel est ton soucis, compréhension du fonctionnement ?
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    for (let i = 0; i < size; i++) {
        let x;
        let y;
        do {
            // récup. de 2 valeurs aléatoires
            x = Math.floor(Math.random() * (canvas / pas)) * pas;
            y = Math.floor(Math.random() * (canvas / pas)) * pas;
        }
        // test si elles existent dans l'Array coords, si OUI on relance la récup
        while (coord.filter(p => p[0] === x && p[1] === y).length)
        // si NON on stoque les valeurs
        coord.push([x, y]);
    }

  5. #5
    Membre confirmé
    Bonjour,
    Citation Envoyé par Drelasor Voir le message
    on m'a transmis cette solution fonctionnelle
    Oui, elle semble fonctionnelle, mais générer de l'aléatoire tant que le résultat ne convient pas est une solution à éviter.
    De plus, la condition du while est lourdingue, il est plus léger de travailler sur les clés d'un objet.
    Mais sinon, la solution la plus classique est de mettre toutes les cases dans un Array et de mélanger aléatoirement ce tableau.
    Je donne la fonction du mélange, car elle n'est pas facile à concevoir :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function melanger(tableau)
    	{
    	for(let i=tableau.length-1;i>0;i--)
    		{
    		const j=Math.floor(Math.random()*(i+1));
    		const element=tableau[i];
    		tableau[i]=tableau[j];
    		tableau[j]=element;
    		}
    	return tableau;
    	}

  6. #6
    Modérateur

    Salut Loralina.

    Il aurait été effectivement préférable de stocker des {"posX": x, "posY": y} plutôt que des [x, y] voire même de travailler sur des entiers et las convertir en position après.

    Je trouve que la méthode n'est pas déconnante car dans le cas présent il a besoin de x valeurs seulement sur z possibles même si cela risque de commencer à mouliner si le x devient grand et encore.

    L'exemple que tu donnes n'est pas forcément judicieux, dans le cas présent, car il faut connaitre le tableau de départ, le « mélanger » et ensuite conserver un certain nombres de valeurs.

    Je me permets une petite remarque sur ton code, qui lui est tout à fait opérationnel, il est inutile de faire un return du tableau celui-ci étant modifié dans la fonction.
    Peut-être serait-il intéressant d'en faire une copie pour ne pas modifier le tableau en entrée, mais cela dépend du besoin biensûr.

  7. #7
    Membre confirmé
    Bonsoir NoSmoking,
    Citation Envoyé par NoSmoking Voir le message
    Il aurait été effectivement préférable de stocker des {"posX": x, "posY": y} plutôt que des [x, y] voire même de travailler sur des entiers et las convertir en position après.
    Oui, on peut faire ça (je ne parlais pas de ça en fait, mais pas grave ).
    Pour moi, le tableau [x,y] est bien aussi dans le cas présent.
    Enfin, c'est sous réserve qu'on n'ajoute pas d'autres informations ensuite, genre [x,y,idElement,couleur].
    Parfois, le besoin arrive dans un second temps et on se retrouve partagé entre compléter le tableau et retoucher le code pour utiliser un objet.

    Citation Envoyé par NoSmoking Voir le message
    Je trouve que la méthode n'est pas déconnante
    Moi je la déconseille à chaque fois que possible.

    Il existe d'autres situations où il est acceptable que la condition d'arrêt d'une boucle dépende de la validité d'un nombre aléatoire, mais c'est en général combiné avec un compteur pour limiter le nombre de tentatives.
    Je fais référence à des algorithmes où on ne peut pas définir l'ensemble des cas possibles tellement il est grand ou alors très difficile à déterminer.
    Dans ces cas là, on est contraint de tenter un certain nombre de générations aléatoires, faute de mieux.

    Citation Envoyé par NoSmoking Voir le message
    L'exemple que tu donnes n'est pas forcément judicieux, dans le cas présent
    Ca reste la solution standard.
    Bien sûr qu'il y a des cas où ça peut paraître un peu excessif, mais à moins de cas extrêmes (pas du tout le cas ici), on peut néanmoins toujours y avoir recours.

    Dans les jeux, le suffle est vraiment un incontournable (mais attention à utiliser le bon algorithme !).
    Le coup de la grille est un grand classique.

    Citation Envoyé par NoSmoking Voir le message
    il est inutile de faire un return du tableau celui-ci étant modifié dans la fonction.
    Je sais bien, mais je l'avais mis à la base pour comparaison avec d'autres algorithmes qui génèrent un nouveau tableau (comparaison que j'avais faite il y a quelques temps).

    Après, c'est aussi une habitude de certains (pas trop chez moi) pour réduire le code, car cela permet de faire une chaîne d'appels, exemple :
    element=traitementQuelconque(tab).pop();

    Un autre type de raccourci :
    let tab=traitementQuelconque([0,1,2,3]);

  8. #8
    Modérateur

    Citation Envoyé par Loralina
    Oui, on peut faire ça (je ne parlais pas de ça en fait, mais pas grave ).
    J'avais juste remarqué qu'une application de la méthode filter() sur des objets était plus performante, tout étant relatif et il faudrait surement faire de plus tester mais bon ... , que sur des array.


    Citation Envoyé par Loralina
    Moi je la déconseille à chaque fois que possible.
    Ce n'est pas non plus ma démarche première et je suis bien d'accord sur la problématique possible, donc qui fatalement arrivera, pour la sortie de boucle.


    Citation Envoyé par Loralina
    ... car cela permet de faire une chaîne d'appels, ...
    Effectivement pour le chainage cela peut être utile. Personnellement je fais une copie du tableau même si cela peut être gourmand suivant la taille.

    Mais attendons que Drelasor nous en dise éventuellement plus.

  9. #9
    Membre confirmé
    Bonjour,
    Citation Envoyé par NoSmoking Voir le message
    J'avais juste remarqué qu'une application de la méthode filter() sur des objets était plus performante, tout étant relatif et il faudrait surement faire de plus tester mais bon ... , que sur des array.
    Merci pour la précision et l'information (à vérifier à l'occasion pour la performance, sachant qu'on a parfois des résultats assez contradictoires d'un navigateur à l'autre).

    Je comprends peut-être mieux du coup ton interprétation de ce que j'avais dit.
    Je précise ce que je voulais dire ("il est plus léger de travailler sur les clés d'un objet") avec un exemple :
    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
    // /!\/!\/!\ version plus rapide du code proposé, mais dont je déconseille l'utilisation, tout comme pour le précédent, en raison de sa complexité temporelle potentiellement/théoriquement à risques /!\/!\/!\
    const nb_largCase=50; //largeur case
    const nb_hautCase=40; //hauteur case
    const nb_nombCaseX=20; //nombre cases x
    const nb_nombCaseY=10; //nombre cases y
    const nb_nombCaseElem=8; //nombre cases avec élément dessus
    const ob_ob_caseElem={}; //cases avec élément dessus
    for(let k=0;k<nb_nombCaseElem;k++)
    	{
    	while(true)
    		{
    		const i=Math.floor(Math.random()*nb_nombCaseX);
    		const j=Math.floor(Math.random()*nb_nombCaseY);
    		if(ob_ob_caseElem[i+"_"+j]===undefined)
    			{
    			ob_ob_caseElem[i+"_"+j]={i,j,x:i*nb_largCase,y:j*nb_hautCase}; //écrire i:i,j:j pour Internet Explorer
    			break;
    			}
    		}
    	}
    for(const st_i in ob_ob_caseElem)
    	{
    	console.log(ob_ob_caseElem[st_i]);
    	}

    Variantes possibles sans break, avec un do while etc.
    Si on préfère, on peut mettre les valeurs dans un tableau et utiliser l'objet uniquement pour le contrôle (dans ce cas on peut mettre null ou true comme valeur : ob_ob_caseElem[i+"_"+j]=null).

    Citation Envoyé par NoSmoking Voir le message
    Personnellement je fais une copie du tableau même si cela peut être gourmand suivant la taille.
    C'est le revers de la médaille.
    Les deux approches sont bien et rien n'empêche d'avoir les deux variantes dans son arsenal.
    Surtout que l'algorithmique d'un jeu gourmand peut différer grandement de celui qu'on utilise plus classiquement dans des traitements ponctuels. On peut avoir besoin de variantes très optimisées de routines qui habituellement ne posent pas de problème dans des applications plus statiques.

  10. #10
    Nouveau Candidat au Club
    Je viens seulement de lire toutes vos réponses , merci beaucoup , je suis encore débutant j'ai surtout un problème de compréhension je vais relire tous vos posts

  11. #11
    Modérateur

    @Loralina :
    Je précise ce que je voulais dire ("il est plus léger de travailler sur les clés d'un objet") avec un exemple
    houlà effectivement j'étais complétement à l'ouest quand je t'ai lu donc !!!! mais je suis bien d'accord.

    @Drelasor :
    Je te laisse digérer

###raw>template_hook.ano_emploi###