Nombre aléatoire
bleub13
Membre
Bonjour,
je débute en dévéloppement. Je viens de commencer une application qui est un quizz.
J'ai créé des tableaux où je stocke mes questions. Un nombre est géré aléatoirement qui va allé piocher dans les tableaux.
Cependant, j'aimerai que les valeurs déjà utilisé soit interdite pour éviter de retomber sur une même question. Je ne sais pas comment faire.
Merci pour votre aide /smile.png' class='bbc_emoticon' alt=':)' />
je débute en dévéloppement. Je viens de commencer une application qui est un quizz.
J'ai créé des tableaux où je stocke mes questions. Un nombre est géré aléatoirement qui va allé piocher dans les tableaux.
Cependant, j'aimerai que les valeurs déjà utilisé soit interdite pour éviter de retomber sur une même question. Je ne sais pas comment faire.
Merci pour votre aide /smile.png' class='bbc_emoticon' alt=':)' />
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
TRUE => la question est utilisable
FALSE => la question n'est plus utilisable
Si tu as 50 questions, au début ça va aller, mais quand tu en auras posé 48 et qu'il t'en reste donc plus que 2 à choisir, tu vas devoir relancer un sacré paquet de fois ton random pour espérer tomber sur une des deux qui restent... et je te parle pas de quand il n'en reste qu'une !
Donc non, ce n'est pas vraiment top comme solution.
Mieux vaut faire l'inverse et garder un tableau de celles qui restent à poser, et faire son random dans ce tableau.
Je comprends la logique du code mais je ne sais pas comment l'adapter pour moi.
(Question*q correspond à quoi ? J'ai du mal avec la syntaxe )
Voici un aperçu de mon code... si vous pouviez m'éclairer...
un champ NSString *nomQuestion;
un champ NSString *reponseA;
un champ NSString *reponseB;
un champ NSString *reponseC;
un champ NSString *reponseD;
un champ int nombreReponsePossible;
un champ int bonneReponse;
Sinon tu vas te compliquer la vie pour gérer les réponses !
Oui, sauf si je n'utilise le random que pour les 45 premières questions. Il suffit ensuite de parcourir le tableau linéairement pour récupérer les 5 dernières questions. J'utilise cette technique depuis mon premier jeu de rôle sur Amstrad 6128.
Bleub13, tu devrais essayer de définir tes questions dans un fichier plist. C'est beaucoup plus souple d'emploi qu'une définition en "dur" dans le code source.
Ce code me semble correcte, mais pourquoi "casser" votre tableau de question ?
Tu mets une autre variable de type BOOL ou char (meme taille je crois) que set a 1 si la question est deja passer
et si c'est 0, cela veut dire que la question n'a pas encore été poser ?
Pis si dans ton arc4random (D'ou elle sort cette fonction ^^), il te sort une question deja poser, refait un random ou regarde celui d'avant et d'apres s'il a deja été poser ?
Ceci étant dis, arc4random peut être remplacer par :
C'est plus commun comme fonction ^^
Et pour les réponses un petite classe ayant:
M'voyer ?
Ah tu veux dire que les problèmes de mémoire n'existent plus avec les machine actuelles ? Merci d'ensoleiller ma journée.
Tirer une question au hasard dans ton tableau de toutes tes questions, et si jamais la question est déjà posée retirer un nombre au hasard encore et encore jusqu'à enfin tomber sur une question pas encore posée, ça va être loin d'être optimisé et plutôt long (la probabilité de tomber sur une question déjà posée augmentant au fur et à mesure que tu as posé de plus en plus de questions bien sûr, donc le nombre de retirages nécessaire va aller en augmentant).
Quand tu auras déjà posé 49 questions sur tes 50 questions par exemple (si tu en as 50 en tout), il ne t'en restera qu'une seule, pourtant tu vas n'avoir qu'une seule chance sur 50 que ton random tombe dessus, donc tu vas pas tomber dessus tout de suite, et devoir refaire un sacré paquet de tirages avant d'avoir la chance de tomber dessus !
Alors que si tu ne fais ton tirage que sur les questions restantes et pas sur toutes les questions, tu n'as rien du tout à faire à côté, pas besoin de test ni de re-tirage puisque tu tombes forcément sur une question pas encore posée. Beaucoup plus rapide, et beaucoup plus optimal.
Bien sûr le tableau de alreadyAskedQuestions est une copie du tableau contenant toutes tes questions, tu fais la copie au début de ton jeu et tu l'écrèmes au fur et à mesure que tu poses tes questions... et si tu recommences le jeu tu n'as qu'à refaire une copie de ton tableau de question avec [font=courier new,courier,monospace]self.alreadyAskedQuestions = [[allQuestions mutableCopy] autorelease];[/font] et le tour est joué, tes questions sont réinitialisées en une simple ligne de code (alors qu'avec des flags tu serais obligé de tout repasser question par question pour le remettre à NO...)
Bref je ne vois aucun inconvénient à ma méthode, et en plus elle est en complexité algorithmique O(1) alors que l'algo consistant à réitérer jusqu'à trouver est O(n) et que le nombre de retirages nécessaires et de temps pour tomber sur une question non posée va augmenter linéairement... donc je ne vois mais alors pas du tout quel avantage la solution de "tirer dans toutes les questions et retirer jusqu'à trouver une non posée" est intéressante ou mieux que de ne tirer que dans les questions non encore posées ?! C'est quoi l'avantage de l'autre solution ?!
Ah la fameuse complexité des algorithmes, une notion que beaucoup de développeurs néglige...
Ce seul argument suffit à me faire choisir l'algorithme de Ali plutôt que celui de Xodia.
Le seul avantage de la méthode que je propose est qu'elle est simple a coder pour un débutant.
Apres j'avoue que la tienne est pas trop compliquer non plus, le seul truc est de bien gérer la mémoire.
Faut aussi voir les test de perf pour voir lequel prend le plus de temps (en sachant qu'en arrière-plan pour modifier les tableaux il faut boucler dessus, le redimensionner etc... (Au niveau interne des classes)) A tester..
La structure interne des NSArray est franchement super optimisée, Apple a fait un gros travail dessus (cf l'article de RidiculousFish que j'ai déjà cité plusieurs fois et qui explique tout ça avec le détail des perfs et tout), ce qui fait que pour modifier un NSMutableArray ça prend 3 fois rien de temps.
Ca n'a vraiment rien à voir avec des tableau C par exemple. Avec NSArray, pour modifier le tableau pas besoin de boucler dessus (principe de la liste chaà®née, ça enlève un élément en plein milieu sans pb), pas besoin de le redimentionner (de toute façon il est alloué par chunks), donc au final un removeObjectAtIndex prend un temps négligeable (par rapport à si tu devais faire la même chose avec un tableau C où ça sera une méga galère par contre)
A chaque tirage, on envoie l'élément tiré à la case M-1 du tableau où M est le nombre d'éléments restants à tirer et on effectue le prochain tirage sur les M-2 premiers éléments.
C'est un peu tirer les cheveux ton truc /xd-laugh.gif' class='bbc_emoticon' alt='xd' />
Faut faire attention a faire trop "joujou" avec les pointeurs comme sa, c'est facilement plantable si tu le fais pas bien.
Mais si tu fais cela, il faut switcher les deux pointeurs (celui piocher et celui qu'on prend la place).
J'avais créé donc une liste chaà®née.
J'randomisais mon "k" et après, je supprimais ce k-ième élément, réduisant par la même occasion le max du random.
En bref, la méthode utilisée par le Croco sans objet :°)
Exemple :
Tu as le tableau suivant de longueur 7 :
Tu tires un nombre aléatoire entre 0 et 6 : 2 (c'est à dire C). Tu permutes C avec la valeur à l'index 6 et tu réduis N.
La valeur C ne peut plus être tirée car N vaut maintenant 6. Tu tires un nouveau nombre aléatoire entre 0 et 5. Tu permutes la valeur avec la valeur à l'index 5 et tu réduis à nouveau N.
La méthode présente plusieurs avantages :
Au final le code serait, à mon sens, plus lisible.. non?
Par contre si on parle de plusieurs milliers de questions je pense effectivement que le côté -removeObjectAtIndex: (dans 'questions') puis -addObject: (dans la 'answeredQuestions') risque de prendre plus de temps qu'un -exchangeObjectAtIndex:withObjectAtIndex:
Il y a un tableau de perfs quelque part concernant -exchangeObjectAtIndex:withObjectAtIndex: ?
Bref, toutes les solutions proposées sont viables, mais ça dépend des cas. je préfèrerai utiliser 2 arrays si je suis sûr d'avoir entre 0 et 200 objets par exemple.. (je dis ça arbitrairement). Dans le cas où l'intervalle 0-XX où XX pourrait être faramineux, je vais préférer le méthode de Baarde..
Effectivement, avoir un seul tableau qui contient tous les objets peut être source de confusion. Mais on peut très bien concevoir une classe ayant un niveau d'abstraction plus élevé et utilisant le tableau dans son implémentation.
En ce qui concerne les performances, je pense que le gain est assez négligeable (sur une machine actuelle).
Mais par intuition ça me paraissait la meilleure solution car on n'a rien à copier, rien à supprimer et l'algo a un comportement constant tout au long du jeu (si on suppose que la méthode exchangeObjectAtIndex:withObjectAtIndex: aura toujours le même comportement).
C'est une version optimisée en mémoire de la version à deux tableaux en fait.
Je trouve plus élégant de jouer avec N que de faire des copies de tableaux mais c'est une question de goût...
Après c'est sans doute moins facile à lire, mais ce n'est pas grave si c'est bien encapsulé.
De toutes façons, c'est un cas où le plus important c'est d'encapsuler l'ago et de bien choisir les interfaces de l'objet qui gère les questions pour pouvoir changer la mécanique interne si nécessaire.
Cela ne sert à rien de se prendre la tête quand on n'a pas tous les éléments en main, autant se concentrer sur l'aspect modulaire et "refactorable" du code pour sortir une version au plus vite et la confronter à une utilisation réelle.
La solution de FKDEV est bien aussi hein, mais plus casse-tête à mettre en place, pour peu de gain finalement en terme de perfs.
La question de l'utilisation mémoire est vraiment un faux problème, j'espère que vous avez conscience comme l'a souligné Louka qu'on ne duplique pas les questions, et donc qu'on a pas 2x50 questions en mémoire si on a 50 questions à l'origine. On fait des retain sur les questions, donc on a toujours seulement 50 instances, retenues 2 fois (une fois par chaque tableau), et pas 100 instances en mémoire.
Au final la seule chose qu'on a en mémoire en plus du tableau de toutes les questions, c'est un objet qui fait genre 20 octets on va dire (l'instance du conteneur NSMutableArray, mais sans son contenu), le contenu de ce NSMutableArray étant des objets déjà en mémoire ailleurs de toute façon.
J'aimerais maintenant qu'il me sauvegarde les questions déjà posés quand je ferme l'application et la relance pour rejouer.
J'ai trouvé des tutos mais je ne comprend pas vraiment tout ...