通过数字范围随机化

Randomizing through number range

我正在尝试让应用程序的这一部分正常工作,前提是用户单击一个按钮并且标签打印一个随机生成的 1-12 之间的数字。我已经能够成功地做到这一点,但我也希望它不重复任何已经打印的随机数。

我尝试做的是将任何打印的数字放入一个数组,然后在每次生成新数字时检查该数组。

我已经让它在 Playground 中运行,但无法在真实项目中运行。

这是我的项目的代码。

    var usedNumbers = [Int]()
    var randomConv = 0

func randomize() {
    lblRandom.text = "\(arc4random_uniform(12) + 1)"
    randomConv = Int(lblRandom.text!)!
}

@IBAction func btnRandomPressed(sender: AnyObject) {
    randomize()
    if usedNumbers.contains(randomConv) {       
        randomize()

    } else {    
        usedNumbers.append(randomConv)

    }

    if usedNumbers.count == 12 {
        btnRandom.hidden = true
    } 
}

这是我 playground 的代码。

var lblRandom = "\(arc4random_uniform(12) + 1)"
var randomConv = 0
var usedNumbers = [Int]()

func randomize() {
lblRandom = "\(arc4random_uniform(12) + 1)"
randomConv = Int(lblRandom)!
}

repeat {
randomize()

if usedNumbers.contains(randomConv) {
    randomize()   
} else {
    usedNumbers.append(randomConv)
    print(lblRandom)
}

} while usedNumbers.count < 12

我不太确定为什么您的代码不起作用,但请尝试使用此代码。

var usedNumbers = [Int]()
var randomConv = 0

@IBAction func btnRandomPressed(sender: AnyObject) {
     randomConv = Int(arc4random_uniform(12) + 1)

        if usedNumbers.contains(randomConv) {
            // If you find a duplicate you fire the event again and a new number will be randomized
            print("Exists \(randomConv)")
            btn_Pressed.sendActionsForControlEvents(.TouchUpInside)

        } else {
            print(randomConv)
            lblTest.text = String(randomConv)
            usedNumbers.append(randomConv)

       }
}

更新
usedNumbers.contains(randomConv) 条件为 true 时,您可以使用此行再次触发按钮事件:btn_Pressed.sendActionsForControlEvents(.TouchUpInside) - btn_Pressed 是 Storyboard 中的按钮出口。

我已经更新了代码块,以便您可以看到一个完整的示例。

更新 2,另一种解决方案

func randomize(){
    repeat {
        if (usedNumbers.count == 12){
            return
        }
        randomConv = Int(arc4random_uniform(12) + 1)
    } while usedNumbers.contains(randomConv)

    usedNumbers.append(randomConv)
    lblTest.text = String(randomConv)
}

@IBAction func btnRandomPressed(sender: AnyObject) {
     randomize()
}

另一个解决方案:

var availableNumbers = Array(1...12)
var randomConv = 0    

@IBAction func btnRandomPressed(sender: AnyObject) {
    if availableNumbers.count > 0 {
        let randIndex = Int(arc4random_uniform(UInt32(availableNumbers.count)))
        randomConv = availableNumbers.removeAtIndex(randIndex)

        someLabel.text = "\(randomConv)"
    }
}

您的程序以要绘制的可用数字数组开始。然后通过绘制随机索引并从数组中删除所述索引处的元素来随机选择数组的元素。它会自动调整您的数组大小,并且您确定不会再次绘制相同的数字。

系统已经为此提供了一个工具:GKShuffledDistribution 是 GameplayKit 中众多随机化实用程序之一。它与其他 GKRandom 类 不同的一件事正是您所要求的——它确保不重复已经从其随机池中 "drawn" 得到的值。

这是一个例子:

import GameplayKit
let shuffle = GKShuffledDistribution(forDieWithSideCount: 12)
for _ in 1...100 { print(shuffle.nextInt()) }

使用 playground 绘制结果图表,您会注意到没有数字会立即重复(图中没有水平线),而且没有数字每 12 "rolls".

如果您想自己实现类似的行为,您可以通过使用 SetDictionary<Int, Bool> 之类的东西来存储 already-used 或 yet-unused 值,因为它们可以在不搜索整个数据结构的情况下响应 contains