Salida de una baraja barajada usando entrada aleatoria

9

De entrada y salida:

Entrada : Una cadena uniformemente aleatoria, infinitamente larga de '0's y' 1's, tomada de stdin. Se supone que la cadena es verdaderamente aleatoria, no seudoaleatoria. Es uniforme porque cada personaje es igualmente probable que sea un '0' o '1'.

¡Cuidado! La entrada es infinitamente larga, por lo que no puede almacenarlo todo en la memoria utilizando una función como raw_input () en python. Si no me equivoco, golfscript fallará con una entrada infinita, ya que empuja toda la entrada a la pila antes de correr.

Salida : un mazo estándar aleatorio uniformemente aleatorio, sin comodines. Es uniforme porque todos los pedidos son igualmente probables.

Cada carta en la salida es su rango, A, 2-9, T, J, Q o K concatenados con su palo, c, d, ho s. Por ejemplo, el 10 de espadas esTs

Las cartas del mazo deben estar separadas por espacios.

No puede utilizar bibliotecas o funciones aleatorias integradas porque no son realmente aleatorias, solo pseudoaleatorias.

Entrada de ejemplo

Puede usar el siguiente script de Python para canalizar la entrada en su programa:

import sys, random
try:
    while True:
        sys.stdout.write(str(random.randint(0,1)))
except IOError:
    pass

Si guarda el script como rand.py, pruebe su programa con python rand.py | your_program

En Python 3 se ejecuta como se esperaba, pero en Python 2.7 recibo un mensaje de error después de la salida de mi programa, pero solo después de que todo está hecho, así que simplemente ignore el mensaje de error.

Salida de ejemplo:

Así es como se debe imprimir el mazo si se baraja en un orden ordenado:

Ac 2c 3c 4c 5c 6c 7c 8c 9c Tc Jc Qc Kc Ad 2d 3d 4d 5d 6d 7d 8d 9d Td Jd Qd Kd Ah 2h 3h 4h 5h 6h 7h 8h 9h Th Jh Qh Kh As 2s 3s 4s 5s 6s 7s 8s 9s Ts Js Qs Ks

Puntuación:

Este es un código de golf. El código más corto gana.

Programa de ejemplo:

Aquí hay una solución de Python 2.7, no golfizada.

import sys
def next():
    return int(sys.stdin.read(1))==1
def roll(n):
    if n==1:
        return 0
    if n%2==0:
        r=roll(n/2)
        if next():
            r+=n/2
        return r
    else:
        r=n
        while(r==n):
            r=roll(n+1)
        return r
deck = [rank+suit for suit in 'cdhs' for rank in 'A23456789TJQK']
while len(deck)>0:
    print deck.pop(roll(len(deck))),
caja de cartón
fuente
3
"Si no me equivoco, golfscript fallará con una entrada infinita, ya que empuja toda la entrada a la pila antes de correr". Bueno, esa es una forma de sacarlo de la carrera.
dmckee --- ex gatito moderador el
Estoy un poco confundido, perdóname. ¿Qué tiene que ver la entrada con la baraja de baraja real? Quizás solo necesito un poco de aclaración.
jdstankosky
1
No puede usar funciones pseudoaleatorias en su código, por lo que debe usar la entrada (que suponemos que es realmente aleatoria) para generar aleatoriedad. Por ejemplo, en python puede usar (sys.stdin.read (1) == '1') para obtener un booleano aleatorio, pero no puede usar (random.randint (0,1) == 1), porque es solo seudoaleatorio.
cardboard_box

Respuestas:

7

Ruby, 89 87 caracteres

l=*0..51;l.map{l-=[i=l[gets(6).to_i 2]||redo];$><<'A23456789TJQK'[i/4]+'cdhs'[i%4]+' '}

Editar: versión anterior

l=*0..51;(l-=[i=l[gets(6).to_i 2]];i&&$><<'A23456789TJQK'[i/4]+'cdhs'[i%4]+' ')while l[0]
Howard
fuente
3

Python 122

import sys
D=[R+S for S in'cdhs'for R in'A23456789TJQK']
while(D):
    x=int(sys.stdin.read(6),2)
    if x<len(D):print D.pop(x)

Explicación:

Las tarjetas no utilizadas se almacenan en D. Esto simplemente obtiene el siguiente índice aleatorio válido de la secuencia de entrada y extrae ese elemento de D.

A menos que me falte algo, no debería haber un sesgo. El script arrojará cualquier índice inválido> len(D), pero esto no da lugar a un sesgo para números más bajos porque cada pop sucesivo reducirá el índice de cada elemento pasado que i.

Scleaver
fuente
¿Entonces descartas la mayor parte de la entrada aleatoria (infinita)? ¿Dejas de barajar una vez que no tienes cartas "sin usar"?
Leigh
3

Perl, 80 caracteres

Aquí hay otra implementación que no sufre el sesgo y tiene dos caracteres más cortos:

$/=1x9;$_=A23456789TJQK;s/./$&s$&c$&d$&h/g;%h=map{<>.$_,"$_ "}/../g;say values%h

implementación anterior (82 caracteres):

$/=1x9;$_=A23456789TJQK;s/./$&s$&c$&d$&h/g;say map/..$/&&$&.$",sort map<>.$_,/../g

Descripción de implementación anterior:

# set input record separator (how internal readline() delimits lines) to "11111111"
$/ = 1x9; 

# constructs a string representation of all 52 cards: "AsAc(...)KdKh"
$_ = A23456789TJQK; s/./$&s$&c$&d$&h/g;

# for each pair of characters (each card) in the string $_
foreach $card (/../g)
{
    # read from STDIN until $/ is found (this may NEVER occur!), which
    # results in a random string of 1s and 0s
    $weight = <>; 

    # append the card identifier onto the random string
    $card = $weight . $card;

    # add this new card identifier to a new list
    push @cards, $card;
}

# sort the cards with their random string prefix
sort @cards;

# for each card in the "randomly sorted" list
foreach $card (@cards)
{
    # capture the final two characters from the card (the rank and suit), 
    # and append a space onto them
    $card =~ /..$/;  
    $card = $card . $";

    print $card;
}
ardnew
fuente
Es curioso: ¿alguien puede demostrar que este enfoque produce cada baraja con la misma probabilidad?
Howard
2
Si estoy leyendo esto correctamente (IANAPH), asigna "pesos" aleatorios a cada tarjeta, y luego los ordena por peso. Cuando a dos cartas se les asigna el mismo peso, se dejarán en orden sort, lo que dará lugar a un sesgo hacia el orden alfabético.
stand
tienes razón, @boothby. el tipo deja esta solución con un sesgo en el caso de que varias tarjetas tengan el mismo "peso". tampoco se puede garantizar que esta solución produzca un resultado. Agregaré una descripción de cómo funciona para que alguien más inteligente que yo pueda analizarlo
partir del
Está perfectamente bien si algunas entradas hacen que el programa nunca termine, siempre que la probabilidad de que el programa termine se acerque a 1 a medida que el tiempo se acerca al infinito. El programa de ejemplo nunca termina en una entrada de todos los '1'. Estoy bastante seguro de que en realidad es imposible obtener una aleatoriedad uniforme al saber que su programa termina después de una cierta cantidad de bits leídos.
caja de cartón el
1
¿Cómo puede elegir un número aleatorio uniforme entre 1 y 3 con un número finito de bits? Tendrá que hacer eso cerca del final de la mezcla de Fisher-Yates, y el factorial (52) es divisible por 3, por lo que comparte el mismo problema.
cardboard_box
3

C, 197 178 161 caracteres

EDITAR : Usando una nueva función aleatoria, que es mucho más corta: lee un entero de 4 dígitos sy lo usa s%64. Cada número decimal de 6 dígitos hecho de 0 y 1 solamente, toma %64resultados en un resultado único, por lo que la aleatoriedad es buena.
Este enfoque consume muchos más bits aleatorios, pero es significativamente más corto.

B[52],t,s,i=104;
r(){scanf("%6d",&s);s%=64;s>i&&r();}
main(){
    for(;i--;)B[i%52]=i<52
        ?r(),t=B[s],B[s]=B[i],printf("%c%c\n","23456789ATJQK"[t/4],"cdhs"[t%4]),t
        :i-52;
}

La lógica básica es simple: inicialice una matriz de 52 entradas con 0..51, baraje (reemplace aleatoriamente el elemento x con otro del rango 0..x), imprima formateado (n / 4 = rango, n% 4 = palo) .
Un bucle, que se ejecuta 104 veces, realiza la inicialización (primeras 52 ejecuciones), barajar e imprimir (últimas 52 ejecuciones).
Se genera un número aleatorio tirando nbits aleatorios, hasta que 1<<nsea ​​al menos el máximo deseado. Si el resultado es más que el máximo, vuelva a intentarlo.

Ugoren
fuente
Esto complicado s>7?"ATJQK"[s-8]:s+50es más largo que lo simple "A23456789TJQK"[s]. En segundo lugar, puede usar t/4y en t%4lugar de t%13y t/13.
Howard
No es necesario tvolver a colocarlo en la matriz cuando se
emite
3

unix shell ~ 350

Esto no es corto ni bonito, ni es eficiente, sin embargo, me preguntaba qué tan difícil sería hacer esto con las utilidades estándar de shell de Unix.

Esta respuesta divide la cadena binaria infinita en longitudes de 6 bits y solo elige aquellas que están en el rango correcto (1-52), aquí la cadena binaria infinita se simula con urandom y xxd:

</dev/urandom xxd -b | cut -d' ' -f2-7 | tr -d ' \n'

El corte y la selección se realizan con fold, sed y bc:

random_source | {echo ibase=2; cat | fold -w6 | sed -r 's/^/if(/; s/([^\(]+)$/\1 <= 110100 \&\& \1 > 0) \1/'}

Esto produce líneas como:

if(101010 <= 110100 && 101010 > 0) 101010

Que se puede dirigir a bc.

De esta secuencia de números, la secuencia de la baraja se elige así (estoy usando zsh, pero la mayoría de las conchas modernas deberían ser adaptables a esto):

deck=({1..52})
seq_of_numbers | while read n; do 
  if [[ -n $deck[n] ]]; then 
    echo $n; deck[n]=""
    [[ $deck[*] =~ "^ *$" ]] && break
  fi
done

La secuencia de números aleatorios ahora debe cambiarse a nombres de tarjeta. La secuencia del nombre de la tarjeta se genera fácilmente con GNU paralelo:

parallel echo '{2}{1}' ::: c d s h ::: A {2..9} T J Q K

Combinando la salida de los dos últimos comandos con pegar y ordenando los números:

paste random_deck card_names | sort -n | cut -f2 | tr '\n' ' '

Todo como un monstruoso one-liner (solo probado en zsh):

paste \
  <(deck=({1..52}); \
    </dev/urandom xxd -b | cut -d' ' -f2-7 | tr -d ' \n' |
      {echo ibase=2; fold -w6 | sed -r 's/^/if(/; s/([^\(]+)$/\1 <= 110100 \&\& \1 > 0) \1/'} | 
      bc | 
      while read n; do 
        if [[ -n $deck[n] ]]; then 
          echo $n; deck[n]=""
          [[ -z ${${deck[*]}%% *} ]] && break
        fi
      done) \
  <(parallel echo '{2}{1}' ::: c d s h ::: A {2..9} T J Q K) | 
sort -n | cut -f2 | tr '\n' ' '

Editar: versión de bash agregada

Aquí hay una versión que funciona en bash. Eliminé los { }índices in-shell y array están basados ​​en cero. El vacío de la matriz se verifica con la expansión de parámetros, un poco más eficiente y también se adopta en el ejemplo anterior.

paste \
  <(deck=($(seq 52)); \
    </dev/urandom xxd -b | cut -d' ' -f2-7 | tr -d ' \n' | 
      (echo ibase=2; fold -w6 | sed -r 's/^/if(/; s/([^\(]+)$/\1 <= 110100 \&\& \1 > 0) \1/') | 
        bc | 
        while read n; do 
          if [[ -n ${deck[n-1]} ]]; then 
            echo $n
            deck[n-1]=""
            [[ -z ${deck[*]%% *} ]] && break
          fi
        done \
  ) \
  <(parallel echo '{2}{1}' ::: c d s h ::: A {2..9} T J Q K) | 
sort -n | cut -f2 | tr '\n' ' '; echo
Thor
fuente
2

K&R c - 275

  • v3 Indice directamente en los literales de cadena
  • v2 Sugerencia de luser droog en los comentarios para usar cadenas y reemplazó los charliterales restantes con intliterales

Golfizado:

#define F for(i=52;--i;)
#define P putchar 
M=1<<9-1,i,j,k,t,v,s,a[52];r(){t=0,j=9;while(--j)t=t<<1|(getchar()==49);
return t;}main(){F a[i]=i;F{k=i+1;do{j=r();}while(j>M/k*k-1);j%=i;t=a[i];
a[i]=a[j];a[j]=t;}F{s=a[i]&3;v=a[i]>>2;P(v>7?"TJQKA"[v-8]:v+50);
P("cdhs"[s]);P(32);}}

Bastante fuerza bruta aquí. Acabo de leer nueve bits de la entrada para formar una salida RNG mínima, y ​​hago la reducción habitual del módulo redibujar si los valores no utilizados al final para obtener una salida uniforme para alimentar una selección aleatoria.

Esta versión sin golf difiere en que toma la entrada en /dev/urandomlugar del formato de entrada descrito.

#include <stdio.h>
M=1<<8-1, /* RANDMAX */
  i, j, k, /* counters */
  t, /* temporary for swapping, and accumulating */
  a[52]; /* the deck */
r(){ /* limited, low precision rand() that depends on a random stream
    of '0' and '1' from stdin */
  t=0,j=9;
  while(--j)t=t<<1|(getchar()&1);
  return t;
}
main(){
  for(i=52;--i;)a[i]=i;  /* initialize the deck */
  for(i=52;--i;){
    /*  printf("shuffling %d...\n",i); */
    k=i+1;
    do { /* draw *unifromly* with a a-unifrom generator */
      j=r(); 
      /* printf("\t j=0x%o\n",j); */
    }while(j>M/k*k-1); /* discard values we can't mod into evently */
    j%=i;
    t=a[i];a[i]=a[j];a[j]=t; /* swap */
  }
  for(i=52;--i;){ /* output the deck */
    j=a[i]&3;
    k=a[i]>>2;
    putchar(k>7?"TJQKA"[k-8]:k+'2');
    putchar("cdhs"[j]);
    putchar(' ');
  }
}
dmckee --- gatito ex moderador
fuente
+1 Tengo mucho que aprender. Por cierto, ¿por qué no "TJQKA"y "cdhs"?
luser droog
Oh. Derecha. ints. Lo entiendo. Todavía podría valer la pena guardar toda la puntuación. Incluso podría factorizar la charsalida getchary putcharcon una macro pastosa loca ...
luser droog 02 de
1
Las sustituciones de macros necesitan ganar mucho porque tienen que comenzar #define N y terminar con una nueva línea que cuenta como un personaje y eso es 11, más el bit que está reemplazando. Ciertamente, hay algunos caracteres más al reemplazar algunos o todos los literales de caracteres con literales int, pero es tarde aquí ... tal vez lo haré en otro momento.
dmckee --- ex gatito moderador el
@luserdroog Más claro se dirigió ahora. Por supuesto, las cadenas son mejores, aunque debe especificar el tipo, porque los caracteres son enteros cortos. Además, puedo combinarlos y las sustituciones ASCII obtienen un montón de golpes de una vez.
dmckee --- ex-gatito moderador el
0

PHP, 158 caracteres

Se agregaron nuevas líneas para evitar que el bloque de código gane barras de desplazamiento, se pueden eliminar con seguridad.

for($i=52,$x='shdcKQJT98765432A';$i--;$c[]=$x[4+$i%13].$x[$i/13]);
while(ord($i=fgetc(STDIN)))$c[$i]^=$c[$a]^=$c[$i]^=$c[$a=2+($a+++$i)%50];
die(join(' ',$c));

Antes de que me digan que agregue un <?php, déjeme saber que puede invocar PHP sin esta etiqueta con bastante facilidad, usando:cat golf.php | php -a

De golf y comentado:

// Abuse of the for construct to save a bit of space, and to make things more obscure looking in general.
for (
    // Card suit and number are reversed because we're using a decrementor to count
    // down from 52, instead of up to 52
    $i = 52,
    $x = 'shdcKQJT98765432A';
    // Condition AND per-loop decrement
    $i--;
    // Add a new element to the array comprising of $i mod 13 + 4 (to skip suit ids)
    // followed by simply $i divided by 13 to pick a suit id.
    $c[] =
        $x[4 + $i % 13] .
        $x[$i / 13]
);

while(

    // Assignment inside the condition, a single character from input.
    ord($i = fgetc(STDIN))
)
    // In-place swap. Shorter than using a single letter temporary variable.
    // This is the pseudo-random shuffle.
    $c[$i] ^=
    $c[$a] ^=
    $c[$i] ^=
    $c[
        // We use the input (0 or 1) to identify one of two swap locations at the
        // start of the array. The input is also added to an accumulator (to make
        // the increments "random") that represents a swap destination.
        $a = 2 + ($a++ + $i) % 50
    ];

// Dramatic way of doing "echo" in the same space.
die(
    join(' ', $c)
);

Hay dos errores esperados, que no afectan la salida del programa.

La primera es porque $ano se inicializa, pero el NULL se convierte a 0 y el programa continúa.

El segundo es porque la secuencia de caracteres parece obtener una nueva línea desde algún lugar, incluso si no se proporciona (buen ol 'PHP), y ese es un índice indefinido en la matriz. Es el último carácter de entrada y no afecta a la salida.

Leigh
fuente