Comment faire un nombre aléatoire entre la plage pour arc4random_uniform ()?


129

donc mon objectif dans ce codebit est de lancer deux dés au hasard et comme nous le savons tous, votre dé régulier n'a que 6 faces, j'ai donc importé Foundation pour accéder à arc4random_uniform (UInt32). J'ai essayé d'utiliser la plage de (1..7) pour éviter d'obtenir au hasard 0, mais cela a renvoyé une erreur que je n'ai pas trop appréciée. J'ai essayé de faire ceci:

dice1 = arc4random_uniform(UInt32(1..7))

mais qui est revenu

Impossible de trouver une surcharge pour 'init' qui accepte les arguments fournis

J'espère que ce sont suffisamment d'informations pour que vous puissiez m'aider :)

Veuillez noter que je ne fais cela que dans une aire de jeux pour pratiquer le swift. Il n'est pas impératif que j'apprenne à faire cela; je ne fais que bricoler avant de me lancer dans la création d'applications réelles: D

//imports random number function
import Foundation
//creates data storage for dice roll
var dice1: UInt32 = 0
var dice2: UInt32 = 0
//counter variable
var i = 0
//how many times snake eyes happens
var snakeeyes = 0
 //how many times a double is rolled
var `double` = 0
//rolls dice 100 times
while i < 100{
    //from here
    //sets dice roll

Cela renvoie une erreur de 'Range $ T3' n'est pas convertible en UInt32

   dice1 = arc4random_uniform(1..7)
   dice2 = arc4random_uniform(1..7)
    //checks for snake eyes
    if dice1 == 1 && dice2 == 1 {
        snakeeyes = snakeeyes + 1

    }
    //checks for doubles
    if dice1 == dice2{
        `double` = `double` + 1
    }
    //increases counter
        i = i + 1
    //to here
}
println("You got Snake Eyes \(snakeeyes) times.")
println("You got Doubles, \(`double`) times.")

4
Je pense que vous devriez faire dice1 = arc4random_uniform(6) + 1pour obtenir la plage 1 - 6. Je ne fais pas d'objectif iOS C et je n'ai aucune connaissance du langage rapide. La méthode aléatoire devrait vous renvoyer 0 - 5, et + 1 sera 1 - 6.
Sky

1
La plage est une donnée d'objet elle-même, ce n'est pas une donnée entière, c'est pourquoi vous obtenez l'erreur lorsque l'argument ne prend que (UInt32) -u_int32_t arc4random_uniform(u_int32_t upper_bound);
Sky

aha! merci ciel! a fait une affirmation pour tester si elle allait moins de 0 et peut confirmer que c'était exactement ce dont j'avais besoin, mettez-la comme réponse afin que je puisse la cocher comme telle!
arcreigh

probabilité = Int (arc4random_uniform (UInt32 (total))) - si vous avez plusieurs plaintes de casting qui ne sont pas spécifiques (parce que la tête de type / les en-têtes ne sont pas fonctionnels)
bshirley

Ceci est intégré à partir de Swift 4.2 comme indiqué ci-dessous stackoverflow.com/a/50696901/1148030
Peter Lamberg

Réponses:


260

Je crois que tu devrais faire

dice1 = arc4random_uniform(6) + 1;

pour obtenir la gamme 1 - 6. Je ne fais pas d'objectif C d'iOS et je n'ai aucune connaissance du langage rapide. La méthode aléatoire doit renvoyer une valeur comprise entre 0 et 5, et + 1 en fera une valeur comprise entre 1 et 6.

Si vous avez besoin d'une plage entre 10 et 30, disons

int random = arc4random_uniform(21) + 10;

2
@JoeSmith vous avez exactement raison sur ce point, il devrait être arc4random_uniform (21) +10 pour renvoyer une plage entre 10 et 30 car la limite supérieure n'est pas inclusive. La partie "arc4random_uniform (20) +10" est basée sur l'édition et les votes de la communauté.
Sky

Oui, je viens de tester et pour obtenir une couleur aléatoire (c'est-à-dire voulant une valeur aléatoire comprise entre 0 et 255 inclus), j'ai utilisé: "arc4random_uniform (256) + 0"
Chris Allinson

91

J'ai fait une extension de type Int. testé dans la cour de récréation, j'espère que cela est utile. Il accepte également les plages négatives:

extension Int
{
    static func random(range: Range<Int> ) -> Int
    {
        var offset = 0

        if range.startIndex < 0   // allow negative ranges
        {
            offset = abs(range.startIndex)
        }

        let mini = UInt32(range.startIndex + offset)
        let maxi = UInt32(range.endIndex   + offset)

        return Int(mini + arc4random_uniform(maxi - mini)) - offset
    }
}

utiliser comme

var aRandomInt = Int.random(-500...100)  // returns a random number within the given range.

ou définissez-le comme une extension de plage en tant que propriété comme ceci:

extension Range
{
    var randomInt: Int
    {
        get
        {
            var offset = 0

            if (startIndex as Int) < 0   // allow negative ranges
            {
                offset = abs(startIndex as Int)
            }

            let mini = UInt32(startIndex as Int + offset)
            let maxi = UInt32(endIndex   as Int + offset)

            return Int(mini + arc4random_uniform(maxi - mini)) - offset
        }
    }
}

// usage example: get an Int within the given Range:
let nr = (-1000 ... 1100).randomInt

6
Votre extension est magnifique: 3 Une véritable utilisation de Swift!
Kalzem

J'aime l'extension Range.
David James du

Bonne réponse. Ma seule mise en garde serait de dire que randomInt: n'est pas une extension naturelle de Int ou de Range. J'ajouterais simplement ceci en tant que fonction autonome dans un fichier d'utilitaires.
Vince O'Sullivan

Doit être mis à jour pour swift 3, remplacez range.startIndex par range.lowerBound à la place et endIndex est maintenant upperBound
Joseph Astrahan

62

Quelques bonnes réponses, mais je voulais juste partager ma fonction de génération de nombres aléatoires Swift préférée pour les entiers positifs:

Swift 2

func randomNumber(range: Range<Int> = 1...6) -> Int {
    let min = range.startIndex
    let max = range.endIndex
    return Int(arc4random_uniform(UInt32(max - min))) + min
}

Swift 3

Voici une mise à jour rapide pour Swift 3 et, en prime, elle fonctionne désormais pour tout type de valeur conforme au protocole SignedInteger - beaucoup plus pratique pour les applications de données de base qui doivent spécifier Int16, Int32, etc. En bref, si vous vraiment besoin qu'il fonctionne également sur des entiers non signés, copiez simplement la fonction entière puis remplacez-la SignedIntegerpar UnsignedIntegeret toIntMax()par toUIntMax().

func randomNumber<T : SignedInteger>(inRange range: ClosedRange<T> = 1...6) -> T {
    let length = (range.upperBound - range.lowerBound + 1).toIntMax()
    let value = arc4random().toIntMax() % length + range.lowerBound.toIntMax()
    return T(value)
}

Swift 4

Grâce à la suppression de toIntMax () dans Swift 4, nous devons maintenant utiliser un autre moyen de conversion en un type entier commun. Dans cet exemple, j'utilise Int64 qui est assez grand pour mes besoins, mais si vous utilisez des entiers non signés ou si vous avez un type personnalisé Int128 ou Int256, vous devez les utiliser.

public func randomNumber<T : SignedInteger>(inRange range: ClosedRange<T> = 1...6) -> T {
    let length = Int64(range.upperBound - range.lowerBound + 1)
    let value = Int64(arc4random()) % length + Int64(range.lowerBound)
    return T(value)
}

Encore un, pour le total random-phile, voici une extension qui retourne un élément aléatoire de n'importe quel Collectionobjet de type. Notez que cela utilise la fonction ci-dessus pour générer son index, vous aurez donc besoin des deux.

extension Collection {
    func randomItem() -> Self.Iterator.Element {
        let count = distance(from: startIndex, to: endIndex)
        let roll = randomNumber(inRange: 0...count-1)
        return self[index(startIndex, offsetBy: roll)]
    }
}

Usage

randomNumber()

renvoie un nombre aléatoire compris entre 1 et 6.

randomNumber(50...100)

renvoie un nombre compris entre 50 et 100 inclus. Naturellement, vous pouvez remplacer les valeurs de 50 et 100 par ce que vous voulez.

Swift 4.2

Hélas, ma meilleure réponse StackOverflow a enfin été rendue obsolète. Vous pouvez maintenant l'utiliser simplement Int.random(in: 1 ... 6)pour générer un nombre aléatoire dans une plage donnée. Fonctionne également pour d'autres formes de nombres entiers et flottants. Types de collecte fournissent également maintenant shuffle()et randomElement()fonctions. Il n'y a donc plus besoin de fonctions de randomisation sophistiquées à moins que vous ne souhaitiez utiliser un type de randomiseur spécifique.


1
J'ai regardé cela et j'ai pensé que cela devait être faux car (max - min) = 5, ce qui donne un entier aléatoire dans la plage de 0 à 4 (plus 1 faisant 1 à 5). Mais en mettant le code dans un terrain de jeu Xcode, il était évident que cela fonctionnait. La raison en est que max est en fait égal à 7 puisque endIndex renvoie "La première position" après la fin "de la collection." (comme indiqué dans la documentation d'Apple). Donc, une bonne réponse et un exercice d'apprentissage utile pour moi.
Vince O'Sullivan

Cela fonctionne également avec des entiers négatifs. randomNumber(-3 ... -1)fonctionne tant que vous avez des espaces avant et après le .... Vous pouvez également utiliser random(-3 ..< -1pour exclure le dernier numéro.
Carter Medlin

Utilisez ClosedIntervalplutôt que Rangesi vous souhaitez que cela fonctionne avec des non-entiers.
Carter Medlin

Je ne le ferais pas. Les types d'intervalle étaient obsolètes dans Swift 3. Il existe probablement un moyen d'utiliser Generics pour étendre les fonctionnalités du code, mais je n'ai pas eu le temps, l'envie ou la raison d'enquêter.
Ash

1
Voilà, une version générique entière du code.
Ash


18

Si vous voulez, je crée cela pour des nombres aléatoires. c'est l'extension du nombre Int et Double, Float

/**
    Arc Random for Double and Float
*/
public func arc4random <T: IntegerLiteralConvertible> (type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, UInt(sizeof(T)))
    return r
}
public extension Int {
    /**
    Create a random num Int
    :param: lower number Int
    :param: upper number Int
    :return: random number Int
    By DaRkDOG
    */
    public static func random (#lower: Int , upper: Int) -> Int {
        return lower + Int(arc4random_uniform(upper - lower + 1))
    }

}
public extension Double {
    /**
    Create a random num Double
    :param: lower number Double
    :param: upper number Double
    :return: random number Double
    By DaRkDOG
    */
    public static func random(#lower: Double, upper: Double) -> Double {
        let r = Double(arc4random(UInt64)) / Double(UInt64.max)
        return (r * (upper - lower)) + lower
    }
}
public extension Float {
    /**
    Create a random num Float
    :param: lower number Float
    :param: upper number Float
    :return: random number Float
    By DaRkDOG
    */
    public static func random(#lower: Float, upper: Float) -> Float {
        let r = Float(arc4random(UInt32)) / Float(UInt32.max)
        return (r * (upper - lower)) + lower
    }
}

UTILISATION :

let randomNumDouble = Double.random(lower: 0.00, upper: 23.50)
let randomNumInt = Int.random(lower: 56, upper: 992)
let randomNumInt =Float.random(lower: 6.98, upper: 923.09)

Opérateur binaire / ne peut pas être appliqué à deux opérandes doubles
Jason G

13

Swift 3/4:

func randomNumber(range: ClosedRange<Int> = 1...6) -> Int {
    let min = range.lowerBound
    let max = range.upperBound
    return Int(arc4random_uniform(UInt32(1 + max - min))) + min
}

8

C'est parce que arc4random_uniform () est défini comme suit:

func arc4random_uniform(_: UInt32) -> UInt32

Il prend un UInt32 comme entrée et crache un UInt32. Vous essayez de lui transmettre une plage de valeurs. arc4random_uniform vous donne un nombre aléatoire entre 0 et et le nombre que vous passez (exclusivement), donc si par exemple, vous vouliez trouver un nombre aléatoire entre -50 et 50, comme dans [-50, 50]vous pourriez utiliserarc4random_uniform(101) - 50


Sky a parfaitement répondu à ma question.Je pense que vous dites la même chose également merci beaucoup de confirmer qu'en définissant dice1,2 = arc4random_uniform (6) +1 a effectivement fixé la plage à 1-6, j'ai testé cela avec une affirmation: D
arcreigh

6

J'ai modifié la réponse de @DaRk -_- D0G pour travailler avec Swift 2.0

/**
Arc Random for Double and Float
*/
public func arc4random <T: IntegerLiteralConvertible> (type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, sizeof(T))
    return r
}
public extension Int {
    /**
    Create a random num Int
    :param: lower number Int
    :param: upper number Int
    :return: random number Int
    By DaRkDOG
    */
    public static func random (lower: Int , upper: Int) -> Int {
        return lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
    }

}
public extension Double {
    /**
    Create a random num Double
    :param: lower number Double
    :param: upper number Double
    :return: random number Double
    By DaRkDOG
    */
    public static func random(lower: Double, upper: Double) -> Double {
        let r = Double(arc4random(UInt64)) / Double(UInt64.max)
        return (r * (upper - lower)) + lower
    }
}
public extension Float {
    /**
    Create a random num Float
    :param: lower number Float
    :param: upper number Float
    :return: random number Float
    By DaRkDOG
    */
    public static func random(lower: Float, upper: Float) -> Float {
        let r = Float(arc4random(UInt32)) / Float(UInt32.max)
        return (r * (upper - lower)) + lower
    }
}

La solution la plus rapide ici! Merci beaucoup!
Andrew le


3

En rapide ...

Ceci est inclusif, l'appel random(1,2)renverra un 1 ou un 2, cela fonctionnera également avec des nombres négatifs.

    func random(min: Int, _ max: Int) -> Int {
        guard min < max else {return min}
        return Int(arc4random_uniform(UInt32(1 + max - min))) + min
    }

3

La réponse est juste un code de ligne:

let randomNumber = arc4random_uniform(8999) + 1000 //for 4 digit random number
let randomNumber = arc4random_uniform(899999999) + 100000000 //for 9 digit random number
let randomNumber = arc4random_uniform(89) + 10    //for 2 digit random number
let randomNumber = arc4random_uniform(899) + 100  //for 3 digit random number

La solution alternative est:

    func generateRandomNumber(numDigits: Int) -> Int{
    var place = 1
    var finalNumber = 0;
    var finanum = 0;
    for var i in 0 ..< numDigits {
        place *= 10
        let randomNumber = arc4random_uniform(10)         
        finalNumber += Int(randomNumber) * place
        finanum = finalNumber / 10
           i += 1
    }
    return finanum
}

Bien que l'inconvénient soit que le nombre ne peut pas commencer à partir de 0.


2

Depuis Swift 4.2:

Int {    
    public static func random(in range: ClosedRange<Int>) -> Int
    public static func random(in range: Range<Int>) -> Int
}

Utilisé comme:

Int.random(in: 2...10)

2

Edit: Swift 4.2+ fournit ceci maintenant:

(100...200).randomElement()

C'est idiomatique pour moi d'étendre Range:

public extension Range where Bound == Int {
    var random: Int {
        return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound)))
    }
}

public extension ClosedRange where Bound == Int {
    var random: Int {
        return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound + 1)))
    }
}

Utilisé:

let foo = (100..<600).random

Probablement juste une chose stylistique. Il n'y a aucun avantage inhérent à l'une ou l'autre méthode, c'est juste ce avec quoi vous vous sentez le plus à l'aise.
Ash

1
Pour les personnes qui considèrent ce « style » J'ai une recommandation de langue pour eux C. S'amuser!
mxcl

Je suis sûr que quelqu'un l'avait déjà fait il y a 3 ans :) stackoverflow.com/questions/34712453/…
Leo Dabus

1

J'ai réussi à créer un nombre aléatoire en utilisant le code suivant:

var coin = arc4random_uniform(2) + 1

J'espère que cela peut vous aider.


0

Solution Swift 3 Xcode Beta 5. Basé sur la réponse de Ted van Gaalen.

extension Int
  {
     static func random(range: Range<Int> ) -> Int
    {
        var offset = 0

        if range.lowerBound < 0   // allow negative ranges
        {
            offset = Swift.abs(range.lowerBound)
        }

        let mini = UInt32(range.lowerBound + offset)
        let maxi = UInt32(range.upperBound   + offset)

        return Int(mini + arc4random_uniform(maxi - mini)) - offset
    }
}

0

var rangeFromLimits = arc4random_uniform ((UPPerBound - LOWerBound) + 1)) + LOWerBound;


0

espérons que cela fonctionne. créer un nombre aléatoire entre la plage pour arc4random_uniform ()?

var randomNumber = Int(arc4random_uniform(6))
print(randomNumber)

0

On trouve probablement utile cette version un peu mise à jour de l' Rangeextension de la réponse de Ted van Gaalen utilisant Swift 4 / Xcode 9+ :

extension CountableClosedRange where Bound == Int {
    var randomFromRange: Bound {
        get {
            var offset = 0
            if lowerBound < 0 {
                offset = abs(lowerBound)
            }
            let mini = UInt32(lowerBound + offset)
            let maxi = UInt32(upperBound + offset)
            return Int(mini + arc4random_uniform(maxi - mini)) - offset
        }
    }
}

let n = (-1000 ... 1000).randomFromRange
print(n)

Ou cette solution un peu "hacky" pour supporter les intervalles ouverts et fermés:

extension CountableRange where Bound == Int {
    var randomFromRange: Bound {
        return uniformRandom(from: lowerBound, to: upperBound)
    }
}

extension CountableClosedRange where Bound == Int {
    var randomFromRange: Bound {
        return uniformRandom(from: lowerBound, to: upperBound - 1)
    }
}

func uniformRandom(from: Int, to: Int) -> Int {
    var offset = 0
    if from < 0 {
        offset = abs(from)
    }
    let mini = UInt32(from + offset)
    let maxi = UInt32(to + offset)
    return Int(mini + arc4random_uniform(maxi - mini)) - offset
}

Je ne sais pas s'il existe un moyen d'ajouter une propriété aux deux types d'intervalles simultanément.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.