酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

Swiftでカードをシャッフルする

60枚のカードを偏りなくランダムに並び替える方法として、「Fisher-Yates shufflアルゴリズムを用いて自作で配列をシャッフルさせる - Qiita」で紹介されているFisher-Yatesシャッフルアルゴリズムが有名です。調べたらWikipediaでより詳細に「フィッシャー–イェーツのシャッフル - Wikipedia」にて、このアルゴリズムが解説されています。

カードをシャッフルする

下記のようなCard型があるとします。

class Card: NSObject {
    var id: Int

    init(id: Int) {
        self.id = id
    }
    
    override var description: String {
        return "Card(id: \(id))"
    }
}

今回ぼくは「How do I shuffle an array in Swift? - Stack Overflow」をそのまま使わせてもらうことにしました。

extension MutableCollection {
    /// Shuffles the contents of this collection.
    mutating func shuffle() {
        let c = count
        guard c > 1 else { return }

        for (firstUnshuffled, unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
            // Change `Int` in the next line to `IndexDistance` in < Swift 4.1
            let d: Int = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
            let i = index(firstUnshuffled, offsetBy: d)
            swapAt(firstUnshuffled, i)
        }
    }
}

extension Sequence {
    /// Returns an array with the contents of this sequence, shuffled.
    func shuffled() -> [Element] {
        var result = Array(self)
        result.shuffle()
        return result
    }
}

実験

1〜60まで並んでいる60枚のカードをシャッフルしてみました。

        var array = [Card]()
        for i in 1 ... 60 {
            array.append(Card(id: i))
        }
        
        let array1 = array.shuffled()
        print(array1)

実行結果です。

[Card(id: 12), Card(id: 58), Card(id: 45), Card(id: 29), Card(id: 17), Card(id: 56), Card(id: 22), Card(id: 9), Card(id: 42), Card(id: 15), Card(id: 49), Card(id: 33), Card(id: 44), Card(id: 23), Card(id: 14), Card(id: 24), Card(id: 51), Card(id: 37), Card(id: 19), Card(id: 16), Card(id: 36), Card(id: 1), Card(id: 30), Card(id: 43), Card(id: 59), Card(id: 38), Card(id: 50), Card(id: 41), Card(id: 60), Card(id: 13), Card(id: 5), Card(id: 26), Card(id: 11), Card(id: 57), Card(id: 34), Card(id: 47), Card(id: 40), Card(id: 54), Card(id: 25), Card(id: 10), Card(id: 48), Card(id: 35), Card(id: 20), Card(id: 27), Card(id: 3), Card(id: 2), Card(id: 39), Card(id: 28), Card(id: 18), Card(id: 21), Card(id: 53), Card(id: 31), Card(id: 4), Card(id: 46), Card(id: 52), Card(id: 6), Card(id: 8), Card(id: 32), Card(id: 55), Card(id: 7)]