Objective-C to ASOC ex4.

After checking Shane’s code for the framework “GameplayKit”

I made Apple’s example in Objective-C to ASOC.

use framework "Foundation"
use framework "GameplayKit"
use scripting additions

(** Objective-C 
* Reference: https://developer.apple.com/documentation/gameplaykit/gkgaussiandistribution?language=objc
* GKRandomSource *random = [[GKRandomSource alloc] init];
* GKRandomDistribution *dice3d6;
* dice3d6 = [[GKGaussianDistribution alloc]
*              initWithRandomSource:random lowestValue:3 highestValue:18];
* // Roll the dice...
* int diceRoll = [dice3d6 nextInt];
*)

set randomSource to current application's GKRandomSource's alloc()'s init()
set dice3d6 to current application's GKGaussianDistribution's alloc()'s initWithRandomSource:randomSource lowestValue:3 highestValue:18

return (dice3d6's nextInt()) as integer
set randomSource to current application's GKRandomSource's alloc()'s init()
set shuffled to current application's GKShuffledDistribution's alloc()'s initWithRandomSource:randomSource lowestValue:1 highestValue:6

-- return (shuffled's nextInt()) as integer

-- Log the output of 100
set shuffleDist to current application's GKShuffledDistribution's d6
repeat with i from 1 to 100
	log {shuffleDist's nextInt() as integer}
end repeat
-- Reference: https://developer.apple.com/documentation/gameplaykit/gkrandomsource/1501128-arraybyshufflingobjectsinarray
-- Returns an array whose contents are the same as those of the specified array, but in a random order determined by the random source.
set theArray to {1,2, 3, 4, 5, 6, 7, 8, 9}
set theArray to current application's NSArray's arrayWithArray:theArray
set randomSource to current application's GKRandomSource's alloc()'s init()
set shuffled to randomSource's arrayByShufflingObjectsInArray:theArray
return shuffled as list
1 Like

Fredrik,

is there a reason you are using text instead of integers in the line:

initWithRandomSource:randomSource lowestValue:"3" highestValue:"18"

upon reading the documentation for GameplayKit, it seems to be expecting numbers like so

initWithRandomSource:randomSource lowestValue:3 highestValue:18

Just wondering

1 Like

No reason, you are right I will change it…

1 Like

I’m currently using

set randomSource to current application's GKRandomSource's alloc()'s init()
set randItem to current application's GKRandomDistribution's alloc()'s initWithRandomSource:randomSource lowestValue:1 highestValue:c

(randItem's nextInt()) as integer

I would like to use

func nextInt(upperBound: Int) → Int

I dont know how to write it correctly in AppleScriptObjC

** EDIT

I figured it out below

(randItem's nextIntWithUpperBound:i) as integer

Thanks Fredrik71 for the thread. I wanted to learn a bit about getting random numbers with ASObjC and this was a good starting point.

A more particular goal of my research was to settle on an ASObjC script that returns a specific number of random numbers from a particular range of numbers. In the end, I settled on Shane’s second script below–it’s fast and compact, and it is sufficiently random for my needs.

-- Shane 1 - 42 milliseconds
use framework "Foundation"
use framework "GameplayKit"
use scripting additions

set x to current application's GKARC4RandomSource's sharedRandom()
set theList to {}
repeat 1000 times
	set end of theList to x's nextIntWithUpperBound:1000
end repeat
count theList --> 1000

-- Shane 2 - 21 milliseconds
use framework "Foundation"
use framework "GameplayKit"
use scripting additions

set x to current application's GKRandomDistribution's distributionWithLowestValue:1 highestValue:1000
set theList to {}
repeat 1000 times
	set end of theList to x's nextInt()
end repeat
count theList --> 1000

-- From this thread - 22 milliseconds
use framework "Foundation"
use framework "GameplayKit"
use scripting additions
set theList to {}
set randomSource to current application's GKRandomSource's alloc()'s init()
set randomItem to current application's GKRandomDistribution's alloc()'s initWithRandomSource:randomSource lowestValue:1 highestValue:1000
repeat 1000 times
	set end of theList to randomItem's nextInt()
end repeat
count theList --> 1000

-- Basic AppleScript -- 88 milliseconds (remove comment)
set theList to {}
repeat 1000 times
	# set end of theList to random number from 1 to 1000
end repeat
count theList --> 1000

Thread with Shane’s scripts:

BTW, there are occasions where I want to create a shuffled list of numbers with a specific range, and I think the following may be the way to do this. The timing result to create a list of 1,000 numbers was 24 milliseconds.

use framework "Foundation"
use framework "GameplayKit"
use scripting additions
set startNumber to 1
set endNumber to 10
set theList to {}
set randomSource to current application's GKRandomSource's alloc()'s init()
set shuffled to current application's GKShuffledDistribution's alloc()'s initWithRandomSource:randomSource lowestValue:startNumber highestValue:endNumber
repeat endNumber times
	set end of theList to shuffled's nextInt()
end repeat
theList --> {9, 10, 8, 2, 3, 5, 4, 7, 6, 1}
1 Like

@peavine
Your code will call at least 12 times to bridge objective-c call, I know there have been talk in this forum about doing many calls to objective-c in repeat loop. become slower and vanilla AppleScript. Only a reminder… :), thanks for the regard about this topic.

When this code will only do 3 I think.

use framework "Foundation"
use framework "GameplayKit"
use scripting additions
set theArray to {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
set theArray to current application's NSArray's arrayWithArray:theArray
set randomSource to current application's GKRandomSource's alloc()'s init()
set shuffled to randomSource's arrayByShufflingObjectsInArray:theArray
return shuffled as list
1 Like

Fredrik71. I tested the following script which involved no bridging, and it took almost twice as long to run with both scripts set to create and shuffle 1000 numbers (45 milliseconds versus 24 milliseconds).

use framework "Foundation"
use framework "GameplayKit"
use scripting additions

set startNumber to 1
set endNumber to 1000
set theShuffledNumbers to current application's NSMutableArray's new()
set theShuffledSource to current application's GKShuffledDistribution's alloc()'s initWithRandomSource:(current application's GKRandomSource's alloc()'s init()) lowestValue:startNumber highestValue:endNumber
repeat endNumber times
	theShuffledNumbers's addObject:(theShuffledSource's nextInt())
end repeat
return theShuffledNumbers as list
2 Likes

@peavine
It looks like the setter is slower and getter. The my search on goggle for benchmark of
setter and getter function say the same things.

Maybe Shane knows more.

my script below runs in 3 Milliseconds

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "GameplayKit"
use scripting additions

generateListC(1000)

on generateListC(x as integer) -- "BEST" so far (COCOA)
	local i, theArray, randomSource, shuffled
	script M
		property nlist : {1}
	end script

	repeat with i from 2 to x
		set end of M's nlist to i
	end repeat
	set theArray to current application's NSArray's arrayWithArray:(M's nlist)
	set randomSource to current application's GKRandomSource's alloc()'s init()
	set shuffled to randomSource's arrayByShufflingObjectsInArray:theArray
	return shuffled as list
end generateListC

And here is a slightly shorter one - same speed

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "GameplayKit"
use scripting additions

generateListC(1000)

on generateListC(x as integer) -- "BEST" so far (COCOA)
	local i, theArray, randomSource, shuffled
	script M
		property nlist : {1}
	end script
	
	repeat with i from 2 to x
		set end of M's nlist to i
	end repeat
	set theArray to current application's NSArray's arrayWithArray:(M's nlist)
	set shuffled to theArray's shuffledArray() as list
	return shuffled as list
end generateListC

Fredrik71. Sorry but I don’t know what this means :frowning:

BTW, there are actually two topics dealt with in this thread, which are getting a random list and a shuffled list. I referenced one of Shane’s posts above on getting a list of random numbers with ASObjC; a post by Shane on getting a shuffled list with ASObjC is at:

My rewrite of Shane’s suggestion to shuffle an existing list is:

use framework "Foundation"
use framework "GameplayKit"
set theList to {"a", "b", "c", "d", "e"}
set randomSource to current application's GKMersenneTwisterRandomSource's new()
# set randomSource to current application's GKARC4RandomSource's new() -- an alternative
set shuffledList to randomSource's arrayByShufflingObjectsInArray:theList
return shuffledList as list

# Documentation:
# GKMersenneTwisterRandomSource. A basic random number generator implementing the Mersenne Twister algorithm, which is more random, but slower than the default random source.

On occasion, the user may want to get a shuffled list of numbers in a specified range (say 1 to 1000). This can be done with the GKShuffledDistribution class (48 milliseconds) but it’s much faster simply to create a list of numbers with a repeat loop and then to use Shane’s above suggestion (3 milliseconds total). This is also the approach taken by Robert and it works great :slight_smile:

To store a value in memory is slower and to get a value that alredy excist in memory.
In other words the time it takes to read data in memory is lower and it would be to write
to memory with some data.

In your case it doesn’t matter, but it could matter alot for app that emulate something.
Take rosetta some example… first run it takes time, next run its faster…

To give other example. I show here on macscripter how I could search text content from more and 15000 files in less and 3 seconds. And that was on my old computer from 2012.
The way I did it… I load the contents from file and did the search on the data. Instead of having Finder or other ways to search the disk for files. In other words it was faster to set the location of some files and it would be to read it first and next do search on its contents.