代码之家  ›  专栏  ›  技术社区  ›  John Biesnecker

针对短序列的更好的随机“感觉”整数生成器

  •  4
  • John Biesnecker  · 技术社区  · 15 年前

    我正试图找出一种方法来创建随机数,让它在短序列上“感觉”随机。这是一个小测验游戏,有四个可能的选择,软件需要选择四个地点中的一个放置正确的答案,然后用干扰器填充其他三个。

    显然, arc4random % 4 将在一个长序列上产生足够多的随机结果,但在一个短序列中完全有可能(并且经常发生!)让同一号码的五个或六个连续回来。这就是我要避免的。

    我也不想简单地说“永远不要选同一个正方形两次”,因为这样每个问题只会得到三个可能的答案,第一个问题除外。目前我正在做这样的事情:

    bool acceptable = NO;
    do {
      currentAnswer = arc4random() % 4;
      if (currentAnswer == lastAnswer) {
        if (arc4random() % 4 == 0) {
          acceptable = YES;
        }
      } else {
        acceptable = YES;
      }
    } while (!acceptable);
    

    我忽略了一个更好的解决方案吗?

    4 回复  |  直到 15 年前
        1
  •  3
  •   msw    15 年前

    如果你的问题是如何计算 currentAnswer 通过非迭代地使用示例的概率,Guffa得到了您的答案。

    如果问题是如何避免随机聚类而不破坏等价性,并且您知道列表长度的上界,那么考虑以下类似于取消排序的算法:

    from random import randrange
    # randrange(a, b) yields a <= N < b
    
    def decluster():
        for i in range(seq_len):
            j = (i + 1) % seq_len
            if seq[i] == seq[j]:
                i_swap = randrange(i, seq_len) # is best lower bound 0, i, j?
                if seq[j] != seq[i_swap]:
                    print 'swap', j, i_swap, (seq[j], seq[i_swap])
                    seq[j], seq[i_swap] = seq[i_swap], seq[j]
    
    seq_len = 20
    seq = [randrange(1, 5) for _ in range(seq_len)]; print seq
    decluster(); print seq
    decluster(); print seq
    

    其中与实际工作的python代码的任何关系纯属巧合。我很确定之前的概率是保持不变的,它看起来确实打破了集群(偶尔还会增加一些)。但我很困,所以这只是为了娱乐。

        2
  •  3
  •   Will    15 年前

    然后填充一个结果数组, shuffle 然后按顺序分配。

    所以只有8个问题:

    answer_slots = [0,0,1,1,2,2,3,3]
    
    shuffle(answer_slots)
    
    print answer_slots
     [1,3,2,1,0,2,3,0]
    
        3
  •  0
  •   Guffa    15 年前

    要将重复数字的概率降低25%,可以选择一个介于0和3.75之间的随机数字,然后旋转它,使0.75以上一个答案结束。

    为了避免使用浮点值,可以将这些因子乘以四:

    伪代码(其中 / 是整数除法):

    currentAnswer = ((random(0..14) + lastAnswer * 4) % 16) / 4
    
        4
  •  0
  •   drawnonward    15 年前

    设置加权数组。假设最后一个值是2。创建这样的数组:

    array = [0,0,0,0,1,1,1,1,2,3,3,3,3];
    

    然后在数组中选择一个数字。

    newValue = array[arc4random() % 13];
    

    现在切换到使用数学而不是数组。

    newValue = ( ( ( arc4random() % 13 ) / 4 ) + 1 + oldValue ) % 4;
    

    对于P可能性和A权重 0<W<=1 用途:

    newValue = ( ( ( arc4random() % (P/W-P(1-W)) ) * W ) + 1 + oldValue ) % P;
    

    对于p=4和w=1/4,(p/w-p(1-w))=13。这表示最后一个值将是其他值的1/4。

    如果你完全排除了最新的答案,它将和最新的答案经常出现一样引人注目。我不知道你觉得什么样的体重合适,但1/4是一个很好的起点。