¿Hay algo de malo con este algoritmo de barajar?

He estado haciendo un pequeño recreativo informático de vacaciones. Mi mini-proyecto fue una simulación del juego italiano de "tomboli". Un bloque de construcción clave fue una simulación del siguiente proceso;

El juego está controlado por un hombre con una bolsa de 90 canicas, numerada del 1 al 90. Extrae canicas una a una al azar de la bolsa, cada vez que llama a los jugadores el número de la canica.

Después de pensarlo un poco, escribí el siguiente código para este bloque de construcción;

// NBR marbles, numbered 1...NBR are in a bag. Simulate randomly
//  pulling them from the bag, one by one, until the bag is empty
void bag( int random_sequence[NBR] )
{
    int i;

    // Store each marble as it is pulled out
    int *store = random_sequence;

    // Array of marbles still in the bag
    int not_yet_pulled[NBR];
    for( i=0; i<NBR; i++ )
        not_yet_pulled[i] = i+1;    // eg NBR=90; 1,2,3 ... 90

    // Loop pulling marbles from the bag, one each time through
    for( i=NBR; i>=1; i-- )
    {
        int x = rand();
        int idx = x%i;  // eg i=90 idx is random in range 0..89
                        // eg i=89 idx is random in range 0..88
                        //            ...
                        // eg i=1  idx is random in range 0..0
                        //    (so we could optimize when i=1 but not worth the bother)
        *store++  = not_yet_pulled[idx];

        // Replace the marble just drawn (so it cannot be pulled again)
        //     with the last marble in the bag. So;
        //     1) there is now one less marble in the bag
        //     2) only marbles not yet pulled are still in the bag
        // If we happened to pull the last marble in the *current subarray*, this is
        //    not required but does no harm.
        not_yet_pulled[idx] = not_yet_pulled[i-1];
    }
}

Sé que hay sutilezas y trampas en todo el lugar en la simulación del juego con números aleatorios, así que aunque estoy bastante contento con mi código, mi confianza es un poco menos del 100%. Así que mis preguntas son;

1) ¿Hay algún problema con mi código?

2) [si la respuesta a 1) es no] ¿Estoy, sin saberlo, utilizando un algoritmo de barajado estándar?

3) [si la respuesta a 2) es no] ¿Cómo se compara mi algoritmo con las alternativas estándar?

EDITAR Gracias a todos los que respondieron. Voy a aceptar la respuesta de Aidan Cully porque resultó que estaba redescubriendo el algoritmo de Fisher-Yates y revelando que eso llega al meollo de la cuestión. Por supuesto, no es de extrañar que me haya ahorrado tiempo y esfuerzo haciendo una investigación por adelantado. Pero por otro lado fue un divertido proyecto de pasatiempo. El resto de la simulación era rutinaria, esta era la parte más interesante, y me habría privado de disfrutar al no tener una oportunidad. Además, estaba tratando de simular a un hombre sacando canicas de una bolsa, y fue bastante tarde en la pieza que me di cuenta de que la situación era exactamente análoga para barajar cartas.

Otro punto de interés es que hay un pequeño defecto, identificado por Ken, quien señala que el patrón de rand ()% N a menudo no es una buena forma de elegir un número aleatorio del rango 0..N-1.

Finalmente, mi versión de Fisher-Yates carece del truco elegante que permite la propiedad agradable de barajar en su lugar. Como resultado, mi algoritmo terminaría con un orden aleatorio igualmente aleatorio pero invertido.

Respuestas a la pregunta(8)

Su respuesta a la pregunta