编程学C#(5):构建蜂巢模拟系统

来源:互联网 发布:淘宝订单号什么意思 编辑:程序博客网 时间:2024/04/29 12:55

编程学C#(5):构建蜂巢模拟系统

 

一、     上帝创世

       在宇宙天地尚未形成之前,黑暗笼罩着无边无际的空虚混饨,上帝那孕育着生命的灵运行其中,投入其中,施造化之工,展成就之初,使世界确立,使万物齐备。

       上帝用七天创造了天地方物。这创造的奇妙与神秘非形之笔墨所能写尽,非诉诸言语所能话透。

 

       第一日,上帝说:“要有光!”便有了光。上帝将光与暗分开,称光为昼,称暗为夜。于是有了晚上,有了早晨。

       第二日,上帝说:“诸水之间要有空气隔开。”上帝便造了空气,称它为天。

       第三日,上帝说:“普天之下的水要聚在一处,使旱地露出来。”于是,水和旱地便分开。上帝称旱地为大陆,称众水聚积之处为海洋。上帝又吩咐,地上要长出青草和各种各样的开花结籽的蔬菜及结果子的树,果子都包着核。世界便照上帝的话成就了。

       第四日,上帝说:“天上要有光体,可以分管昼夜,作记号,定节令、日子、年岁,并要发光普照全地。”于是上帝造就了两个光体,给它们分工,让大的那个管理昼,小的那个管理夜。上帝又造就了无数的星斗。把它们嵌列在天幕之中。

       第五日,上帝说,“水要多多滋生有生命之物,要有雀鸟在地面天空中飞翔。”上帝就造出大鱼和各种水中的生命,使它们各从其类;上帝又造出各样的飞鸟,使它们各从其类。上帝看到自己的造物,非常喜悦,就赐福这一切,使它们滋生繁衍,普及江海湖汊、平原空谷。

       第六日,上帝说:“地要生出活物来;牲畜、昆虫、野兽各从其类。”于是,上帝造出了这些生灵,使它们各从其类。上帝看到万物并作,生灭有继,就说:“我要照着我的形象,按着我的样式造人,派他们管理海里的鱼、空中的鸟、地上的牲畜和地上爬行的一切昆虫。”上帝就照着自己的形象创造了人。上帝本意让人成为万物之灵,就赐福给他们,对他们说:“要生养众多,遍满地面,治理地上的一切,也要管理海里的鱼、空中的鸟和地上各样活物。”按《圣经》的说法,人类是这个世界的管理者和支配者。

 

        第七日,天地万物都造齐了,上帝完成了创世之功。在这一天里,他歇息了,并赐福给第六天,圣化那一天为特别的日子,因为他在那一天完成了创造,歇工休息。就这样星期日也成为人类休息的日子。

"造化钟神秀,阴阳割分晓。"上帝就是这样开辟鸿蒙,创造宇宙万物的。

 

二、     太极生两仪

       老子的《道德经》第四十二章:

       道生一,一生二,二生三,三生万物,万物负阴而抱阳,冲气以为和。

       意思是:道生一,一是太极;一生二,二是阴阳;二生三,三是天地人;三生万物,万物是万事万物。

       道是独一无二的,道本身包含阴阳二气,阴阳二气相交而形成一种适匀的状态,万物在这种状态中产生。万物背阴而向阳,并且在阴阳二气的互相激荡而成新的和谐体。

 

       曾仕强教授在《易经的奥秘》中讲:

        “太极生两仪,两仪生四象,四象生八卦。一阴一阳之谓道,天地人三才不能分割。”

 

        “从太极到八卦是创造,八卦以后就是演化,创造和演化是同时存在的。自然把人创造出来以后,人就开始不断演化,并不是每个时代都创造不同的人。”

 

三、     蜂巢模拟系统

哦,现在让我们也享受一下构建的乐趣,模拟一个蜂巢系统。

第一天,我们说:“要有花。”便有了花(Flower类),花会变老,长出花粉,并且最终会枯萎、凋谢。

第二天,我们说:“要有蜜蜂。” 便有了蜜蜂(Bee类),它有几个不同的状态(在某个花朵上采集花粉,返回蜂巢),并且它会根据其状态知道要做什么。

第三天,我们说:“要有蜂巢。” 便有了蜂巢(Hive类),它包含有入口,出口,幼蜂培育地,还有把花粉转化为蜂蜜的蜂蜜工厂。

第四天,我们说:“要有世界。” 便有了世界(World类),它无时无刻不在管理蜂巢,花朵和蜜蜂。

第五天,我们说:“要有信息。”于是创建一个主窗体,它从其他类那儿收集统计数据,并且维持世界的运行。


第六天,我们说:“开始吧。”于是程序运转,蜂巢系统开始不断演化,花开花谢,蜜蜂采蜜、酿蜜,繁衍生息。

 

1、       花(Flower类)

Flower 类需要一个由 Point 定义的位置,有年龄,还有寿命。随着时间的流逝,鲜花会变老。然后,当年龄到达了寿命值的时候,花朵会死去。

写出基本的类框架 Location  Age  Alive  Nectar  NectarHarvested 都是自动属性。 NectarHarvested 是可写的,其他四个都是只读的。

②给类添加一些常量:

LifeSpanMin ,花朵的最短寿命

LifeSpanMax ,花朵的最长寿命

MaxNectar ,一朵花朵可以含有多少花粉

NectarAddedPerTurn ,花朵每次变老的时候会增加多少花粉

NectarGatheredPerTurn ,一个生命周期中有多少花粉会被采集

③创建构造方法:

Flower类的构造方法需要接受一个 Point 来指明花朵的位置,还要接受一个 Random 类的实例。

④编写HarvestNectar ()方法的代码

每次调用这个方法的时候,它都会去检查每个生命周期中采集的花粉量是否大于剩余的花粉量。如果是的话,返回0。否则,就应该把在这个生命周期中采集的花粉量从剩余的花粉量中减去,并且返回收集了多少花粉。

⑤编写Go ()方法的代码

这个方法促使花朵变老。假设每次调用这个方法的时候,一个生命周期就会逝去,所以要适当的更新花朵的年龄。你也需要看看年龄是否大于花朵的寿命。如果是的话,花朵死亡。

假设花朵还是活着的,你需要给它添加花在每个生命周期中获得的花粉量。确保去检查花可以容纳的最大花粉量,不要超过那个值。

我们最后要把它做成有动画效果的,会有蜜蜂飞来飞去的图片。

 

2、       蜜蜂(Bee类)

花朵上的花粉准备好要被采集,所以我们需要一个Bee 类。 蜜蜂知道自己的年龄,知道自己是否在蜂巢中,知道自己可以采集多少花粉。我们还会添加一个方法来把蜜蜂向着某个特定的目的地移动。

蜜蜂可以做很多事情。给蜜蜂创建一个叫做BeeState 的枚举。还需要创建一个只读的自动属性,叫做 CurrentState,它用来让蜜蜂保存自己的状态(6种)。把蜜蜂的初始状态设置为 idle (空闲),还有,在 Go ()方法中,写一个switch 语句,其中要含有枚举中每个枚举项的选项。

 

3、       蜂巢(Hive 类)

我们已经有了蜜蜂和充满花粉的花朵。我们需要写一些代码来让蜜蜂采集花粉,但是在此之前,蜜蜂最初是在哪儿被创建的呢?它们又把花粉带到哪儿去?这时就用到了Hive 类(蜂巢)。

蜂巢不仅仅是蜜蜂们的归宿。它内部有很多地点,每一个地点都对应着世界中的不同的坐标。里面有入口和出口,还有生育幼蜂的孵化园,还有把花粉转化为蜂蜜的蜂蜜工厂。

蜂巢扮演的另一个角色就是要用蜂蜜来维持蜂巢的运转。蜂巢的运转需要蜂蜜创建幼蜂也需要蜂蜜。蜂蜜工厂会把蜜蜂们采集的花粉转化为蜂蜜。每一单位的花粉可以产生0.25 单位的蜂蜜。

 

 随着时间的流转,蜂巢靠着消耗蜂蜜来维持运转和创建幼蜂。同时蜜蜂们采集来花粉并转化为蜂蜜,这就维持了蜂巢的长久运行。

①  编写Hive 类的框架代码

②    定义Hive 的常量

初始蜜蜂数(6 )需要一个常量,开始时候的蜂蜜数量( 3.2 ),蜂巢最多可以承载的蜂蜜数( 15 ),花粉向蜂蜜转化率( 0.25),最大蜜蜂数( 8 ),可以生育幼蜂的最小蜂蜜数( 4 )。

③    写代码来操作位置

首先,编写GetLocation ()方法。它要接受一个 string ,在 locations 字典中查找并返回相关的地点。如果查找不到,抛出一个 ArgumentException 

④    Hive 的构造方法

当一个蜂巢初始化的时候,会把蜂蜜量设置为初始值。需要设置蜂巢中的所有地点,

还需要创建一个Random 的新实例。然后,要调用 AddBee ()方法 -- 每次创建一个幼蜂都要传入刚刚创建的 Random 实例。

蜂巢的Go ()方法

很多时候,蜂后没有时间来生育幼蜂。我们没有一个QueenBee类,但是我们来假设蜂蜜足够的时候会有十分之一的几率去创建一只幼蜂。

 

4、        World 

World 负责协调模拟器中的每一个方面:记录所有的蜜蜂,告诉蜂巢是否有足够的控件来容纳更多的蜜蜂,定位花朵,等等

World对象的最重要的任务之一就是在模拟器中的每一轮去调用每一朵花,每一只蜜蜂还有蜂巢的 Go ()方法。换句话说, World 维持了模拟器世界中的生命的运转。

每个对象的Go()方法都应该在我们的模拟器中的每一轮,或者叫做每一个回合中被调用。每一轮可以是任意的一段时间 ... 比如说,一轮可以是 10 秒,或者 60 秒,或者是 10 分钟。

每一轮在动画中表现为一帧,所以世界每一轮只改变一小点。

关键是每一轮都会影响世界中的每一个对象。蜂巢每一轮检查是否需要增加更多的蜜蜂。然后每只蜜蜂运行一轮,向着目的地移动一点点距离或者是做一个小动作,并变老。然后每朵花运行一轮,产生一点花粉并变老。这正是World 做的:它确定每一次 World  Go ()方法被调用,每个对象都会获得一轮的行动。

 

5、        Sun 

自己构建了一个Sun类,很简单的,只记录了太阳的年龄(初始=0),位置;在给定位置可以画太阳,这样太阳也动起来了。当然太阳也有 Go ()方法,被World  Go ()方法调用。

 

6、            串行化

序列化又称串行化,是.NET运行时环境用来支持用户定义类型的流化的机制。其目的是以某种存储形成使自定义对象持久化,或者将这种对象从一个地方传输到另一个地方。

“打开”和“保存”,可以实时保存对象。Serialize真是个奇妙的东西,一个简单的bf.Serialize(output,world);居然能保存所有的对象。

“打开”过程是反序列化,获取所有对象信息,然后调用刷新画面。

 

7、            打印

有了PrintDocumentPrintDialogPrintPreviewDialog3个类,我们很轻松的就能设计一个程序的打印功能,实际上我们主要用到的是PrintDocument类;然后在画布上画出所打印的内容即可。

 

0 0
原创粉丝点击