Below is a Python code to do this but the proof that all permutations are equally likely is left as an exercise for the reader (meaning, I don't know how to prove it and I am not sure the probabilities are really equal :) ).
The idea is this:
- For each position in the resulting array we choose an element from
the original array that is not further than the desired distance and
that has not been chosen before.
- If at some position we find out that we have an not-chosen element from the original
array exactly the maximum distance behind the current
position, we choose that element (the last-chance choice).
import random
initial_array = [x for x in range(1, 10)]
max_distance = 3
element_taken = [(i < max_distance) or i > (len(initial_array) + max_distance - 1) for i in range(len(initial_array) + max_distance * 2)]
result = [0] * len(initial_array)
for i in range(len(initial_array)):
print ("Position", i)
print ("Original", initial_array)
print (" Result", result)
print (" Taken", element_taken)
if not element_taken[i]:
element_taken[i] = True
result[i] = initial_array[i - max_distance]
print ("Had to use last-chance move from %d to %d" % (i - max_distance, i))
continue
possible_positions = [position for position in range(i - max_distance, i + max_distance + 1) if not element_taken[max_distance + position]]
print ("Possible positions", possible_positions)
position = random.choice(possible_positions)
print ("Moving %d to %d" % (position, i))
result[i] = initial_array[position]
element_taken[max_distance + position] = True
print ()
print (" Final", result)