如何使一个函数永远不会在Lua中选择两倍相同的数字

时间:2014-02-22 03:29:22

标签: for-loop random lua lua-table

我正在尝试创建一个生成随机数的函数,但绝不会两次。

这是我到目前为止所得到的,但它不起作用。它编译,但然后再次在我的数组中插入相同数字的多次。

quiz = 10
array = {}
array[1] = 0 -- just to have something in it because it won't work in my loop otherwise...
ok = false

repeat
    rdm = math.ceil(math.random() * quiz)

    for i = 0, #array do
        if(rdm == array[i]) then
            break -- to break the for loop to pick a new number
        elseif(rdm ~= array[i]) then
            ok = true -- to end the repeat loop
            table.insert(array, rdm) -- to keep a track of what I got so far
        end
    end
until ok == true

for b = 0, #array do -- #array should be ten
    print(array[b])
end

它的作用是生成相同数字的多倍,并表示它与表格中的数字不同...

我想我的问题来自逻辑......但我不知道它对我来说有什么意义

2 个答案:

答案 0 :(得分:2)

如果您知道最多需要N个数字,则可以预生成随机数并根据其值将其插入表中。然后你的函数从该表中随机选取一个数字并删除该数字。类似的东西:

local rands = {}
local numRands = 100

-- populate table of random numbers
while #rands < numRands do
    local r = math.random(1,1000)
    rands[r]=r -- if duplicate, table stays same
end

local function getNeverSameRandom() 
    local index = math.random(1,numRands)
    return table.remove(rands, index)
end

如果您不知道要填充多少,请通过表格跟踪:

local randsUsed = {}
local maxRand = 1000000 -- largest random # you want
local function getNeverSameRandom() 
    local rnd
    repeat 
         rnd = math.random(1,maxRand)
    until randsUsed[rnd] == nil
    randsUsed[rnd] = rnd
    return rnd
end

问题当然是如果你多次调用getNeverSameRandom,比如最大随机数的一半,你的randsUsed表将会变得非常充实,而repeat-until将需要更长时间。最终,表格将满,并且该函数将处于无限循环中。您可以通过跟踪计数器轻松检查,但不能使用#randsUsed,因为randsUsed是一个带有“洞”的表,因此无法使用#操作。例如:

local randsUsedCount  = 0
local function getNeverSameRandom() 
    if randsUsedCount == maxRand then
        error("No more random #'s left in range 1-"..maxRand)
    end
    local rnd
    repeat 
         rnd = math.random(1,maxRand)
    until randsUsed[rnd] == nil
    randsUsed[rnd] = rnd
    randsUsedCount = randsUsedCount  + 1
    return rnd
end

答案 1 :(得分:2)

最简单的方法是使用您需要的序列预填充元素数组(例如,1..1000),然后使用Fisher-Yates algorithm之类的内容对元素进行洗牌:

local rands, n = {}, 1000
-- prepopulate
for i = 1, n do rands[i] = i end
-- shuffle
for i = n, 2, -1 do
  local j = math.random(i)
  rands[j], rands[i] = rands[i], rands[j]
end
-- use
print(table.remove(rands))

同一页面也有进行初始化和改组的算法的“由内而外”版本。