Xáo trộn một bộ bài không có biến cục bộ [đã đóng]


14

Mục tiêu của câu đố này là lấy một bộ bài gồm 52 lá bài và xáo trộn nó sao cho mỗi lá bài ở một vị trí ngẫu nhiên.

Được:

  • Một mảng, deckgồm 52 số nguyên khác nhau đại diện cho các thẻ. Khi bạn bắt đầu, deckchứa chính xác một trong mỗi thẻ theo thứ tự không xác định.
  • Hàm, int rand(min, max)trả về một số nguyên ngẫu nhiên giữa ints minmax, đã bao gồm. Bạn có thể cho rằng chức năng này là thực sự ngẫu nhiên.
  • Một chức năng, void swap(x, y)hoán đổi hai thẻ trong bộ bài. Nếu bạn gọi swap(x, y), các thẻ tại các vị trí xysẽ chuyển đổi địa điểm.

Khi nào:

  • Các cuộc gọi chương trình shuffle()(hoặc shuffle(deck)hoặc deck.shuffle()hoặc tuy nhiên thực hiện của bạn thích để chạy),

Sau đó:

  • deck nên chứa chính xác một trong mỗi thẻ theo thứ tự hoàn toàn ngẫu nhiên.

Cuộc đuổi bắt:

Bạn không thể khai báo bất kỳ biến nào. Gọi swaprandbao nhiêu tùy thích, nhưng bạn không thể khai báo bất kỳ biến nào của riêng bạn. Điều này bao gồm các forbộ đếm vòng lặp - thậm chí những cái ẩn như trong a foreach.

Làm rõ:

  • Bạn có thể thay đổi các chi tiết nhỏ cho phù hợp với ngôn ngữ bạn đã chọn. Ví dụ: bạn có thể viết swapđể chuyển đổi hai số nguyên bằng cách tham chiếu. Thay đổi nên làm cho điều này hoạt động với ngôn ngữ của bạn, không làm cho câu đố dễ dàng hơn.
  • deck có thể là một biến toàn cục hoặc bạn có thể lấy nó làm tham số.
  • Bạn có thể làm bất cứ điều gì bạn muốn với nội dung của nó deck, nhưng bạn không thể thay đổi độ dài của nó.
  • Thẻ của bạn có thể được đánh số 0-51, 1-52 hoặc bất cứ thứ gì bạn thích.
  • Bạn có thể viết điều này bằng bất kỳ ngôn ngữ nào, nhưng không gian lận với shufflechức năng tích hợp sẵn trong ngôn ngữ của bạn .
  • Có, bạn có thể viết cùng một dòng 52 lần. Sẽ không có ai ấn tượng.
  • Thời gian thực hiện không thành vấn đề, nhưng sự ngẫu nhiên thực sự thì có.
  • Đây không thực sự là mã golf, nhưng hãy thoải mái giảm thiểu / làm xáo trộn mã của bạn.

Chỉnh sửa: Mã nồi hơi và trình hiển thị

Nếu bạn đã sử dụng .NET hoặc JavaScript, đây là một số mã kiểm tra bạn có thể thấy hữu ích:

JavaScript:

C #:

Mã này sắp xếp và xáo trộn bộ bài vài nghìn lần và thực hiện một số thử nghiệm vệ sinh cơ bản: Đối với mỗi lần xáo trộn, nó xác minh rằng có chính xác 52 lá bài trong bộ bài không lặp lại. Sau đó, trình hiển thị biểu đồ tần số của mỗi thẻ kết thúc tại mỗi vị trí trong bộ bài, hiển thị bản đồ nhiệt độ xám.

Đầu ra của trình hiển thị sẽ trông giống như tuyết không có hoa văn rõ ràng. Rõ ràng nó không thể chứng minh tính ngẫu nhiên thực sự, nhưng đó là cách nhanh chóng và dễ dàng để kiểm tra tại chỗ. Tôi khuyên bạn nên sử dụng nó hoặc một cái gì đó tương tự, bởi vì một số lỗi nhất định trong thuật toán xáo trộn dẫn đến các mẫu rất dễ nhận ra trong đầu ra. Đây là một ví dụ về đầu ra từ hai triển khai, một với một lỗ hổng chung:

Đầu ra trực quan

Phiên bản không hoàn hảo sẽ xáo trộn một phần bộ bài, vì vậy có thể sẽ ổn nếu bạn kiểm tra mảng bằng tay. Trình hiển thị giúp dễ dàng nhận thấy một mẫu.


Nhiều mảng mô hình ngôn ngữ là vô hạn hiệu quả, do đó cho phép $ boong [52] trở đi được sử dụng thay cho các biến cục bộ. Có lẽ điều này cũng nên bị cấm.
Timwi 17/03/2016

2
Các chức năng được coi là biến? các tham số chức năng được coi là biến?
zzzzBov

1
@zzzzBov - Điều tôi nghĩ đến là các tham số hàm sẽ được coi là biến, nhưng tôi không chỉ định điều đó trước câu trả lời của @ mellamokb. Tôi biết nó có thể được thực hiện mà không có bất kỳ tham số nào khác ngoài deckchính nó.
Justin Morgan

1
@eBusiness - Đó là một vấn đề với tôi, không phải là câu hỏi. Và tôi đã nâng cao tinh thần vì người trả lời đã tìm thấy một kẽ hở.
Justin Morgan

1
@user không rõ - Tôi nghĩ tôi hiểu. Câu trả lời về cơ bản là bạn có thể đảm nhận bất cứ việc triển khai swapnào bạn thích, miễn là nó hoàn thành mục đích cơ bản của nó. Một phần lý do của tôi để đưa swapra là để mọi người có thể coi nó là "ma thuật" và tập trung vào vấn đề chính mà không phải lo lắng về việc nó hoạt động theo ngôn ngữ của họ. Bạn có thể làm điều đó hoặc tự viết swap, tùy bạn.
Justin Morgan

Câu trả lời:


9

JavaScript

Tôi tin rằng đây là hình thức giải pháp dự định, tôi sử dụng thẻ ở vị trí 0 để theo dõi tiến độ, chỉ xáo trộn các thẻ đã được sử dụng làm bộ đếm, điều này đạt được tiêu chuẩn 52! hoán vị với một phân phối bằng nhau hoàn hảo. Thủ tục phức tạp bởi hoán đổi XOR không cho phép một phần tử được hoán đổi bởi chính nó.

Chỉnh sửa: Tôi đã xây dựng một cách sắp xếp sắp xếp từng phần tử vào vị trí ngay trước khi nó được sử dụng, do đó cho phép phần này hoạt động với một mảng chưa được sắp xếp. Tôi cũng bỏ cuộc gọi đệ quy có lợi cho một vòng lặp while.

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

Đó chính xác là những gì tôi đã nghĩ trong đầu. Ngay sau khi tôi kiểm tra điều này, tôi sẽ nâng cấp và có thể chấp nhận.
Justin Morgan

Xuất hiện để hoạt động tốt, mặc dù khi kiểm tra kỹ hơn, nó không hoàn toàn giống như của tôi. Được chấp nhận và tôi sẽ sớm đăng câu trả lời của mình.
Justin Morgan

Đây còn được gọi là thuật toán xáo trộn Knuth ( en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle ).
Bob

14

Haskell

Đây là một thực hiện miễn phí điểm. Không có biến, tham số chính thức hoặc đệ quy rõ ràng. Tôi đã qua sử dụng lambdabot 's @pl( 'vô nghĩa') refactoring tính năng khá một chút.

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]

Đây là quy trình thử nghiệm của tôi để đảm bảo các số được phân phối đồng đều:

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

Đây là thuật toán gốc:

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 cho Haskell. Bây giờ tôi phải học Haskell để tôi có thể đọc nó. : P
Justin Morgan

Làm thế nào là tiến độ được lưu trữ?
aaaaaaaaaaaa

8
Tôi nghi ngờ bất cứ ai nhưng các lập trình viên Haskell sẽ nói rằng mã của họ là vô nghĩa và tự hào về nó.
aaaaaaaaaaaa

4
Đây ((.) .) . (. (++))và đây (((.) . (,)) .)là yêu thích của tôi. Wow lambdabot. Chỉ là, wow.
Dan Burton

2
@eBusiness "điểm miễn phí" hoàn toàn không giống như "vô nghĩa".
fredoverflow

6

J

Bỏ qua bộ bài đó là một biến số, rõ ràng ...

52 ? 52

Tất nhiên, nếu bạn thực sự muốn một chức năng, có chức năng này, nó sẽ hoạt động ngay cả khi bạn quên loại bỏ những người thích đùa (hoặc cố gắng xáo trộn một cái gì đó không phải là thẻ).

{~ (# ? #)

Vậy nên...

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

Điều này có lẽ nằm ngoài mục đích của câu hỏi, mà sẽ là tự thực hiện việc xáo trộn từ rand ( ?). Tôi có thể làm điều đó sau khi tôi không được phép làm việc.

Giải trình

Giải thích về 52 ? 52:

  • x ? y là x các mục duy nhất ngẫu nhiên từ y.

Giải thích {~ (# ? #)là khó hơn vì dĩa và móc . Về cơ bản, nó giống như shuffle =: 3 : '((# y) ? (# y)) { y', có một đối số ngầm ( y).

  • # y cho chiều dài của y
  • Điều này cho 52? 52 như trước đây, đó là một hoán vị ngẫu nhiên của 0..51
  • x { y là mục của y trong chỉ mục x hoặc (trong trường hợp này) các mục trong chỉ mục trong x.
  • Điều này cho phép bạn xáo trộn bất cứ thứ gì được truyền vào, không chỉ các số nguyên.

Xem J Từ vựng để biết chi tiết về các toán tử, mặc dù cú pháp và ngữ nghĩa khá khó khăn vì lập trình xếp hạng và ngầm định.


+1: Làm việc trên golf-code khi được cho là đang hoạt động .. lol Tôi cũng vậy: P
mellamokb 17/03/2016

1
Bạn có thể giải thích điều này cho người khuyết tật J không? Gần đây tôi đã nghe nó được mô tả như một vụ nổ trong một nhà máy biểu tượng cảm xúc ( codegolf.stackexchange.com/questions/1294/anagram-code-golf/ trộm ), nghe có vẻ đúng.
Justin Morgan

@Justin: Giải thích thêm.
Jesse Millikan

Điều này cũng hoạt động trong APL. Cú pháp giống nhau, vì vậy tôi sẽ không bận tâm thêm câu trả lời mới ( {52?⍵}là một hàm ẩn danh lấy 52 mục ngẫu nhiên từ đối số của nó, ở đây sẽ là danh sách 52 số nguyên)
Arc676

4

Con trăn

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:]nghĩa là gì? Điều đó có tái diễn trên một mảng con deckkhông?
Justin Morgan

Có, [1:] có nghĩa là phân đoạn từ chỉ mục 1 đến cuối mảng. Vì vậy, nó đệ quy xáo trộn mọi thứ trừ phần tử đầu tiên, gán (bản sao) nó trở lại cùng một vị trí trong mảng ban đầu, sau đó đặt ngẫu nhiên phần tử đầu tiên vào đâu đó.
Keith Randall

Rất thông minh. Tôi nghĩ rằng đây là một trong những giải pháp đẹp nhất ở đây và nó sử dụng thuật toán Fisher-Yates một cách chính xác. +1. Đây là một cách hay để tôi thấy vẻ đẹp của ngôn ngữ mà tôi không quen thuộc.
Justin Morgan

2
Bạn có thể thích các a, b = b, amẹo.
Ray

3

Sử dụng đại diện nhân tố

Trong biểu diễn hệ số của một hoán vị, một phần tử i nhận các giá trị từ 0 đến Ni. Vì vậy, một hoán vị ngẫu nhiên chỉ rand(0,i)dành cho mỗi Ni.

Trong J:

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

Ở đâu ? xrand(0,x-1)|.>:i.5252 51 ... 1

Sau đó nếu a là giá trị của ith Factadic, chúng tôi thực hiện hoán đổi : swap(deck[i], deck[i+a]). Danh sách các cặp để trao đổi là:

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

Việc hoán đổi chúng tôi sẽ sử dụng các tác phẩm như thế này:

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

Nó không thực sự "bằng cách tham chiếu" nhưng không có chức năng thực sự trong J.

Chúng tôi sẽ sử dụng chiều dài của boong (#deck ) để tránh sử dụng hằng số.

Hoàn thành chương trình trong 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

C #

Đây là câu trả lời của riêng tôi dựa trên thuật toán Fisher-Yates . Sẽ cung cấp cho bạn một shuffle hoàn hảo nếu trình tạo số ngẫu nhiên của bạn là đủ tốt.

Phiên bản tiếng Anh:

  1. Liên tục trao đổi thẻ tại deck[0]với tại deck[v], tại đó vmệnh giá của thẻ tại deck[0]. Lặp lại cho đến khiv == 0 . Điều này sẽ sắp xếp một phần bộ bài, nhưng điều đó không thành vấn đề. Bây giờ bạn biết Thẻ 0 nằm ở phía trước bộ bài, có nghĩa là bạn có thể đánh cắp khoảng trống đó trong mảng và sử dụng nó làm bộ đếm vòng lặp. Đây là "mánh gian lận" chính cho vấn đề biến cục bộ.
  2. Bắt đầu từ vị trí 1 (thẻ thứ hai trong cỗ bài), trao đổi thẻ tại ivới thẻ tại rand(i, 51). Lưu ý rằng bạn cần rand(i, 51), KHÔNG rand(1, 51) . Điều đó sẽ không đảm bảo rằng mỗi thẻ được chọn ngẫu nhiên.
  3. Đặt deck[0]lại về 0. Bây giờ toàn bộ cỗ bài được xáo trộn ngoại trừ thẻ đầu tiên, vì vậy hãy trao đổi deck[0]với deck[rand(0, 51)]và bạn đã hoàn tất.

Phiên bản 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)]);
}

Phiên bản 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));

... nơi swap(a, b)trao đổi deck[a]với deck[b].


2

Ruby, một dòng

Đây có được coi là gian lận? Nó nên là ngẫu nhiên như nó được.

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

( randPhương thức của Ruby chỉ lấy một đối số và sau đó tạo một số n sao cho 0 <= number <đối số.)

Ngoài ra - tương tự như giải pháp Perl của sogart, nhưng theo tôi biết thì nó không gặp phải vấn đề:

deck = deck.sort_by{rand}

Ruby's sort_by khác với sort - trước tiên, nó tạo ra danh sách các giá trị để sắp xếp mảng theo và chỉ sau đó sắp xếp nó theo chúng. Sẽ nhanh hơn khi tốn kém để tìm ra tài sản mà chúng tôi sắp xếp, chậm hơn một chút trong tất cả các trường hợp khác. Nó cũng hữu ích trong mã golf: P


Tôi sẽ không gọi đó là gian lận, nhưng deck[0..51]sẽ bỏ qua quy tắc "không biến" bằng cách sử dụng một tính năng của ngôn ngữ. Thật công bằng, tôi chỉ nghĩ rằng nó thua một số thử thách. :) Tôi không biết Ruby; bạn có thể giải thích (0..51).map{deck.delete_at(rand deck.length)}một phần? Điều đó có xóa thẻ từ deck?
Justin Morgan

@JustinMorgan có, 52 lần nó xóa một thẻ ngẫu nhiên khỏi deckvà thêm nó vào danh sách kết quả nội bộ mapđang tích lũy. Sau đó, khi không có gì còn lại trong là decknhững mapkết quả được sao chép vào deck. Về cơ bản có tạm thời, nhưng đó là một tính năng ngôn ngữ chứ không phải là một biến rõ ràng :)
hobbs

deck.sort_by!{rand}ngắn hơn
Eric Duminil

1

JavaScript

LƯU Ý: Giải pháp này về mặt kỹ thuật không chính xác vì nó sử dụng tham số thứ hai i, trong lệnh gọi đến shuffle, được tính là một biến ngoài.

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

Gọi với shuffle(deck,52)

Một ví dụ hoạt động hoàn chỉnh (phải sửa đổi swapmột chút vì không có tham chiếu qua ints trong 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);

Làm tốt. Những gì tôi có trong đầu là xem xét các tham số shufflelà biến, nhưng tôi không xác định đó là +1. Đẹp sử dụng đệ quy, quá.
Justin Morgan

-1, không tạo ra tất cả các hoán vị, điều này là hiển nhiên bởi vì phần tử 51 sẽ không bao giờ chiếm vị trí ban đầu của nó và vì bạn chỉ gọi rand đủ để tạo 51! hoán vị trong số 52 có thể!
aaaaaaaaaaaa

2
@eBusiness: Trong thông số kỹ thuật ban đầu, bộ bài được sắp xếp tùy ý, không nhất thiết phải theo thứ tự 1-52. Tôi chỉ sử dụng nó bởi vì nó là dễ nhất.
mellamokb

1
@eBusiness: Tôi đã sửa đổi để cho phép khả năng để phần tử ở cùng một vị trí, bằng cách sử dụng deck[rand(0,i-1)]thay vì deck[rand(0,i-2)]. Cũng trao đổi tất cả các cách để i=0thay vì dừng lại ở i=1. cái đó có giúp ích không?
mellamokb

Yup, điều đó nên làm điều đó, ngoại trừ việc bây giờ bạn phá vỡ đặc tả trao đổi XOR.
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] << " ";
}

Tránh các yếu tố hoán đổi với chính họ, vì vậy phải gọi hai lần là ngẫu nhiên.


swap(deck[rand(1, 51)], (deck[0] - 51) / 100);Làm thế nào sẽ swapbiết nơi để đặt giá trị thứ hai? Bạn cũng đang thiếu a ).
Justin Morgan

Rất tiếc, cảm ơn. Tôi bắt đầu chuyển phần đó trong một lần sửa đổi và phải bị phân tâm trước khi hoàn thành nó: P
Matthew Đọc

Downvote không phải từ tôi, BTW. Tôi sẽ kiểm tra khi tôi có thể.
Justin Morgan

ĐỒNG Ý. Tôi đã làm cho nó dễ dàng hơn để kiểm tra bằng cách cung cấp một chương trình đầy đủ.
Matthew Đọc

1
Rất thông minh. Giải pháp của riêng tôi được sử dụng deck[0], nhưng không phải theo cách bạn có.
Justin Morgan

1

D

shuffle(int[] d){
    while(d.length){
        if([rand(0,d.length-1)!=0)swap(d[0],d[rand(1,d.length-1)]);
        d=d[1..$];
    }
}

1

Một giải pháp Perl khác, thực sự tạo ra đầu ra phân phối đồng đều:

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

say join " ", shuffle_integers 1 .. 52;

Giải pháp này sử dụng Perl's rand, trả về một số ngẫu nhiên x trong phạm vi 0 ≤ x <1. Nó thêm một số ngẫu nhiên như vậy vào mỗi số nguyên trong đầu vào, sắp xếp các số theo các phần phân số của chúng và cuối cùng loại bỏ các phần phân số đó một lần nữa .

(Tôi tin rằng việc sử dụng các biến đặc biệt $_, $a$bnằm trong tinh thần của thách thức, bởi vì đó là cách perl vượt qua đầu vào mapsort, và họ đang không được sử dụng cho bất kỳ mục đích nào khác trong các mã. Trong mọi trường hợp, tôi tin rằng chúng thực sự là bí danh cho các giá trị đầu vào, không phải là các bản sao độc lập. Tuy nhiên, đây thực sự không phải là một sự xáo trộn tại chỗ; cả hai mapsorttạo các bản sao của đầu vào trên ngăn xếp.)


1

Java

Tôi ngạc nhiên không ai nói rõ ràng: (Tôi sẽ cho rằng hoán đổi (x, x) không làm gì cả.

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

OK, ok, nó có thể ngắn hơn:

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

Burlesque

Những gì bạn đang thực sự yêu cầu là một hoán vị ngẫu nhiên của một danh sách các số nguyên? r@sẽ cung cấp cho chúng tôi tất cả các hoán vị, và chúng tôi chỉ chọn một ngẫu nhiên.

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

Vì chúng ta cần sự ngẫu nhiên thực sự, một cái gì đó Burlesque không có khả năng thực hiện vì Burlesque không có chức năng I / O mà bạn cần để cung cấp một số nguồn ngẫu nhiên thông qua STDIN.

Đó có lẽ là thứ tôi sẽ sửa trong phiên bản sau (nghĩa là tạo một hạt giống ngẫu nhiên khi khởi động và đẩy nó lên ngăn xếp thứ cấp hoặc thứ gì đó tương tự, nhưng bản thân Trình thông dịch Burlesque không có I / O).


0

Javascript

Tôi không chắc liệu đó có phải là "gian lận" hay không nhưng giải pháp của tôi sử dụng mảng cục bộ của các đối số của hàm. Tôi bao gồm các chức năng tự làm của tôi rand() swap()filldeck(). Lưu ý thú vị, điều này nên làm việc với một sàn có kích thước bất kỳ.

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

Đó là gian lận, tôi nghĩ. Tuy nhiên, đó là sự gian lận rất thông minh, rất tốt.
Justin Morgan

0

Tcl , 32 byte

Lạm dụng timechức năng phục vụ để đo thời gian tập lệnh đang chạy, nhưng cũng có thể phục vụ như một cơ chế lặp mà không cần khai báo bất kỳ biến nào.

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

Hãy thử trực tuyến!


Tôi có đúng rằng điều này chỉ thực hiện 52 lần hoán đổi ngẫu nhiên? Điều đó là không đủ cho một shuffle thực sự. Tôi đã chạy nó một vài lần và đếm trung bình 8 thẻ vẫn ở vị trí bắt đầu của họ, và xác suất của nó với một lần xáo trộn thực sự là khoảng 9x10 ^ -6 .
Justin Morgan

@JustinMorgan: Bạn có thể vui lòng giải thích cho tôi cách tính xác suất tốt hơn không?
sergiol

-1

perl - đây không phải là một shuffle thích hợp như được giải thích trong các ý kiến!

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

Tôi nghĩ rằng tôi đã không sử dụng bất cứ thứ gì như một trao đổi, vv có phải là một phần của vấn đề?


4
Điều đó sẽ hoạt động nếu sắp xếp theo một hàm ngẫu nhiên là một cách tạo ra phân phối ngẫu nhiên. Tuy nhiên không phải vậy. -1
aaaaaaaaaaaa

và tại sao không? bạn có thể cho tôi một liên kết để đọc ???
sogart

2
Chất lượng của kết quả sẽ thay đổi rất nhiều tùy thuộc vào thuật toán sắp xếp, nhưng trong hầu hết các trường hợp, kết quả sẽ rất xa so với hàm ngẫu nhiên phân phối bằng nhau. Đây là một bài viết về chủ đề: sroucheray.org/blog/2009/11/ trên
aaaaaaaaaaaa

-1

JavaScript 4 dòng

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

Câu trả lời ban đầu không đủ ngẫu nhiên. Việc trao đổi không được đảm bảo để chạm vào từng mục trong bộ bài.

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

Không tạo ra một shuffle ngẫu nhiên thực sự. Đây là một thử nghiệm trực quan hóa: jsfiddle.net/muk1b nhịp . Tôi đã thay đổi shufflemã của bạn một chút để phù hợp với swaptriển khai của tôi , nhưng đây là nguyên văn: jsfiddle.net/m7km4u6g
Justin Morgan

Để làm rõ, nhận xét trên áp dụng cho phiên bản mới, vẫn không ngẫu nhiên.
Justin Morgan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.