Làm cách nào để xáo trộn thẻ cho trò chơi bài?


13

Tôi đang cố gắng phát triển một trò chơi bài cho Android Ai có thể gợi ý cho tôi cách viết mã để xáo trộn hiệu quả các thẻ chơi không?

Câu trả lời:


21

Xáo trộn thẻ là một thuật toán dễ viết bằng trực giác và hoàn toàn sai khi làm như vậy. Có một tài liệu tham khảo tốt để thực hiện xáo trộn thẻ một cách chính xác trên Wikipedia . Những gì tôi trình bày ở đây là một phiên bản thuật toán được đơn giản hóa một chút trên trang đó theo Thuật toán hiện đại .

Đây là ý tưởng cơ bản, bằng tiếng Anh đơn giản:

Hãy xem xét một bộ bài. Đối với cuộc thảo luận này, bạn có thể có bất kỳ số lượng thẻ nào trong bộ bài và chúng có thể bắt đầu theo bất kỳ thứ tự nào.

Chúng ta sẽ nói về "vị trí" trong bộ bài, trong đó "vị trí" là có bao nhiêu lá bài trong bộ bài cao hơn bộ bài ở vị trí đó. Ví dụ: thẻ ở trên cùng của bộ bài nằm ở vị trí 0, thẻ bên dưới ở vị trí 1 (vì có 1 thẻ cao hơn nó - thẻ trên cùng) và trong bộ bài 52 thẻ tiêu chuẩn, phía dưới Thẻ ở vị trí 51, vì 51 thẻ cao hơn so với nó trong bộ bài.

Bây giờ, chúng tôi xem xét từng vị trí trong bộ bài, từng vị trí một, bắt đầu từ dưới lên và làm việc theo cách của chúng tôi lên đến đỉnh.

Đối với mỗi vị trí, chúng tôi chọn ngẫu nhiên một trong các thẻ ở vị trí đó hoặc ở vị trí được đánh số thấp hơn (hãy nhớ rằng, trên cùng của bộ bài là 0 và chúng tôi đang tiến lên từ dưới cùng của bộ bài, vì vậy đối với từng vị trí, bạn thực sự chọn tất cả các thẻ ở và trên vị trí đó và chọn ngẫu nhiên một trong những thẻ đó).

Khi chúng tôi thực hiện lựa chọn ngẫu nhiên, chúng tôi trao đổi thẻ ở vị trí chúng tôi hiện đang xem xét với thẻ chúng tôi đã chọn ngẫu nhiên. Nếu chúng tôi chọn ngẫu nhiên thẻ đã ở vị trí đó, thì không có trao đổi nào được thực hiện.

Sau khi hoán đổi (hoặc không tráo đổi, nếu chúng tôi chọn ngẫu nhiên thẻ đã ở vị trí chúng tôi đang xem xét), chúng tôi chuyển sang vị trí tiếp theo trong bộ bài và tiếp tục.

Trong giả, với n là số lượng thẻ trong boong, và một là một mảng đại diện cho boong, ngoại hình thuật toán như thế này:

for each i in [n .. 1] do
     j  random integer in [ 0 .. i ]
     exchange a[j] and a[i]

1
Thuật toán cũng được hiển thị độc đáo ở đây: bost.ocks.org/mike/alerskyms/#shuffling
Felsir

9

Trước tiên, bạn xác định một chuỗi tất cả các thẻ bạn muốn xáo trộn:

List<Card> shuffled = new ArrayList<Card>();
shuffled.addAll(allCards);

Sau đó, bạn đi qua từng vị trí trong chuỗi và gán cho nó một thẻ ngẫu nhiên.

Random random = new Random();
for (int i = shuffled.size() - 1; i >= 0; i--) {
    int j = random.nextInt(i + 1);

    /* swap cards i,j */
    Card card = shuffled.get(i);
    shuffled.set(i, shuffled.get(j));
    shufflet.set(j, card);
}

Bây giờ shuffledlà một chuỗi ngẫu nhiên của tất cả các thẻ của bạn.


3
cái này được gọi là shuffle của Knuth: en.wikipedia.org/wiki/Knuth_shuffle
krolth

2

Tôi muốn kết hợp và đề cập đến "định dạng bảo toàn mã hóa" như một phương pháp để xáo trộn các thẻ trong trò chơi.

Về cơ bản những gì bạn có là một thuật toán mã hóa nhận giá trị 0 đến 51 và một khóa (hạt giống xáo trộn) và tạo ra giá trị 0 đến 51. Vì mã hóa có thể đảo ngược theo định nghĩa có nghĩa là bất kỳ 2 số đầu vào nào cũng không thể mã hóa thành cùng một số đầu ra, có nghĩa là nếu bạn đã mã hóa 0 đến 51, bạn sẽ nhận được 0 đến 51 làm đầu ra theo một thứ tự khác. Nói cách khác, bạn có sự xáo trộn của mình và thậm chí không cần thực hiện bất kỳ sự xáo trộn thực tế nào.

Trong trường hợp này, bạn phải tạo hoặc tìm một thuật toán mã hóa mất 6 bit và phun ra 6 bit (0-63). Để rút thẻ tiếp theo từ bộ bài, bạn có một biến chỉ số bắt đầu từ 0, bạn mã hóa chỉ mục đó, tăng chỉ số và xem giá trị xuất phát từ mật mã. Nếu giá trị là> = 52, bạn bỏ qua nó và tạo một số mới (và dĩ nhiên tăng chỉ số một lần nữa). Vì mã hóa 0-63 sẽ dẫn đến 0-63 là đầu ra, theo một thứ tự khác, bạn chỉ cần bỏ qua bất kỳ giá trị nào xuất hiện> = 52 để thuật toán của bạn mất 0-51 và thoát ra 0-51.

Để chia sẻ lại bộ bài, đặt chỉ số về 0 và thay đổi khóa mã hóa (xáo trộn hạt giống).

Thuật toán của bạn không cần phải có chất lượng mật mã (và không nên, vì điều đó sẽ tốn kém về mặt tính toán!). Một cách thực sự tốt để đưa ra một thuật toán mã hóa có kích thước tùy chỉnh như thế này là sử dụng mạng lưới, cho phép bạn tùy chỉnh kích thước và chất lượng tùy theo nhu cầu của bạn. Đối với chức năng tròn của mạng lưới, tôi muốn giới thiệu một cái gì đó như murmurhash3 vì nó nhanh và có hiệu ứng tuyết lở tốt, điều này sẽ làm cho các xáo trộn xuất hiện ngẫu nhiên.

Kiểm tra bài đăng trên blog của tôi để biết thêm thông tin chi tiết và mã nguồn: http://blog.demofox.org/2013/07/06/fast-lightgra-random-shuffle-feftality-fixed/


Câu trả lời này như hiện tại được đặt ra không giúp ích nhiều khi URL chắc chắn rơi ra khỏi bề mặt của Internet. Xem xét chi tiết trong câu trả lời về các điểm nổi bật của bài viết được liên kết, để câu trả lời có thể tự đứng vững.
Lars Viklund

1
Điểm hay của Lars, được cập nhật với nhiều thông tin hơn để người đọc ít nhất có thể tìm kiếm thêm thông tin về tất cả các thành phần cụ thể của giải pháp xáo trộn thẻ bằng cách sử dụng định dạng mã hóa. Cảm ơn!
Alan Wolfe

1

Các java 1,5 enum hướng dẫn có một cách thú vị để thực hiện một cỗ bài, xây dựng boong, xáo trộn và xử lý. Tất cả đều rất đơn giản khi sử dụng enums vàCollections

public class Card {
    public enum Rank { DEUCE, THREE, FOUR, FIVE, SIX,
        SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE }

    public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES }

    private final Rank rank;
    private final Suit suit;
    private Card(Rank rank, Suit suit) {
        this.rank = rank;
        this.suit = suit;
    }

    public Rank rank() { return rank; }
    public Suit suit() { return suit; }
    public String toString() { return rank + " of " + suit; }

    private static final List<Card> protoDeck = new ArrayList<Card>();

    // Initialize prototype deck
    static {
        for (Suit suit : Suit.values())
            for (Rank rank : Rank.values())
                protoDeck.add(new Card(rank, suit));
    }

    public static ArrayList<Card> newDeck() {
        return new ArrayList<Card>(protoDeck); // Return copy of prototype deck
    }
}

Và lớp để quản lý bộ bài.

public class Deal {
    public static void main(String args[]) {
        int numHands = Integer.parseInt(args[0]);
        int cardsPerHand = Integer.parseInt(args[1]);
        List<Card> deck  = Card.newDeck();
        Collections.shuffle(deck);
        for (int i=0; i < numHands; i++)
            System.out.println(deal(deck, cardsPerHand));
    }

    public static ArrayList<Card> deal(List<Card> deck, int n) {
         int deckSize = deck.size();
         List<Card> handView = deck.subList(deckSize-n, deckSize);
         ArrayList<Card> hand = new ArrayList<Card>(handView);
         handView.clear();
         return hand;
     }
}


-2
    ArrayList deckCards = new ArrayList<Card>();
    //add your cards to the deck
    deckCards.add(card1);
    deckCards.add(card2);
    deckCards.add(card3);
    ....
    //shuffle the array list
    Collections.shuffle(deckCards);

1
Câu trả lời chỉ có mã được khuyến khích.
SurvivalMachine
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.