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

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;
                }
        }
}

你可能感兴趣的:(游戏,算法,Blog,Google,Flash)