ฉันจะสลับไพ่สำหรับเกมไพ่ได้อย่างไร


13

ฉันกำลังพยายามพัฒนาการ์ดเกมสำหรับ Android ใครสามารถแนะนำฉันถึงวิธีการเขียนรหัสเพื่อการสับไพ่อย่างมีประสิทธิภาพได้หรือไม่?

คำตอบ:


21

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

นี่คือแนวคิดพื้นฐานในภาษาอังกฤษธรรมดา:

พิจารณาไพ่หนึ่งสำรับ สำหรับการสนทนานี้คุณสามารถมีการ์ดจำนวนเท่าใดก็ได้ในสำรับและพวกเขาอาจเริ่มในลำดับใด ๆ

เราจะพูดถึง "ตำแหน่ง" ในเด็คโดยที่ "ตำแหน่ง" คือจำนวนการ์ดในเด็คที่สูงกว่าการ์ดในตำแหน่งนั้น ตัวอย่างเช่นการ์ดที่อยู่ด้านบนของเด็คอยู่ที่ตำแหน่ง 0 การ์ดที่อยู่ที่ตำแหน่ง 1 (เนื่องจากมีการ์ดสูงกว่าการ์ด 1 ใบ - การ์ดอันดับสูงสุด) และในเด็คการ์ดมาตรฐาน 52 การ์ดด้านล่าง ไพ่อยู่ที่ตำแหน่ง 51 เนื่องจากไพ่ 51 ใบสูงกว่าในสำรับ

ตอนนี้เราพิจารณาแต่ละตำแหน่งในสำรับหนึ่งครั้งโดยเริ่มจากด้านล่างและดำเนินการจนสุดทาง

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

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

หลังจากทำการสลับ (หรือไม่ทำการสลับถ้าเราสุ่มเลือกการ์ดที่อยู่ในตำแหน่งที่เรากำลังพิจารณาอยู่) เราจะย้ายไปยังตำแหน่งถัดไปในเด็คและดำเนินการต่อ

ใน pseudocode กับnเป็นจำนวนของบัตรในสำรับและเป็นอาร์เรย์ตัวแทนดาดฟ้าอัลกอริทึมลักษณะเช่นนี้

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

1
อัลกอริทึมสามารถมองเห็นได้เป็นอย่างดีที่นี่: bost.ocks.org/mike/algorithms/#shuffling
Felsir

9

คุณกำหนดลำดับของการ์ดทั้งหมดที่คุณต้องการสับเปลี่ยนก่อน:

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

จากนั้นคุณเดินผ่านทุกตำแหน่งตามลำดับและกำหนดการ์ดแบบสุ่ม

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

ตอนนี้shuffledเป็นลำดับสุ่มของไพ่ทั้งหมดของคุณ


3
สิ่งนี้เรียกว่าการสับเปลี่ยนของ Knuth: en.wikipedia.org/wiki/Knuth_shuffle
krolth

2

ฉันต้องการพูดสอดและพูดถึง "รูปแบบการเก็บรักษาการเข้ารหัส" เป็นวิธีสำหรับการสับไพ่ในเกม

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

ในกรณีนี้คุณต้องสร้างหรือค้นหาอัลกอริทึมการเข้ารหัสที่ใช้เวลา 6 บิตและคาย 6 บิต (0-63) หากต้องการดึงไพ่ใบถัดไปจากเด็คคุณจะมีตัวแปรดัชนีซึ่งเริ่มต้นที่ศูนย์คุณจะเข้ารหัสดัชนีนั้นเพิ่มดัชนีและดูค่าที่ออกมาจากรหัส หากค่าคือ> = 52 คุณจะไม่สนใจและสร้างหมายเลขใหม่ (และเพิ่มดัชนีอีกครั้งแน่นอน) เนื่องจากการเข้ารหัส 0-63 จะทำให้ 0-63 เป็นเอาต์พุตในลำดับที่แตกต่างกันคุณเพียงแค่ละเว้นค่าใด ๆ ที่ออกมา> = 52 เพื่อให้คุณมีอัลกอริทึมที่ใช้ใน 0-51 และแยก 0-51

เพื่อสับไพ่สำรับตั้งดัชนีกลับเป็นศูนย์และเปลี่ยนคีย์การเข้ารหัส (เมล็ดสลับ)

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

ลองอ่านโพสต์บล็อกของฉันเพื่อรับข้อมูลที่ละเอียดยิ่งขึ้นและรหัสที่มา: http://blog.demofox.org/2013/07/06/fast-lightweight-random-shuffle-functionality-fixed/


คำตอบนี้เนื่องจากมีการใช้ถ้อยคำในปัจจุบันไม่ได้ช่วยอะไรมากนักเมื่อ URL หลุดจากพื้นผิวของอินเทอร์เน็ตอย่างหลีกเลี่ยงไม่ได้ พิจารณาอย่างละเอียดในคำตอบของประเด็นสำคัญของบทความที่เชื่อมโยงเพื่อให้คำตอบสามารถยืนได้ด้วยตัวเอง
Lars Viklund

1
จุดที่ดี Lars ได้รับการอัปเดตพร้อมข้อมูลเพิ่มเติมเพื่อให้ผู้อ่านสามารถค้นหาข้อมูลเพิ่มเติมเกี่ยวกับส่วนประกอบเฉพาะทั้งหมดของโซลูชันสำหรับการสับไพ่โดยใช้รูปแบบการเข้ารหัสที่รักษาไว้ ขอบคุณ!
Alan Wolfe

1

การสอนด้วยjava 1.5 enumมีวิธีที่น่าสนใจในการนำไพ่สำรับมาสร้างดาดฟ้าสับไพ่และติดต่อกัน ง่ายมากโดยใช้enums และ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
    }
}

และชั้นเรียนเพื่อจัดการดาดฟ้า

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

0

เพียงใช้ฟังก์ชั่นอย่าง itertools เหมือนบน Python ฉันไม่ทราบชื่อของฟังก์ชั่นเดียวกันใน Java ลอง " http://code.google.com/p/neoitertools/ "

ค้นหาการเรียงสับเปลี่ยนทั้งหมดของวัตถุที่เรียกว่า "ไพ่"


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