Game Development Journal 6: GKRandom

As of my last blog post, I now have a deck of flower cards. It is represented in an array of various struct instances that all conform to a Card protocol.

Games would not be very interesting if we didn’t have random elements. In order for me to proceed with my game, I need to implement a method to “shuffle” my deck of cards.

Initially, my plan was to do some research into various randomization algorithms. I was looking for an excuse to do more research into computerized randomization, but I don’t feel this application will fit the bill. My research yielded two results:

  1. iOS has a built in framework specifically for randomization
  2. Other languages have this functionality built directly into their Array class

One thing I am trying to avoid with this project is falling down rabbit holes. I thought it would be interesting to compare rolling my own randomization against the ones that are built into Gameplay Kit, but that is a waste of time. I am not rolling my own cryptography, so the built in randomization tools are fine.

Additionally, I feel that there are a lot of aspects of Gameplay Kit that people are completely unaware of. It seems to be something of a lost framework that I see very few people actually talk about or show in production. In the spirit of trying to figure out the best way to solve problems, I have decided that I would like to try and implement Gameplay Kit whenever possible so that awareness of this framework can improve.

GKRandom

Apple has a nice overview of the various options they have for their randomization components.

GKRandom is a protocol that has two classes that conform to it: GKRandomSource and GKRandomDistribution.

GKRandomDistribution is set up to generate random numbers based on a range. This would be ideal for doing something like rolling a dice. There are even built in functions based on both six-sided dice and twenty-sided dice. Good news if you are and Dungeons and Dragons fan!

I could write an algorithm to implement this to force it to suit my needs, but it’s worthwhile to see if the other class would work better.

Looking at GKRandomSource’s documentation shows that there is a built in method called arrayByShufflingObjects(in: [Any]). Since I decided to turn my deck into an array and not a dictionary, this seems ideal.

GKRandomSource is not meant to be used directly. It is a super class that has three different subclasses based on different random algorithms:

  • GKARC4RandomSource: This is the default randomization algorithm. This works well with just about any game scenario.
  • GKLinearCongruentialRandomSource: This is a more performant algorithm. It’s less random, but also less resource intensive. If you’re counting the milliseconds in your game loop and you don’t need something super random, you might want to consider this.
  • GKMersenneTwisterRandomSource: This is the most random of the random source classes, but it is also the slowest.

Since all three of these inherit from GKRandomSource, they all have the method to shuffle an array. It’s just a question of which one suits my purposes.

I think any of them would work. Shuffling a deck of cards tends to be less random than rolling a die by the nature of how difficult it is to get a genuinely random distribution, so having the most random distribution is probably overkill.

I am tentatively going to choose the fastest algorithm, the GKLinearCongruentialRandomSource. I don’t think that the performance aspect is an issue. The deck is only generated at the beginning of a hand, along with all other setup steps. If this were being run every single frame then performance would be an issue.

Instead, I am trying to mimic an actual game playing experience. If you are shuffling decks of cards, you’re not going to get super random distributions. Additionally, the way that I have initialized the deck by grouping the cards by class rather than suit, the initial deck layout is fairly mixed up anyway.

My final code to add shuffling functionality is as follows:

// Random Functions: Need to generate a "shuffled" deck of cards

func shuffleDeck(deck: [Card]) -> [Card] {
    let randomGenerator = GKLinearCongruentialRandomSource()
    return randomGenerator.arrayByShufflingObjects(in: deck) as! [Card]
}

let shuffledDeck = shuffleDeck(deck: deck)

By using Gameplay Kit, I was able to get the functionality I needed with one function that uses two lines of code.

Conclusions

It feels kind of anticlimactic to write a whole blog post to end saying I resolved the issue with two lines of code. But I feel like it’s important to emphasize the value of simple solutions.

I feel like we, as a community, feel the need to implement more complicated solutions. If I don’t write out my random algorithm in Swift, then I am not a real programmer. Except that’s not true.

First off, implementing my algorithm in Swift will result in me having more code that I have to maintain. Swift is still rapidly changing. Swift 2.2 is legacy code. More lines of pure Swift means more things that change that I have to go back and update a few times a year. No thank you.

Second, it would have taken up more lines of code. Right now the algorithm is abstracted away and I don’t have to have it in my code.

Third, there is no point in reinventing the wheel. My need to shuffle an array of objects is a common enough problem that Apple provided me a simple solution for it. They will maintain it and ensure that it keeps working. If it’s deprecated then it’s on me to go back and find what it changed to, but for all intents and purposes I never have to touch this again.

Fourth, I know that this algorithm is accurate because Apple gave it to me. They have people who know more about this stuff than I do who wrote and tested this so I don’t have to.

Fifth, if I ever for some reason bring on another person onto my project, it’s much simpler for that person to read that code snippet than it would be to walk through the programming logic associated with the algorithm. It’s plain what the function does and if they have questions they can read Apple’s documentation.

I have added this new playground here. It’s basically the same as the refactored playground but with the added random function and its call. Those lines are at the bottom.

Moral of the story is, if someone gives you the ability to do something in two lines of code, for the love of God just take it!!

god