`

[转]利用伪随机数压缩保存游戏状态

阅读更多
http://uh.9ria.com/space-12147-do-blog-id-4007.html

计算机是无法计算“真”随机数的,而只能计算“伪”随机数。所谓伪随机数,并不是按投硬币的方法来实现,而是从一个特定数开始,通过算法从一个“随机值”计算另一个“随机值”,并保证两者关系尽可能看上去混乱而且最终在区间内数值分配均匀。
因为伪随机数是按上一个数作为参数计算出来的,所以它需要一个初值,而这个初值则被称为“随机种子”。一般这个随机种子都是取的当前系统时间。也就是说,两台电脑在同一毫秒初始化并生成的第一个随机数一定是同一个。
因为伪随机数仅仅是计算得到的,它除了随机种子外并没有偶然性。如果你给定一个随机种子,通过这个随机种子计算出的所有“随机数”一定都是一样的。
一般的语言其实都是有设置“随机种子”的功能的,但AS3没有,所以只能自己实现随机算法。如果想利用伪随机数的特性,可以用下面这个类来生成随机数(创建后用nextInt方法,参数是大小范围)
http://code.google.com/p/ghostcat/source/browse/trunk/GhostCat/src/ghostcat/util/RandomSeed.as


下面我就来说说利用这个特性能做什么。

比如我们需求要显示一个电影院的所有观众,他们有多种类型,会坐在不同的地方,不同的进入和离开时间。而服务端并不关心影院的具体情况,只需要你显示出正确的人数即可。那么,它就不需要计算出所有的信息并传递到客户端,而是让客户端自己随意生成,也就是使用随机数生成。但问题是,如果简单使用随机数生成而不保存状态,关闭游戏再进,或者在别的玩家眼里,看到的影院状态就会完全不同(除了总人数)

这时候就可以利用伪随机数。然服务端生成一个随机数保存起来来作为随机种子,客户端使用这个种子来生成自己需要的随机数序列。因为同样种子生成的随机数序列一定是相同的,那么就可以重现第一次生成影院状态的过程,并得到相同的结果。



package ghostcat.util
{
        import flash.utils.ByteArray;

        /**
         * 伪随机数 
         * @author flashyiyi
         * 
         */
        public class RandomSeed
        {
                private static const MULTIPLIER_HIGH:uint=5;
                private static const ADDEND:uint=11;
                private static const MULTIPLIER_LOW:uint=58989;
                private static const MULTIPLIER_MID:uint=57068;
                
                private var seedHigh:uint;
                private var seedLow:uint;
                private var seedMid:uint;
                
                private static var seedExtra:uint=2353648897;
                
                public function RandomSeed(high:uint=0x80000000, low:uint=0)
                {
                        if (high == 0x80000000 && low == 0)
                        {
                                var bytes:ByteArray = new ByteArray();
                                bytes.writeDouble(new Date().time);
                                bytes.position = 0;
                                high = bytes.readUnsignedInt() + seedExtra;
                                low = bytes.readUnsignedInt() + (high >>> 16);
                                seedExtra++;
                        }
                        setSeed(high, low);
                        return;
                }
                
                public function setSeed(high:uint, low:uint):void
                {
                        this.seedHigh = high & 65535 ^ MULTIPLIER_HIGH;
                        this.seedMid = low >> 16 & 65535 ^ MULTIPLIER_MID;
                        this.seedLow = low & 65535 ^ MULTIPLIER_LOW;
                        return;
                }
                
                private function next(max:uint):uint
                {
                        var v2:Number = 0;
                        var v3:Number = 0;
                        var v4:Number = 0;
                        
                        v4 = seedLow * MULTIPLIER_LOW;
                        v2 = seedLow * MULTIPLIER_HIGH + seedMid * MULTIPLIER_MID + seedHigh * MULTIPLIER_LOW;
                        v3 = seedLow * MULTIPLIER_MID;
                        v2 = v2 + (v3 >>> 16);
                        v3 = v3 & 65535;
                        v3 = v3 + seedMid * MULTIPLIER_LOW;
                        v2 = v2 + (v3 >>> 16);
                        v3 = v3 & 65535;
                        v3 = v3 + (v4 >>> 16);
                        v2 = v2 + (v3 >>> 16);
                        v4 = v4 & 65535;
                        v3 = v3 & 65535;
                        v2 = v2 & 65535;
                        v4 = v4 + ADDEND;
                        v3 = v3 + (v4 >>> 16);
                        v2 = v2 + (v3 >>> 16);
                        v4 = v4 & 65535;
                        v3 = v3 & 65535;
                        v2 = v2 & 65535;
                        seedLow = v4;
                        seedMid = v3;
                        seedHigh = v2;
                        if (max == 0)
                                return 0;
                        
                        return (v2 << 16 | v3) >>> 32 - max;
                }
                
                public function nextInt(max:int):uint
                {
                        var v2:Number = 0;
                        var v3:Number = 0;
                        
                        if (max == 0 || !((max & 2147483648) == 0))
                                throw new Error();
                        
                        if ((max & -max) == max)
                        {
                                v2 = 0;
                                if ((max & 4294901760) != 0)
                                {
                                        v2 = v2 + 16;
                                }
                                if ((max & 4278255360) != 0)
                                {
                                        v2 = v2 + 8;
                                }
                                if ((max & 4042322160) != 0)
                                {
                                        v2 = v2 + 4;
                                }
                                if ((max & 3435973836) != 0)
                                {
                                        v2 = v2 + 2;
                                }
                                if ((max & 2863311530) != 0)
                                {
                                        v2 = v2 + 1;
                                }
                                return next(v2);
                        }
                        do 
                        {
                                v2 = next(31);
                                v3 = v2 % max;
                        }
                        while ((v2 - v3 + max - 1) < 0);
                        return v3;
                }
        }
}
分享到:
评论

相关推荐

    CubeUpsetCreater:创建 2~7 个有序魔方翻转并创建 3 个有序魔方的打乱图案

    4. **随机数生成**:打乱魔方的过程可能依赖于随机数生成,这需要了解如何在Java中生成伪随机数。 5. **错误修复**:识别和修复“创建中断模式”的错误是软件开发的重要部分,这涉及到调试技巧和理解程序执行流程。...

    凌阳单片机SPCE061A讲义

    - **堆栈**:一种特殊的内存区域,用于保存函数调用过程中的状态信息。 - **FLASH**:非易失性存储器,用于存放程序代码和常量数据。 ##### 2.3 SPCE061A的输入/输出接口 - **I/O端口结构**:支持数字输入输出。 - ...

    python标准库

    `random`模块提供了生成伪随机数的函数。 ##### 2.17 whrandom模块 `whrandom`模块提供了基于Mersenne Twister算法的随机数生成器。 ##### 2.18 md5模块 `md5`模块提供了MD5哈希函数,用于生成消息摘要。 #####...

    vc++ 应用源码包_1

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_2

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_6

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_5

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_3

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

Global site tag (gtag.js) - Google Analytics