ランダム入力を使用してシャッフルされたデッキを出力します


9

入出力:

入力:stdinから取得した、一様にランダムで無限に長い「0」と「1」の文字列。文字列は、疑似ランダムではなく、真にランダムであると想定されます。各文字が「0」または「1」に等しくなる可能性が高いという点で均一です。

気をつけて!入力は無限に長いため、Pythonでraw_input()のような関数を使用してすべてをメモリに格納することはできません。私が間違っていなければ、golfscriptは実行前に入力全体をスタックにプッシュするため、無限入力で失敗します。

出力:ジョーカーのない、均一にランダムにシャッフルされた標準デッキ。すべての順序付けが等しく可能であるという点で均一です。

出力の各カードは、ランク、A、2-9、T、J、Q、またはKと、それに合わせて、c、d、h、またはsを連結したものです。たとえば、スペードの10はTs

デッキのカードはスペースで区切る必要があります。

組み込みのランダムライブラリまたは関数は、真にランダムではなく、疑似ランダムであるため使用できません。

入力例

次のpythonスクリプトを使用して、入力をプログラムにパイプすることができます。

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

スクリプトをrand.pyとして保存する場合は、プログラムをテストしてください python rand.py | your_program

python 3では期待どおりに実行されますが、python 2.7ではプログラムの出力後にエラーメッセージが表示されますが、すべての処理が完了した後にのみ表示されるため、エラーメッセージは無視してください。

出力例:

並べ替えられた順序にシャッフルされた場合にデッキを印刷する方法は次のとおりです。

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

得点:

これはコードゴルフです。最短のコードが勝ちます。

プログラム例:

これは、Python 2.7ソリューションであり、ゴルフではありません。

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
「私が間違っていなければ、golfscriptは実行前に入力全体をスタックにプッシュするため、無限入力で失敗します。」まあ、それは実行からそれを取り除く一つの方法です。
dmckee ---元モデレーターの子猫

私は少し混乱しています、許してください。入力は実際のデッキのシャッフルとどのように関係していますか?たぶん、少しだけ説明が必要です。
jdstankosky

1
コードで擬似ランダム関数を使用することはできないため、ランダム性を生成するには、入力(真にランダムであると想定)を使用する必要があります。たとえば、Pythonでは(sys.stdin.read(1)== '1')を使用してランダムなブール値を取得できますが、(random.randint(0,1)== 1)は使用できません。疑似ランダムのみです。
cardboard_box

回答:


7

Ruby、89 87文字

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

編集:以前のバージョン

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)

説明:

未使用のカードはDに格納されます。これは、入力ストリームから次の有効なランダムインデックスを取得し、その要素をDからポップするだけです。

私が何かを逃していない限り、偏見があってはなりません。スクリプトは無効なインデックス>をスローしますlen(D)が、連続するポップごとにiよりも過去の各要素のインデックスが減少するため、数値が小さくなるというバイアスは発生しません。


(無限)ランダム入力のほとんどを破棄しますか?つまり、「未使用」のカードがなくなると、シャッフルを停止しますか?
リー

3

Perl、80文字

これは、バイアスの影響を受けず、2文字短い別の実装です。

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

古い実装(82文字):

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

古い実装の説明:

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

ちょっと気になる:このアプローチが同じ確率でカードの各デッキを生成することを誰かが示すことができますか?
ハワード

2
この権利(IANAPH)を読んでいる場合、ランダムな「重み」が各カードに割り当てられ、重みによって並べ替えられます。2枚のカードに同じ重みが割り当てられている場合、それらはによって並べ替えられsort、その結果、アルファベット順の偏りが生じます。
ブース

あなたは正しい、@ boothby。複数のカードが同じ「重み」を持っている場合、ソートはこのソリューションにバイアスを残します。また、このソリューションが結果を生成することを保証することもできません。私よりも賢い人がそれを分析できるように、それがどのように機能するかの説明を追加します
ardnew '11

プログラムが終了する確率が、時間が無限大に近づくにつれて1に近づく限り、一部の入力によってプログラムが終了しない場合は、まったく問題ありません。サンプルプログラムは、すべて「1」の入力で終了することはありません。プログラムが特定のビット数を読み取った後に終了することを知っている間、均一なランダム性を得るのは実際には不可能だと私は確信しています。
cardboard_box

1
有限のビット数で、1〜3の一様に乱数を選択するにはどうすればよいですか。フィッシャーイェーツのシャッフルの終わり近くでこれを行う必要があります。factorial(52)は3で割り切れるので、同じ問題を共有します。
cardboard_box

3

C、197 178 161文字

編集:はるかに短い新しいランダム関数を使用します-4桁の整数sを読み取って使用しs%64ます。0と1のみで構成される6桁の10進数はそれぞれ%64、一意の結果になるため、ランダム性は良好です。
このアプローチは、はるかに多くのランダムビットを消費しますが、大幅に短くなります。

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

基本的なロジックは単純です-52 intの配列を0..51で初期化し、シャッフルします(ランダムに要素xを0..xの範囲の別のものに置き換えます)、印刷形式(n / 4 = rank、n%4 = suit) 。
104回実行される1つのループは、初期化(最初の52回の実行)、シャッフル、および印刷(最後の52回の実行)を実行します。
乱数は、少なくとも望ましい最大値になるnまで、ランダムビットをプルすることによって生成され1<<nます。結果が最大値を超えている場合は、再試行してください。


これs>7?"ATJQK"[s-8]:s+50は単純なものよりも複雑です"A23456789TJQK"[s]。次にt/4、andのt%4代わりにt%13andを使用できますt/13
ハワード

t出力時にアレイに戻す必要はありません
l4m2

3

UNIXシェル〜350

これは短くもきれいでもないし、効率的でもありませんが、標準のUNIXシェルユーティリティでこれを行うのはどれほど難しいかと思いました。

この答えは、無限バイナリ文字列を6ビット長に切り刻み、正しい範囲(1-52)にあるもののみを選択します。ここで、無限バイナリ文字列は、urandomとxxdによってシミュレートされます。

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

チョッピングと選択は、fold、sed、bcで行われます。

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

これにより、次のような行が生成されます。

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

これはbcに送ることができます。

この数字のストリームから、デッキのシーケンスは次のように選択されます(私はzshを使用していますが、最新のほとんどのシェルはこれに適応可能です):

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

ランダム化された数列をカード名に変更する必要があります。カード名シーケンスは、GNUパラレルで簡単に生成されます。

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

最後の2つのコマンドの出力を貼り付けて数値を並べ替える:

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

1つの巨大なワンライナーとしての全体(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' ' '

編集-追加されたbashバージョン

これはbashで動作するバージョンです。シェル内を削除し、{ }配列のインデックスはゼロベースです。配列の空性は、パラメータ拡張でチェックされますが、少し効率的で、上記の例でも採用されています。

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文字列リテラルに直接インデックスを付ける
  • v2コメントでのluser droogからの提案。文字列を使用し、残りのcharリテラルをintリテラルで置き換えました。

ゴルフ:

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

ここではかなりの総当たりです。入力から9ビットを読み取って、最小限のRNG出力を形成し、通常の再描画時の未使用の値による最後の係数の削減を行って、均一な出力を得て、選択をシャッフルします。

この非ゴルフバージョンは/dev/urandom、記述された入力形式からではなく、入力を取得する点が異なります。

#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学ぶことはたくさんあります。ところで、なぜない"TJQKA""cdhs"
luser droog

ああ。正しい。ints。わかった。句読点をすべて保存するには、それでも価値があるかもしれません。考慮しても可能性があるcharからgetcharputchar狂気のペースト状のマクロとの...
luserはドローグ

1
マクロ置換は、文字としてカウントされる#define N 改行で始まり、改行で終了する必要があり、11に加えて、置き換えるビットがあるため、多くのことを得る必要があります。文字リテラルの一部またはすべてをintリテラルに置き換えると、確かにさらにいくつかの文字がありますが、ここでは遅いです...多分私はもう一度やります。
dmckee ---元モデレーターの子猫

@luserdroog Clearerが今向かっています。もちろん文字列の方が優れています-タイプを指定する必要があります-文字は単なる短い整数なのでです。加えて、それらを組み合わせることができ、ASCII置換により、一連のストロークが一度に取得されます。
dmckee ---元モデレーターの子猫2012

0

PHP、158文字

コードブロックにスクロールバーが表示されないようにするために改行が追加され、安全に削除できます。

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

を追加するように指示される前に、次の<?phpコマンドを使用して、このタグなしでPHPを簡単に呼び出せることを知っておいてください。cat golf.php | php -a

脱ゴルフとコメント:

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

プログラムの出力に影響を与えない2つの予期されるエラーがあります。

1つ目は、$aが初期化されていないためですが、NULLは0に変換され、プログラムは続行します。

2番目の理由は、文字ストリームが提供されていなくても(文字列がPHPの場合)、文字ストリームがどこかから改行を取得しているように見え、それが配列内の未定義のインデックスであるためです。これは入力の最後の文字であり、出力には影響しません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.