สับไพ่โดยไม่มีตัวแปรในตัวเครื่อง [ปิด]


14

เป้าหมายของปริศนานี้คือการสำรับไพ่ 52 ใบและสับไพ่เพื่อให้ไพ่แต่ละใบอยู่ในตำแหน่งสุ่ม

ได้รับ:

  • อาเรย์deck, ของจำนวนเต็ม 52 ที่แตกต่างกันที่เป็นตัวแทนของการ์ด เมื่อคุณเริ่มต้นให้deckประกอบด้วยหนึ่งในบัตรแต่ละใบในลำดับที่ไม่รู้จักบางอย่าง
  • ฟังก์ชั่นint rand(min, max)ที่จะส่งกลับจำนวนเต็มแบบสุ่มระหว่าง ints minและmaxรวม คุณสามารถสันนิษฐานได้ว่าฟังก์ชั่นนี้สุ่มอย่างแท้จริง
  • ฟังก์ชั่นvoid swap(x, y)ที่แลกเปลี่ยนไพ่สองใบในสำรับ หากคุณโทรหาswap(x, y)การ์ดที่ตำแหน่งxและyจะเปลี่ยนสถานที่

เมื่อไหร่:

  • การเรียกโปรแกรมshuffle()(หรือshuffle(deck)หรือdeck.shuffle()หรือการนำไปใช้ของคุณชอบที่จะทำงาน),

แล้ว:

  • deck ควรมีหนึ่งบัตรแต่ละใบตามลำดับการสุ่มอย่างสมบูรณ์

จับ:

คุณไม่สามารถประกาศตัวแปรใด ๆ โทรswapและrandมากเท่าที่คุณต้องการ แต่คุณไม่สามารถประกาศตัวแปรใด ๆ ของคุณเอง ซึ่งรวมถึงforเคาน์เตอร์ห่วง - foreachแม้คนโดยปริยายเช่นเดียวกับใน

ชี้แจง:

  • คุณสามารถเปลี่ยนรายละเอียดเล็กน้อยเพื่อให้เหมาะกับภาษาที่คุณเลือก ตัวอย่างเช่นคุณสามารถเขียนswapเพื่อสลับจำนวนเต็มสองจำนวนโดยการอ้างอิง การเปลี่ยนแปลงควรจะทำให้งานของคุณเป็นภาษาของคุณไม่ใช่เพื่อให้ไขปริศนาง่ายขึ้น
  • deck สามารถเป็นตัวแปรทั่วโลกหรือคุณสามารถใช้เป็นพารามิเตอร์
  • คุณสามารถทำสิ่งที่คุณต้องการเนื้อหาของdeckแต่คุณไม่สามารถเปลี่ยนความยาวได้
  • บัตรของคุณสามารถมีหมายเลข 0-51, 1-52 หรืออะไรก็ได้ที่คุณต้องการ
  • คุณสามารถเขียนสิ่งนี้ในภาษาใดก็ได้ แต่ไม่มีการโกงด้วยshuffleฟังก์ชั่นในตัวของภาษาของคุณ
  • ใช่คุณสามารถเขียนบรรทัดเดียวกัน 52 ครั้ง ไม่มีใครจะประทับใจ
  • เวลาในการดำเนินการไม่สำคัญ แต่จะมีการสุ่มที่แท้จริง
  • นี่ไม่ใช่การเข้ารหัสกอล์ฟ แต่คุณสามารถย่อ / ทำให้งงงวยรหัสของคุณได้

แก้ไข: รหัสหม้อไอน้ำและ Visualizer

หากคุณใช้. NET หรือ JavaScript นี่คือรหัสทดสอบบางส่วนที่คุณอาจพบว่ามีประโยชน์:

JavaScript:

ค#:

รหัสนี้จัดเรียงและสับไพ่หลายพันครั้งและทำการทดสอบสติพื้นฐาน: สำหรับการสุ่มแต่ละครั้งจะตรวจสอบว่ามีไพ่ 52 ใบในสำรับโดยไม่มีการทำซ้ำ จากนั้น Visualizer จะแปลงความถี่ของการ์ดแต่ละใบที่สิ้นสุดในแต่ละสถานที่บนดาดฟ้าโดยแสดงแผนที่ความร้อนระดับสีเทา

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

เอาท์พุท Visualizer

รุ่นที่มีข้อบกพร่องจะสับเปลี่ยนสำรับได้บางส่วนดังนั้นอาจดูดีถ้าคุณตรวจสอบอาร์เรย์ด้วยมือ เครื่องมือสร้างภาพช่วยให้สังเกตรูปแบบได้ง่ายขึ้น


หลาย ๆ โมเดลอาเรย์เป็นแบบไม่มีที่สิ้นสุดอย่างมีประสิทธิภาพดังนั้นจึงอนุญาตให้ใช้ $ deck [52] และอื่น ๆ เพื่อใช้แทนตัวแปรท้องถิ่น บางทีสิ่งนี้ควรถูกห้ามเช่นกัน
Timwi

2
ฟังก์ชั่นมีการพิจารณาตัวแปรหรือไม่? ฟังก์ชั่นใดบ้างที่ถือว่าเป็นตัวแปร?
zzzzBov

1
@zzzzBov - สิ่งที่ฉันมีอยู่ในใจคือพารามิเตอร์ของฟังก์ชันจะถูกพิจารณาว่าเป็นตัวแปร แต่ฉันไม่ได้ระบุไว้ก่อนคำตอบของ @ mellamokb ฉันรู้ว่ามันสามารถทำได้โดยไม่มีพารามิเตอร์อื่นใดนอกจากdeckตัวเอง
Justin Morgan

1
@eBusiness - นั่นเป็นปัญหาสำหรับฉันไม่ใช่คำถามเอง และฉันก็ลุกขึ้นเพราะผู้ตอบพบช่องโหว่
Justin Morgan

1
@ ผู้ใช้ที่ไม่รู้จัก - ฉันคิดว่าฉันเข้าใจ คำตอบนั้นเป็นพื้นฐานที่คุณสามารถสันนิษฐานได้ว่าการใช้งานที่swapคุณต้องการตราบใดที่มันตอบสนองวัตถุประสงค์พื้นฐานของมัน ส่วนหนึ่งของเหตุผลของฉันในการswapรับมอบคือเพื่อให้ผู้คนสามารถปฏิบัติต่อมันเป็น 'เวทมนตร์' และมุ่งเน้นไปที่ปัญหาหลักโดยไม่ต้องกังวลว่ามันจะทำงานในภาษาที่พวกเขาเลือก คุณสามารถทำได้หรือเขียนเองswapก็ขึ้นอยู่กับคุณ
Justin Morgan

คำตอบ:


9

JavaScript

ฉันเชื่อว่านี่เป็นรูปแบบการแก้ปัญหาที่ตั้งใจไว้ฉันใช้การ์ดในตำแหน่ง 0 เพื่อติดตามความคืบหน้าเพียงสับไพ่ที่ใช้แล้วเป็นตัวนับแล้วสิ่งนี้จะได้มาตรฐาน 52! การเรียงสับเปลี่ยนที่มีการกระจายเท่ากันอย่างสมบูรณ์แบบ ขั้นตอนนั้นซับซ้อนโดย XOR swap ที่ไม่อนุญาตให้มีการสลับองค์ประกอบด้วยตัวเอง

แก้ไข: ฉันสร้างขึ้นในการเรียงลำดับที่เรียงลำดับแต่ละองค์ประกอบไว้ก่อนที่มันจะถูกใช้ดังนั้นการอนุญาตให้สิ่งนี้ทำงานกับอาร์เรย์ที่ไม่เรียงลำดับ ฉันยังลดการโทรซ้ำแบบวนซ้ำ

deck=[]
for(a=0;a<52;a++){
    deck[a]=a
}
function swap(a,b){
    deck[a]=deck[b]^deck[a]
    deck[b]=deck[b]^deck[a]
    deck[a]=deck[b]^deck[a]
}
function rand(a,b){
    return Math.floor(Math.random()*(1+b-a))+a
}
function shuffle(){
    while(deck[0]!=0){ //Sort 0 into element 0
        swap(0,deck[0])
    }
    while(deck[0]<51){ //Run 51 times
        while(deck[deck[0]+1]!=deck[0]+1){ //Sort element deck[0]+1 into position deck[0]+1
            swap(deck[deck[0]+1],deck[0]+1)
        }
        swap(0,deck[0]+1) //Swap element deck[0]+1 into position 0, thus increasing the value of deck[0] by 1
        if(rand(0,deck[0]-1)){ //Swap the element at position deck[0] to a random position in the range 1 to deck[0]
            swap(deck[0],rand(1,deck[0]-1))
        }
    }
    if(rand(0,51)){ //Swap the element at position 0 to a random position
        swap(0,rand(1,51))
    }
}
for(c=0;c<100;c++){
    shuffle()
    document.write(deck+"<br>")
}

นั่นคือสิ่งที่ฉันมีอยู่ในใจ ทันทีที่ฉันทดสอบสิ่งนี้ฉันจะโหวตขึ้นและอาจยอมรับ
Justin Morgan

ดูเหมือนว่าจะทำงานได้ดีแม้ว่าการตรวจสอบอย่างใกล้ชิดจะไม่เหมือนกับของฉัน ยอมรับและฉันจะโพสต์คำตอบของฉันเองในไม่ช้า
จัสตินมอร์แกน

วิธีนี้เรียกอีกอย่างว่าอัลกอริทึม Knuth shuffle ( en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle )
บ๊อบ

14

Haskell

นี่คือการดำเนินการที่ไม่มีจุด ไม่มีตัวแปรพารามิเตอร์ที่เป็นทางการหรือการสอบถามซ้ำอย่างชัดเจน ฉันใช้คุณลักษณะการปรับโครงสร้างของlambdabot@pl ("ไม่มีจุดหมาย") สักหน่อย

import Data.List
import Control.Applicative
import Control.Monad
import System.Random

shuffle :: [a] -> IO [a]
shuffle = liftM2 (<$>) ((fst .) . foldl' (uncurry ((. flip splitAt) . (.) .
          (`ap` snd) . (. fst) . flip flip tail . (ap .) . flip flip head .
          ((.) .) . (. (++)) . flip . (((.) . (,)) .) . flip (:))) . (,) [])
          (sequence . map (randomRIO . (,) 0 . subtract 1) . reverse .
          enumFromTo 1 . length)

main = print =<< shuffle [1..52]

นี่คือขั้นตอนการทดสอบของฉันเพื่อให้แน่ใจว่าตัวเลขถูกกระจายอย่างสม่ำเสมอ:

main = print . foldl' (zipWith (+)) (replicate 52 0)
       =<< replicateM 1000 (shuffle [1..52])

นี่คืออัลกอริทึมดั้งเดิม:

shuffle :: [a] -> IO [a]
shuffle xs = shuffleWith xs <$>
             sequence [randomRIO (0, i - 1) | i <- reverse [1..length xs]]

shuffleWith :: [a] -> [Int] -> [a]
shuffleWith xs ns = fst $ foldl' f ([], xs) ns where
    f (a,b) n = (x:a, xs++ys) where
        (xs, x:ys) = splitAt n b

+1 สำหรับ Haskell ตอนนี้ฉันต้องเรียนรู้ Haskell ดังนั้นฉันจึงสามารถอ่านสิ่งนี้ได้ : P
Justin Morgan

ความคืบหน้าจัดเก็บอย่างไร
aaaaaaaaaaaa

8
ฉันสงสัยใคร แต่โปรแกรมเมอร์ของ Haskell จะบอกว่ารหัสของพวกเขาไม่มีจุดหมายและภูมิใจในตัวมัน
aaaaaaaaaaaa

4
นี้((.) .) . (. (++))และนี่(((.) . (,)) .)เป็นที่ชื่นชอบของฉัน ว้าว lambdabot แค่ว้าว
Dan Burton

2
@eBusiness "point free" นั้นไม่เหมือนกับ "ไร้จุดหมาย"
fredoverflow

6

J

การไม่คำนึงถึงสำรับนั้นเป็นตัวแปรมีสิ่งที่ชัดเจน ...

52 ? 52

แน่นอนถ้าคุณต้องการฟังก์ชั่นจริงๆมีสิ่งนี้ซึ่งจะใช้ได้แม้ว่าคุณลืมที่จะลบนักเลง

{~ (# ? #)

ดังนั้น...

shuffle =: {~ (# ? #)
deck =: i. 52
shuffle deck

นี่อาจอยู่นอกเจตนาของคำถามซึ่งจะนำไปใช้ในการสับเปลี่ยนตัวเองจาก rand ( ?) ฉันอาจทำในภายหลังเมื่อฉันไม่ควรทำงาน

คำอธิบาย

คำอธิบายของ52 ? 52:

  • x ? y คือ x รายการที่ไม่ซ้ำแบบสุ่มจาก y

คำชี้แจง{~ (# ? #)เป็นเรื่องยากเพราะส้อมและตะขอ โดยพื้นฐานแล้วมันเหมือนกับshuffle =: 3 : '((# y) ? (# y)) { y'ซึ่งมีอาร์กิวเมนต์หนึ่งนัย ( y)

  • # y ให้ความยาวของ y
  • สิ่งนี้ให้ 52? 52 อย่างที่เคยเป็นมาก่อนซึ่งเป็นการสุ่มเปลี่ยนเป็น 0..51
  • x { y คือรายการของ y ในดัชนี x หรือ (ในกรณีนี้) รายการในดัชนีใน x
  • สิ่งนี้จะช่วยให้คุณสามารถสับเปลี่ยนสิ่งที่ส่งผ่านไม่ใช่เพียงจำนวนเต็ม

ดูคำศัพท์ Jสำหรับรายละเอียดของตัวดำเนินการแม้ว่าไวยากรณ์และความหมายค่อนข้างยุ่งยากเล็กน้อยเนื่องจากการจัดอันดับและการเขียนโปรแกรมโดยปริยาย


+1: ทำงานกับ code-golf เมื่อควรจะทำงาน .. lol ฉันก็เช่นกัน: P
mellamokb

1
คุณช่วยอธิบายสิ่งนี้ได้ผลอะไรกับคนพิการ J? ฉันเพิ่งได้ยินว่ามันอธิบายว่าเป็นการระเบิดในโรงงานอิโมติคอน ( codegolf.stackexchange.com/questions/1294/anagram-code-golf/ ...... ) ซึ่งฟังดูดี
Justin Morgan

@Justin: เพิ่มคำอธิบายแล้ว
Jesse Millikan

ใช้งานได้ใน APL เช่นกัน ไวยากรณ์เหมือนกันดังนั้นฉันจะไม่รำคาญที่จะเพิ่มคำตอบใหม่ ( {52?⍵}เป็นฟังก์ชันที่ไม่ระบุชื่อที่ใช้ 52 รายการแบบสุ่มจากการโต้เถียงซึ่งนี่จะเป็นรายการของจำนวนเต็ม 52 รายการ)
Arc676

4

หลาม

import random
def rand(x, y):
 return random.randrange(x, y+1)

def swap(deck, x, y):
 deck[x] ^= deck[y]
 deck[y] ^= deck[x]
 deck[x] ^= deck[y]

def shuffle(deck):
 if len(deck)>1:
  deck[1:]=shuffle(deck[1:])
  if rand(0,len(deck)-1)>0:swap(deck, 0, rand(1, len(deck)-1))
 return deck

print shuffle(range(52))

อะไร[1:]หมายถึง? สิ่งนั้นจะชดเชยให้กับ sub-array ของdeckหรือไม่?
Justin Morgan

ใช่ [1:] หมายถึงอาร์เรย์ย่อยจากดัชนี 1 ถึงจุดสิ้นสุดของอาร์เรย์ ดังนั้นมันจึงวนซ้ำทุกอย่างยกเว้นองค์ประกอบแรกกำหนด (สำเนา) กลับไปที่เดิมในอาร์เรย์เดิมจากนั้นสุ่มวางองค์ประกอบแรกที่ใดที่หนึ่ง
Keith Randall

ฉลาดมาก. ฉันคิดว่านี่เป็นหนึ่งในโซลูชั่นที่สวยที่สุดที่นี่และใช้อัลกอริทึม Fisher-Yates อย่างถูกต้อง +1 นี่เป็นวิธีที่ดีสำหรับฉันที่จะเห็นความงามของภาษาที่ฉันไม่คุ้นเคย
Justin Morgan

2
คุณอาจชอบa, b = b, aเคล็ดลับ
เรย์

3

การใช้การเป็นตัวแทนปัจจัย

ในการเป็นตัวแทนการเปลี่ยนแปลงปัจจัยองค์ประกอบฉันใช้ค่าจาก 0 ถึง Ni ดังนั้นการเปลี่ยนรูปแบบสุ่มเป็นเพียงrand(0,i)สำหรับทุก Ni

ในเจ:

? |.>:i.52
2 39 20 26 ... 2 0 1 0 0 0

ที่? xเป็นrand(0,x-1)และ|.>:i.52เป็น52 51 ... 1

แล้วถ้าaคือค่าของที่ i factoradic swap(deck[i], deck[i+a])เราจะแลกเปลี่ยน: รายการคู่ที่จะสลับคือ:

(,. i.52) ,. (,. ((?|.>:i.52)+i.52))
0 33
1 20
2  3
...
49 50
50 50
51 51

การสลับเราจะใช้ผลงานแบบนี้:

deck
24 51 14 18 ...
deck =: 0 1 swap deck
51 24 14 18 ...

มันไม่ได้จริงๆ "โดยการอ้างอิง" แต่ไม่มีฟังก์ชั่นที่แท้จริงใน J

เราจะใช้ความยาวของเด็ค ( #deck) เพื่อหลีกเลี่ยงการใช้ค่าคงที่

เสร็จสิ้นโปรแกรมใน J:

deck =: 52 ? 52                           NB. Initial random deck
swap =: 4 : 'deck =: (x { y) (|.x) } y'   NB. Given swap "function"
f =: 3 : 0                                NB. function that calls the swap for a pair
({.y) swap deck
}.y
)
f^:(#deck) (,.,.[:,.]+[:?[:|.>:) i.#deck

3

ค#

นี่คือคำตอบของตัวเองในการตามขั้นตอนวิธีการฟิชเชอร์เยตส์ ควรให้การสับเปลี่ยนที่สมบูรณ์แบบหากเครื่องสร้างหมายเลขสุ่มของคุณดีพอ

ฉบับภาษาอังกฤษ:

  1. ซ้ำแล้วซ้ำเล่าสลับการ์ดที่deck[0]หนึ่งที่deck[v]ซึ่งเป็นมูลค่าของบัตรที่v ทำซ้ำจนกว่าdeck[0] v == 0นี่จะเรียงลำดับสำรับบางส่วน แต่ไม่สำคัญ ตอนนี้คุณรู้แล้วว่าการ์ด 0 อยู่ที่ด้านหน้าของเด็คซึ่งหมายความว่าคุณสามารถขโมยพื้นที่นั้นในอาเรย์และใช้เป็นตัวนับลูป นี่คือกุญแจสำคัญ "โกง" สำหรับปัญหาของตัวแปรท้องถิ่น
  2. เริ่มต้นที่ตำแหน่งที่ 1 (บัตรที่สองในสำรับ) สลับการ์ดที่หนึ่งที่i rand(i, 51)โปรดทราบว่าคุณต้องการrand(i, 51), ไม่ rand(1, 51)ไม่สามารถมั่นใจได้ว่าการ์ดแต่ละใบจะถูกสุ่ม
  3. ตั้งdeck[0]กลับเป็น 0 ทีนี้สำรับทั้งหมดจะถูกสับยกเว้นไพ่ใบแรกดังนั้นแลกเปลี่ยนdeck[0]กับdeck[rand(0, 51)]คุณเสร็จแล้ว

รุ่น C #:

public static void shuffle(int[] deck)
{
    while (deck[0] > 0)
        swap(ref deck[0], ref deck[deck[0]]);

    for (deck[0] = 1; deck[0] < 52; deck[0]++)
        swap(ref deck[deck[0]], ref deck[rand(deck[0], 51)]);

    deck[0] = 0;
    swap(ref deck[0], ref deck[rand(0, 51)]);
}

รุ่น Javascript:

while (deck[0] > 0)
    swap(0, deck[0]);

for (deck[0] = 1; deck[0] < 52; deck[0]++)
    swap(deck[0], rand(deck[0], 52));

deck[0] = 0;
swap(0, rand(0, 52));

... ที่swap(a, b)แลกเปลี่ยนกับdeck[a]deck[b]


2

ทับทิมหนึ่งบรรทัด

นี่ถือว่าเป็นการโกงหรือไม่? ควรสุ่มตามที่ได้รับ

deck=(0..51).to_a # fill the deck
deck[0..51] = (0..51).map{deck.delete_at(rand deck.length)}

( randวิธีการของรูบี้ใช้เวลาเพียงหนึ่งอาร์กิวเมนต์เท่านั้นจากนั้นสร้างตัวเลข n เช่นนั้น 0 <= หมายเลข <อาร์กิวเมนต์)

นอกจากนี้ - คล้ายกับโซลูชัน Perl ของ sogart แต่เท่าที่ฉันรู้ว่ามันไม่ประสบปัญหา:

deck = deck.sort_by{rand}

sort_by ของ Ruby นั้นแตกต่างจาก sort - ก่อนอื่นมันจะสร้างรายการของค่าเพื่อเรียงลำดับของอาร์เรย์และจากนั้นเรียงลำดับตามค่าเหล่านั้นเท่านั้น มันเร็วกว่าเมื่อมีราคาแพงในการค้นหาอสังหาริมทรัพย์ที่เราเรียงลำดับค่อนข้างช้ากว่าในทุกกรณี นอกจากนี้ยังมีประโยชน์ในโค้ดกอล์ฟ: P


ฉันจะไม่เรียกมันว่าการโกงต่อ แต่deck[0..51]ทำกฎ "ไม่มีตัวแปร" โดยใช้คุณสมบัติของภาษา มันยุติธรรมฉันแค่คิดว่ามันจะสูญเสียความท้าทาย :) ฉันไม่รู้ทับทิม คุณอธิบาย(0..51).map{deck.delete_at(rand deck.length)}ส่วนนี้ได้ไหม นั่นเป็นการลบไพ่deckหรือไม่
Justin Morgan

@JustinMorgan ใช่ 52 ครั้งจะลบการ์ดสุ่มจากdeckและเพิ่มลงในรายการผลลัพธ์ภายในที่mapสะสม จากนั้นเมื่อมีอะไรเหลืออยู่ในผลที่ได้รับการคัดลอกลง โดยทั่วไปมีชั่วคราว แต่ก็คุณสมบัติภาษามากกว่าตัวแปรอย่างชัดเจน :)deckmapdeck
ฮอบส์

deck.sort_by!{rand}สั้นกว่า
Eric Duminil

1

JavaScript

หมายเหตุ: วิธีการแก้ปัญหานี้ไม่ถูกต้องทางเทคนิคเพราะใช้พารามิเตอร์ตัวที่สองiในการเรียกshuffleซึ่งนับเป็นตัวแปรภายนอก

function shuffle(deck, i) {
    if (i <= 0)
        return;
    else {
        swap(deck[rand(0,i-1)], deck[i-1]);
        shuffle(deck, i - 1);
    }
}

โทรไปด้วย shuffle(deck,52)

ตัวอย่างการทำงานที่สมบูรณ์ (ต้องแก้ไขswapเล็กน้อยเนื่องจากไม่มีการอ้างอิงแบบเป็น int ใน JavaScript):

function rand(min, max) { return Math.floor(Math.random()*(max-min+1)+min); }
function swap(deck, i, j) {
    var t=deck[i];
    deck[i] = deck[j];
    deck[j] = t;
}

function shuffle(deck, i) {
    if (i <= 0)
        return;
    else {
        swap(deck, rand(0,i-1), i-1);
        shuffle(deck, i - 1);
    }
}

// create deck
var deck=[];
for(i=0;i<52;i++)deck[i]=i;
document.writeln(deck);
shuffle(deck,52);
document.writeln(deck);

ทำได้ดี. สิ่งที่ฉันมีอยู่ในใจก็คือการพิจารณาshuffleว่าตัวแปรเป็นตัวแปร แต่ฉันไม่ได้ระบุอย่างนั้น +1 ใช้การสอบถามซ้ำด้วยเช่นกัน
Justin Morgan

-1 ไม่สร้างการเรียงสับเปลี่ยนทั้งหมดนี่เป็นสิ่งที่เห็นได้ชัดเพราะองค์ประกอบ 51 จะไม่ครอบครองเป็นตำแหน่งเดิมและเนื่องจากคุณเรียกแรนด์เพียงพอที่จะสร้าง 51! การเรียงสับเปลี่ยนจาก 52 ที่เป็นไปได้!
aaaaaaaaaaaa

2
@eBusiness: ในข้อมูลจำเพาะดั้งเดิมเด็คจะได้รับคำสั่งโดยพลการไม่จำเป็นต้องอยู่ในคำสั่ง 1-52 ฉันเพิ่งใช้มันเพราะมันง่ายที่สุด
mellamokb

1
@eBusiness: ผมแก้ไขเพื่อให้เป็นไปได้ของการออกจากองค์ประกอบในจุดเดียวกันโดยใช้แทนdeck[rand(0,i-1)] deck[rand(0,i-2)]นอกจากนี้ยังสลับไปตลอดทางจนถึงแทนที่จะหยุดที่i=0 i=1มันช่วยได้ไหม
mellamokb

ใช่ที่ควรทำยกเว้นว่าตอนนี้คุณแบ่งข้อกำหนด XOR swap
aaaaaaaaaaaa

1

C ++

#include <cstdlib>
#include <ctime>
#include <iostream>

int deck[52];

void swap(int a, int b) {
    deck[a] ^= deck[b];
    deck[b] ^= deck[a];
    deck[a] ^= deck[b];
}

int r(int a, int b) {
    return a + (rand() % (b - a + 1));
}

void s(int *deck) {
    swap(1, r(2, 51));
    deck[0] *= 100;

    for(deck[0] += 2; (deck[0] % 100) < 51; deck[0]++) {
        swap(deck[0] % 100,
          r(0, 1) ? r(1, (deck[0] % 100) - 1) : r((deck[0] % 100) + 1, 51));
    }
    swap(51, r(1, 50)); 

    deck[0] = (deck[0] - 51) / 100;
    swap(r(1, 51), 0);
}

int main(int a, char** c)
{
    srand(time(0));

    for (int i = 0; i < 52; i++)
        deck[i] = i;

    s(deck);
    s(deck);

    for (int i = 0; i < 52; i++)
        std::cout << deck[i] << " ";
}

หลีกเลี่ยงการเปลี่ยนองค์ประกอบด้วยตัวเองดังนั้นจึงต้องเรียกสองครั้งเพื่อสุ่ม


swap(deck[rand(1, 51)], (deck[0] - 51) / 100);จะswapทราบได้อย่างไรว่าจะใส่ค่าที่สองไว้ที่ใด )นอกจากนี้คุณยังขาดหายไป
จัสตินมอร์แกน

โอ๊ะขอบคุณ ฉันเริ่มเคลื่อนไหวส่วนนั้นในระหว่างการแก้ไขและต้องมีสมาธิก่อนที่จะจบ: P
Matthew อ่าน

การลงคะแนนเสียงไม่ได้มาจากฉัน BTW ฉันจะทดสอบเมื่อฉันสามารถ
Justin Morgan

ตกลง. ฉันทำให้การทดสอบง่ายขึ้นโดยการจัดโปรแกรมเต็มรูปแบบ
Matthew อ่าน

1
ฉลาดมาก. โซลูชันของฉันใช้deck[0]แต่ไม่ใช่ในแบบที่คุณมี
Justin Morgan


1

โซลูชัน Perl อื่นซึ่งสร้างเอาต์พุตที่กระจายอย่างสม่ำเสมอ:

sub shuffle_integers {
    map int, sort {$a-int $a <=> $b-int $b} map $_+rand, @_;
}

say join " ", shuffle_integers 1 .. 52;

วิธีการแก้ปัญหานี้ใช้ Perl ของrandซึ่งจะส่งกลับตัวเลขสุ่มxในช่วง 0 ≤ x <1 มันจะเพิ่มตัวเลขสุ่มดังกล่าวให้กับจำนวนเต็มแต่ละตัวในอินพุตเรียงลำดับตัวเลขตามส่วนที่เป็นเศษส่วนของพวกเขา .

(ผมเชื่อว่าการใช้งานของตัวแปรพิเศษ$_, $aและ$bอยู่ในจิตวิญญาณของความท้าทายเนื่องจากผู้ที่มีวิธีการ Perl ผ่านการป้อนข้อมูลเพื่อmapและsortและพวกเขากำลังไม่ได้ใช้เพื่อวัตถุประสงค์อื่นใดในรหัส. ในกรณีใด ๆ ผมเชื่อว่า พวกเขาเป็นนามแฝงกับค่าอินพุตไม่ใช่สำเนาอิสระนี่ไม่ใช่การสับเปลี่ยนแบบแทนที่ แต่ทั้งคู่mapและsortสร้างสำเนาของอินพุตในสแต็ก)


1

ชวา

ฉันประหลาดใจที่ไม่มีใครระบุชัดเจน: (ฉันจะถือว่า swap (x, x) ไม่ทำอะไรเลย

    static void shuffle(){
        swap(1,rand(0,1));
        swap(2,rand(0,2));
        swap(3,rand(0,3));
        swap(4,rand(0,4));
        swap(5,rand(0,5));
        swap(6,rand(0,6));
        swap(7,rand(0,7));
        swap(8,rand(0,8));
        swap(9,rand(0,9));
        swap(10,rand(0,10));
        swap(11,rand(0,11));
        swap(12,rand(0,12));
        swap(13,rand(0,13));
        swap(14,rand(0,14));
        swap(15,rand(0,15));
        swap(16,rand(0,16));
        swap(17,rand(0,17));
        swap(18,rand(0,18));
        swap(19,rand(0,19));
        swap(20,rand(0,20));
        swap(21,rand(0,21));
        swap(22,rand(0,22));
        swap(23,rand(0,23));
        swap(24,rand(0,24));
        swap(25,rand(0,25));
        swap(26,rand(0,26));
        swap(27,rand(0,27));
        swap(28,rand(0,28));
        swap(29,rand(0,29));
        swap(30,rand(0,30));
        swap(31,rand(0,31));
        swap(32,rand(0,32));
        swap(33,rand(0,33));
        swap(34,rand(0,34));
        swap(35,rand(0,35));
        swap(36,rand(0,36));
        swap(37,rand(0,37));
        swap(38,rand(0,38));
        swap(39,rand(0,39));
        swap(40,rand(0,40));
        swap(41,rand(0,41));
        swap(42,rand(0,42));
        swap(43,rand(0,43));
        swap(44,rand(0,44));
        swap(45,rand(0,45));
        swap(46,rand(0,46));
        swap(47,rand(0,47));
        swap(48,rand(0,48));
        swap(49,rand(0,49));
        swap(50,rand(0,50));
        swap(51,rand(0,51));
    }

ตกลงตกลงมันสั้นกว่า:

package stackexchange;

import java.util.Arrays;

public class ShuffleDry1
{
    static int[] deck = new int[52];

    static void swap(int i, int j){
        if( deck[i]!=deck[j] ){
            deck[i] ^= deck[j];
            deck[j] ^= deck[i];
            deck[i] ^= deck[j];
        }
    }

    static int rand(int min, int max){
        return (int)Math.floor(Math.random()*(max-min+1))+min;
    }

    static void initialize(){
        for( int i=0 ; i<deck.length ; i++ ){
            deck[i] = i;
            swap(i,rand(0,i));
        }
    }

    static void shuffle(){
        while( deck[0]!=0 ) swap(0,deck[0]);
        for( deck[0]=52; deck[0]-->1 ; ) swap(deck[0],rand(deck[0],51));
        swap(0,rand(0,51));
    }

    public static void main(String[] args) {
        initialize();
        System.out.println("init: " + Arrays.toString(deck));
        shuffle();
        System.out.println("rand: " + Arrays.toString(deck));
    }

}

1

ล้อเลียน

สิ่งที่คุณขอจริง ๆ คือการเรียงสับเปลี่ยนสุ่มของรายการจำนวนเต็ม? r@จะให้พีชคณิตทั้งหมดกับเราและเราเลือกสุ่ม

blsq ) {1 2 3}r@sp
1 2 3
2 1 3
3 2 1
2 3 1
3 1 2
1 3 2
blsq ) {1 2 3}r@3!!BS
2 3 1

เนื่องจากเราต้องการการสุ่มอย่างแท้จริงบางสิ่งบางอย่าง Burlesque ไม่สามารถทำได้เนื่องจาก Burlesque ไม่มีฟังก์ชัน I / O ที่คุณต้องการให้แหล่งที่มาของการสุ่มผ่าน STDIN

นั่นอาจเป็นสิ่งที่ฉันจะแก้ไขในรุ่นที่ใหม่กว่า (เช่นสร้างเมล็ดแบบสุ่มเมื่อเริ่มต้นและผลักไปที่กองซ้อนหรืออะไรแบบนั้น แต่ Burlesque Interpreter นั้นไม่มี I / O)


0

จาวาสคริ

ฉันไม่แน่ใจว่ามันเป็น "การโกง" หรือไม่ แต่โซลูชันของฉันใช้อาเรย์ท้องถิ่นดั้งเดิมของอาร์กิวเมนต์ของฟังก์ชัน ผมรวมฟังก์ชั่นที่สร้างตัวเองของฉันและrand() swap() filldeck()สิ่งที่ควรทราบคือควรใช้กับเด็คทุกขนาด

    var deck = [];

    function shuffle(){
        main(deck.length);
    }

    function main(){
        arguments[0] && swap( arguments[0]-=1, rand(0, deck.length-1) ), main(arguments[0]);
    }

        function rand(min, max){
            return Math.floor( Math.random()*(max-min+1) )+min;
        }

        function swap(x, y){
            var _x = deck[x], _y = deck[y];
            deck[x] = _y, deck[y] = _x;
        }


        function filldeck(dL){
            for(var i=0; i<dL; i++){
                var ran = rand(1,dL);
                while( deck.indexOf(ran) >= 0 ){
                    ran = rand(1,dL);
                }
                deck[i] = ran;
            }
        }

    filldeck(52);
    shuffle();

ฉันคิดว่ามันเป็นการโกง อย่างไรก็ตามการโกงที่ฉลาดมากเป็นงานที่ดีมาก
จัสตินมอร์แกน

0

Tcl , 32 ไบต์

timeฟังก์ชันการใช้งานที่ไม่เหมาะสมซึ่งทำหน้าที่วัดจำนวนเวลาที่สคริปต์ใช้งานอยู่ แต่ยังสามารถทำหน้าที่เป็นกลไกการวนซ้ำได้โดยไม่ต้องประกาศตัวแปรใด ๆ

time {lswap $D [rand] [rand]} 52

ลองออนไลน์!


ฉันจะแก้ไขให้ถูกต้องหรือไม่ว่านี่จะทำการสุ่ม 52 ครั้งเท่านั้น? นั่นไม่เพียงพอสำหรับการสับเปลี่ยนที่แท้จริง ฉันวิ่งมันไม่กี่ครั้งและนับเฉลี่ย 8 บัตรยังคงอยู่ในตำแหน่งเริ่มต้นของพวกเขาและความน่าจะเป็นของที่มีการสับเปลี่ยนที่แท้จริงเป็นเรื่องเกี่ยวกับ 9x10
จัสตินมอร์แกน

@JustinMorgan: คุณช่วยอธิบายการคำนวณความน่าจะเป็นให้ดีขึ้นได้มั้ย
sergiol

-1

Perl - นี่ไม่ใช่การสลับที่เหมาะสมตามที่อธิบายไว้ในความคิดเห็น!

my @deck = (0..51);
@deck = sort {rand() <=> rand()} @deck;
print join("\n",@deck);

ฉันคิดว่าฉันไม่ได้ใช้อะไรเลยในการแลกเปลี่ยน ฯลฯ จำเป็นต้องมีส่วนหนึ่งของปัญหาหรือไม่?


4
หากการเรียงลำดับโดยฟังก์ชั่นแบบสุ่มเป็นวิธีการสร้างการแจกแจงแบบสุ่ม อย่างไรก็ตามมันไม่ได้เป็น -1
aaaaaaaaaaaa

และทำไมมันไม่? คุณสามารถให้ลิงค์เพื่ออ่านได้ไหม
sogart

2
คุณภาพของผลลัพธ์จะแตกต่างกันอย่างมากขึ้นอยู่กับอัลกอริทึมการเรียงลำดับ แต่ในเกือบทุกกรณีผลลัพธ์จะห่างไกลจากฟังก์ชันการแจกแจงที่เท่าเทียมกันมาก นี่คือบทความเกี่ยวกับหัวข้อ: sroucheray.org/blog/2009/11/…
aaaaaaaaaaaa

-1

JavaScript 4 บรรทัด

function shuffle() {
  while(deck[0]!=0)swap(deck[0],rand(1,51))
  while(deck[0]++!=104)swap(deck[0]%51+1,rand(1,51))
  deck[0]=0
  swap(0,rand(0,51))
}

คำตอบดั้งเดิมที่ไม่สุ่มพอ การสลับไม่รับประกันว่าจะแตะแต่ละรายการในเด็ค

// shuffle without locals
function shuffle() {
  deck.map(function(){swap(deck[rand(0,51)],deck[rand(0,51)])});
}

ไม่สุ่มแบบสุ่มจริง นี่คือการทดสอบ Visualizer: jsfiddle.net/muk1bthm ฉันเปลี่ยนshuffleรหัสของคุณเล็กน้อยเพื่อให้ตรงกับswapการใช้งานของฉันแต่นี่มันเป็นคำต่อคำ: jsfiddle.net/m7km4u6g
Justin Morgan

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