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

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

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

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

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

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

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

#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <Windows.h>
#include <assert.h>

#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:

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

posted @ 2011-03-05 14:14  egmkang  阅读(...)  评论(...编辑  收藏