我有一个从数组中随机选择随机元素的函数和一个每秒执行该函数的计时器。 如何确保同一元素永远不会在一行中出现两次或更多?
随机洗牌者:
@objc func Shuffler() {
let array = ["1", "2", "3", "4", "5"]
let RandomWordGen = Int(arc4random_uniform(UInt32(arrray.count)))
Label.text = array[RandomWordGen]
}
计时器:
override func viewDidLoad() {
super.viewDidLoad()
let shuffleDuration: TimeInterval = 1.0
let timer2 = Timer.scheduledTimer(
timeInterval: shuffleDuration,
target: self,
selector: #selector(Shuffler),
userInfo: nil,
repeats: true
)
}
这是游戏工程中常见的问题。 请注意,所有链接的答案都是错误的,并且错过了细微之处。
让我们使用伪代码。
从表面上看,你所做的就是:
words = dog, cat, emu, horse
previousSelection = nil
function chooseOneNonRepeating
tryAgain:
result = words.randomItem
however! ...
if result == previousSelection
goto tryAgain
previousSelection = result
return result
从表面上看是“有效”的,但是。。。
它实际上是一个不确定算法的例子。
注意,只有当随机性表现得“合理”时,它才真正起作用。
说上一个词是emu--说它又被选中了。 那么,你再掷一次骰子。 它可能会一次又一次地被选中。
现在,作为一个“正常人”,你可能会说,“好吧,现在,这永远不会引起问题!”
幸运的是,程序员不是正常人。 问任何一个程序员,你就会知道使用这种不确定的算法可能会产生大量的实质性问题。
就是这么简单。 假设数组有10个项,从0到9。
跟踪上次的选择。 (一开始自然设置为零。)
假设之前的选择是五个。
- - - - - X - - - -
你所做的就是这个。 滚动一个随机数,不是从零到九而是从零到八。
现在只要从上一个向前走那么远就行了。 就这么简单。
假设你掷6步,走六步
5 6! - - - X 1 2 3 4
所以新的随机项是第二个(索引==1)。
所以只是
new index = ( previous index + random ) % length
因此,
r = (r + (random number from 0 to length-1)) % length
唯一需要照顾的特殊情况:
•如果数组的长度为“1”,则无法选择与上次不同的随机项:)
(如果你想要推广到避免最后N个项目,不要减去,而是选择一个随机数,它是全部长度,但是当你“着陆”在结果上时,不断检查它是否是前一个列表中的一个,并且向前一步,但是,为了记录,当然要确保排除组小于整个数组。)
我希望这条信息能帮助新的程序员想象如何处理这些问题!