Saída de um baralho embaralhado usando entrada aleatória


9

Entrada / Saída:

Entrada : Uma sequência uniformemente aleatória, infinitamente longa, de '0' e '1', tirada de stdin. A string é assumida como sendo verdadeiramente aleatória, não pseudo-aleatória. É uniforme que cada personagem tem a mesma probabilidade de ser um '0' ou '1'.

Cuidado! A entrada é infinitamente longa, portanto você não pode armazenar tudo na memória usando uma função como raw_input () em python. Se não me engano, golfscript falhará com entrada infinita, pois coloca toda a entrada na pilha antes da execução.

Saída : Um baralho padrão aleatório e aleatoriamente uniforme, sem coringas. É uniforme, pois todos os pedidos são igualmente prováveis.

Cada carta na saída é sua classificação, A, 2-9, T, J, Q ou K concatenadas com seu naipe, c, d, h ou s. Por exemplo, o 10 de espadas éTs

As cartas do baralho devem ser separadas por espaços.

Você não pode usar bibliotecas ou funções aleatórias internas porque elas não são verdadeiramente aleatórias, apenas pseudo-aleatórias.

Exemplo de entrada

Você pode usar o seguinte script python para canalizar a entrada no seu programa:

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

Se você salvar o script como rand.py, teste seu programa com python rand.py | your_program

No python 3, ele é executado conforme o esperado, mas no python 2.7, recebo uma mensagem de erro após a saída do meu programa, mas somente depois que tudo estiver pronto, então ignore a mensagem de erro.

Exemplo de saída:

Veja como o baralho deve ser impresso, se for embaralhado em uma ordem classificada:

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

Pontuação:

Este é um código de golfe. O menor código vence.

Exemplo de programa:

Aqui está uma solução python 2.7, não jogada de golfe.

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))),

3
"Se não me engano, o golfscript falhará com entrada infinita, pois coloca toda a entrada na pilha antes da execução". Bem, essa é uma maneira de tirar isso da corrida.
dmckee --- ex-moderador gatinho

Estou um pouco confuso, me perdoe. O que a entrada tem a ver com o baralhamento real do baralho? Talvez eu só precise de um pouco de esclarecimento.
Jdstankosky

11
Você não pode usar funções pseudo-aleatórias em seu código, então você precisa usar a entrada (que estamos assumindo ser verdadeiramente aleatória) para gerar aleatoriedade. Por exemplo, em python, você pode usar (sys.stdin.read (1) == '1') para obter um booleano aleatório, mas não pode usar (random.randint (0,1) == 1) porque é apenas pseudo-aleatório.
cardboard_box

Respostas:


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: versão anterior

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

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)

Explicação:

Os cartões não utilizados são armazenados em D. Isso simplesmente obtém o próximo índice aleatório válido do fluxo de entrada e exibe esse elemento em D.

A menos que esteja faltando alguma coisa, não deve haver um viés. O script lançará quaisquer índices inválidos> len(D), mas isso não resultará em um viés para números mais baixos, porque cada pop sucessivo reduzirá o índice de cada elemento além de i.


Então você descarta a maior parte da entrada aleatória (infinita)? Ou seja, você para de embaralhar uma vez que não possui cartões "não utilizados"?
Leigh

3

Perl, 80 caracteres

aqui está outra implementação que não sofre o viés e é dois caracteres mais curta:

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

implementação antiga (82 caracteres):

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

descrição antiga da implementação:

# 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;
}

Apenas curioso: alguém pode mostrar que essa abordagem produz cada baralho com a mesma probabilidade?
Howard

2
Se estou lendo isso corretamente (IANAPH), ele atribui 'pesos' aleatórios a cada cartão e depois classifica por peso. Quando duas cartas recebem o mesmo peso, elas são deixadas em ordem sort, resultando em um viés em relação à ordem alfabética.
usar o seguinte comando

você está certo, @ boothby. o tipo deixa essa solução com um viés no caso de vários cartões terem o mesmo "peso". também não é possível garantir que essa solução jamais produza um resultado. Vou acrescentar uma descrição de como ele funciona para que alguém mais esperto do que eu possa analisá-lo
ardnew

É perfeitamente bom que algumas entradas façam com que o programa nunca termine, desde que a probabilidade de término do programa se aproxime de 1 quando o tempo se aproxima do infinito. O programa de exemplo nunca termina com uma entrada de todos os '1s. Tenho certeza de que é realmente impossível obter uma aleatoriedade uniforme enquanto o programa termina após um certo número de bits lidos.
cardboard_box

11
Como você pode escolher um número uniformemente aleatório entre 1 e 3 com um número finito de bits? Você precisará fazer isso perto do final do shuffle de Fisher-Yates, e o fatorial (52) é divisível por 3, para que ele compartilhe o mesmo problema.
cardboard_box

3

C, 197 178 161 caracteres

EDIT : Usando uma nova função aleatória, que é muito mais curta - lê um número inteiro de 4 dígitos se usa s%64. Cada número decimal de 6 dígitos composto apenas por 0 e 1 %64resulta em um resultado único, portanto a aleatoriedade é boa.
Essa abordagem consome muito mais bits aleatórios, mas é significativamente mais curta.

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;
}

A lógica básica é simples - inicialize uma matriz de 52 ints com 0..51, embaralhe (substitua aleatoriamente o elemento x por outro do intervalo 0..x), imprima no formato (n / 4 = classificação, n% 4 = naipe) .
Um loop, que é executado 104 vezes, faz a inicialização (primeiras 52 execuções), baralhamento e impressão (últimas 52 execuções).
Um número aleatório é gerado puxando nbits aleatórios, até que 1<<nseja pelo menos o máximo desejado. Se o resultado for maior que o máximo - tente novamente.


Este complicado s>7?"ATJQK"[s-8]:s+50é mais longo que o simples "A23456789TJQK"[s]. Segundo, você pode usar t/4e em t%4vez de t%13e t/13.
Howard

Não precisa ainda colocar tde volta para a matriz quando a saída
l4m2

3

shell unix ~ 350

Isso não é curto nem bonito, nem é eficiente, no entanto, eu queria saber o quão difícil seria fazer isso com os utilitários de shell unix padrão.

Esta resposta divide a cadeia binária infinita em comprimentos de 6 bits e escolhe apenas aquelas que estão no intervalo correto (1-52), aqui a cadeia binária infinita é simulada por urandom e xxd:

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

O corte e seleção são feitos com fold, sed e bc:

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

Isso produz linhas como:

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

Que pode ser direcionado para bc.

A partir desse fluxo de números, a sequência do baralho é escolhida assim (estou usando zsh, mas a maioria dos shells modernos deve ser adaptável a isso):

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

A sequência numérica aleatória agora precisa ser alterada para nomes de cartões. A sequência do nome do cartão é facilmente gerada com o GNU paralelo:

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

Combinando a saída dos dois últimos comandos com colar e classificar os números:

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

A coisa toda como um one-liner monstruoso (testado apenas no 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 - versão do bash adicionada

Aqui está uma versão que funciona no bash. Eu removi os { }índices in-shell e array são baseados em zero. O vazio da matriz é verificado com a expansão dos parâmetros, um pouco mais eficiente e também adotada no exemplo acima.

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

2

K&R c - 275

  • Índice v3 nos literais da cadeia diretamente
  • v2 Sugestão do luser droog nos comentários para usar strings e substituir charliterais restantes por intliterais

Golfe:

#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 força bruta aqui. Acabei de ler nove bits da entrada para formar uma saída RNG mínima e fazer a redução usual do módulo redesenhar-se-não-usar-os-valores-no-final para obter uma saída uniforme para alimentar um shuffle de seleção.

Esta versão sem golfe difere na medida em que recebe a entrada /dev/urandome não no 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(' ');
  }
}

+1 Eu tenho muito a aprender. BTW, por que não "TJQKA"e "cdhs"?
Luser droog 02/11/12

Oh. Direita. ints. Entendi. Pode ainda valer a pena salvar toda a pontuação. Pode até levar o charfora getchare putcharcom uma macro pastosa louco ...
luser Droog

11
As substituições de macro precisam ganhar muito, pois precisam começar #define N e terminar com uma nova linha que conta como caractere e que é 11, mais a parte que você está substituindo. Certamente há mais alguns caracteres na substituição de alguns ou de todos os literais de caracteres por literais int, mas é tarde aqui ... talvez eu faça isso outra vez.
dmckee --- gatinho ex-moderador

@luserdroog Clearer foi agora. É claro que as strings são melhores - embora você precise especificar o tipo - porque os caracteres são apenas inteiros curtos. Além disso, eu posso combiná-los e as substituições ASCII recebem vários golpes de uma só vez.
dmckee --- gatinho ex-moderador

0

PHP, 158 caracteres

Novas linhas foram adicionadas para impedir que o bloco de código ganhe barras de rolagem; elas podem ser removidas com segurança.

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 que me digam para adicionar um <?php, saiba que você pode chamar o PHP sem essa tag facilmente, usando:cat golf.php | php -a

De-golfe e comentou:

// 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)
);

Há dois erros esperados, que não afetam a saída do programa.

O primeiro é porque $anão foi inicializado, mas o NULL é convertido em 0 e o programa continua.

A segunda é porque o fluxo de caracteres parece obter uma nova linha de algum lugar, mesmo que não seja fornecida (bom e velho PHP), e esse é um índice indefinido na matriz. É o último caractere da entrada e não afeta a saída.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.