VBA新手教程:抽卡模拟实战(3)

兴趣真的是最好的老师

从头开始学习一门编程语言,如果不能设定一个明确的目标:我要用他来干什么,解决什么问题。那么整个过程可以说是相当痛苦了,而且还很快会忘!所以今天咱们就来实际解决一个问题:用蒙特卡洛法实现简易的模拟抽卡功能!

复习一下

复习个屁都鸽了一个多月了,忘了之前讲的啥了,自己翻翻前面的都不难!

今天的小目标

(喜爱炉石的小朋友看过来)
做一个预测抽卡的功能:假设所有的卡牌种类数为S,抽取每张卡牌的概率是一定的即1/S,想求在有放回的抽取了N张卡牌后,获得的卡牌种类的期望X是多少。
我猜此刻数学系的小伙伴儿已经带着一脸不屑拿起笔开始算了,好的,咱们比谁快!

正经的教程开始

蒙特卡洛法

蒙特卡罗法也称统计模拟法、统计试验法。是把概率现象作为研究对象的数值模拟方法。是按抽样调查法求取统计值来推定未知特性量的计算方法。蒙特卡罗是摩纳哥的著名赌城,该法为表明其随机抽样的本质而命名。故适用于对离散系统进行计算仿真试验。在计算仿真中,通过构造一个和系统性能相近似的概率模型,并在数字计算机上进行随机试验,可以模拟系统的随机特性。——百度百科
总结:构造相同环境多次试验最后得到的平均值即为近似值。

很Low的界面

很low的界面
如图,填写如下信息:
总卡牌数、抽卡次数、模拟次数,程序会读取相应值。
最后的期望显示在cells(6,”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 手牌(1 to 总卡牌数) as interger会报错,因为Dim不支持定义动态长度,锅都在“总卡牌数”是一个变化的值!
c) 两层的循环,第一层:模拟次数;第二层,抽卡的次数。这个理解吧!
d) 每一次模拟的时候,清空手牌,Erase擦掉就可以啦!Erase只可以对数组使用,意义为初始化数组(理解成“擦掉”也是可以的。)
e) 这里有一个知识点,就是Erase和Redim的顺序。我们在Dim 手牌() as integer时,定义的是一个非固定数组,所以在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、 以前的预告留着挖坑了,下期再介绍一些字符串处理的实战,帮你把兴趣搞上来!

今日毒奶

宇宙可能就是上帝掷骰子模拟出来的,蒙特卡洛无敌!

墨迹在最后

欢迎在下方留言与我们一起探讨学习营造河蟹氛围。
讲解错误、疏漏、难于理解的地方不欢迎批评指正!生气!
你就留言指责吧,不会让你上墙的!
就这样再见!

终于可以开通打赏了哈哈哈哈!我觉得自己要致富了!
你的4块3毛8是我前进的动力!
然鹅如果你对我有不满有批评我还是不会让你上墙的!

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值