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

C++ Discussion :

[C++14] Génération de nombres pseudoaléatoires


Sujet :

C++

  1. #1
    Membre très actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Mai 2014
    Messages
    227
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2014
    Messages : 227
    Par défaut [C++14] Génération de nombres pseudoaléatoires
    Bonjour, je suis en train de coder un petit jeu car je me fais sérieusement chi*r pour passer le temps et j'ai un petit problème avec celui-ci. Le problème vient du fait que j'ai voulu créer des nombres aléatoires différents à chaque lancement de mon programme, donc rien de plus simple qu'un petit std::time(nullptr) comme seed de générateur. Sauf que j'avais oublié une chose, c'est que std::time retourne un temps en secondes ce qui n'est pas très safe et aléatoire et pour une raison inconnue à cause de ceci mon programme plante ( peut-être que si la seed est la même pour deux générateurs il y a une exception non gérée ? ) donc j'ai voulu essayer de créer un seed avec ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    std::chrono::time_point<std::chrono::system_clock> temps = std::chrono::system_clock::now();
    auto const seed = temps;
    Mais cela ne fonctionne pas et ni ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    std::chrono::time_point<std::chrono::system_clock> temps = std::chrono::_V2::system_clock::now();
    auto const seed = temps;
    et encore moins celui là :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    auto const seed = std::chrono::system_clock::now();
    Bref j'ai essayé pas mal de choses mais les erreurs de conversions sont inébranlable ( même via du static_cast etc... )

    Donc j'ai deux demandes :
    1 - Es que quelqu'un connais un bon générateur ( fournit avec la stl ) non déterministe avec un code à me proposer pour la seed ( si seed il y a.. ) ?
    2 - Es normal et pourquoi mon programme plante une fois sur 2 avec mes générateurs ?

    Je vous remercie



    Ps : Si un peu de code vous intéresse, le voici :

    Spell.hpp


    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
    28
    29
     
    #ifndef Spell_included
    #define Spell_included
     
    #include <iostream>
    #include <random>
    #include <chrono>
     
    class Spell
    {
    public:
     
        Spell();
        Spell( std::string const &name, unsigned short const &dmgMin, unsigned short const &dmgMax, unsigned short const &dmgCritMin, unsigned short const &dmgCritMax );
     
        std::string name() const;
        unsigned short dmg() const;
        unsigned short dmgCrit() const;
     
    private:
     
        std::string const spell_name;
        unsigned short const spell_dmg_min;
        unsigned short const spell_dmg_max;
        unsigned short const spell_dmg_crit_min;
        unsigned short const spell_dmg_crit_max;
    };
     
    #endif // Spell_included
    Spell.cpp


    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
    28
    29
    30
    31
    32
    33
     
    #include "Spell.hpp"
     
    Spell::Spell() : spell_name{"???"}, spell_dmg_min{0}, spell_dmg_max{0}, spell_dmg_crit_min{0}, spell_dmg_crit_max{0}
    {
     
    }
     
    Spell::Spell( std::string const &name, unsigned short const &dmgMin, unsigned short const &dmgMax, unsigned short const &dmgCritMin, unsigned short const &dmgCritMax ) : spell_name{name}, spell_dmg_min{dmgMin}, spell_dmg_max{dmgMax}, spell_dmg_crit_min{dmgCritMin}, spell_dmg_crit_max{dmgCritMax}
    {
     
    }
     
    std::string Spell::name() const
    {
        return spell_name;
    }
     
    unsigned short Spell::dmg() const
    {
        auto const seed = std::time(nullptr);
        std::default_random_engine engin { seed };
        std::normal_distribution<float> distrib( spell_dmg_min, spell_dmg_max );
        return static_cast<unsigned short>(distrib(engin));
    }
     
    unsigned short Spell::dmgCrit() const
    {
        auto const seed = std::time(nullptr);
        std::default_random_engine engin { seed };
        std::normal_distribution<float> distrib( spell_dmg_crit_min, spell_dmg_crit_max );
        return static_cast<unsigned short>(distrib(engin));
    }
    Monster.hpp


    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
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    #ifndef Monster_included
    #define Monster_included
     
    #include <iostream>
    #include <vector>
    #include <tuple>
    #include <random>
    #include <chrono>
     
    #include "Spell.hpp"
     
    class Monster
    {
    public:
     
        Monster();
        Monster( std::string const &name, unsigned int const &level, unsigned short const &actions, unsigned int const &life, unsigned int const &xpToDrop, float const &force, std::vector<Spell> const &spells );
        ///constructeur copie
        std::string name() const;
        std::vector<std::tuple<std::string, unsigned int, bool>> attack() const;
        unsigned int getXp() const;
        unsigned int life() const;
        unsigned int maxLife() const;
        unsigned int level() const;
        bool isAlive() const;
     
    private:
     
        std::string const monster_name;
        unsigned int monster_life_max;
        unsigned int monster_life;
        unsigned int const monster_drop_xp;
        unsigned int const monster_level;
        float monster_force;
        std::vector<Spell> monster_spells;
        unsigned short monster_actions;
        float monster_critical_chance;
     
    };
     
    #endif // Monster_included
    Monster.cpp


    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
    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
     
    #include "Monster.hpp"
     
    Monster::Monster() : monster_name{"???"}, monster_life_max{0}, monster_life{0}, monster_drop_xp{0}, monster_level{0}, monster_force{0}, monster_actions{0}, monster_critical_chance{0}
    {
        monster_spells.push_back(Spell());
    }
     
    Monster::Monster( std::string const &name, unsigned int const &level, unsigned short const &actions, unsigned int const &life, unsigned int const &xpToDrop, float const &force, std::vector<Spell> const &spells ) : monster_name{name}, monster_life_max{life}, monster_life{life}, monster_drop_xp{xpToDrop}, monster_level{level}, monster_force{force}, monster_spells{spells}, monster_actions{actions}
    {
        monster_critical_chance = 90.0f;
    }
     
    std::string Monster::name() const
    {
        return monster_name;
    }
     
    std::vector<std::tuple<std::string, unsigned int, bool>> Monster::attack() const
    {
        std::vector<std::tuple<std::string, unsigned int, bool>> attacks;
     
        auto const seed = std::time(nullptr);
        std::default_random_engine engin { seed };
        std::normal_distribution<float> distrib( 0, static_cast<float>(monster_spells.size()) - 1);
        std::uniform_int_distribution<> crit(static_cast<int>(monster_critical_chance),100);
        unsigned int selector{0};
     
        for( size_t i{0}; i < monster_spells.size(); ++i )
        {
            selector = static_cast<unsigned int>(distrib(engin));
            if( crit(engin) == 100 )
                attacks.push_back(std::make_tuple(monster_spells[selector].name(), static_cast<unsigned int>(monster_spells[selector].dmgCrit() * monster_force), true ));
            else
                attacks.push_back(std::make_tuple(monster_spells[selector].name(), static_cast<unsigned int>(monster_spells[selector].dmg() * monster_force), false ));
        }
        return attacks;
    }
     
    unsigned int Monster::getXp() const
    {
        return monster_drop_xp;
    }
     
    unsigned int Monster::life() const
    {
        return monster_life;
    }
     
    unsigned int Monster::maxLife() const
    {
        return monster_life_max;
    }
     
    unsigned int Monster::level() const
    {
        return monster_level;
    }
     
    bool Monster::isAlive() const
    {
        bool b{false};
        b = monster_life == 0 ? false : true;
        return b;
    }
    PPs : Veuillez m'excuser de la non propreté du code ( il n'est pas commenté aussi x) ) c'est encore un brouillon :p
    - d'ailleurs il y à plusieurs fautes comme par exemple le i de la boucle for de attack() qui est useless et qui n'est d’ailleurs pas comparé avec la bonne chose.
    - et je viens de remarqué que c'est une grosse connerie de créer mon générateur dans une fonction

  2. #2
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Je n'ai pas lu ton code, mais pour initialiser un générateur de nombres aléatoires, std::random_device est très bien
    http://en.cppreference.com/w/cpp/num.../random_device
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  3. #3
    Membre Expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Par défaut
    Hello

    La solution de JolyLoic est la bonne.

    En revanche, je pense que tu devrais t'intéresser à ton fameux problème de conversion, car ça risque de te servir pour d'autres parties de ton jeu. Dans la STL, now() est un time_point, un point isolé dans le temps. Cela ne se mesure pas ! Le fait que ce soit représenté en temps depuis EPOCH est un détail d'implémentation. En revanche, ce qui se mesure, c'est la distance entre deux time_point, et ceci est représenté par duration, qui lui peut se mesurer et donc être converti en entier.

    Pour obtenir un entier comme tu as cherché à le faire il faut donc : prendre la date actuelle, mesurer sa distance à EPOCH, puis convertir cela en entier. Ce qui nous donne, par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <chrono>
     
    int main(void) {
        using namespace std::chrono;
        // Truc basique
        auto const integral_number = system_clock::now().time_since_epoch().count();
        // Pour avoir plus de précision et choisir l'unité
        auto const integral_number_ms = duration_cast<milliseconds>(high_resolution_clock::now().time_since_epoch()).count();
        return 0;
    }
    Et enfin dernière remarque, il est rare d'avoir besoin de sécurité pour un générateur de jeu, il suffit que la seed change à chaque partie et qu'il soit assez bon pour être agréable au gameplay. Les générateurs sécurisés sont plus lourd à l'exécution sans forcément un réel apport au gameplay.

  4. #4
    Membre très actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Mai 2014
    Messages
    227
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2014
    Messages : 227
    Par défaut
    Je vous remercie pour vos réponses et donc je vais tester le code et ci cela ne plante pas le sujet sera résolu :p

    Citation Envoyé par JolyLoic Voir le message
    Je n'ai pas lu ton code, mais pour initialiser un générateur de nombres aléatoires, std::random_device est très bien
    http://en.cppreference.com/w/cpp/num.../random_device
    Random device ne prend pas de seed et n'est pas du tout aléatoire vu qu'a chaque exécution c'est la même chose :p

    Citation Envoyé par jblecanard Voir le message
    Hello

    La solution de JolyLoic est la bonne.

    En revanche, je pense que tu devrais t'intéresser à ton fameux problème de conversion, car ça risque de te servir pour d'autres parties de ton jeu. Dans la STL, now() est un time_point, un point isolé dans le temps. Cela ne se mesure pas ! Le fait que ce soit représenté en temps depuis EPOCH est un détail d'implémentation. En revanche, ce qui se mesure, c'est la distance entre deux time_point, et ceci est représenté par duration, qui lui peut se mesurer et donc être converti en entier.

    Pour obtenir un entier comme tu as cherché à le faire il faut donc : prendre la date actuelle, mesurer sa distance à EPOCH, puis convertir cela en entier. Ce qui nous donne, par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <chrono>
     
    int main(void) {
        using namespace std::chrono;
        // Truc basique
        auto const integral_number = system_clock::now().time_since_epoch().count();
        // Pour avoir plus de précision et choisir l'unité
        auto const integral_number_ms = duration_cast<milliseconds>(high_resolution_clock::now().time_since_epoch()).count();
        return 0;
    }
    Et enfin dernière remarque, il est rare d'avoir besoin de sécurité pour un générateur de jeu, il suffit que la seed change à chaque partie et qu'il soit assez bon pour être agréable au gameplay. Les générateurs sécurisés sont plus lourd à l'exécution sans forcément un réel apport au gameplay.
    J'ai tester avec ton code là c'est pire ça plante tout le temps ^^"

  5. #5
    Membre Expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Par défaut
    Hello

    "Ca plante tout le temps" n'est pas une information très précise, et ça ne veut pas dire que le générateur y soit pour quelque chose. Ca plante comment ? Où ? Pourquoi ? Utilises un débugger et si tu es sous Linux ou Mac OS, exécutes un coup avec Valgrind pour voir...

    J'ai regardé ton code, et tu n'utilises pas le générateur correctement. Un générateur aléatoire est une machine à état. Lorsque tu appelles ta fonction membre attack(), tu crées un générateur à chaque fois. Il ne faut pas : il faut créer un générateur une seule fois que tu réutilises. La seed n'est censée être utilisée qu'au démarrage du jeu, pas à chaque appel d'une génération aléatoire...

  6. #6
    Membre très actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Mai 2014
    Messages
    227
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2014
    Messages : 227
    Par défaut
    Oui je sais bien c'est pourquoi dans mon premier message j'ai dit que ce n'était qu'une grosse connerie donc à la place j'ai créer une fonction dnas mon main mais c'est deg, et c'est bel et bien à cause des générateur car j'ai tester avec des valeurs fixe et là plus aucun problèmes. Donc bon je sais pas trop quoi faire pour le coup

  7. #7
    Expert confirmé

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 033
    Billets dans le blog
    12
    Par défaut
    Juste comme ça, tu peux afficher les valeurs retournées par les distributions, lorsque tu les utilises pour accéder à un élément dans un tableau?
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Vu que tu rand des float, et cast en (unsigned) int/float dans tous les sens, pour sortir un index de tableau, comment être étonné que ça plante quelque part ?
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  9. #9
    Membre très actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Mai 2014
    Messages
    227
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2014
    Messages : 227
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Vu que tu rand des float, et cast en (unsigned) int/float dans tous les sens, pour sortir un index de tableau, comment être étonné que ça plante quelque part ?
    Non ça ne peut pas planter car ça ne dépassera jamais la valeur max de l'index, par contre tu viens de me faire penser que tout ce qui est compris entre 0,000001 et 1 sera transformé en 1 donc il y a très peu de chance pour tomber sur le premier sort, donc oui je vois pas pourquoi je n'ai pas utilisé de générateur int :/ ? étant donné que c'est un brouillon c'était sûr qu'il y aurait des fautes de temps à autre, donc je vais tout corriger au maximum et je reviens vers vous, par contre quelqu'un à une meilleure idée d'où je devrai mettre mon générateur aléatoire ? car dans une fonction c'est bien beau même à chaque appel trop rapide je risque d'avoir les mêmes valeurs :p et même si j'ai une autre solution d'où mettre ceci, j'aimerais juste savoir où vous, vous l'auriez mis ? ( je ne sais pas si on peux passer un générateur en paramètre je vais regarder aussi ça mais ça à pas l'air très propre non plus )

  10. #10
    Expert confirmé

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 033
    Billets dans le blog
    12
    Par défaut
    Tu sais à quel endroit ça plante, avec un générateur aléatoire?
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  11. #11
    Membre très actif
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Mai 2014
    Messages
    227
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2014
    Messages : 227
    Par défaut
    J'ai trouver l'erreur ! dans mon main j'avais simplement créer un aléatoire pour généré des monstre et j'avais oublié de faire - 1 à la taille de mon vecteur ! du coup maintenant cela ne plante plus ! Je vous remercie à tous pour votre aide ^^

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 06/07/2016, 14h15
  2. Réponses: 10
    Dernier message: 19/01/2012, 12h56
  3. Génération de nombre aléatoires
    Par rebaudo dans le forum Smalltalk
    Réponses: 1
    Dernier message: 29/11/2007, 12h54
  4. Génération de nombres uniques
    Par developper dans le forum Algorithmes et structures de données
    Réponses: 5
    Dernier message: 12/09/2005, 14h42
  5. recherche algo de génération de nombre aléatoire
    Par Pascale38 dans le forum MFC
    Réponses: 2
    Dernier message: 26/01/2004, 14h20

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