棋牌开发和随机数脱不开关系,因为无论牛牛、梭哈 、还是斗地主 、麻将 ,发到的牌都是要运用随机函数的 。

随机数是指理论上没有规律可循、在指定范围内每个数的出现几率相等、无法根据之前的数来预测下一个数的数列 。一般随机数生成器的基本原理是:首先初始化一个随机种子 ,其初始值可以是任意的整数;在每次获取随机数时,以随机种子为基础进行某种特殊的运算,获得一个随机数并返回之 ,然后再对随机种子进行某种运算,改变随机种子的值。这样,就可以生成许多比较随机的数 ,但同一个初始值的随机种子将会生成完全相同的随机数列。

自然界中发生的现象,只有两种可能:一种是在一定条件下,必然会出现的(或必然不会出现的)事情 ,如向上抛出的物体必然会下落等;另一种是在一定条件下,不能预见它出现的结果,如“石头 、剪子、布” ,又如每次从同一高度落下同一只硬币,就不能够预见它哪一面向上,哪一面向下 。也就是说 ,正、反两面的出现是随机的。

随机数就是这样的一种不可预知其出现数值的数字序列 ,就像每次掷同一颗质地均匀的骰子,可能出现1到6几个数字。这六个数就是随机数的序列 。

将放射性物质在一定的时间内放出的粒子数作为随机数,是最理想的。因为它没有人工的干预 ,所以它是真正的随机数。然而这种随机数,使用起来非常复杂,十分不便 。因而在实际中 ,并不采用这种方法,而是用计算机制作出来。由计算机产生的随机数,是在0和1之间的 、无穷无尽的序列。然后根据需要 ,再在此基础上扩大、转化成任意范围内的随机数 。

由计算机制作的随机数,是按照一定的公式计算出来的。这里涉及到伪随机数的概念,什么是伪随机数呢?伪随机数是使用一些称为种子(seed)的初始值通过某种算法得到的。这个算法是确定的 ,因此产生的数字序列在统计上并不是随机的 。不过,假如这个算法优良,那么结果得到的数字序列就能够通过许多合理的随机性测试 。这些数字通常被称为伪随机数(psreudorandom number)。除非你知道算法和种子 ,否则就不大能推测出这个序列。因此 ,严格来说,并不是真正的随机数,人们把它叫做“伪随机数 ” 。尽管如此 ,在实际应用中,还是能够满足要求的。伪随机数的缺点是,它具有周期性。就是说 ,经过一定的序列之后,它又重复回来了 。如果这个周期很大,对实际应用并没有什么影响。我们权且可以把它当做随机数看待罢了。随机数在生活当中有着非常广泛的应用 ,电脑游戏、各种摇彩活动 、心理试验、统计工作等,都离不开随机数 。寻找计算简单、循环周期很大的随机数,则是数学家的课题。

计算机擅长生成伪随机数 ,但不擅长生成真正的随机数。伪随机数看起来是随机的,但在算法上是基于前一个随机数计算的 。真正的随机数是不可预测的,不重复的 ,不确定的 ,并不是将前一个随机数作为输入来生成的。为随机数序列总会重复,只要使用相同的种子,便可准确再现。常用的一种情况:使用当前时间周期数初始化随机数生成器 。生成随机数的理想方式是使用随机的物理源 ,在没有硬件源的情况下,从大量不相关的源中获取随机输入,并使用一个强大的混合函数将他们混合在一起 。

    用于随机输入的有:系统日期和时间;系统启动后经过的时间(最小时间单位);用户名或ID;计算机名称或ID;系统线程和进程的状态;CPU继存器的状态;CPU周期(又称机器周期 ,机器内部各种操作大致可归属为对CPU内部的操作和对主存的操作两大类,由于CPU内部操作速度较快,CPU访问一次内存所花的时间较长 ,因此用从内存读取一条指令字的最短时间来定义,这个基准时间就是CPU周期(机器周期)。一个指令周期常由若干CPU周期构成。),栈中的内容;鼠标和游戏杆的位置;最后N次击键或控制器输入之间的时间间隔;内存状态(已分配的字节数 、可用的字节数等);硬盘驱动器的状态;最后的N个系统消息;GUI状态(窗口位置);最后N个网络分组之间的时间间隔;最后N个网络分组中的数据;存储在主存储器、视频存储器等的半随机地址中的数据;硬件标示符:CPUID ,硬盘驱动器ID,BIOSID,网卡ID等 。每种输入都提供了一定程度的随机性 ,从输入源获得的混乱程度越高 ,输出的随机性越强。

    硬件源(物理源)的输入来源:来自无源声卡(如麦克风)的输入;摄象机的输入;驱动器(硬盘,光驱,DVD)的寻道时间;INTER810芯片组的硬件RNG等。

    混合函数的使用:以非线性的方式将各项输入组合起来 ,生成输出 。DES(以及其他对称加密程序);DIFFIE-HELLMAN(以及其他公共密钥加密程序);MD5,SHA-1(以及其他哈希加密程序)。

棋牌开发中的随机数 麻将 地主 棋牌开发 棋牌技术  第1张

    局限性:速度慢,结果的随机度完全取决与输入样本的混乱程度。适用于可持续使用几天的随机数生成器种子值 。

好了 ,下面来看一下这句话是什么意思:
srand(time(NULL));
先看srand()函数有什么作用。它是用来设定种子(seed)的,例:srand(n),则n就是你设定的种子。如果每次设定的种子相同 ,比如srand(1),那么相当于不调用srand()函数(注意 :如果不显式调用srand()函数,系统只会默认调用一次srand(1)函数,即在第一个rand()函数之前调用;执行第2个第3个……rand()之前不会再调用srand(1)) ,那么接下来你再调用rand(),得到的随机数序列是相同的,这里给一个例子:

windows 32 console

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

void main( void )
{
int i;

棋牌开发中的随机数 麻将 地主 棋牌开发 棋牌技术  第2张

/ Seed the random-number generator with current time so that
the numbers will be different every time we run.
/
//srand( (unsigned)time( NULL ) );

/ Display 10 numbers. /
for( i = 0;   i < 10;i++ )
printf( ”  %6dn”, rand() );
}

注意,这个程序中 ,我把srand( (unsigned)time( NULL ) )给注释起来了 ,所以每次运行该程序时,种子是默认给出的,都是同一个值 ,(vc++中默认种子的值为1),既然种子一样,就像我前面提到的 ,算法是一定的,所以每次产生的随机数序列都是相同的 。在我的电脑上每次运行程序都产生这10个数:

41

18467

6334

26500

19169

15724

11478

29358

26962

24464

所以说这些数是伪随机数。因为真正的随机数每次产生时都不应该相同,包括这个序列也不应该相同。所以说我们要产生真正的随机数 ,就应当在每次调用rand()之前设定不同的种子,怎样做到这一点呢?使用time(NULL) 。

time(NULL)返回的是一个time_t类型的数据,实际上是一个无符号整型(unsigned int)的数据 ,在这个32位的无符号数中,高16位存放当前Date(年月日)的信息,低16位存当前放Time(时分秒)的信息 。时间是在不断变化的,所以每次调用time(NULL)返回的值是不同的(当然两次调用的时间间隔大于等于1秒才行 ,因为time_t中的信息只精确到秒)
这样srand(time(NULL));    就可以保证每次都会设定新的 种子 ,从而再调用rand()时会得到不同的随机数序列:再给个例子[2]这个例子仅仅是把前面的例子多加了一句srand(time(NULL));    )

windows 32 console

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

void main( void )
{
int i;

/ Seed the random-number generator with current time so that
the numbers will be different every time we run.
/
srand(time(NULL));

/ Display 10 numbers. /
for( i = 0;   i < 10;i++ )
printf( ”  %6dn ”, rand() );
}

这样每次运行程序都会得到10个不同的数,并且每次得到的这10个数都是不同的(注意理解我的意思,每次产生的10个数组成的序列不同)。

注意time(NULL)的作用其实就是将当前时间保存到一个UNIT中返回 ,

time_t osBinaryTime=time(NULL);相当于以下代码:

CTime   t=CTime::GetCurrentTime();

time_t   osBinaryTime=t.GetTime();

未经允许不得转载! 作者:棋牌源码网,转载或复制请以超链接形式并注明出处棋牌源码网

原文地址:《棋牌开发中的随机数》发布于:2021-08-06