Seuls les membres ayant 30 points peuvent parler sur le chat.

Forum Casio - Vos tutoriels et astuces


Index du Forum » Vos tutoriels et astuces » [Tutoriel] L'aléatoire en C/C++
Dark stormHors ligneMembre d'honneurPoints: 10921 Défis: 176 Message

[Tutoriel] L'aléatoire en C/C++

Posté le 25/02/2014 18:17

Besoin d'un peu d'aléatoire dans tes programmes C/C++ ? Ce tuto est fait pour toi !


Prérequis :

Tout d'abord, la génération de nombres aléatoires de manière "classique" en C/C++ repose sur les fonctions rand() et srand(). Celles-ci sont incluses dans la bibliothèque stdlib.h, il sera donc nécessaire de l'inclure dans le header de notre projet.


Générer des nombres aléatoires :

Pour générer un nombre aléatoire, le microprocesseur est incapable d'en déterminer un lui même. Il faut l'aider un peu, et c'est ce que l'on a fait en rentrant dans la calculatrice une fonction de ce type :

static unsigned int lastrandom=0x12345678;

unsigned int random(int seed = 0)
{
        if(seed) lastrandom = seed;
        lastrandom = ( 0x41C64E6D * lastrandom ) + 0x3039;
        return (lastrandom >> 16);
}


Bref, lors de son premier appel, la fonction rand() retournera alors le nombre de seed 0, puis celui dont le seed est la dernière valeur générée. On aura donc, par exemple
-> 0x 52 07 EB F8
-> 0x 72 65 C8 62
-> Etc.

Le problème, c'est que du coup, à chaque lancement du programme on aura les mêmes valeurs, puisque le seed original est le même...

Pour palier à cela, on détermine plus ou moins aléatoirement le seed avant le premier appel de la fonction avec srand(int position). On ne l'utilisera qu'une seule fois, au tout début du programme.

Le plus dur dans tout ça, c'est de trouver un nombre qui soit suffisamment "aléatoire" pour qu'il soit différent à chaque fois. Pour cela, nous allons utiliser le syscall RTC_getTicks().

RTC_getTicks() est une fonction très pratique qui retourne le nombre de ticks, c'est à dire de fractions (1/128) de seconde qui se sont écoulés depuis une certaine date (inconnue). Autant dire que la probabilité que le programme soit lancé deux fois en 1/128 seconde est minimale.

Voici le code à inclure :
static int SysCallCode[] = {0xD201422B,0x60F20000,0x80010070};
static int (*SysCall)(int R4, int R5, int R6, int R7, int FNo ) = (void*)&SysCallCode;

int RTC_getTicks()
{
     return (*SysCall)(0, 0, 0, 0, 0x3B);
}


Pour résumer, générer un nombre aléatoire se fait de cette façon :
1) On initialise avec srand(RTC_getTicks());
2) On récupère le nombre avec rand() : int nbAlea = rand();


Traitement du nombre aléatoire :

C'est bien joli, mais rand() ne retourne qu'un nombre compris entre 0 et 2^32-1 = 4294967295. Et nous voudrions un nombre entier entre 0 et 10, par exemple. C'est pour cela que nous allons modifier ce nombre :

Nombre entier entre 0 et max :
Nous allons utiliser le modulo (%), opération très pratique qui retourne le résultat de la division euclidienne de a par b (a%b). Or, puisque que ce reste n'est jamais supérieur à b, il est forcément égal à 0, 1, 2, 3, ..., b-1. Nous pouvons donc faire, pour générer un nombre entre 0 (inclus) et max (exclus) :
int rand_int(int max)
{
    return rand() % max;
}


Nombre entier entre min et max :
Toujours en utilisant le modulo, il est possible de bidouiller la fonction ci-dessus pour inclure le fait d'avoir un minimum :
int rand_int_ab(int min, int max)
{
    return rand() % (max - min) + min;
}

On a donc un nombre entier aléatoire entre min (inclus) et max (exclus).

Nombre décimal entre min et max :
Le problème du modulo, c'est qu'il ne permet que de travailler sur des entiers. Nous allons donc devoir nous en passer pour la génération de nombre décimaux (sous forme de float).
Nous avons vu que rand() retournait un nombre entre 0 et 2^32. Donc en supposant que RAND_MAX = 2^32, rand() / RAND_MAX est compris entre 0 et 1. Sachant que RAND_MAX est déjà défini dans "time.h", on peut l'utiliser tel quel. On en déduit alors la fonction suivante :
float rand_float_ab(float min, float max)
{
    return ( rand() / RAND_MAX ) * (max - min) + min;
}



Conclusion et annexes :

Ce tuto touche à son terme, j'espère qu'il t'aura été utile, et que tu as compris les bases de la fonction rand().
Si toutefois tu souhaite plus d'informations, ou que tu as une question, n'hésite-pas à laisser un commentaire ci-dessous !

De plus, tu trouvera peut-être ton bonheur sur l'ancien Site du Zéro, et plus particulièrement ici.


A bientôt sur Planète Casio !


Pages : 1, 2, 3, 4Suivante
LephenixnoirEn ligneAdministrateurPoints: 16866 Défis: 140 Message

Citer : Posté le 25/02/2014 18:53 | #


Dark Storm a écrit :
les fonctions rand() srand() [...] incluses dans la bibliothèque time.h

Petite erreur de ta part je crois
Ces fonctions font partie de stdlib. D'ailleurs c'est marqué dans le "C Standard Libraries.pdf"
Dark stormHors ligneMembre d'honneurPoints: 10921 Défis: 176 Message

Citer : Posté le 25/02/2014 20:11 | #


Au temps pour moi c'est corrigé
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
TotoyoHors ligneMembre d'honneurPoints: 15959 Défis: 101 Message
AlphacreatorHors ligneMembrePoints: 1464 Défis: 43 Message

Citer : Posté le 26/02/2014 09:54 | #


Louloux, en regardant le code de Mipjabok, j'ai vu que tu utilisais "rand()%128" pour générer un nombre aléatoire entre 0 et 128 mais je n'ai pas vu d'initialisation, tu fais comment?
LephenixnoirEn ligneAdministrateurPoints: 16866 Défis: 140 Message

Citer : Posté le 26/02/2014 10:00 | #


L'initialisation de srand se fait souvent avec la fonction getTicks()
AlphacreatorHors ligneMembrePoints: 1464 Défis: 43 Message

Citer : Posté le 26/02/2014 10:06 | #


Ok, je verrais comment il a fait quand je rentrerai chez moi.
Dark stormHors ligneMembre d'honneurPoints: 10921 Défis: 176 Message

Citer : Posté le 26/02/2014 18:41 | #


Sinon une autre astuce pour ne pas utiliser getTicks est de mettre le nombre de frames écoulées depuis le lancement du menu, par exemple
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
LephenixnoirEn ligneAdministrateurPoints: 16866 Défis: 140 Message

Citer : Posté le 26/02/2014 20:20 | #


Mais ça tu est obligé de le calculer toi-même non ?
Dark stormHors ligneMembre d'honneurPoints: 10921 Défis: 176 Message

Citer : Posté le 26/02/2014 20:36 | #


Pas forcément, par exemple :

int i;
int choix;
while(IsKeyUp(KEY_CTRL_EXE))
{
    i++;
    if(IsKeyDown(KEY_CHAR_1)) choix = 1;
    if(IsKeyDown(KEY_CHAR_2)) choix = 2;
}
srand(i);

Finir est souvent bien plus difficile que commencer. — Jack Beauregard
LephenixnoirEn ligneAdministrateurPoints: 16866 Défis: 140 Message

Citer : Posté le 26/02/2014 20:42 | #


Ç'est vrai que ça c'est du pur aléatoire
Mais je pense que je préfère quand même le getTicks()
Dark stormHors ligneMembre d'honneurPoints: 10921 Défis: 176 Message

Citer : Posté le 26/02/2014 20:51 | #


Ben dans notre cas, tu tu lance le jeu un grand nombre de fois, tu as des chances de retomber sur les mêmes valeurs de temps en temps, ce qui n'est pas le cas de RTC_getTicks()
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
LancelotHors ligneMembrePoints: 1274 Défis: 160 Message

Citer : Posté le 26/02/2014 20:54 | #


Et si tu mélange les deux, tu as un super tirage aléatoire !
Calculatrices : Casio 35+ SH4 (modifiée 75) et fx-CG 20 PRIZM
Projets que je soutiens
Des exemples parmi tant d'autres
Pokémon Jade de Dododormeur
Zelda de Smashmaster
Super Geek Brothers de Siapran
Mes Programmes
Mes Programmes
Mes Projets
Mes Projets
ColorLib
Add-ins Jetpack Joyride et Pac-Man sur PRIZM (les 2 non commencés mais en réflexion)
A la recherche des sprites jetpack Joride si quelqu'un les a en couleur
LephenixnoirEn ligneAdministrateurPoints: 16866 Défis: 140 Message

Citer : Posté le 26/02/2014 20:55 | #


J'aimerais savoir comment tu voudrais mélanger les deux
Vu que srand efface la graine précédente
Dark stormHors ligneMembre d'honneurPoints: 10921 Défis: 176 Message

Citer : Posté le 26/02/2014 21:03 | #


Ben "srand(RTC_getTicks() + i);"
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
BtlHors ligneAncien modérateurPoints: 3879 Défis: 107 Message

Citer : Posté le 26/02/2014 21:29 | #


Je pense que Louloux a l'habitude d'utiliser le nombre de frames écoulées depuis le lancement de l'add-ins.
(Il l'avait dit quelque part)
Un excellent tuto video qui vous explique comment transférer des fichiers de l'ordinateur vers la calculatrice et vice versa ma chaine youtube
mes jeux
mes jeux

Jouez à 6 sur une seule calto : Curve Fever
Un die and retry qui vous fera bieeeen rager Test Andropov
un très bon sokoban
le seul vrai jeu de foot en basic : FIFA 12
Ca c'est ce que j'appelle un jeu de reflexion jewel master
Qui vaincra l'intelligence artificielle de cet othello
Le célèbre pacman
Et tant d'autres BTL's games

Le jeu du mois de Novembre et award du jeu le plus dur de l'année 2013 MultiTask, testez-le
NemhardyHors ligneGrand maître des Traits d'EspritPoints: 1235 Défis: 54 Message

Citer : Posté le 02/03/2014 19:30 | #


Dark Storm a écrit :
RTC_getTicks() est une fonction très pratique qui retourne le nombre de ticks, c'est à dire de fractions (1/128) de seconde qui se sont écoulés depuis une certaine date (inconnue)


Et y'a pas moyen de compter à l'envers le nombre de ticks et retomber sur la date (à moins que ce soit spécifique pour chaque calto, ce qui est probable en soir.. ) ?
D'accord c'est complètement inutile, mais simple curiosité.
N'attendez pas qu'il n'y ait plus de miel : スススススススススススススススススススススススススス養蜂家スススススススススススススススススススススススススススススススススススス蜂家
DodormeurHors ligneAncien rédacteurPoints: 3928 Défis: 82 Message

Citer : Posté le 02/03/2014 19:49 | #


cette fonction renvoie le nombre de ticks écoulé depuis minuit (selon le processeur). Donc non, on ne peut retrouver la date a partir de cette fonction. Par contre, avec revolution-fx on peut le savoir
D'ailleurs, cette fonction renvoie au maximum 128*60*60*24 = 11059200, donc encore heureux qu'elle ne va pas plus loin que minuit, sinon on aurait des nombres très très très grand
Pokemon !!!!!! => pokemon stadium/battle

mes meilleurs jeux
Cliquer pour enrouler
un jeu avec des niveaux de gris mais compatible SH4 (mais en monochrome pour les SH4) => bomberman
envie de plonger dans la mer pour ramasser des tresors? => ballon sea
envie de sauver l'univers dans un jeu avec une longue durée de vie? => saviors of the future
un add-in addictif avec plein de secret et de trophées => evasion survival
un shmup bien dur et sadique => saviors 2

projets
Cliquer pour enrouler

pokemon
Cliquer pour enrouler



encodage des données de combat (sprite, attaques et nom)
   100%

systeme de combat
   100%

encodage des données de pokemon (niveau d'apprentisage et evolution)
   100%


moteur de la carte
   50%

level design
   1%

finition de pokemon jade
   42%

merci a tout le monde pour son soutien


projets que je soutiens
Cliquer pour enrouler
minecraft de limachi
zelda prizm de smashmaster (en esperant qu'il puisse le finir)
les tests de marmotti
un RPG de dark storm (dont je connais le nom, mais pas vous ) Arcuz !
NemhardyHors ligneGrand maître des Traits d'EspritPoints: 1235 Défis: 54 Message

Citer : Posté le 02/03/2014 19:54 | #


D'accord, donc c'est depuis minuit déterminé à partir d'un instant 00:00h à un jour t arbitraire c'est ça ?
Il me semblait aussi que ça allait être très grand aussi
N'attendez pas qu'il n'y ait plus de miel : スススススススススススススススススススススススススス養蜂家スススススススススススススススススススススススススススススススススススス蜂家
DodormeurHors ligneAncien rédacteurPoints: 3928 Défis: 82 Message

Citer : Posté le 02/03/2014 20:29 | #


En fait, c'est juste que le processeur est rarement réglé a la bonne heure, mais si il l’était, ce serait le nombre de ticks écoulé depuis minuit du jour actuel
Pokemon !!!!!! => pokemon stadium/battle

mes meilleurs jeux
Cliquer pour enrouler
un jeu avec des niveaux de gris mais compatible SH4 (mais en monochrome pour les SH4) => bomberman
envie de plonger dans la mer pour ramasser des tresors? => ballon sea
envie de sauver l'univers dans un jeu avec une longue durée de vie? => saviors of the future
un add-in addictif avec plein de secret et de trophées => evasion survival
un shmup bien dur et sadique => saviors 2

projets
Cliquer pour enrouler

pokemon
Cliquer pour enrouler



encodage des données de combat (sprite, attaques et nom)
   100%

systeme de combat
   100%

encodage des données de pokemon (niveau d'apprentisage et evolution)
   100%


moteur de la carte
   50%

level design
   1%

finition de pokemon jade
   42%

merci a tout le monde pour son soutien


projets que je soutiens
Cliquer pour enrouler
minecraft de limachi
zelda prizm de smashmaster (en esperant qu'il puisse le finir)
les tests de marmotti
un RPG de dark storm (dont je connais le nom, mais pas vous ) Arcuz !
LoulouxHors ligneAncien administrateurPoints: 7035 Défis: 61 Message

Citer : Posté le 03/03/2014 10:42 | #


Btl a écrit :
Je pense que Louloux a l'habitude d'utiliser le nombre de frames écoulées depuis le lancement de l'add-ins.
(Il l'avait dit quelque part)

Désolé de vous décevoir, mais dans Mipjabok je n'initialise même pas ma fonction rand : je me fiche que le nuage de point quand on perd soit le même à chaque fois qu'on relance le jeu

Ajouté le 03/03/2014 à 10:43 :
Quant aux autres jeux, je prenais effectivement le nombre de frames écoulées depuis le lancement, histoire de pas m'embêter avec le RTC.
Pages : 1, 2, 3, 4Suivante

Planète Casio v42 © créé par Neuronix et Muelsaco 2004 - 2020 | Il y a 118 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd