Emette un mazzo mischiato usando input casuali


9

Input Output:

Input : Una stringa uniformemente casuale, infinitamente lunga, di '0' e '1', presa dallo stdin. Si presume che la stringa sia veramente casuale, non pseudo-casuale. È uniforme in quanto ogni personaggio ha la stessa probabilità di essere "0" o "1".

! attento L'input è infinitamente lungo, quindi non puoi archiviarlo tutto in memoria usando una funzione come raw_input () in Python. Se non sbaglio, golfscript fallirà con l'input infinito, poiché spinge l'intero input nello stack prima della corsa.

Output : un mazzo standard mischiato in modo uniforme e casuale, senza jolly. È uniforme in quanto tutti gli ordini sono ugualmente probabili.

Ogni carta nell'output è il suo rango, A, 2-9, T, J, Q o K concatenati con il suo seme, c, d, h o s. Ad esempio, il 10 di picche èTs

Le carte del mazzo devono essere separate da spazi.

Non è possibile utilizzare librerie o funzioni casuali incorporate perché non sono veramente casuali, ma solo pseudo-casuali.

Esempio di input

Puoi usare il seguente script python per reindirizzare l'input nel tuo programma:

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

Se si salva lo script come rand.py, provare il programma con python rand.py | your_program

In python 3 funziona come previsto, ma in python 2.7 ricevo un messaggio di errore dopo l'output del mio programma, ma solo dopo aver fatto tutto, quindi ignora il messaggio di errore.

Esempio di output:

Ecco come dovrebbe essere stampato il mazzo se fosse mescolato in un ordine ordinato:

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

punteggio:

Questo è un codice golf. Il codice più corto vince.

Esempio di programma:

Ecco una soluzione Python 2.7, non giocata a golf.

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 non sbaglio, golfscript fallirà con l'input infinito, dato che spinge l'intero input nello stack prima della corsa." Bene, questo è un modo per toglierlo dalla corsa.
dmckee --- ex gattino moderatore

Sono un po 'confuso, perdonami. Cosa c'entra l'input con l'effettivo mescolamento del mazzo? Forse ho solo bisogno di un piccolo chiarimento.
jdstankosky,

1
Non puoi usare funzioni pseudo-casuali nel tuo codice, quindi devi usare l'input (che supponiamo sia veramente casuale) per generare casualità. Ad esempio, in Python puoi usare (sys.stdin.read (1) == '1') per ottenere un booleano casuale, ma non puoi usare (random.randint (0,1) == 1), perché è solo pseudo-casuale.
cardboard_box

Risposte:


7

Rubino, 89 87 caratteri

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

Modifica: versione precedente

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)

Spiegazione:

Le carte inutilizzate sono memorizzate in D. Questo semplicemente ottiene il prossimo indice casuale valido dal flusso di input e estrae quell'elemento da D.

A meno che non mi manchi qualcosa, non ci dovrebbe essere un pregiudizio. Lo script eliminerà tutti gli indici non validi> len(D), ma ciò non si tradurrà in una distorsione per i numeri più bassi perché ogni pop successivo ridurrà l'indice di ciascun elemento oltre i.


Quindi scarti la maggior parte dell'input (infinito) casuale? Cioè smetti di mescolare una volta che non hai carte "non utilizzate"?
Leigh,

3

Perl, 80 caratteri

ecco un'altra implementazione che non risente del pregiudizio ed è più corta di due caratteri:

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

vecchia implementazione (82 caratteri):

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

vecchia descrizione dell'implementazione:

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

Solo curioso: qualcuno può dimostrare che questo approccio produce ogni mazzo di carte con la stessa probabilità?
Howard,

2
Se sto leggendo questo diritto (IANAPH), assegna "pesi" casuali a ciascuna carta, quindi ordina per peso. Quando a due carte viene assegnato lo stesso peso, verranno lasciate in ordine sort, determinando una propensione all'ordinamento alfabetico.
stand dal

hai ragione, @boothby. l'ordinamento lascia questa soluzione con una propensione nel caso in cui più carte abbiano lo stesso "peso". inoltre, non si può garantire che questa soluzione produrrà mai un risultato. Aggiungerò una descrizione di come funziona in modo che qualcuno più intelligente di me possa analizzarlo
ardnew,

Va benissimo se alcuni input fanno sì che il programma non termini mai, purché la probabilità che il programma termini l'approccio 1 mentre il tempo si avvicina all'infinito. Il programma di esempio non termina mai con un input di tutti gli "1". Sono abbastanza sicuro che in realtà è impossibile ottenere una casualità uniforme pur sapendo che il tuo programma termina dopo un certo numero di bit letti.
cardboard_box

1
Come si può scegliere un numero uniformemente casuale tra 1 e 3 con un numero finito di bit? Dovrai farlo vicino alla fine del riordino Fisher-Yates e factorial (52) è divisibile per 3, quindi condivide lo stesso problema.
cardboard_box

3

C, 197 178 161 caratteri

EDIT : utilizzando una nuova funzione casuale, che è molto più breve, legge un numero intero di 4 cifre se lo utilizza s%64. Ogni numero decimale di 6 cifre composto solo da 0 e 1, considerato %64genera un risultato unico, quindi la casualità è buona.
Questo approccio consuma molti più bit casuali, ma è significativamente più breve.

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 logica di base è semplice: inizializza un array di 52 pollici con 0..51, shuffle (sostituisci in modo casuale l'elemento x con un altro dell'intervallo 0..x), stampa formattata (n / 4 = classifica, n% 4 = seme) .
Un ciclo, che esegue 104 volte, esegue l'inizializzazione (prime 52 esecuzioni), la riproduzione casuale e la stampa (ultime 52 esecuzioni).
Un numero casuale viene generato estraendo nbit casuali, fino 1<<na quando non è almeno il massimo desiderato. Se il risultato è superiore al massimo, riprovare.


Questo complicato s>7?"ATJQK"[s-8]:s+50è più lungo del semplice "A23456789TJQK"[s]. In secondo luogo è possibile utilizzare t/4e t%4invece di t%13e t/13.
Howard,

Non è necessario rimetterlo tnuovamente nell'array quando viene
emesso

3

shell unix ~ 350

Questo non è breve o carino, né è efficiente, tuttavia mi chiedevo quanto sarebbe stato difficile farlo con le utility di shell unix standard.

Questa risposta taglia la stringa binaria infinita in lunghezze di 6 bit e sceglie solo quelle che sono nell'intervallo corretto (1-52), qui la stringa binaria infinita viene simulata da urandom e xxd:

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

Il taglio e la selezione sono fatti con fold, sed e bc:

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

Questo produce linee come:

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

Quale può essere diretto in bc.

Da questo flusso di numeri, la sequenza del mazzo viene scelta in questo modo (sto usando zsh, ma la maggior parte delle shell moderne dovrebbe essere adattabile a questo):

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

La sequenza numerica randomizzata ora deve essere cambiata in nomi di carte. La sequenza del nome della carta viene facilmente generata con parallelo GNU:

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

Combinando l'output degli ultimi due comandi con incolla e ordinando sui numeri:

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

Il tutto come un mostruoso one-liner (testato solo in 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' ' '

Modifica: aggiunta la versione bash

Ecco una versione che funziona in bash. Ho rimosso l'in-shell { }e gli indici di array sono basati su zero. Il vuoto dell'array viene verificato con l'espansione dei parametri, leggermente più efficiente e adottato anche nell'esempio sopra.

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

  • v3 Index direttamente nei letterali di stringa
  • v2 Il suggerimento del droog utente nei commenti di usare stringhe e ha sostituito i charletterali rimanenti con intvalori letterali

golfed:

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

Praticamente forza bruta qui. Ho appena letto nove bit dall'input per formare un output RNG minimo e faccio la solita riduzione del modulo ridisegnare i valori se non utilizzati alla fine per ottenere un output uniforme per alimentare un shuffle di selezione.

Questa versione non golfata differisce in quanto prende l'input /dev/urandomanziché dal formato di input descritto.

#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 Ho molto da imparare. A proposito, perché no "TJQKA"e "cdhs"?
Luser droog

Oh. Giusto. intS. Capisco. Potrebbe comunque valerne la pena salvare tutta la punteggiatura. Potrebbe anche considerare il charfuori getchare putcharcon una pazza macro pastosa ...
Luser droog

1
Le sostituzioni di macro devono guadagnare molto perché devono iniziare #define N e finire con una nuova riga che conta come carattere e che è 11, oltre al bit che si sta sostituendo. Ci sono certamente alcuni altri personaggi nel sostituire alcuni o tutti i letterali dei personaggi con i letterali int, ma è tardi qui ... forse lo farò un'altra volta.
dmckee --- ex gattino moderatore

@luserdroog Clearer diretto ora. Naturalmente le stringhe sono migliori, anche se è necessario specificare il tipo, perché i caratteri sono solo numeri brevi. Inoltre posso combinarli e le sostituzioni ASCII ottengono un sacco di colpi in una volta sola.
dmckee --- ex gattino moderatore

0

PHP, 158 caratteri

Sono state aggiunte nuove righe per impedire al blocco di codice di ottenere barre di scorrimento, che possono essere rimosse in sicurezza.

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

Prima che mi <?phpvenga detto di aggiungere un , fai sapere che puoi invocare PHP senza questo tag abbastanza facilmente, usando:cat golf.php | php -a

De-golf e commentato:

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

Sono previsti due errori, che non influiscono sull'output del programma.

Il primo è perché $anon è inizializzato, ma il NULL viene convertito in 0 e il programma continua.

Il secondo è perché il flusso di caratteri sembra ottenere una nuova riga da qualche parte, anche se non è fornito (buon vecchio PHP), e questo è un indice indefinito nella matrice. È l'ultimo carattere dell'input e non influisce sull'output.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.