ref: 482f0ce1f33e655ab3085c3c9c2f5d71cd5b1c79
dir: /shuffle.c/
#include "shuffle.h"
void
shuffle_init(Shuffle *s, int (*rndrange)(int max_excluding), int total, int first)
{
assert(first < total && total > 0);
s->m = s->n = total;
s->i = 0;
s->xi = s->x0 = first;
if(total < 4){
s->a = 1;
s->c = 3;
s->m = 7;
return;
}
s->m += 1;
s->m |= s->m >> 1;
s->m |= s->m >> 2;
s->m |= s->m >> 4;
s->m |= s->m >> 8;
s->m |= s->m >> 16;
s->a = 1 + rndrange(s->m/4)*4; /* 1 ≤ a < m && a mod 4 = 1 */
s->c = 3 + rndrange((s->m-2)/2)*2; /* 3 ≤ c < m-1 && c mod 2 = 1 */
}
void
shuffle_resize(Shuffle *s, int total)
{
assert(total > 0);
s->n = total;
}
static int
next(Shuffle *s)
{
int res;
res = s->xi;
if(s->n < 2){
/* if it's less than two items, just use the first one (if any) */
s->x0 = s->xi = s->i = 0;
return 0;
}else if(s->x0 >= s->n){
/* if items were removed up to this one -- update for a period */
s->x0 = 0;
}
for(;;){
s->xi = (s->a*s->xi + s->c) & s->m;
if(s->xi < s->n){
s->i++;
if(s->xi == s->x0)
s->i = 0;
break;
}
}
return res;
}
int
shuffle_one(Shuffle *s, int index)
{
if(s->n < 1 || index < 0)
return index;
index %= s->n;
while(s->i < s->n && s->i != index)
next(s);
return next(s);
}
int
shuffle_for(Shuffle *s, int index)
{
int i, r;
if(index < 0 || index >= s->n)
return index;
for(i = 0; i < s->n; i++){
r = s->i;
if(next(s) == index){
next(s);
return r;
}
}
return index;
}