Lua shuffle with repeating cycle

101 views Asked by At

Having some Lua trouble with a a modification of Fisher-Yates shuffle in place. For example, let's say I have a 16 item table (sequence). I want to shuffle integers 1-4 then apply the shuffled pattern in the table to 1-4, 5-8, 9-12, 13-16. So:

{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }

with a 4 item shuffling pattern of 4,2,3,1 would become:

{ 4, 2, 3, 1, 8, 6, 7, 5, 12, 10, 11, 9, 16, 14, 15, 13 }

The code here is from context and includes the "rising edge" input I am using to reshuffle. If you look at the test pic below you can see that yes, it shuffles each section in place, but it reshuffles each section -- I want the shuffled pattern to repeat.

t = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}

range = 4

local function ShuffleInPlace(t)
    for i = #t, 2, -1 do
    
    local j = math.random(1, range)     
    local k = (math.floor(i/(range+.001)))*range + j
                
    t[i], t[j] = t[j], t[i]
    end
end

-- initialize new table for shuffling
if s == nil then s = {} end 

-- use gate rising edge to shuffle
if prev == nil then prev = 0 end
if gate > 0 and prev <= 0 then  
    s = t
    ShuffleInPlace(s)
end

prev = gate

Test pic:

Shuffle in Audulus

2

There are 2 answers

0
jersmi On

LMD, thank you, your helpful reply is uncovering a solution (by creating the shuffled "pattern" sequence first, outside the iterator). (Still some issues with the first value I'm working out. And I might be looking at some biproducts of the not-so-great math.random function, but that's another story). I'm a novice so any suggestions are appreciated!

-- range input is 0 to 1
seqRange = math.floor(range*(#t*.99))

local function ShuffleRange(x)
    
    if rdm == nil then rdm = {} end
    for m = 1, x do rdm[m] = m end

    for m = #rdm, 2, -1 do
        local j = math.random(m)
        rdm[m], rdm[j] = rdm[j], rdm[m]
        return rdm[m]
    end
end

local function ShuffleInPlace(t)

    y = ShuffleRange(seqRange)           

    for i = #t, 2, -1 do
        local j =  (math.floor(i/(seqRange*1.001)))*seqRange + y
        t[i], t[j] = t[j], t[i]
    end
end
0
Luatic On

Here's how I would do it, implementing the simple approach of first generating a series of swaps and then applying that to the sublists of length n:

math.randomseed(os.time()) -- seed the random

local t = {}; for i = 1, 16 do t[i] = i end -- build table

local n = 4 -- size of subtables
local swaps = {} -- list of swaps of offsets (0-based)
for i = 0, n - 1 do
    -- Insert swap into list of swaps to carry out
    local j = math.random(i, n - 1)
    table.insert(swaps, {i, j})
end

-- Apply swaps to every subtable from i to i + n
for i = 1, #t, n do
    for _, swap in ipairs(swaps) do
        -- Swap: First add offsets swap[1] & swap[2] respectively
        local a, b = i + swap[1], i + swap[2]
        t[a], t[b] = t[b], t[a]
    end
end

print(table.concat(t, ", "))

Example output: 4, 2, 1, 3, 8, 6, 5, 7, 12, 10, 9, 11, 16, 14, 13, 15