Solo por jugar, para poder repetir los valores antes de llegar al final del arreglo cartas, se puede hacer un truco: usar la matriz final como memoria adicional y aplicar la misma idea anterior, e.g.:
http://goo.gl/mOF4jJAun no es como lo descrito, pero la idea se puede aplicar de multiples formas para evitar o forzar repeticiones, sin requerir de estructuras de datos adicionales o contar, la solucion funciona por construccion, como se demuestra en el codigo del link, el que copio aqui:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char a[4][4];
char cartas[] = {'#','%','@','*','!','<','?', '+'};
int total=sizeof(cartas);
int main()
{
for(int i = 0; i < total*2; i++) {
a[i/4][i%4] = cartas[i%8];
}
srand(time(0));
for (int mover_a = total*2-1; mover_a >=0; mover_a--) {
int hacia = mover_a;
int desde = rand() % (hacia + 1);
char temp = a[hacia/4][hacia%4];
a[hacia/4][hacia%4] = a[desde/4][desde%4];
a[desde/4][desde%4] = temp;
printf("\t%c ",a[hacia/4][hacia%4]);
if(mover_a%4 == 0) printf("\n");
}
printf("\n\n");
}
Verlo ejecutando aqui;
http://goo.gl/mOF4jJ