Sortie d'une platine mélangée à l'aide d'une entrée aléatoire

9

Entrée sortie:

Entrée : une chaîne uniformément aléatoire, infiniment longue, de «0 et de 1», prise à partir de stdin. La chaîne est supposée être vraiment aléatoire, pas pseudo-aléatoire. Il est uniforme en ce que chaque caractère est également susceptible d'être un «0» ou un «1».

Prudent! L'entrée est infiniment longue, vous ne pouvez donc pas tout stocker en mémoire en utilisant une fonction comme raw_input () en python. Si je ne me trompe pas, golfscript échouera avec une entrée infinie, car il pousse toute l'entrée sur la pile avant de courir.

Sortie : Un deck standard mélangé de manière uniforme et aléatoire, sans jokers. Il est uniforme en ce sens que toutes les commandes sont également probables.

Chaque carte dans la sortie est son rang, A, 2-9, T, J, Q ou K concaténé avec sa couleur, c, d, h ou s. Par exemple, le 10 de pique estTs

Les cartes du jeu doivent être séparées par des espaces.

Vous ne pouvez pas utiliser de bibliothèques ou de fonctions aléatoires intégrées car elles ne sont pas vraiment aléatoires, uniquement pseudo-aléatoires.

Exemple d'entrée

Vous pouvez utiliser le script python suivant pour diriger les entrées dans votre programme:

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

Si vous enregistrez le script sous rand.py, testez votre programme avec python rand.py | your_program

En python 3, il fonctionne comme prévu, mais en python 2.7 j'obtiens un message d'erreur après la sortie de mon programme, mais seulement après que tout soit fait, donc ignorez simplement le message d'erreur.

Exemple de sortie:

Voici comment imprimer le jeu s'il est mélangé dans un ordre trié:

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

Notation:

Ceci est un golf de code. Le code le plus court gagne.

Exemple de programme:

Voici une solution python 2.7, non golfée.

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))),
boîte en carton
la source
3
"Si je ne me trompe pas, golfscript échouera avec une entrée infinie, car il pousse toute l'entrée sur la pile avant de courir." Eh bien, c'est une façon de le retirer de la course.
dmckee --- chaton ex-modérateur
Je suis un peu confus, pardonnez-moi. Qu'est-ce que l'entrée a à voir avec le brassage réel du jeu? J'ai peut-être juste besoin d'un petit éclaircissement.
jdstankosky
1
Vous ne pouvez pas utiliser de fonctions pseudo-aléatoires dans votre code, vous devez donc utiliser l'entrée (que nous supposons vraiment aléatoire) pour générer le caractère aléatoire. Par exemple, en python, vous pouvez utiliser (sys.stdin.read (1) == '1') pour obtenir un booléen aléatoire, mais vous ne pouvez pas utiliser (random.randint (0,1) == 1), car c'est seulement pseudo-aléatoire.
cardboard_box

Réponses:

7

Ruby, 89 87 caractères

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

Edit: version précédente

l=*0..51;(l-=[i=l[gets(6).to_i 2]];i&&$><<'A23456789TJQK'[i/4]+'cdhs'[i%4]+' ')while l[0]
Howard
la source
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)

Explication:

Les cartes inutilisées sont stockées dans D. Cela obtient simplement le prochain index aléatoire valide du flux d'entrée et fait apparaître cet élément de D.

À moins que je manque quelque chose, il ne devrait pas y avoir de parti pris. Le script rejettera tous les index invalides> len(D), mais cela n'entraîne pas de biais pour les nombres inférieurs car chaque pop successif réduira l'index de chaque élément au-delà de i.

scleaver
la source
Donc, vous jetez la plupart des entrées aléatoires (infinies)? C'est-à-dire que vous arrêtez de mélanger une fois que vous n'avez plus de cartes "inutilisées"?
Leigh
3

Perl, 80 caractères

voici une autre implémentation qui ne souffre pas du biais et qui est plus courte de deux caractères:

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

ancienne implémentation (82 caractères):

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

ancienne description d'implémentation:

# 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
la source
Juste curieux: quelqu'un peut-il montrer que cette approche produit chaque jeu de cartes avec la même probabilité?
Howard
2
Si je lis bien (IANAPH), il attribue des «poids» aléatoires à chaque carte, puis les trie en fonction du poids. Lorsque deux cartes ont le même poids, elles sont laissées dans l'ordre sort, ce qui entraîne un biais vers l'ordre alphabétique.
stand
vous avez raison, @boothby. le tri laisse cette solution avec un biais dans le cas où plusieurs cartes ont le même "poids". il ne peut pas non plus être garanti que cette solution produira un résultat. J'ajouterai une description de la façon dont cela fonctionne afin que quelqu'un plus intelligent que moi puisse l'analyser
ardnew
C'est parfaitement bien si certaines entrées font que le programme ne se termine jamais, tant que la probabilité que le programme se termine approche 1 alors que le temps approche de l'infini. L'exemple de programme ne se termine jamais sur une entrée de tous les «1». Je suis à peu près sûr qu'il est en fait impossible d'obtenir un caractère aléatoire uniforme tout en sachant que votre programme se termine après un certain nombre de bits lus.
cardboard_box
1
Comment pouvez-vous choisir un nombre uniformément aléatoire entre 1 et 3 avec un nombre fini de bits? Vous devrez le faire vers la fin du shuffle de Fisher-Yates, et la factorielle (52) est divisible par 3, donc elle partage le même problème.
cardboard_box
3

C, 197 178 161 caractères

EDIT : Utilisation d'une nouvelle fonction aléatoire, qui est beaucoup plus courte - lit un entier à 4 chiffres set utilise s%64. Chaque nombre décimal à 6 chiffres composé de 0 et 1 seulement, pris %64donne un résultat unique, donc le caractère aléatoire est bon.
Cette approche consomme beaucoup plus de bits aléatoires, mais est beaucoup plus courte.

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 logique de base est simple - initialiser un tableau de 52 pouces avec 0..51, mélanger (remplacer aléatoirement l'élément x par un autre de la plage 0..x), imprimer au format (n / 4 = rang, n% 4 = costume) .
Une boucle, qui s'exécute 104 fois, effectue l'initialisation (52 premières exécutions), le mélange et l'impression (les 52 dernières exécutions).
Un nombre aléatoire est généré en tirant ndes bits aléatoires, jusqu'à ce qu'il 1<<nsoit au moins le maximum souhaité. Si le résultat est supérieur au maximum - réessayez.

ugoren
la source
Ce compliqué s>7?"ATJQK"[s-8]:s+50est plus long que le simple "A23456789TJQK"[s]. Deuxièmement, vous pouvez utiliser t/4et t%4au lieu de t%13et t/13.
Howard
Pas besoin de remettre tdans le tableau lors de la sortie
l4m2
3

shell unix ~ 350

Ce n'est ni court ni joli, ni efficace, mais je me demandais à quel point ce serait difficile de le faire avec les utilitaires shell standard unix.

Cette réponse coupe la chaîne binaire infinie en longueurs de 6 bits et ne choisit que celles qui sont dans la plage correcte (1-52), ici la chaîne binaire infinie est simulée par urandom et xxd:

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

Le hachage et la sélection se fait avec fold, sed et bc:

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

Cela produit des lignes telles que:

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

Qui peut être dirigé vers bc.

À partir de ce flux de nombres, la séquence du jeu est choisie comme ceci (j'utilise zsh, mais la plupart des shells modernes devraient être adaptables à cela):

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

La séquence de nombres aléatoires doit maintenant être changée en noms de cartes. La séquence de noms de cartes est facilement générée avec GNU parallèle:

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

Combiner la sortie des deux dernières commandes avec coller et trier sur les nombres:

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

Le tout comme un monoplace monstrueux (uniquement testé 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' ' '

Modifier - version bash ajoutée

Voici une version qui fonctionne en bash. J'ai supprimé les { }index internes et les tableaux sont basés sur zéro. La vacuité des tableaux est vérifiée avec une expansion des paramètres, légèrement plus efficace et également adoptée dans l'exemple ci-dessus.

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
la source
2

K&R c - 275

  • v3 Index dans les chaînes de caractères directement
  • v2 Suggestion de luser droog dans les commentaires pour utiliser des chaînes et remplacer les charlittéraux restants par des intlittéraux

Golfé:

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

À peu près la force brute ici. Je viens de lire neuf bits de l'entrée pour former une sortie RNG minimale et faire la réduction de module de redessiner si les valeurs inutilisées à la fin pour obtenir une sortie uniforme pour alimenter un shuffle de sélection.

Cette version non-golfée diffère en ce qu'elle prend l'entrée /dev/urandomplutôt que le format d'entrée décrit.

#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 --- chaton ex-modérateur
la source
+1 J'ai beaucoup à apprendre. BTW, pourquoi pas "TJQKA"et "cdhs"?
luser droog
Oh. Droite. ints. J'ai compris. Cela peut valoir la peine de conserver toute la ponctuation. Pourrait même prendre en compte la charsortie getcharet putcharavec une macro pâteuse folle ...
luser droog
1
Les substitutions de macros doivent gagner beaucoup car elles doivent commencer #define N et se terminer par une nouvelle ligne qui compte comme un caractère et c'est 11, plus le bit que vous remplacez. Il y a certainement quelques caractères de plus pour remplacer une partie ou la totalité des littéraux de caractère par des littéraux int, mais il est tard ici ... peut-être que je le ferai une autre fois.
dmckee --- chaton ex-modérateur
@luserdroog Clearer s'est dirigé maintenant. Bien sûr, les chaînes sont meilleures - bien que vous deviez spécifier le type - car les caractères ne sont que des entiers courts. De plus, je peux les combiner et les substitutions ASCII obtiennent un tas de traits en une seule fois.
dmckee --- chaton ex-modérateur
0

PHP, 158 caractères

Des nouvelles lignes ont été ajoutées pour empêcher le bloc de code de gagner des barres de défilement, elles peuvent être supprimées en toute sécurité.

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

Avant qu'on me dise d'ajouter un <?php, sachez que vous pouvez invoquer PHP sans cette balise assez facilement, en utilisant:cat golf.php | php -a

De-golfé et commenté:

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

Il y a deux erreurs attendues, qui n'affectent pas la sortie du programme.

Le premier est parce que $an'est pas initialisé, mais le NULL est converti en 0 et le programme continue.

Le second est parce que le flux de caractères semble obtenir une nouvelle ligne quelque part, même s'il n'est pas fourni (bon vieux PHP), et c'est un index non défini dans le tableau. Il s'agit du dernier caractère d'entrée et n'affecte pas la sortie.

Leigh
la source