guy
Version:
npm dependencies checker
130 lines (111 loc) • 7.37 kB
text/coffeescript
'use strict'
#===========================================================================================================
# UNSORTING
#-----------------------------------------------------------------------------------------------------------
@shuffle = ( list, ratio = 1 ) ->
### Shuffles the elements of a list randomly. After the call, the elements of will be—most of the time—
be reordered (but this is not guaranteed, as there is a realistic probability for recurrence of orderings
with short lists).
This is an implementation of the renowned Fisher-Yates algorithm, but with a twist: You may pass in a
`ratio` as second argument (which should be a float in the range `0 <= ratio <= 1`); if set to a value
less than one, a random number will be used to decide whether or not to perform a given step in the
shuffling process, so lists shuffled with zero-ish ratios will show less disorder than lists shuffled with
a one-ish ratio.
Implementation gleaned from http://stackoverflow.com/a/962890/256361. ###
#.........................................................................................................
return list if ( this_idx = list.length ) < 2
return @_shuffle list, ratio, Math.random, @random_integer.bind @
#-----------------------------------------------------------------------------------------------------------
@get_shuffle = ( seed_0 = 0, seed_1 = 1 ) ->
### This method works similar to `get_rnd`; it accepts two `seed`s which are used to produce random number
generators and returns a predictable shuffling function that accepts arguments like Bits'N'Pieces
`shuffle`. ###
rnd = @get_rnd seed_0
random_integer = @get_rnd_int seed_1
return ( list, ratio = 1 ) => @_shuffle list, ratio, rnd, random_integer
#-----------------------------------------------------------------------------------------------------------
@_shuffle = ( list, ratio, rnd, random_integer ) ->
#.........................................................................................................
return list if ( this_idx = list.length ) < 2
#.........................................................................................................
loop
this_idx += -1
return list if this_idx < 1
if ratio >= 1 or rnd() <= ratio
# return list if this_idx < 1
that_idx = random_integer 0, this_idx
[ list[ that_idx ], list[ this_idx ] ] = [ list[ this_idx ], list[ that_idx ] ]
#.........................................................................................................
return list
#===========================================================================================================
# RANDOM NUMBERS
#-----------------------------------------------------------------------------------------------------------
# ### see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number ###
# @MIN_SAFE_INTEGER = -( 2 ** 53 ) - 1
# @MAX_SAFE_INTEGER = +( 2 ** 53 ) - 1
#-----------------------------------------------------------------------------------------------------------
@random_number = ( min = 0, max = 1 ) ->
### Return a random number between min (inclusive) and max (exclusive).
From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
via http://stackoverflow.com/a/1527820/256361. ###
return Math.random() * ( max - min ) + min
#-----------------------------------------------------------------------------------------------------------
@integer_from_normal_float = ( x, min = 0, max = 2 ) ->
### Given a 'normal' float `x` so that `0 <= x < 1`, return an integer `n` so that `min <= n < min`. ###
return ( Math.floor x * ( max - min ) ) + min
#-----------------------------------------------------------------------------------------------------------
@random_integer = ( min = 0, max = 2 ) ->
### Return a random integer between min (inclusive) and max (exclusive).
From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
via http://stackoverflow.com/a/1527820/256361. ###
return @integer_from_normal_float Math.random(), min, max
#-----------------------------------------------------------------------------------------------------------
@get_rnd_int = ( seed = 1, delta = 1 ) ->
### Like `get_rnd`, but returns a predictable random integer generator. ###
rnd = @get_rnd seed, delta
return ( min = 0, max = 1 ) => @integer_from_normal_float rnd(), min, max
#-----------------------------------------------------------------------------------------------------------
@get_rnd = ( seed = 1, delta = 1 ) ->
### This method returns a simple deterministic pseudo-random number generator—basically like
`Math.random`, but (1) very probably with a much worse distribution of results, and (2) with predictable
series of numbers, which is good for some testing scenarios. You may seed this method by passing in a
`seed` and a `delta`, both of which must be non-zero numbers; the ensuing series of calls to the returned
method will then always result in the same series of numbers. Here is a usage example that also shows how
to reset the generator:
CND = require 'cnd'
rnd = CND.get_rnd() # or, say, `rnd = CND.get_rnd 123, 0.5`
log rnd() for idx in [ 0 .. 5 ]
log()
rnd.reset()
log rnd() for idx in [ 0 .. 5 ]
Please note that there are no strong guarantees made about the quality of the generated values except the
(1) deterministic repeatability, (2) boundedness, and (3) 'apparent randomness'. Do **not** use this for
cryptographic purposes. ###
#.........................................................................................................
R = ->
R._idx += 1
x = ( Math.sin R._s ) * 10000
R._s += R._delta
return x - Math.floor x
#.........................................................................................................
R.reset = ( seed, delta ) ->
### Reset the generator. After calling `rnd.reset` (or `rnd.seed` with the same arguments), ensuing calls
to `rnd` will always result in the same sequence of pseudo-random numbers. ###
seed ?= @._seed
delta ?= @._delta
#.......................................................................................................
unless ( typeof seed ) is 'number' and ( Number.isFinite seed ) then throw new Error "^3397^ expected a number, got #{rpr seed}"
unless ( typeof delta ) is 'number' and ( Number.isFinite delta ) then throw new Error "^3398^ expected a number, got #{rpr delta}"
#.......................................................................................................
throw new Error "seed should not be zero" unless seed != 0
throw new Error "delta should not be zero" unless delta != 0
#.......................................................................................................
R._s = seed
R._seed = seed
R._delta = delta
R._idx = -1
return null
#.........................................................................................................
R.reset seed, delta
#.........................................................................................................
return R