core.bmx 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. SuperStrict
  2. Rem
  3. bbdoc: Math/Random numbers
  4. End Rem
  5. Module Random.Core
  6. ModuleInfo "Version: 1.10"
  7. ModuleInfo "Author: Mark Sibly, Floyd"
  8. ModuleInfo "License: zlib/libpng"
  9. ModuleInfo "Copyright: Blitz Research Ltd"
  10. ModuleInfo "Modserver: BRL"
  11. ModuleInfo "History: 1.10"
  12. ModuleInfo "History: Refactored to allow multiple generators."
  13. ModuleInfo "History: Added SetRandom(), GetRandomName() and GetRandomNames()."
  14. ModuleInfo "History: 1.09"
  15. ModuleInfo "History: Moved to Random.Core."
  16. ModuleInfo "History: 1.08"
  17. ModuleInfo "History: New API to enable custom random number generators."
  18. ModuleInfo "History: 1.07"
  19. ModuleInfo "History: Added support for multiple generators"
  20. ModuleInfo "History: 1.06"
  21. ModuleInfo "History: Module is now SuperStrict"
  22. ModuleInfo "History: 1.05 Release"
  23. ModuleInfo "History: Fixed Rand() with negative min value bug"
  24. ? Threaded
  25. Import BRL.Threads
  26. ?
  27. Private
  28. Global GlobalRandom:TRandom
  29. Global random_factories:TRandomFactory
  30. Global random_names:String[]
  31. Public
  32. Type TRandomFactory
  33. Field _succ:TRandomFactory
  34. Field _instance:TRandom
  35. Method New()
  36. _succ=random_factories
  37. random_factories=Self
  38. End Method
  39. Method Init()
  40. _instance = Create()
  41. GlobalRandom = _instance
  42. End Method
  43. Method GetName:String() Abstract
  44. Method Create:TRandom(seed:Int) Abstract
  45. Method Create:TRandom() Abstract
  46. Function Find:TRandomFactory(name:String)
  47. Local factory:TRandomFactory = random_factories
  48. While factory
  49. If factory.GetName() = name Then
  50. Return factory
  51. End If
  52. factory = factory._succ
  53. Wend
  54. Return Null
  55. End Function
  56. Function Create:TRandom(name:String)
  57. Local factory:TRandomFactory = Find(name)
  58. If factory Then
  59. Return factory.Create()
  60. End If
  61. Return Null
  62. End Function
  63. Function Create:TRandom(seed:Int, name:String)
  64. Local factory:TRandomFactory = Find(name)
  65. If factory Then
  66. Return factory.Create(seed)
  67. End If
  68. Return Null
  69. End Function
  70. End Type
  71. Private
  72. Global LastNewMs:Int = MilliSecs()
  73. Global SimultaneousNewCount:Int = 0
  74. ? Threaded
  75. Global NewRandomMutex:TMutex = TMutex.Create()
  76. ?
  77. Public
  78. Function GenerateSeed:Int()
  79. ? Threaded
  80. NewRandomMutex.Lock
  81. ?
  82. Local currentMs:Int = MilliSecs()
  83. Local auxSeed:Int
  84. If currentMs = LastNewMs Then
  85. SimultaneousNewCount :+ 1
  86. auxSeed = SimultaneousNewCount
  87. Else
  88. LastNewMs = currentMs
  89. SimultaneousNewCount = 0
  90. auxSeed = 0
  91. End If
  92. ? Threaded
  93. NewRandomMutex.Unlock
  94. ?
  95. Function ReverseBits:Int(i:Int)
  96. If i = 0 Then Return 0
  97. Local r:Int
  98. For Local b:Int = 0 Until 8 * SizeOf i
  99. r :Shl 1
  100. r :| i & 1
  101. i :Shr 1
  102. Next
  103. Return r
  104. End Function
  105. ' left-shift before reversing because SeedRnd ignores the most significant bit
  106. Return currentMs ~ ReverseBits(auxSeed Shl 1)
  107. End Function
  108. Rem
  109. bbdoc: Random number generator
  110. about:
  111. By creating multiple TRandom objects, multiple independent
  112. random number generators can be used in parallel.
  113. End Rem
  114. Type TRandom
  115. Rem
  116. bbdoc: Generate random float
  117. returns: A random float in the range 0 (inclusive) to 1 (exclusive)
  118. End Rem
  119. Method RndFloat:Float() Abstract
  120. Rem
  121. bbdoc: Generate random double
  122. returns: A random double in the range 0 (inclusive) to 1 (exclusive)
  123. End Rem
  124. Method RndDouble:Double() Abstract
  125. Rem
  126. bbdoc: Generate random double
  127. returns: A random double in the range min (inclusive) to max (exclusive)
  128. about:
  129. The optional parameters allow you to use Rnd in 3 ways:
  130. [ @Format | @Result
  131. * `Rnd()` | Random double in the range 0 (inclusive) to 1 (exclusive)
  132. * `Rnd(x)` | Random double in the range 0 (inclusive) to n (exclusive)
  133. * `Rnd(x,y)` | Random double in the range x (inclusive) to y (exclusive)
  134. ]
  135. End Rem
  136. Method Rnd:Double(minValue:Double = 1, maxValue:Double = 0) Abstract
  137. Rem
  138. bbdoc: Generate random integer
  139. returns: A random integer in the range min (inclusive) to max (inclusive)
  140. about:
  141. The optional parameter allows you to use #Rand in 2 ways:
  142. [ @Format | @Result
  143. * `Rand(x)` | Random integer in the range 1 to x (inclusive)
  144. * `Rand(x,y)` | Random integer in the range x to y (inclusive)
  145. ]
  146. End Rem
  147. Method Rand:Int(minValue:Int, maxValue:Int = 1) Abstract
  148. Rem
  149. bbdoc: Set random number generator seed
  150. End Rem
  151. Method SeedRnd(seed:Int) Abstract
  152. Rem
  153. bbdoc: Get random number generator seed
  154. returns: The current random number generator seed
  155. about: Used in conjunction with SeedRnd, RndSeed allows you to reproduce sequences of random
  156. numbers.
  157. End Rem
  158. Method RndSeed:Int() Abstract
  159. Rem
  160. bbdoc: Gets the name of this random number generator
  161. End Rem
  162. Method GetName:String() Abstract
  163. End Type
  164. Rem
  165. bbdoc: Sets the current random number generator to @name.
  166. about: If no generator called @name is found, the current random number generator remains active.
  167. End Rem
  168. Function SetRandom(name:String)
  169. Local factory:TRandomFactory = TRandomFactory.Find(name)
  170. If factory Then
  171. GlobalRandom = factory._instance
  172. End If
  173. End Function
  174. Rem
  175. bbdoc: Gets the name of the current random number generator.
  176. returns: The name of the current random number generator, or #Null if none is set.
  177. End Rem
  178. Function GetRandomName:String()
  179. If GlobalRandom Then
  180. Return GlobalRandom.GetName()
  181. End If
  182. End Function
  183. Rem
  184. bbdoc: Gets the names of available random number generators.
  185. End Rem
  186. Function GetRandomNames:String[]()
  187. If random_names Then
  188. Return random_names
  189. End If
  190. Local names:String[] = New String[0]
  191. Local factory:TRandomFactory = random_factories
  192. While factory
  193. names :+ [ factory.GetName() ]
  194. factory = factory._succ
  195. Wend
  196. random_names = names
  197. Return random_names
  198. End Function
  199. Rem
  200. bbdoc: Creates a new TRandom instance.
  201. End Rem
  202. Function CreateRandom:TRandom(name:String = Null)
  203. If name Then
  204. Return TRandomFactory.Create(name)
  205. End If
  206. If GlobalRandom Then
  207. Return random_factories.Create()
  208. Else
  209. Throw "No Random installed. Maybe Import BRL.Random ?"
  210. End If
  211. End Function
  212. Rem
  213. bbdoc: Creates a new TRandom instance with the given @seed.
  214. End Rem
  215. Function CreateRandom:TRandom(seed:Int, name:String = Null)
  216. If name Then
  217. Return TRandomFactory.Create(seed, name)
  218. End If
  219. If GlobalRandom Then
  220. Return random_factories.Create(seed)
  221. Else
  222. Throw "No Random installed. Maybe Import BRL.Random ?"
  223. End If
  224. End Function
  225. Rem
  226. bbdoc: Generate random float
  227. returns: A random float in the range 0 (inclusive) to 1 (exclusive)
  228. End Rem
  229. Function RndFloat:Float()
  230. If GlobalRandom Then
  231. Return GlobalRandom.RndFloat()
  232. Else
  233. Throw "No Random installed. Maybe Import BRL.Random ?"
  234. End If
  235. End Function
  236. Rem
  237. bbdoc: Generate random double
  238. returns: A random double in the range 0 (inclusive) to 1 (exclusive)
  239. End Rem
  240. Function RndDouble:Double()
  241. If GlobalRandom Then
  242. Return GlobalRandom.RndDouble()
  243. Else
  244. Throw "No Random installed. Maybe Import BRL.Random ?"
  245. End If
  246. End Function
  247. Rem
  248. bbdoc: Generate random double
  249. returns: A random double in the range min (inclusive) to max (exclusive)
  250. about:
  251. The optional parameters allow you to use Rnd in 3 ways:
  252. [ @Format | @Result
  253. * `Rnd()` | Random double in the range 0 (inclusive) to 1 (exclusive)
  254. * `Rnd(x)` | Random double in the range 0 (inclusive) to n (exclusive)
  255. * `Rnd(x,y)` | Random double in the range x (inclusive) to y (exclusive)
  256. ]
  257. End Rem
  258. Function Rnd:Double(minValue:Double = 1, maxValue:Double = 0)
  259. If GlobalRandom Then
  260. Return GlobalRandom.Rnd(minValue, maxValue)
  261. Else
  262. Throw "No Random installed. Maybe Import BRL.Random ?"
  263. End If
  264. End Function
  265. Rem
  266. bbdoc: Generate random integer
  267. returns: A random integer in the range min (inclusive) to max (inclusive)
  268. about:
  269. The optional parameter allows you to use #Rand in 2 ways:
  270. [ @Format | @Result
  271. * `Rand(x)` | Random integer in the range 1 to x (inclusive)
  272. * `Rand(x,y)` | Random integer in the range x to y (inclusive)
  273. ]
  274. End Rem
  275. Function Rand:Int(minValue:Int, maxValue:Int = 1)
  276. If GlobalRandom Then
  277. Return GlobalRandom.Rand(minValue, maxValue)
  278. Else
  279. Throw "No Random installed. Maybe Import BRL.Random ?"
  280. End If
  281. End Function
  282. Rem
  283. bbdoc: Set random number generator seed
  284. End Rem
  285. Function SeedRnd(seed:Int)
  286. If GlobalRandom Then
  287. GlobalRandom.SeedRnd seed
  288. Else
  289. Throw "No Random installed. Maybe Import BRL.Random ?"
  290. End If
  291. End Function
  292. Rem
  293. bbdoc: Get random number generator seed
  294. returns: The current random number generator seed
  295. about: Used in conjunction with SeedRnd, RndSeed allows you to reproduce sequences of random
  296. numbers.
  297. End Rem
  298. Function RndSeed:Int()
  299. If GlobalRandom Then
  300. Return GlobalRandom.RndSeed()
  301. Else
  302. Throw "No Random installed. Maybe Import BRL.Random ?"
  303. End If
  304. End Function