I spent some time learning how to create random and shuffled arrays with GameplayKit and found this topic to be a bit involved. So, I thought I would summarize what I’ve learned.
First, you should decide whether the randomization needs to be “cryptographically robust”. If so, GameplayKit should not be used.
Next, you need to select a random source. Games have particular requirements and, as a result, not all of the random sources are random in the lay sense of the term. However, GKARC4RandomSource and GKMersenneTwisterRandomSource are reasonably random, and they are probably the best choices in most circumstances.
Thirdly, you should decide whether you want to create a random or shuffled array–the primary distinction being that a random array can include duplicates and a shuffled array will not (provided the source array doesn’t include duplicates).
To shuffle an array, there are three basic options. At first glance the GKShuffledDistribution class seems a good choice but is slow in my testing. The second and third options are similar and are demonstrated below:
use framework "Foundation"
use framework "GameplayKit"
use scripting additions
set theList to {"a", "b", "c", "d", "e"}
-- use arrayByShufflingObjectsInArray
set randomSource to current application's GKARC4RandomSource's new()
set shuffledArray to randomSource's arrayByShufflingObjectsInArray:theList
return shuffledArray as list
-- use shuffledArrayWithRandomSource
set theArray to current application's NSArray's arrayWithArray:theList
set randomSource to current application's GKARC4RandomSource's new()
set shuffledArray to theArray's shuffledArrayWithRandomSource:randomSource
return shuffledArray as list
If a randomized array is desired, the situation is both simpler and more complicated. The following comment from the documentation applies to games but applies equally well to a more generalized use:
In most cases, you need random numbers that are uniformly distributed across a specific range. For this task, use the GKRandomDistribution class.
The following is an example,
use framework "Foundation"
use framework "GameplayKit"
use scripting additions
set startNumber to 1
set endNumber to 10
set numberCount to 5
set randomNumbers to current application's NSMutableArray's new()
set randomDistribution to current application's GKRandomDistribution's distributionWithLowestValue:startNumber highestValue:endNumber
repeat numberCount times
randomNumbers's addObject:(randomDistribution's nextInt())
end repeat
return randomNumbers as list
The above script does not specify a random source and that’s because distributionWithLowestValue:highestValue: defaults to GKARC4RandomSource. To designate a random source:
use framework "Foundation"
use framework "GameplayKit"
use scripting additions
set startNumber to 1
set endNumber to 10
set numberCount to 5
set randomNumbers to current application's NSMutableArray's new()
set randomSource to current application's GKMersenneTwisterRandomSource's new()
set randomDistribution to current application's GKRandomDistribution's alloc()'s initWithRandomSource:randomSource lowestValue:1 highestValue:10
repeat numberCount times
randomNumbers's addObject:(randomDistribution's nextInt())
end repeat
return randomNumbers as list
A simple question is how to randomize an existing array directly, and I couldn’t find an easy answer to that. So, I created an array of random numbers and applied those random numbers to the source array. For example,
use framework "Foundation"
use framework "GameplayKit"
use scripting additions
set theList to {"a", "b", "c", "d", "e"}
set theArray to current application's NSArray's arrayWithArray:theList
set arrayCount to theArray's |count|()
set randomItems to current application's NSMutableArray's new()
set randomDistribution to current application's GKRandomDistribution's distributionWithLowestValue:0 highestValue:(arrayCount - 1)
repeat arrayCount times
set randomItem to theArray's objectAtIndex:(randomDistribution's nextInt())
randomItems's addObject:randomItem
end repeat
return randomItems as list
A final comment should be made concerning basic AppleScript. The “random number” command can be used to get a random number, and the “some” reference form will randomly return an item from a list. Both of these are easy to implement and reasonably quick, and they will satisfy in most situations. However, as far as I am aware, there is not a direct method to shuffle a list with basic AppleScript
A MacScripter thread on this topic can be found here
An informative page from the GameplayKit documentation can be found here