尊重博主版权,该博客引用了以下博客内容: 详谈JS中实现种子随机数及作用

最近开发遇到了一个新功能,要求做到相同随机数。何为相同随机数,即每次使用相同的随机种子,产生相同的数字。在网上找了一下,只找到上面一篇博客,所以,这里为了让更多的人了解,博主决定自己写一篇博客,将原博客内容引用过来,让更多的人能够了解到这一内容。

其实,我们平时在开发过程中,经常会遇到随机数问题,例如,随机抽奖,微信飞机大战中,随机产生敌人位置等等。但实际上这些都是伪随机,用C语言开发的时候,使用random函数的时候,会发现,当我们直接调用这个方法的时候,每次运行都产生相同的随机数,所以,在调用这个方法的时候,都会用时间来做随机种子。当然,在JS中直接调用Math.random方法,就能直接产生随机数,这里不需要设置时间种子,JS底层已经为我们设置了随机种子,而且,每次是不一样的。既然是伪随机,那么,我们可以根据这个特性,每次设置相同的随机数,每次运行的时候,都产生相同的随机数。

Math.seed = 5; 
Math.seededRandom = function(max, min) { 
    max = max || 1;
    min = min || 0; 
    Math.seed = (Math.seed * 9301 + 49297) % 233280; 
    var rnd = Math.seed / 233280.0;
    return min + rnd * (max - min); 
for (var i= 0; i<10; i++) {
     console.log(Math.seededRandom()); 
这里的Math.seed是自己定义的一个变量,Math.seededRandom也是自己定义的一个方法,如果不喜欢这种方式,也可以定义成其他的名字。下面,引用原博主的内容: 

运行如上代码你会发现如果种子Math.seed不变,那么生成的随机数是不会变化的,哦了,如果引入这个函数,那么重现游戏场景可以实现了,虽然还需要做更多的细节处理,但机制上是能保证的,本文的重点不是实现一个这样的游戏。

本文的重点是:(Math.seed * 9301 + 49297) % 233280,为什么会是这三个值,而不是其它的到底这三个数字有什么神秘的

像Math.seededRandom这种伪随机数生成器叫做线性同余生成器(LCG, Linear Congruential Generator),几乎所有的运行库

提供的rand都是采用的LCG,形如:

I n+1=aI n+c(mod m)

生成的伪随机数序列最大周期m,范围在0到m-1之间。要达到这个最大周期,必须满足:
1.c与m互质

2.a - 1可以被m的所有质因数整除

3.如果m是4的倍数,a - 1也必须是4的倍数

以上三条被称为Hull-Dobell定理。作为一个伪随机数生成器,周期不够大是不好意思混的,所以这是要求之一。因此才有了:

a=9301, c = 49297, m = 233280这组参数,以上三条全部满足。

下面,我们来继续讨论刚刚上面的恢复敌人位置的问题。现在我们可以自己产生随机数了,而且,按照我们的要

求,可以每次都产生相同的随机数了。也就是说,我们可以每次随机敌人的位置了。

这时有人会问,为什么要每次产生相同的随机数呢?其实,这里有很大的用处,例如,我们在玩一个游戏的时候,随机产生了几个敌人的位置,这个时候,如果网络不好,重新连接进来,会发现,敌人的位置变了,此时,玩家看起来,就会发小屏幕上敌人位置发生了跳动,从玩家体验的角度来说,这是一种很差的体验。有人会说,为什么不在恢复现场的时候,直接将敌人的位置全部发送回来呢?下面,我来举一个简单的例子,来说明这个问题:

如果我们将敌人定义为1~10种类型,那么,正常情况下,如果我们为了在重新进入游戏的时候,继续上面的进度进行游戏,我们会将敌人类型和敌人位置都传回来,此时,我们传回来的数据格式,我用JSON简单来表示,大概应该是这种:

'enemyList':[{ 'enemyType':1, 'x':33, 'y':25 'enemyType':2, 'x':45, 'y':67 'enemyType':3, 'x':84, 'y':12

那么,如果我们需要在服务器记录所有敌人的位置,如果用户量比较大,其实这数据量就挺大的了,而且,在重新进入游戏的时候,其实传回来的数据也是不少的。那下面,我们换一种思路,这次,我们每次计算玩家的位置都用随机数来计算,然后,当我们重新进入游戏的时候,服务器将相同的随机数种子发送到客户端,让服务器自己计算位置,同时将敌人的类型发回来,大概的数据格式如下:

'seed': 12345, 'enemyList':[1,2,3]
有没有觉得很精简,这样,不仅服务器储存的数据量大大减少,而且,服务器给客户端发包的时候,数据量也较少了好多,差不多是之前的1/3,这在开发中,真的好处很多的,玩家网络不好,中间网络断了,重新连接,可以恢复玩家当前的场景,网络不好,重连的时候,数据量减少了好多,如果用第一种办法,那重连了数据量反倒挺大的,这并不符合开发的要求啊,所以,在这里,随机数就真的起了大的作用。

以上就是产生相同随机数的方法,如果有什么描述不清楚地地方,欢迎大家留言交流!

尊重博主版权,该博客引用了以下博客内容:详谈JS中实现种子随机数及作用最近开发遇到了一个新功能,要求做到相同随机数。何为相同随机数,即每次使用相同的随机种子,产生相同的数字。在网上找了一下,只找到上面一篇博客,所以,这里为了让更多的人了解,博主决定自己写一篇博客,将原博客内容引用过来,让更多的人能够了解到这一内容。其实,我们平时在开发过程中,经常会遇到随机数问题,例如,随机抽奖,微信飞机大战中,随... 用于JavaScript的种子式伪随机生成器。 它可以用作普通脚本或。 字是使用单种形式的生成的。 尽管此方法对于大多应用程序来说都是可行的,但在密码学上却不强。 jsrand支持在组上保存和恢复生成器状态以及常见操作: (选择随机元素), (随机选择元素), (随机选择元素而不重复)和 。 choice choices getState inRange intInRange noConflict random randomize sample setState shuffle $ npm install seeded-rand 只需下载dist / jsrand.min.js和(可选) dist / jsrand.mi https://blogs.unity3d.com/cn/2015/01/07/a-primer-on-repeatable-random-numbers/ (英文原版) http://www.manew.com/thread-37144-1-1.html 不管创建什么样的程序,几乎都离不开随机数.如果您想多次生成同样的结果,这就需要随机数是可重复的。   在本片文章中... 使用相同的随机种子,换一个设备,还能得到相同的随机序列吗? 由于对随机数生成理解不够深刻,还引发了一次跟同事之间的小讨论。不知为不知,在这里承认自己以前对随机数理解有限,把过程和经验记录于此。 随机数的基础用法和特性 编程过程中,随机数的基础用法和特性广为人知。但为了防止有对这个概念还不清楚的新手,还是先简单说明一下。 编程获随机数的基本做法是: 在程序初始... Math.seededRandom = function (max, min) { max = max || 1 //(设置最大值) min = min || 0 //(设置最小值) Math.seed = (Math.seed * 9301 + 49297) % 233280 var rnd = Math.seed / 233280.0
游戏中经常要用到随机数,但如果一个没有随机种子的的生成器,就没法重复之前的随机数了。js的Math.random就用不了随机种子,只好自己弄了一个,有了随机种子,每次只要传入相同的种子,都会得到同样的随机数。直接代码: function seededRandom(seed, min, max) { seed = (seed * 9301 + 49297) % 233280; Javascript 的Math.random可以做前两个约束,但第三个是开放的,这就是问题所在; 如果您不能每次都可靠地重现相同的一组伪随机,那么这又是另一个可能导致测试运行期间出现不必要差异的因素。 鉴于该库的性能也可能会有所不同并成为一个因素,因此有一个例程旨在生成一组给定长度的随机数。 这个库是模块化的。 它有一组通用函两个不同的生成器。 seed (x) :将生成器播种到x 。 generate() :生成一个介于 0 和 1 之间的浮点。 generate (min, max) :在min和max之间生成一个浮点。 integer () :生成 0 到 1 之间的整。 integer (min, max) :生成
randoma用户友好的伪随机生成器(PRNG),这在密码上是不安全的。 安装$ npm install randoma用法const Randoma = require('randoma'); const random =新的Random randoma用户友好的伪随机生成器(PRNG),这在密码上不是安全的。 安装$ npm install randoma用法const Randoma = require('randoma'); const random = new Randoma({seed:10}); random.integer(); // => 2027521326 random.integer(); // => 677268843(新的Randoma({seed:':unicorn:'})。integer()); // => 1659974344(new Randoma({seed:':unicorn:'})。integer()); // => 1659974344 API const random = new Randoma(options)options类型:对象
有一个随机数生成器:首先输入一个正整n表示要生成随机数的位,然后它会生成一个n位的不包含前导为0的正十进制生成器还有一个性质,就是它生成的第i位上(从左到右)的字永远不等于i。 比如生成的位长度为1的,那它不能生成0和1,;如果位为2,不能生成10,11,12,13,14,15,16,17,18,19,22,32,42,54,62,72,82,92 求给定输入n,它一共能生成
是的,JavaScript中的Math.random()生成的是伪随机,但是可以使用真随机数生成器来生成0到23之间的真随机数。 一种方法是使用外部真随机数生成器API。例如,可以使用Random.org的API,该API提供了真正的随机数。您可以使用XMLHttpRequest向其API发送请求,并使用返回的随机数。 另一种方法是使用硬件随机数生成器。硬件随机数生成器是依赖于物理过程的设备,例如热噪声,放电噪声等。它们可以生成真正的随机数。在Web应用程序中,可以使用WebCrypto API中提供的硬件随机数生成器。 以下是使用Random.org API生成0到23之间的真随机数的示例代码: ```javascript const xhr = new XMLHttpRequest(); xhr.open('GET', 'https://www.random.org/integers/?num=1&min=0&max=23&col=1&base=10&format=plain&rnd=new'); xhr.onload = function () { if (xhr.status === 200) { const randomNumber = parseInt(xhr.responseText); console.log(randomNumber); } else { console.error('Error generating random number'); xhr.send(); 请注意,这种方法需要从外部API获随机数,因此可能会受到网络延迟和其他问题的影响。
maystar_rnd: 增加addObserver ,插入和拨出耳机之后, handleRouteChange 这个方法不调用。[code=objc] NotificationCenter.default.addObserver(self, selector: #selector(handleRouteChange), name: AVAudioSession.routeChangeNotification, object: AVAudioSession.sharedInstance()) /// 监听耳机插拔 @objc func handleRouteChange(_ notification: Notification) { guard let userInfo = notification.userInfo, let reasonValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt, let reason = AVAudioSession.RouteChangeReason(rawValue:reasonValue) else { return switch reason { case .newDeviceAvailable: // Handle new device available. print("jinrule") case .oldDeviceUnavailable: // Handle old device removed. print("bachule") player?.play() default: () [/code]