Rebol3 Code Examplex


Sattolo cycle

Produce a cyclic permutation with one long cycle.

Rebol [
    title: "Rosetta code: Sattolo cycle"
    file:  %Sattolo_cycle.r3
    url:    https://rosettacode.org/wiki/Sattolo_cycle
]

sattolo-cycle: func [
    "Sattolo's algorithm - generates a random cyclic permutation"
    ;; Unlike Fisher-Yates, this ensures every element moves to a different position
    ;; Creates a single cycle that visits all elements exactly once
    data [series!]   "Input block to create cyclic permutation of"
    /local i j tmp  ;; Local variables: i=current index, j=random index, tmp=swap variable
][
    ;; Make a copy of the input block and get its length
    ;; This prevents modification of the original block
    i: length? data: copy data
    
    ;; Loop from the last element down to the second element
    ;; Key difference from Fisher-Yates: we stop at element 2, not 1
    while [i > 1] [
        ;; CRITICAL: Generate random index j from 1 to i-1 (exclusive of i)
        ;; This is what makes it Sattolo's algorithm instead of Fisher-Yates
        ;; In Rebol, random i gives 1 to i, so random (i - 1) gives 1 to i-1
        j: random (i - 1)
        
        ;; Three-step swap using path notation for direct block access
        ;; Step 1: Store element at random position j in temporary variable
        tmp: data/:j
        
        ;; Step 2: Move current element (at position i) to random position j
        data/:j: data/:i
        
        ;; Step 3: Move stored element to current position i
        ;; Using :tmp to get the value (word evaluation)
        data/:i: :tmp
        
        ;; Move to previous element (working backwards through the block)
        i: i - 1
    ]
    
    ;; Return the block with cyclic permutation
    ;; Every element is guaranteed to be in a different position than it started
    data
]


random/seed 0 ;; to get consistent results

probe sattolo-cycle [1 2 3]
probe sattolo-cycle "abcde"