菲舍尔耶茨洗牌咖啡脚本(Fischer Yates shuffle in coffee-script

2019-10-17 08:07发布

假设Math.random()产生均匀分布的0和1之间的随机数,这是一个正确的执行费耶茨的洗牌? 我要寻找一个非常随机的,均匀分布的,其中在输入阵列(混洗元件的数量arr可以指定)(如required )。

shuffle = (arr, required)->
  rnd = (int) ->
    r = Math.random() * int
    Math.round r

  len = arr.length-1

  for i in [len..1]
    random = rnd(i)
    temp = arr[random]
    arr[random] = arr[i]
    arr[i] = temp
    break if i < len - (required - 2)

  return arr

Answer 1:

有两件事情:

  • 而不是Math.round()尝试Math.floor() ; 在您的实现Math.round()给人的第一元素(位于索引0),比所有其他元素(0.5 / LEN对1 / LEN)的最后一个元素少了机会。 需要注意的是在第一次迭代,你输入arr.length - 1arr.length元素。
  • 如果你想有一个required变量,你还不如让它可选的,因为它默认为数组的长度: shuffle = (arr, required=arr.length)
  • 您返回整个阵列,即使你只洗牌的最后一个元素。 考虑,而不是返回arr[arr.length - required ..]
  • 如果required不在范围[0,arr.length]

全部放在一起(和添加一些天赋):

    shuffle = (arr, required=arr.length) ->
      randInt = (n) -> Math.floor n * Math.random()
      required = arr.length if required > arr.length
      return arr[randInt(arr.length)] if required <= 1

      for i in [arr.length - 1 .. arr.length - required]
        index = randInt(i+1)
        # Exchange the last unshuffled element with the 
        # selected element; reduces algorithm to O(n) time
        [arr[index], arr[i]] = [arr[i], arr[index]]

      # returns only the slice that we shuffled
      arr[arr.length - required ..]

    # Let's test how evenly distributed it really is
    counter = [0,0,0,0,0,0]
    permutations = ["1,2,3","1,3,2","2,1,3","2,3,1","3,2,1","3,1,2"]
    for i in [1..12000]
      x = shuffle([1,2,3])
      counter[permutations.indexOf("#{x}")] += 1

    alert counter


文章来源: Fischer Yates shuffle in coffee-script