i have some question about swift 2 random. I have an enum sub class of all cards example:
enum CardName : Int{
case Card2Heart = 0,
Card2Diamond,
Card2Club,
Card2Spade,
Card3Heart..... }
I want to select 10 random cards on the didMoveToView
i have some question about swift 2 random. I have an enum sub class of all cards example:
enum CardName : Int{
case Card2Heart = 0,
Card2Diamond,
Card2Club,
Card2Spade,
Card3Heart..... }
I want to select 10 random cards on the didMoveToView
To get a unique, random set of numbers you can do the following...
Using the Fisher-Yates shuffle from here... How do I shuffle an array in Swift?
You can do...
var numbers = Array(0...51)
numbers.shuffleInPlace()
let uniqueSelection = numbers[0..<10]
or...
let uniqueSelection = Array(0...51).shuffleInPlace()[0..<10]
This will create a random, unique selection of 10 numbers (cards) from the array of 52 cards that you start with.
You can then iterate this array to get the enums or create an array of all enums to start from etc... There are lots of ways to use this.
In Swift 4.2 (coming with Xcode 10) the task will become much easier:
enum CardName: CaseIterable {
case Card2Heart
case Card2Diamond
case Card2Club
case Card2Spade
case Card3Heart
// ...
}
let randomCard = CardName.allCases.randomElement()
print(randomCard)
let randomCards10 = CardName.allCases.shuffled().prefix(10)
print(randomCards10)
Note there is no need for the enum to inherit from Int
.
Following your last comment, here's a little, simplified example with the constraint of having to keep your enum for making the cards.
We need to include the extensions linked by Fogmeister:
extension MutableCollectionType where Index == Int {
/// Shuffle the elements of `self` in-place.
mutating func shuffleInPlace() {
// empty and single-element collections don't shuffle
if count < 2 { return }
for i in 0..<count - 1 {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
extension CollectionType {
/// Return a copy of `self` with its elements shuffled
func shuffle() -> [Generator.Element] {
var list = Array(self)
list.shuffleInPlace()
return list
}
}
These extensions will allow us to shuffle an array of values.
Which array?
There's many ways, but the simplest option is probably to make an array of indices, which are simple integers (replace 52 with the actual number of cards in your enum):
Array(1...52) // [1, 2, 3, ... , 52]
We shuffle it:
Array(1...52).shuffle() // [33, 42, 7, ...]
Now we have an array of randomized indices. Let's make cards from this with your enum:
Array(0...51).shuffle().flatMap({ CardName(rawValue: $0) })
This is it, we have an array of cards in a random order:
let shuffledDeck = Array(0...51).shuffle().flatMap({ CardName(rawValue: $0) }) // [Card3Heart, Card2Diamond, ...]
and we can take cards from it:
func takeCardsFromDeck(number: Int) -> [CardName] {
if shuffledDeck.count > number {
let cards = Array(shuffledDeck[0..<number])
shuffledDeck.removeRange(0..<number)
return cards
}
return []
}
let tenRandomCards = takeCards(10)
Of course we need to remove from the deck the cards we've dealt, that way each card you draw is unique: we're using removeRange for that.
This example was kept simple on purpose: you still have to verify that there's enough cards in the deck before drawing, and lots of unsuspected other complexities. But it's so fun. ;)
If you want, you can search for additional inspiration in my implementation of these models and others (Deck, Dealer, Player, etc) in my PokerHands repository (MIT Licenced) on GitHub.
Swift 4.2
No need for these extensions anymore, we can use the .shuffle()
and .shuffled()
methods provided by Swift. Just remove the extensions, and rename the methods: the equivalent of our old "shuffleInPlace" is now .shuffle()
and the equivalent of our old "shuffle" is now .shuffled()
.
Note: see Sulthan's answer for an even better solution using Swift 4.2.
Here is the shuffleInPlace()
code that you are missing;
extension MutableCollectionType where Index == Int {
mutating func shuffleInPlace() {
if count < 2 { return }
for i in 0..<count - 1 {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
how to randomly spread enum values set
import Darwin // arc4random_uniform
enum E:Int {
case E1, E2, E3, E4, E5, E6, E7, E8, E9, E10
static var set:[E] { return (E.E1.rawValue...E.E10.rawValue).flatMap { E(rawValue: $0) }}
}
func spread(i:Int = 0, arr:[E])->([E],[E]) {
var i = i == 0 ? arr.count : i
var e:[E] = []
var arr = arr
while i > 0 && arr.count > 0 {
let idx = Int(arc4random_uniform(UInt32(arr.count-1)))
e.append(arr.removeAtIndex(idx))
i -= 1
}
return (e,arr)
}
let e1 = spread(3, arr: E.set)
let e2 = spread(2, arr: e1.1)
// ... spread the rest
let e3 = spread(arr: e2.1)
print(e1, e2, e3, separator:"\n")
/*
([E.E8, E.E6, E.E4], [E.E1, E.E2, E.E3, E.E5, E.E7, E.E9, E.E10])
([E.E1, E.E7], [E.E2, E.E3, E.E5, E.E9, E.E10])
([E.E5, E.E3, E.E2, E.E9, E.E10], [])
*/