Keluaran deck dikocok menggunakan input acak

9

Input output:

Input : String acak '0' dan '1' yang seragam, panjang, dan tak terhingga, diambil dari stdin. String diasumsikan benar-benar acak, bukan pseudo-acak. Ini seragam karena setiap karakter memiliki kemungkinan yang sama untuk menjadi '0' atau '1'.

Cermat! Inputnya panjang sekali, jadi Anda tidak bisa menyimpan semuanya dalam memori menggunakan fungsi seperti raw_input () dalam python. Jika saya tidak salah, skrip golf akan gagal dengan input yang tidak terbatas, karena mendorong seluruh input ke stack sebelum menjalankan.

Output : Dek standar acak acak acak, tanpa pelawak. Ini seragam karena semua pemesanan memiliki kemungkinan yang sama.

Setiap kartu dalam output adalah peringkatnya, A, 2-9, T, J, Q atau K yang digabungkan dengan suit, c, d, h atau s. Misalnya, 10 sekop adalahTs

Kartu-kartu geladak harus dipisahkan oleh spasi.

Anda tidak boleh menggunakan pustaka atau fungsi acak bawaan karena tidak benar-benar acak, hanya pseudo-acak.

Contoh input

Anda dapat menggunakan skrip python berikut untuk memasukkan input ke program Anda:

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

Jika Anda menyimpan skrip sebagai rand.py, uji program Anda dengan python rand.py | your_program

Dalam python 3 ini berjalan seperti yang diharapkan, tetapi dalam python 2.7 saya mendapatkan pesan kesalahan setelah output program saya, tetapi hanya setelah semuanya selesai, jadi abaikan saja pesan kesalahan itu.

Contoh output:

Begini cara dek harus dicetak jika kebetulan diacak menjadi urutan:

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

Mencetak:

Ini adalah kode golf. Kode terpendek menang.

Contoh program:

Berikut ini adalah solusi python 2.7, bukan 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))),
kotak kardus
sumber
3
"Jika saya tidak salah, skrip golf akan gagal dengan input tak terbatas, karena mendorong seluruh input ke stack sebelum menjalankan." Nah, itu salah satu cara untuk menghilangkannya.
dmckee --- ex-moderator kitten
Saya sedikit bingung, maafkan saya. Apa yang harus dilakukan input dengan pengocokan deck yang sebenarnya? Mungkin saya hanya perlu sedikit klarifikasi.
jdstankosky
1
Anda tidak dapat menggunakan fungsi pseudo-acak dalam kode Anda, jadi Anda perlu menggunakan input (yang kami anggap benar - benar acak) untuk menghasilkan keacakan. Misalnya, dalam python Anda dapat menggunakan (sys.stdin.read (1) == '1') untuk mendapatkan boolean acak, tetapi Anda tidak dapat menggunakan (random.randint (0,1) == 1), karena itu hanya pseudo-acak.
cardboard_box

Jawaban:

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]+' '}

Edit: versi sebelumnya

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

Penjelasan:

Kartu yang tidak digunakan disimpan dalam D. Ini hanya mendapatkan indeks acak yang valid berikutnya dari aliran input dan muncul elemen itu dari D.

Kecuali saya kehilangan sesuatu, seharusnya tidak ada bias. Skrip akan membuang semua indeks yang tidak valid> len(D), tetapi ini tidak menghasilkan bias untuk angka yang lebih rendah karena setiap pop yang berurutan akan mengurangi indeks setiap elemen di masa lalu daripada saya.

scleaver
sumber
Jadi, Anda membuang sebagian besar input acak (tak terbatas)? Apakah Anda berhenti mengocok begitu Anda tidak memiliki kartu "tidak digunakan"?
Leigh
3

Perl, 80 karakter

berikut ini adalah implementasi lain yang tidak mengalami bias dan dua karakter lebih pendek:

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

implementasi lama (82 karakter):

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

deskripsi implementasi lama:

# 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
sumber
Hanya ingin tahu: adakah yang bisa menunjukkan bahwa pendekatan ini menghasilkan setiap setumpuk kartu dengan probabilitas yang sama?
Howard
2
Jika saya membaca hak ini (IANAPH), itu memberikan 'bobot' acak untuk setiap kartu, dan kemudian mengurutkan berdasarkan berat. Ketika dua kartu diberi bobot yang sama, mereka akan dibiarkan berurutan sort, menghasilkan bias terhadap pemesanan alfabet.
stan
kamu benar, @boothby. semacam itu tidak meninggalkan solusi ini dengan bias dalam hal beberapa kartu memiliki "berat" yang sama. itu juga tidak dapat dijamin bahwa solusi ini akan pernah membuahkan hasil. Saya akan menambahkan deskripsi cara kerjanya sehingga seseorang yang lebih pintar dari saya dapat menganalisanya
ardnew
Tidak apa-apa jika beberapa input menyebabkan program tidak pernah berhenti, selama probabilitas bahwa program berakhir mendekati 1 ketika waktu mendekati tak terbatas. Contoh program tidak pernah berhenti pada input semua '1's. Saya cukup yakin itu sebenarnya tidak mungkin untuk mendapatkan keacakan seragam sambil mengetahui program Anda berakhir setelah sejumlah bit membaca.
cardboard_box
1
Bagaimana Anda bisa memilih angka acak seragam antara 1 dan 3 dengan jumlah bit terbatas? Anda harus melakukannya di akhir shuffle Fisher-Yates, dan faktorial (52) dapat dibagi dengan 3 sehingga berbagi masalah yang sama.
cardboard_box
3

C, 197 178 161 karakter

EDIT : Menggunakan fungsi acak baru, yang jauh lebih pendek - membaca bilangan bulat 4 sdan menggunakan s%64. Setiap angka desimal 6 digit yang terbuat dari 0 dan 1 saja, diambil %64hasilnya dalam hasil yang unik, sehingga keacakannya baik.
Pendekatan ini mengkonsumsi lebih banyak bit acak, tetapi jauh lebih pendek.

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

Logika dasarnya sederhana - inisialisasi array 52 int dengan 0..51, shuffle (ganti elemen x secara acak dengan yang lain dari rentang 0..x), cetak berformat (n / 4 = peringkat, n% 4 = cocok) .
Satu loop, yang berjalan 104 kali, melakukan inisialisasi (52 kali pertama), pengocokan dan pencetakan (52 kali terakhir).
Angka acak dihasilkan dengan menarik nbit acak, hingga 1<<nsetidaknya maksimum yang diinginkan. Jika hasilnya lebih dari maksimum - coba lagi.

ugoren
sumber
Rumit s>7?"ATJQK"[s-8]:s+50ini lebih panjang dari yang sederhana "A23456789TJQK"[s]. Kedua, Anda bisa menggunakan t/4dan t%4bukannya t%13dan t/13.
Howard
Tidak perlu lagi dimasukkan tke dalam array ketika mengeluarkan
l4m2
3

shell unix ~ 350

Ini tidak pendek atau cantik, juga tidak efisien, tetapi saya bertanya-tanya seberapa sulit untuk melakukan ini dengan utilitas shell unix standar.

Jawaban ini memotong string biner infinite menjadi panjang 6 bit dan hanya memilih yang berada dalam kisaran yang benar (1-52), di sini string biner infinite disimulasikan oleh urandom dan xxd:

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

Pemotongan dan seleksi dilakukan dengan lipatan, sed dan bc:

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

Ini menghasilkan garis-garis seperti:

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

Yang bisa diarahkan ke bc.

Dari aliran angka ini, urutan dek dipilih seperti ini (saya menggunakan zsh, tetapi sebagian besar shell modern harus dapat beradaptasi dengan ini):

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

Urutan nomor acak sekarang perlu diubah menjadi nama kartu. Urutan nama kartu mudah dibuat dengan paralel GNU:

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

Menggabungkan output dari dua perintah terakhir dengan menempelkan dan mengurutkan angka:

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

Semuanya sebagai one-liner mengerikan (hanya diuji dalam 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' ' '

Edit - versi bash ditambahkan

Ini adalah versi yang bekerja di bash. Saya menghapus in-shell { }dan indeks array berbasis nol. Kekosongan larik diperiksa dengan ekspansi parameter, sedikit lebih efisien dan juga diadopsi dalam contoh di atas.

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
sumber
2

K&R c - 275

  • v3Indeks ke dalam string literal secara langsung
  • v2 Saran dari luser droog di komentar untuk menggunakan string dan mengganti charliteral yang tersisa dengan intliteral

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

Cukup banyak kekerasan di sini. Saya baru saja membaca sembilan bit dari input untuk membentuk output RNG minimal, dan melakukan redraw-if-the-un-values-yang tidak digunakan pengurangan modulus pada akhir untuk mendapatkan output yang seragam untuk menyalakan shuffle pilihan.

Versi un-golfed ini berbeda karena dibutuhkan input /dev/urandomdaripada dari format input yang dijelaskan.

#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 --- mantan kucing moderator
sumber
+1 Saya harus banyak belajar. BTW, mengapa tidak "TJQKA"dan "cdhs"?
luser droog
Oh Baik. ints. Saya mengerti. Mungkin masih layak untuk menyimpan semua tanda baca. Bahkan mungkin faktor charkeluar getchardan putchardengan makro pucat gila ...
luser droog
1
Pergantian makro perlu mendapatkan banyak karena mereka harus mulai dengan #define N dan diakhiri dengan baris baru yang dianggap sebagai karakter dan itu 11, ditambah bit yang Anda ganti. Tentu ada beberapa karakter lagi dalam mengganti beberapa atau semua karakter literal dengan literal int, tapi sudah terlambat di sini ... mungkin saya akan melakukannya lain kali.
dmckee --- ex-moderator kitten
@luserdroog Clearer menuju sekarang. Tentu saja string lebih baik - meskipun Anda harus menentukan tipe - karena karakter hanyalah bilangan bulat pendek. Ditambah lagi, saya bisa menggabungkan mereka dan pergantian ASCII mendapatkan banyak pukulan sekaligus.
dmckee --- ex-moderator kitten
0

PHP, 158 karakter

Baris baru telah ditambahkan untuk menghentikan blok kode mendapatkan scrollbar, mereka dapat dengan aman dihapus.

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

Sebelum saya diberitahu untuk menambahkan <?php, beri tahu Anda dapat memanggil PHP tanpa tag ini dengan mudah, menggunakan:cat golf.php | php -a

De-golf dan berkomentar:

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

Ada dua kesalahan yang diharapkan, yang tidak mempengaruhi output program.

Yang pertama adalah karena $atidak diinisialisasi, tetapi NULL dikonversi ke 0 dan program berlanjut.

Yang kedua adalah karena aliran karakter tampaknya mendapatkan baris baru dari suatu tempat, bahkan jika itu tidak disediakan (PHP yang bagus), dan itu adalah indeks yang tidak ditentukan dalam array. Ini adalah karakter input terakhir, dan tidak memengaruhi output.

Leigh
sumber