• [随机数]网游垫装备及其思考


      学而无术者比不学无术者更加愚蠢       ----富兰克林

     

      玩游戏的,总归会有很多心得,网上略微搜一下,就会发现很多垫装备的言论,很多人相信垫装备有用.这是问题!!

      OK,让我们来把问题简化一下,因为装备打造合成概率实在是繁复,所以存在必要的简化.问:

     

      连续的抛一枚硬币,失败N次之后,第N+1次失败的概率是多少?会不会比50%高(!!!这是我们真正要搞定出的问题).

     

      抛硬币,是随机事件.理论上讲,成功失败的概率各50%(头像朝上与否),而且任何两次随即之间完全无关.否则他就不叫随机事件了.当年概率论学的不好,但是头脑里面还有一点意识,我不相信连续的失败可以明显提高成功的概率!

      但是理论学的太差,我不能证明第N+1次的概率还是那么高.....好吧,我只能写代码,看看模拟的真实情况是什么样子,来代码:

    #include <stdlib.h>
    #include <time.h>
    #include <iostream>
    #include <Windows.h>
    #include <assert.h>
    #pragma comment(lib, "advapi32.lib")
    
    #define RANDOM_TIMES	1000000
    #define FAIL_TIMES		5
    #define FAIL_PERCENT	50
    #define PERCENT_MAX		100
    
    //#define C_RANDOM
    
    #ifdef C_RANDOM
    //nop
    #else
    
    #define RAND_MAX		65535
    static HCRYPTPROV		hProvider = 0;
    static const DWORD		dwLength = 2;
    static BYTE				pbBuffer[dwLength] = {};
    
    #endif
    
    static void 
    random_init()
    {
    #ifdef C_RANDOM
    	srand((int)time(0));
    #else
    	DWORD result =::CryptAcquireContextW(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
    	assert(result);
    #endif
    }
    
    static void 
    random_close()
    {
    #ifdef C_RANDOM
    	//nop
    #else
    	::CryptReleaseContext(hProvider, 0);
    #endif
    }
    
    static int 
    _random()
    {
    	unsigned short _rand_value = 0;
    #ifdef C_RANDOM
    	_rand_value = (unsigned short)rand();
    #else
     	DWORD result = ::CryptGenRandom(hProvider, dwLength, pbBuffer);
    	assert(result);
    	_rand_value = *(unsigned short*)pbBuffer;
    #endif
    	return _rand_value;
    }
    
    static long random_count = 0;
    static int 
    random_result()
    {
    	int times = 0;
    	while(times < FAIL_TIMES)
    	{
    		int _num = _random();
    		random_count++;
    		if((1.0f*_num/RAND_MAX) > (1.0f*FAIL_PERCENT/PERCENT_MAX))
    		{
    			times++;
    		}
    		else
    		{
    			times = 0;
    		}
    	}
    	random_count++;
    	return _random();
    }
    
    
    int main(int argc, char* argv[])
    {
    	random_init();
    
    	long times_total = 0;
    	long times_fail = 0;
    	for(int times = 0; times < RANDOM_TIMES;++times)
    	{
    		int x = random_result();
    		if((1.0f*x/RAND_MAX) > (1.0f*FAIL_PERCENT/PERCENT_MAX))
    			times_fail++;
    		times_total++;
    	}
    	std::cout<<"total: "<<times_total<<std::endl;
    	std::cout<<"fail: "<<times_fail<<std::endl;
    	std::cout<<"random_count: "<<random_count<<std::endl;
    	system("pause");
    
    	random_close();
    	return 0;
    }
    

     

      这里用了两种随机数的实现,一种是标准C随机数,另外是CryptGenRandom.Windows下面没/dev/random和/dev/urandom,所以用哪个API代替.

      代码我不想做过多的解释,比较重要的就那几个宏,没事干自己改变一下宏,运行一下,看看结果:-)我这边CryptGenRandom的两次结果:

     

    total: 1000000
    fail: 499497
    random_count: 62905788
    请按任意键继续. . .
    
    total: 1000000
    fail: 499914
    random_count: 62979706
    请按任意键继续. . .
    

      另外再上一次标准C随机数的运行结果:

     

    total: 1000000
    fail: 500330
    random_count: 63103246
    请按任意键继续. . .
    

      可以看到,几次随即模拟的结果,差不多是相似的:连续失败N次之后,第N+1次的概率是不变的. 这才叫随机事件.:-)

     

      但是问题还没完,这里需要架设随机数的质量非常的好,两次随机之间没有关联.事实上,标准C的随机数很难做到这一点(伪随机数生成器).伪随机数,有可能被破解,预测;真随机数不会:-D.

      所以,网游在进行跟RMB相关的随机时,可以考虑一下真随机数,或者是质量稍微好一点的RNG;跟RMB无关的,libc的rand/rand_r足矣~~~~

    PS:

    记得我们一个策划,给怪物掉落的概率设置的太低(20%还是25%),然后打了据说有四十几个怪,一个东西都没掉....后来换成rand_r,效果好了很多.

     

    参考:

    http://msdn.microsoft.com/en-us/library/aa379942(v=vs.85).aspx

  • 相关阅读:
    I.MX6ULL LED C程序(转自左忠凯)
    I.MX6ULL的LED汇编程序
    Linux中的信号
    springboot的模板引擎之简介区分(一)
    springboot常用Starter介绍
    springboot拦截器之Filter和拦截器Interceptor之间的区别(六)
    springboot拦截器之多个自定义拦截器Interceptor的执行顺序(五)
    springboot拦截器之自定义拦截器Interceptor以及新旧配置的对比(四)
    springboot拦截器之自定义监听器listener(三)
    springboot拦截器之自定义原生servlet(二)
  • 原文地址:https://www.cnblogs.com/egmkang/p/1971586.html
Copyright © 2020-2023  润新知