เอาต์พุตสำรับแบบสับโดยใช้อินพุตแบบสุ่ม


9

Input / Output:

อินพุต : สตริงที่มีความยาวและไม่ จำกัด จำนวนสุ่มจาก 0 0 และ '1' มาจาก stdin สตริงจะถือว่าสุ่มอย่างแท้จริงไม่ใช่การสุ่มหลอก มันเหมือนกันในแต่ละตัวละครมีแนวโน้มที่จะเป็น '0' หรือ '1' อย่างเท่าเทียมกัน

ระวัง! อินพุตมีความยาวไม่ จำกัด ดังนั้นคุณจึงไม่สามารถเก็บไว้ในหน่วยความจำได้โดยใช้ฟังก์ชั่นเช่น raw_input () ในไพ ธ อน ถ้าฉันไม่เข้าใจผิด golfscript จะล้มเหลวด้วยอินพุตไม่ จำกัด เนื่องจากมันจะดันอินพุตทั้งหมดไปยังสแต็กก่อนที่จะทำงาน

เอาท์พุท : สำรับสุ่มแบบสุ่มที่สม่ำเสมอโดยไม่ต้องมีโจ๊กเกอร์ มันเหมือนกันในทุกคำสั่งมีแนวโน้มที่เท่าเทียมกัน

การ์ดแต่ละใบในเอ้าท์พุทคืออันดับ, A, 2-9, T, J, Q หรือ K เรียงต่อกันด้วยชุดสูท, c, d, h หรือ s ตัวอย่างเช่น 10 โพดำคือTs

ไพ่ของเด็คควรคั่นด้วยช่องว่าง

คุณไม่สามารถใช้ไลบรารีหรือฟังก์ชั่นสุ่มในตัวเพราะมันไม่ได้สุ่มอย่างเดียวหลอกหลอกเท่านั้น

ตัวอย่างอินพุต

คุณสามารถใช้สคริปต์ไพ ธ อนต่อไปนี้เพื่อไพพ์อินพุตลงในโปรแกรมของคุณ:

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

เกณฑ์การให้คะแนน:

นี่คือรหัสกอล์ฟ รหัสที่สั้นที่สุดชนะ

โปรแกรมตัวอย่าง:

นี่คือวิธีการแก้ปัญหาของงูหลาม 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
คุณไม่สามารถใช้ฟังก์ชั่นหลอกหลอกในรหัสของคุณดังนั้นคุณต้องใช้อินพุต (ซึ่งเราสมมติว่าเป็นสุ่มอย่างแท้จริง ) เพื่อสร้างแบบสุ่ม ตัวอย่างเช่นในไพ ธ อนคุณสามารถใช้ (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)แต่สิ่งนี้ไม่ได้ทำให้มีอคติสำหรับตัวเลขที่ต่ำกว่าเนื่องจากป๊อปต่อเนื่องแต่ละอันจะลดดัชนีของแต่ละองค์ประกอบที่ผ่านมามากกว่าฉัน


ดังนั้นคุณจะทิ้งอินพุตแบบสุ่ม (ไม่ จำกัด ) ส่วนใหญ่หรือไม่ คือคุณหยุดสับไพ่เมื่อคุณไม่มีการ์ด "ที่ไม่ได้ใช้" หรือไม่?
Leigh

3

Perl, 80 ตัวอักษร

นี่คือการติดตั้งอื่นที่ไม่ได้รับผลกระทบจากอคติและสั้นกว่าสองอักขระ:

$/=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;
}

เพียงแค่อยากรู้อยากเห็น: ทุกคนสามารถแสดงให้เห็นว่าวิธีการนี
Howard

2
ถ้าฉันอ่านถูกต้อง (IANAPH) มันจะกำหนด 'น้ำหนัก' แบบสุ่มให้กับการ์ดแต่ละใบแล้วจึงเรียงตามน้ำหนัก เมื่อกำหนดไพ่สองใบที่มีน้ำหนักเท่ากันไพ่จะถูกเรียงตามลำดับsortทำให้เกิดอคติต่อการเรียงลำดับตัวอักษร
บูธโดย

คุณพูดถูก @boothby การเรียงลำดับจะทำให้โซลูชันนี้มีอคติในกรณีที่การ์ดหลายใบมี "น้ำหนัก" เท่ากัน ไม่สามารถรับประกันได้ว่าโซลูชันนี้จะให้ผลลัพธ์ที่แน่นอน ฉันจะเพิ่มคำอธิบายวิธีการทำงานเพื่อให้คนฉลาดกว่าที่ฉันสามารถวิเคราะห์ได้
ardnew

มันสมบูรณ์ดีถ้าอินพุตบางตัวทำให้โปรแกรมไม่สิ้นสุดตราบใดที่ความน่าจะเป็นที่โปรแกรมสิ้นสุดวิธีที่ 1 เมื่อเวลาเข้าใกล้อนันต์ โปรแกรมตัวอย่างจะไม่ยุติในอินพุตของ '1's ทั้งหมด ฉันค่อนข้างแน่ใจว่าเป็นไปไม่ได้ที่จะได้รับการสุ่มอย่างสม่ำเสมอในขณะที่การรู้ว่าโปรแกรมของคุณสิ้นสุดลงหลังจากอ่านบิตจำนวนหนึ่ง
cardboard_box

1
คุณจะเลือกสุ่มตัวเลขอย่างสม่ำเสมอระหว่าง 1 ถึง 3 ด้วยจำนวน จำกัด บิตได้อย่างไร? คุณจะต้องทำอย่างนั้นในตอนท้ายของการสับเปลี่ยน Fisher-Yates และ factorial (52) หารด้วย 3 ดังนั้นมันจึงมีปัญหาร่วมกัน
cardboard_box

3

C, 197 178 161 ตัวอักษร

แก้ไข : การใช้ฟังก์ชั่นแบบสุ่มใหม่ซึ่งเป็นที่สั้นมาก - อ่านจำนวนเต็ม 4 หลักและการใช้งานs s%64ตัวเลขทศนิยม 6 หลักแต่ละรายการที่ทำจาก 0 และ 1 เท่านั้น%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 ints ด้วย 0..51, สุ่ม (แทนที่องค์ประกอบ x ด้วยสุ่มจากช่วง 0..x), จัดรูปแบบการพิมพ์ (n / 4 = อันดับ, n% 4 = ชุด) .
หนึ่งวงวนที่วิ่ง 104 ครั้งทำการเริ่มต้น (52 ครั้งแรก) การสับและการพิมพ์ (การวิ่ง 52 ครั้งสุดท้าย)
หมายเลขสุ่มถูกสร้างขึ้นโดยการดึงnบิตสุ่มจนกว่า1<<nอย่างน้อยก็สูงสุดที่ต้องการ หากผลลัพธ์มากกว่าจำนวนสูงสุด - ลองอีกครั้ง


นี้มีความซับซ้อนมีความยาวมากกว่าที่เรียบง่ายs>7?"ATJQK"[s-8]:s+50 "A23456789TJQK"[s]ประการที่สองคุณสามารถใช้t/4และt%4แทนและt%13 t/13
Howard

ไม่จำเป็นต้องใส่tกลับเข้าไปในอาร์เรย์เมื่อส่งออก
l4m2

3

unix shell ~ 350

นี่ไม่ใช่สั้นหรือสวยและไม่มีประสิทธิภาพ แต่ฉันสงสัยว่ามันจะยากแค่ไหนเมื่อใช้ยูทิลิตี้เชลล์ unix มาตรฐาน

คำตอบนี้สับสตริงไบนารี่อนันต์เป็นความยาว 6 บิตและเลือกสตริงที่อยู่ในช่วงที่ถูกต้อง (1-52) เท่านั้นนี่คือสตริงไบนารี่ที่ไม่สิ้นสุดถูกจำลองโดย urandom และ xxd:

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

การสับและการเลือกจะทำด้วยการพับ, 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

การรวมเอาท์พุทจากคำสั่งสองคำสั่งล่าสุดกับการวางและเรียงลำดับหมายเลข:

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

สิ่งทั้งหมดเป็นหนึ่งซับมหึมา (ทดสอบเฉพาะใน 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' ' '

แก้ไข - เพิ่มเวอร์ชันทุบตี

นี่คือรุ่นที่ใช้ในการทุบตี ฉันลบ{ }ดัชนีin-shell และ array นั้นเป็นศูนย์ การตรวจสอบความว่างเปล่าของอาเรย์จะมีการตรวจสอบการขยายพารามิเตอร์ซึ่งมีประสิทธิภาพมากกว่าเล็กน้อยและนำมาใช้ในตัวอย่างด้านบน

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

แรงเดรัจฉานมากที่นี่ ฉันเพิ่งอ่านเก้าบิตจากอินพุตเพื่อสร้างเอาต์พุต RNG ที่น้อยที่สุดและทำการลดทอนค่าโมดูลัส - ถ้า - ที่ - ไม่ได้ใช้ - - - - - - - end - end - the - the - end - end เพื่อลดเอาท์พุท

รุ่นที่ไม่ได้ตีกอล์ฟนี้แตกต่างกันในการใช้อินพุตจาก/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 ฉันมีอะไรมากมายให้เรียนรู้ BTW ทำไมไม่"TJQKA"และ"cdhs"?
luser droog

โอ้ ขวา. ints ฉันเข้าใจแล้ว อาจยังคุ้มค่าที่จะบันทึกเครื่องหมายวรรคตอนทั้งหมด อาจได้ปัจจัยcharจากgetcharและputcharมีแมโครซีดขาวบ้า ...
luser Droog

1
การทดแทนมาโครจำเป็นต้องได้รับมากเพราะพวกเขาต้องเริ่มต้นด้วย#define N และสิ้นสุดด้วยการขึ้นบรรทัดใหม่ที่นับเป็นตัวละครและนั่นคือ 11 รวมถึงบิตที่คุณกำลังเปลี่ยน มีตัวละครอีกสองสามตัวที่จะแทนที่ตัวอักษรบางส่วนหรือทั้งหมดด้วยตัวอักษร int แต่มันจะมาช้าแล้ว ... บางทีฉันอาจจะทำมันอีกครั้ง
dmckee --- อดีตผู้ดูแลลูกแมว

@luserdroog Clearer มุ่งหน้าไปแล้ว แน่นอนว่าสายอักขระจะดีกว่า - แม้ว่าคุณจะต้องระบุประเภท - เพราะตัวอักษรเป็นเพียงจำนวนเต็มสั้น ๆ บวกฉันสามารถรวมพวกเขาและการแทนที่ ASCII ได้รับพวงของจังหวะในครั้งเดียว
dmckee --- ผู้ดูแลอดีตลูกแมว

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

ก่อนที่ฉันจะถูกบอกให้เพิ่ม a <?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)
);

มีข้อผิดพลาดที่คาดไว้สองประการที่ไม่ส่งผลกระทบต่อผลลัพธ์ของโปรแกรม

แรกคือเนื่องจาก$aไม่ได้เริ่มต้น แต่ NULL ถูกแปลงเป็น 0 และโปรแกรมดำเนินต่อไป

อย่างที่สองเป็นเพราะกระแสตัวละครดูเหมือนจะได้รับการขึ้นบรรทัดใหม่จากที่อื่นแม้ว่ามันจะไม่ได้รับ (ดี ol 'PHP) และนั่นคือดัชนีที่ไม่ได้กำหนดในอาร์เรย์ เป็นอักขระตัวสุดท้ายของอินพุตและไม่มีผลกับเอาต์พุต

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.