Rastgele giriş kullanarak karıştırılmış bir deste çıkışı


9

Giriş çıkış:

Girdi : Düzgün rasgele, sonsuz uzunlukta, stdin'den alınan '0'lar ve' 1'ler dizisi. Dizgenin sözde rastgele değil, gerçekten rastgele olduğu varsayılır. Her karakterin eşit olarak '0' veya '1' olması muhtemeldir.

Dikkatli! Giriş sonsuza kadar uzun olduğundan, python'da raw_input () gibi bir işlevi kullanarak hepsini bellekte saklayamazsınız. Yanılmıyorsam, golfscript sonsuz girdi ile başarısız olur, çünkü çalıştırmadan önce tüm girdiyi yığının üzerine iter.

Çıktı : Eşitsiz rastgele karıştırılmış standart güverte, joker olmadan. Tüm siparişlerin eşit derecede muhtemel olması tekdüzedir.

Çıktıdaki her kart sıra, A, 2-9, T, J, Q veya K, takım elbise, c, d, h veya s ile birleştirilir. Örneğin, maça 10'uTs

Destenin kartları boşluklarla ayrılmalıdır.

Yerleşik rasgele kitaplıkları veya işlevleri kullanamazsınız çünkü bunlar gerçekten rasgele değil, yalnızca sahte rasgele.

Örnek giriş

Programınıza girişi yönlendirmek için aşağıdaki python komut dosyasını kullanabilirsiniz:

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

Komut dosyasını rand.py olarak kaydederseniz, programınızı python rand.py | your_program

Python 3'te beklendiği gibi çalışır, ancak python 2.7'de programımın çıktısından sonra bir hata mesajı alıyorum, ancak sadece her şey yapıldıktan sonra, bu yüzden hata mesajını görmezden gelin.

Örnek çıktı:

Sıralanmış bir sıraya karıştırılmışsa, destenin nasıl yazdırılması gerektiği aşağıda açıklanmıştır:

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

puanlama:

Bu bir kod golf. En kısa kod kazanır.

Örnek program:

İşte bir python 2.7 çözümü, golf değil.

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
"Yanılmıyorsam, golfscript sonsuz girdi ile başarısız olur, çünkü çalıştırmadan önce tüm girdiyi yığının üzerine iter." Peki, bunu koşudan çıkarmanın bir yolu.
dmckee --- eski moderatör kedi yavrusu

Biraz kafam karıştı, affet beni. Girdinin gerçek güverte karıştırma ile ne ilgisi var? Belki biraz açıklığa ihtiyacım var.
jdstankosky

1
Kodunuzda sözde rasgele işlevler kullanamazsınız, bu nedenle rasgelelik oluşturmak için girdiyi ( gerçekten rasgele olduğunu varsaydığımız ) kullanmanız gerekir. Örneğin, python'da rasgele bir boole elde etmek için (sys.stdin.read (1) == '1') kullanabilirsiniz, ancak (random.randint (0,1) == 1) kullanamazsınız, çünkü sadece sözde rastgele.
cardboard_box

Yanıtlar:


7

Ruby, 89 87 karakter

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

Düzenle: önceki sürüm

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

3

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

Açıklama:

Kullanılmayan kartlar D'de saklanır. Bu, bir sonraki geçerli rastgele dizini giriş akışından alır ve bu öğeyi D'den alır.

Bir şeyi kaçırmadıkça, önyargı olmamalı. Komut dosyası geçersiz indeksler atar len(D), ancak ardışık her pop, i'den sonra her öğenin dizinini azaltacağından, bu, daha düşük sayılar için bir sapmaya neden olmaz.


Yani (sonsuz) rasgele girdinin çoğunu atıyorsunuz? Yani "kullanılmayan" kartınız olmadığında karıştırmayı durduruyor musunuz?
Leigh

3

Perl, 80 karakter

burada önyargıdan muzdarip olmayan ve iki karakter daha kısa olan başka bir uygulama var:

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

eski uygulama (82 karakter):

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

eski uygulama açıklaması:

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

Sadece merak ediyorum: Herkes bu yaklaşımın her kart destesini aynı olasılıkla ürettiğini gösterebilir mi?
Howard

2
Bu hakkı (IANAPH) okuyorsam, her karta rastgele 'ağırlıklar' atar ve sonra ağırlıkça sıralar. İki ağırlığa aynı ağırlık atandığında, sırayla bırakılırlar ve sortbu da alfabetik sıralamaya doğru bir önyargıya neden olur.
boothby

haklısın @boothby. sıralama birden fazla kartın aynı "ağırlığa" sahip olması durumunda bu çözümü önyargıyla bırakır. bu çözümün bir sonuç üreteceği de garanti edilemez. Benden daha akıllı birinin analiz edebilmesi için nasıl çalıştığına dair bir açıklama ekleyeceğim
ardnew

Bazı girdilerin, zamanın sonsuza yaklaştıkça programın 1'e yaklaşma olasılığı olduğu sürece, programın hiçbir zaman sonlandırılmamasına neden olması gayet iyi olur. Örnek program hiçbir zaman tüm '1'lerin girişinde sona ermez. Eminim ki belirli sayıda bit okunduktan sonra programınızın sona erdiğini bilerek tekdüze rastgele olma imkansızdır.
cardboard_box

1
Sonlu sayıda bit içeren 1 ile 3 arasında eşit olarak rasgele bir sayı nasıl seçebilirsiniz? Bunu Fisher-Yates karıştırmasının sonuna doğru yapmanız gerekecek ve faktöriyel (52) 3 ile bölünebilir, böylece aynı sorunu paylaşır.
karton_box

3

C 197 178 161 karakter

EDIT : Çok daha kısa olan yeni bir rasgele işlev kullanarak - 4 basamaklı bir tam sayı okur sve kullanır s%64. Yalnızca 0 ve 1'den oluşan her 6 basamaklı ondalık sayı, %64benzersiz bir sonuç verir, bu nedenle rasgelelik iyidir.
Bu yaklaşım çok daha rastgele bitler tüketir, ancak önemli ölçüde daha kısadır.

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

Temel mantık basittir - 52 inçlik bir diziyi 0,51 ile karıştır, karıştır (x öğesini 0..x aralığından rastgele biriyle değiştir), baskı biçimlendirilmiş (n / 4 = sıralama, n% 4 = takım elbise) .
104 kez çalışan bir döngü başlatma (ilk 52 çalıştırma), karıştırma ve yazdırma (son 52 çalıştırma) yapar. En azından istenen maksimum oluncaya kadar rastgele bitler
çekilerek rastgele bir sayı üretilir . Sonuç maksimum değerden fazlaysa - tekrar deneyin. n1<<n


Bu karmaşık s>7?"ATJQK"[s-8]:s+50, basit olandan daha uzundur "A23456789TJQK"[s]. İkinci kullanabileceğiniz t/4ve t%4yerine t%13ve t/13.
Howard

Çıkış tyaparken diziye tekrar
girmenize

3

unix kabuğu ~ 350

Bu kısa veya güzel değil, aynı zamanda verimli değil, ancak bunu standart unix kabuk yardımcı programlarıyla yapmanın ne kadar zor olacağını merak ediyordum.

Bu cevap, sonsuz ikili dizgiyi 6 bit uzunluğa ayırır ve yalnızca doğru aralıkta olanları seçer (1-52), burada sonsuz ikili dizge urandom ve xxd ile simüle edilir:

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

Doğrama ve seçim katlama, sed ve bc ile yapılır:

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

Bu, aşağıdaki gibi çizgiler üretir:

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

Hangi bc yönlendirilebilir.

Bu sayı akışından, güverte sırası şu şekilde seçilir (zsh kullanıyorum, ancak çoğu modern kabuk buna uyarlanabilir):

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

Rasgele sayı dizisinin artık kart adlarına değiştirilmesi gerekiyor. Kart adı sırası, GNU paraleliyle kolayca oluşturulur:

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

Son iki komutun çıktısını yapıştırma ve sayılarla sıralama ile birleştirin:

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

Her şey tek bir tek katmanlı olarak (sadece zsh ile test edildi):

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' ' '

Düzenle - bash sürümü eklendi

İşte bash'da çalışan bir sürüm. Kabuk kaldırıldı { }ve dizi dizinleri sıfır tabanlı. Dizi boşluğu, parametre genişletme ile kontrol edilir, biraz daha verimlidir ve yukarıdaki örnekte de benimsenmiştir.

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 Dizgi değişmezlerini doğrudan dizine ekleme
  • v2 Dize kullanmak için yorumlarda luser droog önerisi ve kalan chardeğişmez intdeğerleri değişmez değerlerle değiştirmek

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

Burada oldukça kaba bir kuvvet var. Minimal bir RNG çıkışı oluşturmak için girişten dokuz bit okudum ve bir seçim shuffle'a güç sağlamak için tekdüze çıktı elde etmek için her zamanki kullanılmayan değerlerin sondaki modül redüksiyonunu yaptım.

Bu golf oynamayan sürüm, girdiyi /dev/urandomaçıklanan giriş biçiminden ziyade alması bakımından farklılık gösterir .

#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 Öğrenecek çok şeyim var. BTW, neden olmasın "TJQKA"ve "cdhs"?
luser droog

Ah. Sağ. ints. Anladım. Tüm noktalama işaretlerini kaydetmek için buna değebilir. Hatta chardışarı getcharve putchardeli bir macun makro ile faktör olabilir ...
luser droog

1
Makro ikamelerinin çok kazanması gerekir, çünkü karakter olarak sayılan ve 11, artı değiştirdiğiniz bit #define N olan bir yeni satırla başlayıp bitmelidirler . Karakter değişmezlerinin bir kısmını veya tamamını int değişmezleriyle değiştirirken kesinlikle birkaç karakter daha var, ancak burada geç kaldı ... belki başka bir zaman yapacağım.
dmckee --- eski moderatör yavru kedi

@luserdroog Clearer şimdi yöneldi. Elbette dizeler daha iyidir - türü belirtmeniz gerekir - çünkü karakterler sadece kısa tamsayılardır. Ayrıca onları birleştirebilirim ve ASCII yedekleri tek seferde bir sürü vuruş alır.
dmckee --- eski moderatör yavru kedi

0

PHP, 158 karakter

Kod bloğunun kaydırma çubukları kazanmasını durdurmak için yeni satırlar eklenmiştir, bunlar güvenle kaldırılabilir.

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

Ben eklemeniz söylenmeden önce <?php, bu etiketi kullanmadan PHP'yi kolayca çağırabileceğinizi bilmenizi sağlayın:cat golf.php | php -a

Golfu kaldırıldı ve yorum yaptı:

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

Programın çıktısını etkilemeyen, beklenen iki hata vardır.

Birincisi, $abaşlatılmadığı için NULL değeri 0'a dönüştürülür ve program devam eder.

İkincisi, karakter akışı, sağlanmamış olsa bile (iyi ol 'PHP) bir yerden yeni bir satır alıyor gibi görünüyor ve bu dizideki tanımlanmamış bir dizin. Girdinin son karakteri ve çıktıyı etkilemez.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.