[RESOLU][Swift]Générer des nombres aléatoires avec une extension ?

DrakenDraken Membre
avril 2015 modifié dans Objective-C, Swift, C, C++ #1

J'ai une routine pour générer des entiers aléatoires à  la demande :



func randomInt(n:Int) ->Int {
return Int(arc4random_uniform(UInt32(n)))
}

Rien de plus facile à  utiliser :



let monTirage = randomInt(6)

Je me suis dit que ce serait intéressant de l'intégrer dans une extension, comme ceci :



extension Int {
init(random:Int) {
self.init(Int(arc4random_uniform(UInt32(random))))
}
}

Utilisation : 



let monTirage = Int(random:6)

Ce serait encore plus sympathique sous cette forme :



let MonTirage = Int.random(6)

J'ai donc tapé ce code :



extension Int {
func random(n:Int)->Int {
return Int(arc4random_uniform(UInt32(n)))
}
}

ça compile, mais ne donne pas l'effet attendu.



let MonTirage = Int.random(6)
println("monTirage: \(monTirage)")

Résultat des courses :


 



 


monTirage: (Function)



 


J'ai tenté de déclarer que MonTirage était un Int :



let monTirage:Int = Int.random(6)

 Xcode (6.1) a poussé des cris d'horreur !


 



 


'(int) -> int' is not convertible to 'int'



 


Moi aussi je pousse un cri "Comment faire pour que Int.random(6) retourne un Int ?"


 


J'ai réussi à  le faire en créant une classe adaptée :



class GenerateurAleatoire {

func randomInt(n:Int) ->Int {
return Int(arc4random_uniform(UInt32(n)))
}
}

Utilisation :



let generateurAleatoire = GenerateurAleatoire()
let monTirage = generateurAleatoire.random(6)

C'est fonctionnel, mais j'aimerais autant me passer d'initialiser une classe juste pour générer un nombre aléatoire. Et c'est moins propre que :



let monTirage = Int.random(6)

Une idée, une piste, une suggestion, une solution, un ticket restaurant ?


 


EDIT: Le forum à  la mauvaise habitude de supprimer les lignes vides autour des balises de code. C'est agaçant et fiche en l'air toute la mise en page du texte. Désolé si mon post semble être un gros pavé indigeste, sans espace libre pour faciliter la lecture !


Mots clés:

Réponses

  • AliGatorAliGator Membre, Modérateur
    avril 2015 modifié #2


    Ce serait encore plus sympathique sous cette forme :


    let MonTirage = Int.random(6)

    J'ai donc tapé ce code :

    extension Int {
    func random(n:Int)->Int {
    return Int(arc4random_uniform(UInt32(n)))
    }
    }

    ça compile, mais ne donne pas l'effet attendu.

    Normal, tu as déclaré là  une méthode d'instance. Si tu voulais utiliser cette méthode ainsi déclarée tu pourrais écrire :
    let tirage = Int().random(6)
    // ou même :
    let autreTirage = 42.random(6)

    Si tu veux pouvoir appeler "Int.random()" il faut que "random()" soit une methode de classe, pas une methode d'instance.


    Bon Int c'est pas une classe mais une struct donc je parle de methode de classe mais en fait on devrait plutôt dire une "methode de Type" (Type methode).


    Pour créer une methode de classe, on écrit "class func". Si le type c'est pas une classe mais un value type comme une struct ou un enum (et c'est ton cas avec Int qui est une struct en Swift) on écrit "static func random(x:Int) -> Int".
  • DrakenDraken Membre
    avril 2015 modifié #3

    ça marche. Merci Ali ! 



    extension Int {
    static func random(n:Int)->Int {
    return Int(arc4random_uniform(UInt32(n)))
    }
    }
  • AliGatorAliGator Membre, Modérateur
    avril 2015 modifié #4
    Une autre solution d'usage serait de déclarer une methode d'instance sur Int qui ne prend pas de paramètre, et utilise la valeur du Int (self) comme valeur max à  la place :

    extension Int {
    func random()->Int {
    return Int(arc4random_uniform(UInt32(self)))
    }
    }

    let tirage = 42.random() // un nombre entre 0 et 42
    Apres c'est juste une histoire de goût (et je préfère ta solution avec une methode de type et la borne en paramètre)
  • DrakenDraken Membre
    avril 2015 modifié #5

    Cela permet d'écrire des fonctions aléatoires avec une certaine élégance. Quelques exemples que je viens de tester :



    // POINT ALEATOIRE SUR L'ECRAN
    let monPoint = CGPoint.random(self.view.frame)


    extension CGPoint {
    static func random(rect:CGRect) ->CGPoint {
    let px = CGFloat.random(rect.width)
    let py = CGFloat.random(rect.height)
    return CGPointMake(rect.origin.x + px, rect.origin.y + py)
    }
    }


    Et :



    // ANGLE ALEATOIRE
    let angle = CGFloat.random(CGFloat(M_PI))


    extension CGFloat {
    static func random(n:CGFloat) ->CGFloat {
    let graine = CGFloat(arc4random())/CGFloat(UInt32.max)
    return graine*n
    }
    }


  • AliGatorAliGator Membre, Modérateur
    avril 2015 modifié #6
    Ceci dit tu peux aller beaucoup plus loin.

    1) Déjà  tu peux prendre un Range<Int> en paramètre plutôt que juste un Int, et ainsi pouvoir fournir à  la fois une borne min et max :
    extension Int
    {
    static func random(range: Range<Int>) -> Int
    {
    let rangeWidth = UInt32(range.endIndex - range.startIndex)
    return range.startIndex + Int(arc4random_uniform(rangeWidth))
    }
    }

    Int.random(0..<10) // Tire un nombre entre 0 (inclus) et 10 (exclus, <10)
    Int.random(-5...5) // Tire un nombre entre -5 (inclus) et 5 (inclus)
    2) Tu peux aussi créer plutôt un RandomGenerator, qui implémenterait les protocols GeneratorType et SequenceType. Pour bien comprendre ce qu'est un Generator et une Sequence, je t'invite à  lire Cet article de NSHipster. (Quelques exemples de RandomGenerators en Swift sur ce Gist trouvé sur le net)
    let doubleGen = UniformRandomDoubleGenerator()
    for n in 1...20 {
    println("Random double #\(n): \(doubleGen.next()!)")
    }
  • DrakenDraken Membre
    avril 2015 modifié #7


    1) Déjà  tu peux prendre un Range<Int> en paramètre plutôt que juste un Int, et ainsi pouvoir fournir à  la fois une borne min et max :



    extension Int
    {
    static func random(range: Range<Int> ) -> Int
    {
    let rangeWidth = UInt32(range.endIndex - range.startIndex)
    return range.startIndex + Int(arc4random_uniform(rangeWidth))
    }
    }

    Int.random(0..<10) // Tire un nombre entre 0 (inclus) et 10 (exclus, <10)
    Int.random(-5...5) // Tire un nombre entre -5 (inclus) et 5 (inclus)



    Je bossais justement sur le sujet, avant de lancer la mise à  jour d'Xcode 6.3  !


  • Draken qui parle de code ça fait bizarre, il est plus habitué au coin canapé !




  • Draken qui parle de code ça fait bizarre, il est plus habitué au coin canapé !




    Ouais, il faut lui troller son post !

  • DrakenDraken Membre
    avril 2015 modifié #10

    Mauvaises langues, j'apprends le Swift à  la Sorbonne, moi ! Et je bosse avec assiduité sur le projet de fin d'étude (bon d'accord, c'est un jeu vidéo !).

  • DrakenDraken Membre
    avril 2015 modifié #11


    2) Tu peux aussi créer plutôt un RandomGenerator, qui implémenterait les protocols GeneratorType et SequenceType. Pour bien comprendre ce qu'est un Generator et une Sequence, je t'invite à  lire Cet article de NSHipster. (Quelques exemples de RandomGenerators en Swift sur ce Gist trouvé sur le net)



    let doubleGen = UniformRandomDoubleGenerator()
    for n in 1...20 {
    println("Random double #\(n): \(doubleGen.next()!)")
    }



    C'est de l'artillerie lourde, ça.. Pour faire de la cryptographie, des calculs statistiques et autres domaines pointus. Moi j'ai juste besoin de calculer des données aléatoires simples dans le cadre d'un jeu vidéo, comme une position, une vitesse, un angle ou la force d'un impact. Je nage dans le petit bassin, moi.. Le arc4random de base me suffit (enfin je crois !).

  • AliGatorAliGator Membre, Modérateur

    Heu en quoi c'est de l'artillerie lourde ? T'as regardé le code ?

    public struct UniformRandomDoubleGenerator: GeneratorType, SequenceType {
      public func next() -> Double? {
        let intervalCount = UInt(1) << 31
        return Double(arc4random_uniform(UInt32(intervalCount))) / Double(intervalCount)
      }
      ...
    }
    Toutes les structs et fonctions utilitaires décrites dans ce post (genre UniformRandomDoubleGenerator) utilisent justement arc4random et arc4random_uniform, donc je ne vois pas en quoi tu appelles ça "de l'artillerie lourde" par rapport à  ton arc4random à  toi c'est la même chose... Tout ça parce que le nom t'a fait peur, c'est ça ?
  • DrakenDraken Membre
    avril 2015 modifié #13

    Oui, exactement. Les termes GeneratorType et SequenceType m'ont rappelé un cours de math particulièrement rébarbatif, un jour où un professeur agacé par des remarques du genre "mais finalement les maths ça sert à  quoi ?", a tenté de nous montrer le coté "pratique" en nous parlant d'algorithmes de cryptographie militaire employant des nombres aléatoires. PENDANT DEUX HEURES !


     


    Il aurais pu parler d'Enigma, du décryptage des codes secrets allemands en 1940 et de Turing, j'aurais adoré. Mais non, c'étais juste du prêchi-précha théorique, avec des mots compliqués sortant (probablement) d'un article d'une revue pour mathématiciens. Avec des histoires sur la prédictibilité des séquences pseudos-aléatoires utilisés "à  tort" dans les ordinateurs, et les moyens mathématiques d'y échapper. 


     


    Cela ne m'a pas donné envie d'ouvrir ton lien, à  tort j'avoue.


     


    De manière anecdotique, j'ai craqué le fameux code de César en quelques minutes en 5e, quand le prof de Latin nous a demandé de traduire un texte historique crypté avec ce fameux code. Faut dire que décaler la position des lettres d'une position A->B, B->C, c'est pas bien compliqué, mais bien trouvé pour l'époque. ça c'est de la cryptographie militaire historique amusante, avec un personnage célèbre (surtout pour les lecteurs d'Asterix). En plus il l'a utilisé pendant la guerre des Gaules, quand les Romains envahissaient les territoires des Gaulois.


     


    ça me fait penser que le code de César est une idée de tuto sympa pour parler de la manipulation des chaà®nes de caractères, genre une extension de la classe String en Swift.

  • AliGatorAliGator Membre, Modérateur
    Lis l'article de NSHipster que j'ai mis en lien.


    Dommage que le manque de pédagogie de ton professeur t'aime à  ce point marqué car c'est pourtant un sujet très intéressant quand on ne l'aborde pas de façon purement théorique mais pragmatique. Les Séquences et les Generators, c'est la vie !
  • DrakenDraken Membre
    avril 2015 modifié #15

    Oh non, ne crois pas que j'ai été marqué à  ce point par UN professeur et UN SEUL cours. C'est vrai que celui-ci était space, mais c'est plus profond que ça.


     


    A la fin du cours préparatoire quelqu'un a décrété que j'étais un débile léger. J'ai passé les deux années suivantes dans une classe spéciale pour attardés. Au lieu d'apprendre les bases scolaires du CE1/CE2, j'avais un dessin à  colorier par jour, et des cubes pour m'occuper le reste du temps. Puis j'ai été lâché en CM1, sans aucune préparation, avec des élèves "normaux". Le résultat à  été catastrophique, pour le reste de ma scolarité. Sans compter que j'étais vraiment persuadé d'être un idiot à  ce moment, et d'une timidité VRAIMENT maladive. Bref un scénario assez classique de ratage scolaire.


     


    Pour reprendre ton analogie fétiche, pas facile de comprendre une explication théorique sur la construction d'un toit quand on ne t'as jamais expliqué ce que sont les murs, ni les fondations, ni le béton, ni une pelle, ni un marteau. Evidement, un adulte peut prendre un livre pour combler ces lacunes, pas un gosse de 6/7 ans conditionné à  penser qu'il est un crétin, incapable de comprendre ce qui est tellement évident pour les autres (les autres qui ont appris les bases pendant 2 ans au lieu de colorier des images de p.. de cygnes). Surtout pas dans un environnement familial d'une rare indigence intellectuelle ! 


     


    De mon point de vue, assez particulier il est vrai, l'école est une machine à  broyer les gens. Mes seuls bons souvenirs sont mes deux ans de BEP d'électronique où les professeurs étaient des gens gentils, avec un vrai sens de la pédagogie et de l'enseignement par la pratique, mais c'était d'anciens professionnels ayant travaillés dans l'industrie, avec l'habitude d'enseigner à  des jeunes avec de gros trous dans leurs cursus. Des types admirables n'hésitant pas à  expliquer par le début des notions censés être apprises depuis toujours, sans culpabiliser les élèves. Tu aurais eu ta place comme prof dans cette école, même si le BEP (BAC-2) est un peu éloigné du niveau de tes considérations habituelles.


     


    Ah oui, j'oubliais, la merveilleuse éducation nationale m'a initialement dirigée vers un BEP de .. carrosserie auto ! Mon dossier scolaire avais été "égaré" à  l'académie. Il ne restait plus que des places en BEP de carrossier quand il a été enfin retrouvé. C'est grâce à  un coup de chance et un désistement trois jours avant la rentrée que j'ai pu entrer en BEP électronique.


     


    Ma brillante réussite au BEP m'a remis un peu d'aplomb pour reprendre des études "longues" avec Bac et BTS. Sauf que les profs du BAC étaient des profs classiques et .. paf .. rebelote. 


     


    Bon j'arrête là , on est sur un forum de programmation, pas dans un article d'une revue féminine sur les dégâts de l'école. C'est juste que je me laisse parfois entrainer dans une profonde amertume quand certains souvenirs remontent à  la surface. Et un profond dégoût pour tout ce qui ressemble à  un enseignement scolaire théorique. Ce n'est pas pour rien que je pense toujours d'abord aux besoins et aspirations des débutants plutôt qu'aux pro expérimentés.


  • J'ai aussi un avis assez semblable sur certains aspects de l'école. Quand j'avais 16 ans, un psycho-machin m'a déclaré "mauvais à  n'importe quoi" ou si tu préfères "bon à  rien". Et on m'a envoyé faire un CAP de monteur électricien ! Je te passe les tribulations intermédiaires, mais à  25 ans, me rendant compte que je n'étais pas plus c.. que les autres, j'ai repris des études et suis sortis à  32 ans de l'INPG par la grande porte. J'en veux toujours à  ce psycho-truc-muche.




  • mais à  25 ans, me rendant compte que je n'étais pas plus c.. que les autres,




     


    Ta précocité t'a sauvé. Il y en a qui ne s'en rende jamais compte.

Connectez-vous ou Inscrivez-vous pour répondre.