Fonctions récursives un peu trop entouziaste

Répondre
Partager Rechercher
oui, j'avais la flemme de la marquer comme il faut
Bon, alors dernièrement j'ai eu des prises de bec avec une fonction récursive, du style
Code PHP:

void FoncRec(string sStr)
{
sStr GetStringLeft(GetStringLength(sStr)-1);
//panne d'idées, c pas ca qu'est important ^_^
FoncRec(sStr);
return;

et là j'avais un message d'erreur, non pas dans le compilateur (c'eut été trop bo)mais dans le jeu, un truc avec des
ERREUR tagIVIDE BY ZERO
ou qq chose du genre.
Et en plus des bout de codes qui s'éxecutaient pas
Le truc énervant
Bon, j'ai finit par imaginer qu'en fait je n'arrêtais jamais la fonction, et que du coup y avait jamais le "return;", donc je restais dedans à tourner en rond, tout seul comme un ***
Alors j'ai finit par faire :
Code PHP:

void FoncRec(string sStr)
{
sStr GetStringLeft(GetStringLength(sStr)-1);
//panne d'idées, c pas ca qu'est important ^_^
if(sStr!="")//on arrête si y a pu besoin
FoncRec(sStr);
return;

mais bon, je me dis que c p-e pas l'idéal . . .

Donc, j'aurais voulu savoir, d'une si c'était ca, de deux si il y avait un meilleur moyen, plus sure, et d'une manière général, quel était la technique pour ces fameuses fonction récursives, parce que cela semble plus compliqué apparement que ce que je croyais, donc ba autant se rensaigner
Les fonctions récursives s'utilisent généralement avec un delay, sinon autant utiliser une boucle.

Pour reprendre ton exemple...
Code PHP:

void FoncRec(string sStr)
{
    while(
GetStringLength(sStr) > 0)
        
sStr GetStringLeft(sStr);
    return 
sStr;

Et un exemple avec une fonction récursive utile, ce serait par exemple...
Code PHP:

void FoncRec(object oNPCstring sStrint nNum 10float fDelay 30.0f)
{
    
AssignCommand(oNPC,SpeakString(sStr));
    
nNum--;
    if(
nNum 0)
        
AssignCommand(oNPC,DelayCommand(FoncRec(oNPC,sStr,nNum,fDelay)));

*ahem*
Ba ca c'est drôle, j'arrive même plus à me rappeler pourquoi j'avais pas fais une boucle . . . bon bref, c'est un truc que g remodifié x fois de toute façon
N'empêche, ca va m'éviter des bourdes ailleurs

Donc, en fait ma question, ca pourrait être :
A quoi sert le return; dans les fonction de type "void" ?
T'en a pas mis dans ton exemple de fonction récursive, c'est voulu ?
Parce que moi j'ai quand même constaté ce probleme d'instruction non exécutées dessous . . . mais éexécutés après la petite correction que j'ai posée
c'est ca qu'est pas normal c ca ? :maoule:
C'est une fautes de ma part, toutes les fonctions sont sensées avoir un retour (même la fonction main). Dans les fonctions de type void, un return; correspond à interrompre l'exécution de la fonction. Exemple :
Code PHP:

void Test()
{
    
SetLocalInt(GetModule(),"Test",1);
    return;
    
SetLocalInt(GetModule(),"Test",2);

Après appel de la fonction, la variable locale Test du module aura la valeur 1, et non pas 2...

Mais en NWScript, les fonctions se terminent en fin d'exécution, ce de toute les façon, et il n'y a pas besoin de décharger la pile, du coup, le return; devient inutile si la fonction s'exécute de bout en bout... Il reste néanmoins possible pour des "Sanity check", par exemple
Code PHP:

void Test(string sTest)
{
    if(
GetStringLength(sTest) == 0) return;
    
SetLocalString(GetModule(),"Test",sTest);

Ici, la variable locale Test du module ne sera modifiée que si sTest contient au moins un caractère quelconque, et donc jamais écrasée.

Citation :
Provient du message de CdN
Code PHP:

void FoncRec(object oNPCstring sStrint nNum 10float fDelay 30.0f)
{
    
AssignCommand(oNPC,SpeakString(sStr));
    
nNum--;
    if(
nNum 0)
        
AssignCommand(oNPC,DelayCommand(FoncRec(oNPC,sStr,nNum,fDelay)));

Euh il ne faut pas oublier le delay dans DelayCommand() :
DelayCommand(fDelay, FoncRec(oNPC, sStr, nNum, fDelay));

Mais j'ai une question, pourquoi mettre :
AssignCommand(oNPC,DelayCommand(fDelay, FoncRec(oNPC,sStr,nNum,fDelay)));
alors que je suppose que :
DelayCommand(fDelay, FoncRec(oNPC,sStr,nNum,fDelay));
devrait suffire, puisque SpeakString() est à chaque fois appelé dans un AssignCommand(). Non ?
Oops, voui, j'ai oublié le delay

Pour que le delay s'ajoute dans la pile du NPC ciblé et pas dans la pile de l'objet en cours. Ainsi, si l'objet en cours est détruit mais pas le NPC, celui-ci continuera à déblatérer ses propos. Sans AssignCommand, la pile sera détruite avec l'objet et le NPC perdra sa langue.

Plus de détails...
@Splotch > La plupart du temps, cette construction vient du fait que l'objet qui à l'origine a exécuté cette fonction risque de disparaître entre temps. Donc, pour être sûr que cette fonction continue à s'exécuter jusqu'à ce que le NPC soit mort (après, elle n'as plus aucun intérêt de toute façon), on en affecte l'exécution au NPC en question. (attention, l'ordre est important : c'est AssignCommand( , Delaycommand() ) et pas l'inverse, pour éviter tout risque)

@Reyan > On utilise les fonctions "récursives différées" dans le NWScript parce que celui-ci ne possède pas d'instruction du type sleep(), mais il ne s'agit que d'un bidouillage, en réalité le véritable intérêt des fonctions récursives en programmation c'est que certains algorithmes y font appel (par exemple on peut programmer la fonction factorielle en récursif (petit exercice : comment ?)), en général les algorithmes récursifs sont élégants mais beaucoup plus lent que les algorithmes qui procèdent par itérations (parce que les algorithmes récursifs mobilisent trop de mémoires, à cause des multiples appels de fonctions simultanés/imbriqués). Note que toute fonction récursive se doit d'avoir deux portes de sortie : l'une qui appelle récursivement la même fonction, et l'autre qui renvoie simplement un résultat sans appel récursif, sinon une fonction récursive ne finirait jamais (ta fonction était dans ce cas, enfin plus ou moins puisqu'elle finissait avec une erreur avant d'avoir grillé le CPU)
ra la fonction factorielle je l'ai vue hier dans un coin où je devais relire trois ou quatre fois caque page . . .
ca devait être un truc du style
Code PHP:

void fac(int i)
{
if(
i<=2) return 1;
else
return 
i*fac(i--);

euh . . . mm . . . mouais, chuis pas très sure de moi là mais bon . . .
C'est presque ça, sauf que c'est if( i < 2 ) et pas if( i <= 2 ) et qu'il faut faire fac( i - 1 ) et pas fac( i-- ) sinon y a une boucle infinie (et puis là, même s'il te donne un nombre négatif, tu lui renvoies 1, mais c'est un détail)

Bon évidemment, la factorielle se fait aussi bien comme ça et ça va plus vite mais bon...pour la beauté du geste !
Code PHP:

int factorielleint n ) {
    
    if( 
) return -1//gestion d'erreur éventuellle
    
if( ) return 1;
    
int result n--;
    while( 
result*=n--;
    return 
result;
    

Je rappelle la solution récursive élégante (pour l'esprit, mais lourde pour la machine) :
Code PHP:

int factorielleint n ) {
    
    if( 
) return -1//gestion d'erreur éventuellle
    
if( ) return 1;
    return 
factorielle);
    

Jedaï, c'est quoi exactement "sleep()" ?
Parceque j'avoue ne pas voir de réel intérêt aux fonctions récursives en NWScript, même si ça reste en général très joli

Et comme le Jedaï, la mobilisation de ressources croît de manière exponentielle.

Je me rappelle avoir essayé de calculer quelque chose comme le 100e terme de la suite de Fibonacci, en récursif, ben le PC a bien mouliné pendant une minute
(il me semble que dans ce cas la fonction est appelée 2^100 fois )
sleep() c'est la fonction que tu utilise pour ordonner à l'OS d'interrompre l'exécution de ton processus pour un temps donné, de façon à libérer totalement le CPU de cette tache.
(Bien sûr, la durée n'est vraiment respecté que si l'on est sur un système temps réel)
Répondre

Connectés sur ce fil

 
1 connecté (0 membre et 1 invité) Afficher la liste détaillée des connectés