从头开始学习一门编程语言,如果不能设定一个明确的目标:我要用他来干什么,解决什么问题。那么整个过程可以说是相当痛苦了,而且还很快会忘!所以今天咱们就来实际解决一个问题:用蒙特卡洛法实现简易的模拟抽卡功能!
复习个屁都鸽了一个多月了,忘了之前讲的啥了,自己翻翻前面的都不难!
(喜爱炉石的小朋友看过来)做一个预测抽卡的功能:假设所有的卡牌种类数为S,抽取每张卡牌的概率是一定的即1/S,想求在有放回的抽取了N张卡牌后,获得的卡牌种类的期望X是多少。我猜此刻数学系的小伙伴儿已经带着一脸不屑拿起笔开始算了,好的,咱们比谁快!
蒙特卡罗法也称统计模拟法、统计试验法。是把概率现象作为研究对象的数值模拟方法。是按抽样调查法求取统计值来推定未知特性量的计算方法。蒙特卡罗是摩纳哥的著名赌城,该法为表明其随机抽样的本质而命名。故适用于对离散系统进行计算仿真试验。在计算仿真中,通过构造一个和系统性能相近似的概率模型,并在数字计算机上进行随机试验,可以模拟系统的随机特性。百度百科
很low的界面如图,填写如下信息:总卡牌数、抽卡次数、模拟次数,程序会读取相应值。最后的期望显示在cells(8,”C”)
1、先定义变量名称类型,然后把数值读进去。为了方便理解咱们还是low一点直接用汉字。这里讲解一下第一行Application.ScreenUpdating=False,从名字上就可以看出叫“屏幕刷新”,然后赋值为False(否),即“屏幕不刷新”。这样每次输入一个值就不用在Excel中展示,可以大大提高程序的运行速度。程序在执行完毕后会自动赋值为True,我们就能看到结果了。类型,为什么有的用Integer,有些用Long。模拟次数很可能会超过30000,所以改成Long型(前面的知识点不赘述了)。
代码段2、思路。a)定义一个手里的牌库,当然种类需要跟总卡牌数一样多。b)然后每抽到一张牌,就更新手牌库,对应的种类就赋值为1,代表已拥有。c)在抽取了“抽卡次数”张卡牌后,记录当前拥有的卡牌数:遍历手牌,如果为1,记录值。添加到一个总计值中,回头都模拟完了除以模拟次数就是期望值。d)以上bc两个过程重复“模拟次数”次,记得每次重置手牌。3、继续写代码a)定义了一个总计值,但是模拟次数多了Long也可能会溢出,管不了那么多了!b)定义了手牌,长度匹配总卡牌数,但是需要在后面Redim(重新定义)一下数组长度,如果直接写成Dim手牌(1to总卡牌数)asinterger会报错,因为Dim不支持定义动态长度,锅都在“总卡牌数”是一个变化的值!c)两层的循环,第一层:模拟次数;第二层,抽卡的次数。这个理解吧!d)每一次模拟的时候,清空手牌,Erase擦掉就可以啦!Erase只可以对数组使用,意义为初始化数组(理解成“擦掉”也是可以的。)e)这里有一个知识点,就是Erase和Redim的顺序。我们在Dim手牌()asinteger时,定义的是一个非固定数组,所以在Erase这个数组时,会重置到这个最开始定义的情况,数组长度就变为了0,所以需要重新redim一下数组长度。
代码段4、最关键的逻辑出现了!a)定义了一个临时的整数TempInt,一会用来存放随机出来的卡牌ID。b)Randomize,重置随机数种子。如果不写这句,很有可能你每次运行随机出来的第一个数都是一样的。(不过影响不大)。c)Rnd随机数,系统会自动生成一个[0,1)左开右闭区间的随机数。所以Rnd*100,生成随机数的区间就变成了[0,100),所以Rnd*100+1就变成了[1,101),因为取不到101这个最大值,所以当用Int函数取整时,会把小数部分都丢掉,我们就完成了在[1,100]区间随机选取整数值的功能。d)其他部分自行看代码理解!已经没生知识点了!
代码段5、结果:直接上图!蒙特卡洛法的结论:经过1000次的模拟,在卡片种类在100种情况下,每次抽取100张卡平均会得到63.322种不同类型的卡牌。
演示结果6、其他模拟条件可以随意更改。
演示结果
电脑卡死了
(电脑死机了)注意1、对于蒙特卡洛法来说,模拟次数越多就越接近真实结果。2、但永远不会得到一个准确结果,满足精度要求即可。3、看你自己电脑性能,模拟次数别手贱填太多,容易死机。
1、自己照着写一遍,然后再默写一遍,你就无敌了!2、可以拓展一下,在总卡牌数一定、模拟次数一定时,设定分别抽取不同的卡牌数,然后模拟出不同的对应结果。可以思考一下如何取值,结果如何呈现。3、可以试着开发一下解决其他问题的模拟工具,比如买彩票!假设一个人每天买一注,平均需要连续购买多少天才能中一等奖!平均花费多少钱!(算完你就再也不碰了戒赌)
1、再讲一个While循环,这个真是没办法确实不能完全被For循环替代。2、写了一堆Bug,咋整?我自己看着都懵!(没错,讲解一下调试方法。)3、以前的预告留着挖坑了,下期再介绍一些字符串处理的实战,帮你把兴趣搞上来!