mirror of
https://gitee.com/drinkjava2/frog.git
synced 2024-11-25 16:04:06 +08:00
Add history\011, yinyan_eatfood
This commit is contained in:
parent
89548a4d75
commit
b8733661b7
34
README.md
34
README.md
@ -81,10 +81,10 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
|
||||
这个版本的目的是为了增加一点趣味性,显得青蛙还是有点"用处"的,省得让人以为这个项目不务正业,青蛙只会找食。这个版本青蛙的脑结构和找食版的青蛙基本相同,区别只是在于环境不同,也就是说它的表现随着环境而变化,这符合"通用人工智能"的概念,即信号感受器官是统一的(通常是眼睛),但能根据不同的环境完成不同的任务。走跷跷板演示是最后一个2维脑的版本,今后这个项目将沉寂一段较长时间,我将致力于将青蛙脑重构为3D金字塔形脑结构(见上文),因为这个项目的缺点已经很明显,它不具备对2维图像的模式识别能力,用随机试错的方式只能处理非常简单的、信号在视网膜的固定区域出现的图像信号。
|
||||
青蛙的找食效率以及走跷跷板平衡的能力都没有优化到顶点,一些构想中的复杂的器官如“与门”、“或门”(不要怀疑大自然能否进化出这些复杂器官)等都没加上,器官的用进废退、奖励信号的利用都没反映,但我认为这些还不关键,目前最急迫的任务应该是先进行3D脑结构建模,让青蛙能具备2维图形的模式识别(和回忆)功能,这个大的架构重构是它能处理复杂图像信息的立足之本,它的图像识别能力和通常的用上千张图片来训练识别一个图片这种工作模式完全不同,它是一种通用的,可自动分类识别所有图像的模式,更符合动物脑的工作模式,记住并回忆出某个图像(或任意输入信号场景的组合),可能只需要这种场景重复出现过几次即可,它是一种无外界信号判定,自动分类的识别模式。
|
||||
2019-09-09 开始3D脑的构建,任务又回到原点:找食,从静止的青蛙要能进化到吃光所有食物。目前只是搭建空的3D框架,还未涉及3D脑模型编程。新的工作存放在core3d目录,原有的旧core目录保留,相应地批处理文件也分为普通版run.bat和3d版run3d.bat,蛋文件也分为普通版eggs.ser和3d版eggs3d.ser。
|
||||
脑的3D版要引入模式识别功能,第一个编程任务是要用这个3D脑模拟出体全息存贮现象,也就等价于模式识别功能,用字母的点阵图像激活它的视觉区,并同时激活一个随意指定的脑区作为字母识别区,然后只激活视觉区的图像,再检查这个随意指定的字母区是否会被激活,而其它字母区基本不激活,例如同时训练字母A、B、C、D一段时间,然后只激活字母A的图像区(即在视网膜区产生光子),其它三个BCD字母区应该没有A字母区活跃(即其它字母区收到的光子数或总能量少于A字母区),这是从从二维图像识别出对应的文字,比较好检测并利用检测结果来进行生存竟争,从大量随机生成的脑细胞播种器官中挑选出有用的器官,注意在同一个脑空间(cube),可以同时存在多个不同器官播种出来的脑细胞(cell)。体全息存贮在物理上很难实现,因为光和材料受物理特性制约,但在虚拟脑中不存在这个物理限制,让虚拟的光子反射、拐弯、增强、拆分都可轻易模拟出。
|
||||
反之,如果对应A字母的脑区兴奋,也要能激活一个模糊的A的像素点阵图像脑内某个区(与视网膜重合或下层),这不好检测,但可以变通一下,比如同时训练C和O两个字母,然后只激活C字母区,并检测O字母区是否有较强的信号,也就是说C字母区会在脑内成像区生成一个C的像素点阵,然后这个像素点阵又会倒过来激活与C图像相似的O字母区(以及所有类似C图像的其它脑区),这是第二步的编程任务,它反映了脑的联想机制。如果说第一步是信息的存贮,是体全息存贮原理的简单实现,这第二步就是信息的检索和联想,相比与普通的体全息存贮,它多了一个联想功能,这个联想功能以后会用到,由痛苦、愉快等奖惩机制来调节这个联想过程一直永无止歇地进行下去。
|
||||
脑的3D版要引入模式识别功能,第一个编程任务是要用这个3D脑模拟出体全息存贮现象,也就等价于模式识别功能,用字母的点阵图像激活它的视觉区,并同时激活一个随意指定的脑区作为字母识别区,然后只激活视觉区的图像,再检查这个随意指定的字母区是否会被激活,而其它字母区基本不激活。体全息存贮在物理上很难实现,因为光和材料受物理特性制约,但在虚拟脑中不存在这个物理限制,让虚拟的光子反射、拐弯、增强、拆分都可轻易模拟出。
|
||||
反之,如果对应A字母的脑区兴奋,也要能激活一个模糊的A的像素点阵图像脑内某个区(与视网膜重合或下层),这就是信息的检索和联想,这个联想功能以后会用到,由痛苦、愉快等奖惩机制来调节这个联想过程一直永无止歇地进行下去。
|
||||
2019-11-11 字母的模式识别功能
|
||||
这是个比较重要的更新,也是切换到3D脑的第一个正式版本更新,它实现了ABCD四个字母的识别。测试时分别用ABCD四个字母,并同时加上一个声音信号,模拟体全息存贮。另外这个模式识别是双向的,如果只单单激活听力区,也会在视网膜区成像。(如果要演示这点,需要将LetterTester.java中的seeImage和hearSound两行注释互换一下,并去除Cell.java中的59和60两行,这两行代码的作用是阻止光子逆向传播到视网膜上)。以下是这个模式识别的截图,黑色的小点表示视网膜发出的视觉波信号,蓝色的表示耳朵发出的听力波信号:在它们交汇的地方,细胞象果冻一样,被波的载体(光子)砸出洞来,每当接收到新的光子,就有可能在旧的洞里砸出光子来并逆向传播,用红色小点来表示,最终在波源处逆向成像。这个工作原理在细胞级别将相关的信号关联起来,也是体全息存贮的模拟实现,可以在三维空间实现信息的高密度存贮:
|
||||
这是切换到3D脑的第一个正式版本更新,它实现了ABCD四个字母的识别。测试时分别用ABCD四个字母,并同时加上一个声音信号,模拟体全息存贮。另外这个模式识别是双向的,如果只单单激活听力区,也会在视网膜区成像。(如果要演示这点,需要将LetterTester.java中的seeImage和hearSound两行注释互换一下,并去除Cell.java中的59和60两行,这两行代码的作用是阻止光子逆向传播到视网膜上)。以下是这个模式识别的截图,黑色的小点表示视网膜发出的视觉波信号,蓝色的表示耳朵发出的听力波信号:在它们交汇的地方,细胞象果冻一样,被波的载体(光子)砸出洞来,每当接收到新的光子,就有可能在旧的洞里砸出光子来并逆向传播,用红色小点来表示,最终在波源处逆向成像。这个工作原理在细胞级别将相关的信号关联起来,也是体全息存贮的模拟实现,可以在三维空间实现信息的高密度存贮:
|
||||
这个模式识别的原理比较简单,不需要任何高等数学知识,每个人都能看懂,而且它可能更符合人脑的工作模式,它可以进行图像到声音的关联,也可以实现声音到图像成像的逆关联,另外还有两个重要优点:1.它可以同时处理多维的信号,也就是说可以同时处理多个图片、声音等信号。 2.它的训练速度非常快,没有采用什么海量的大数据来进行训练,只要任意有关联的信号,哪怕信号只出现一两次,它都会自动将它们关联起来,这个关联是动物的条件反射能够建立的基础。
|
||||
有了模式识别,以后的工作就好办了。今后将在这个模式识别基础上进行扩展,进行多参数优化自动生成器官、声音的编码、把小蛇引入到虚拟环境等等一系列更复杂有趣的任务。
|
||||
2019-11-16 模式识别功能更新
|
||||
@ -94,8 +94,8 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
|
||||
2019-11-26 优化了一下程序,用"对酒当歌人生几何"8个汉字来进行模式识别原理演示,但容错性依然没有,变形、变位后的文字识别率很差。以后要考虑借签算法中的侧抑制、卷积、分层等原理来提高它的容错性,用图形化模拟的方式来实现。总体上算法和图形化模拟是两条路,算法通常可以用模拟的方式来表达,但不是所有模拟都可以归纳成算法,因为模拟(或者说软件本身)有时会非常复杂,不容易总结出规律。也就是说模拟的表现力比算法更强,但模拟的缺点是资源消耗大。
|
||||
2019-12-27 开始设立history目录,给主要的版本直接在history目录下创建副本,以方便运行。在history\003a_legs目录下(依然是2维脑)尝试给青蛙加两条腿,看它能不能自动学会走路。一条腿位于下方,负责左右移动,一条腿位于右侧,负责上下移动,每条腿有抬腿、落腿、转动和相应的感觉细胞。只有当腿落下且转动,而且另一条脚抬起来时青蛙才会位移,具体什么时候抬腿、什么时候转动腿完全由随机数决定。经过一段时间的生存汰淘之后,青蛙会进化出会利用两条腿走路了,但需要的时间非常长,约几个小时之后才达到最高吃食率50%左右,走路风格也比较诡异,是小碎步而不是大踏步。但至少这是青蛙第一次利用两条腿来走路,还是有点意义的,这证明生命进化中就算神经元随机排布,进化出眼睛和腿也是非常简单自然的事。这个实验只给青蛙加了两条腿,但同理如果有四条或更多的腿它应该也是可以随机进化出来的。
|
||||
![result7](result7_legs.gif)
|
||||
2020-05-04 在进行3维脑改造过程中,发现找食率很低,发现自己也看不懂以前的程序怎么编的了,所以在history目录下又添加一个003b_simple目录,把2维脑简化一下,去掉不重要的器官,好仔细分析它的逻辑。
|
||||
2020-05-07 经过一番折腾和走弯路之后,最后还是原汁原味地将2维脑003b目录的逻辑搬到了3维脑core目录里了,实现了同样的找食率(~50%左右)。从现在开始,可以专注于改进3D脑本身了。另外README_ENG.md和开发思路.md这两个不重要的文档不再提交到码云。
|
||||
2020-05-04 在进行3维脑改造过程中,发现找食率很低,自己也看不懂以前的程序怎么编的了,所以在history目录下又添加一个003b_simple目录,把2维脑简化一下,去掉不重要的器官,好分析它的逻辑。
|
||||
2020-05-07 经过一番折腾和走弯路之后,最后还是原汁原味地将2维脑003b目录的逻辑搬到了3维脑core目录里了,实现了同样的找食率(~50%左右)。从现在开始,可以专注于改进3D脑本身了。
|
||||
2020-06-26 小蛇吃青蛙
|
||||
位于history\006目录下,设定小蛇只能看到青蛙,青蛙只能看到蛇(严格说是蛇的舌头)。可以看到小蛇会追着青蛙,而青蛙会躲开小蛇,当然也有躲不开被吃掉的。除了引入负值连线用蓝色线条来表示外,技术细节上倒没有什么突破,但这个实验有趣的地方在于它证实了就算是完全随机的排列脑细胞,在长期的优胜劣汰后,生命也会进化出捕食和逃避行为。即然可以进化出捕食和逃避行为,而生命进化又会向越来越复杂的方向进化,所以这个原理可以解释为意识的萌芽了。高等生命的意识,本质上也无非就是大自然随机运动产生的一种复杂现象而已。
|
||||
![result8](result8_snake.gif)
|
||||
@ -120,7 +120,7 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
|
||||
这个任务看起来和神经网络关系不大,但我觉得有可能利用这个算法来进行器官自动排布,所以还是有一定的意义的,任意复杂的形状生成,今后三维脑的细胞结构,都有可能从这个任务演化出来。
|
||||
输出结果((pama_1234编写):
|
||||
![result10](result10_drawsnake.gif)
|
||||
他的项目位于这里:[细胞画蛇](https://gitee.com/pama1234/cell-painting-snake), 有兴趣研究源码的可以看一看,是基于processing软件编写的。
|
||||
他的项目位于这里:[细胞画蛇](https://gitee.com/pama1234/cell-painting-snake), 有兴趣研究源码的可以看一看,是基于processing编写的。
|
||||
顺便我把我的构思也写在这里,我没有仔细研究他的代码,但估计思路应该大体一致:
|
||||
1.与形状表达相关的基因采用多叉树结构数据结构,树结构是单例,只保存1份在内存中,每个细胞分裂后,端粒酶减一,相当于从树结构往下走一级。
|
||||
2.每个细胞分裂后,为了获得当前细胞的位置,但是又不能复制整个子树,所以要保存一个指针,指向树的当前节点,即子树的顶点。不再分裂的节点可以不保存节点指针。
|
||||
@ -154,7 +154,7 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
|
||||
2021-11-08 成功的细胞分裂尝试
|
||||
位于history\009目录下,这次的细胞分裂算法采用自顶向下的策略,也就是从单个细胞开始,一个细胞分裂成8个(因为1个正方体切三刀正好是8个小正方体)这种方式来进行。这种方案不是从目标形状的局部开始填充,而是从毛胚、从目标的粗轮廓开始利用遗传算法细化,直到细化出每个细节。这种方案的优点是更接近生物实际,符合“从总体到局部”的正常逻辑,而且有高效的基因压缩存储率,为了说明存储率这点,大家可以看看下图左面这个树结构,猜一猜要存储它最少需要多少个字节?
|
||||
![depth_tree](depth_tree.png)
|
||||
答案是最少只需要一个整数7就可以表达这个树结构了。说一下原理:首先所有树结构都可以用行号+深度的方式来表达,详见我的博客[基于前序遍历的无递归的树形结构](https://my.oschina.net/drinkjava2/blog/1818631),获取子树时可以避免递归访问,其次因为采用基因敲除的方式,只需要记录被敲除的树节点的行号和深度就就可以了,最后因为上例固定采用3叉树分形结构,根据行号就可以算出它的深度,所以深度值也可以省略,最后只用一个行号7就可以表达这整棵树了。
|
||||
答案是最少只需要一个整数7就可以表达这个树结构了。说一下原理:首先所有树结构都可以用行号+深度的方式来表达,详见我的博客[基于前序遍历的无递归的树形结构](https://my.oschina.net/drinkjava2/blog/1818631),获取子树时可以避免递归访问,其次因为采用基因敲除的方式,只需要记录被敲除的树节点的行号和深度就就可以了,最后因为固定采用3叉树分形结构,所以深度值也可以省略,只用一个行号7就可以表达这整棵树了。
|
||||
下图是这个算法的动画,可以看出它与上次的演示是不同的分裂模式,是先有总体后有细节。项目中实际采用的是8叉树,深度用细胞边长表示:
|
||||
![result14](result14_wa3d.gif)
|
||||
细胞分裂算法一方面可以利用来生成和优化物理形状(比方虚拟风叶、翅膀、受力结构等形状),另一方面它和神经网络的形成算法是有共通点的,因为众所周知心脏形状、血管网络、大脑神经网络都是由基因控制细胞分裂出来的。所以以后有可能利用这个算法来自动生成和优化神经网络触突三维空间分布结构。
|
||||
@ -174,18 +174,28 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什
|
||||
细胞分裂研究算法目前还不能结束(打脸自己),还要先解决这个缺色问题。多参数的进化,如果一旦某个参数被误删除就不能再进化回来,这种算法是不能接受的。
|
||||
|
||||
2022-01-15 多参数的细胞分裂继续改进:阴阳无极八卦阵算法
|
||||
位于history\009c目录下,采用了阴阳(黑白)节点算法,阴节点基因会删除节点下所有节点,是自顶向下的减材加工,阳节点基因会保留节点下所有节点,是自底向上的增材加工。利用遗传算法的大样本筛选,把自顶向下和自底向上两个进化方向结合起来,这样基本能解决误删分支后缺色不能补回这个问题。而且对于奖罚不再象以前一样要设成差距很大的值,animal.java中awardAAAA()原来要设成8000, 现在设成20也不会产生缺色现象。这个版本是研究技术细节问题,看不懂的同学们可以跳过。
|
||||
考虑到这个算法的特点,我给它起名“阴阳无极八卦阵算法“,阴阳是指它有阴阳两种节点,无极是指它的分裂阶数没有限制,八卦阵是指它采用了多个8叉树结构,每一维细胞参数都对应一个8叉树。
|
||||
位于history\009c目录下,采用了阴阳(黑白)节点算法,阴节点基因会删除节点下所有节点,是自顶向下的减材加工,阳节点基因会保留节点下所有节点,是自底向上的增材加工。利用遗传算法的大样本筛选,把自顶向下和自底向上两个进化方向结合起来,这样基本能解决误删分支后缺色不能补回这个问题。而且对于奖罚不再象以前一样要设成差距很大的值,animal.java中awardAAAA()原来要设成8000, 现在设成20也不会产生缺色现象。考虑到这个算法的特点,我给它起名“阴阳无极八卦阵算法“,阴阳是指它有阴阳两种节点,无极是指它的分裂阶数没有限制,八卦阵是指它采用了多个8叉树结构,每一维细胞参数都对应一个8叉树。
|
||||
|
||||
2022-07-22 树的生长演示
|
||||
位于history\010目录,演示一个树的生长。因为以前小鱼是手工指定一个三维像素点阵模板,有点作弊的嫌疑,所以这次演示是基于规则而不是模板来生成一棵树,这棵树的形状仅由以下规则决定:
|
||||
位于history\010目录,演示一个树的生长。这个演示是基于规则而不是模板来生成一棵树,这棵树的形状仅由以下规则决定:
|
||||
1.树根位于底部中心
|
||||
2.树的每个细胞水平方向四周不能有其它细胞
|
||||
3.树的每个细胞正下方不能有细胞,但必须在斜下方至少有一个细胞
|
||||
基于这三条规则,利用阴阳无极八卦阵分裂算法,树能够自动进化出来,但要耐心等一会儿。这个演示的意义是表示形状可以由规则来决定,不同的规则能进化出不同的形状,生物会通过改变自己的形状来适应环境规则。
|
||||
这个项目下一个任务就要基于形状由规则决定这个原理,制定模式识别奖惩规则,然后利用分裂算法,让细胞自动在空间上排布出不同细胞参数,从而进化出具有初步模式识别功能的神经网络,比方说,识别出0,1,2 ,3数字。大自然生物的模式识别不是通过人为设计算法,而就是这样无脑随机分裂细胞进化出来的。
|
||||
基于这三条规则,利用阴阳无极八卦阵分裂算法,树能够自动进化出来。这个演示的意义是表示形状可以由规则来决定,不同的规则能进化出不同的形状,生物会通过改变自己的形状来适应环境规则。
|
||||
![result17](result17_tree_grow.gif)
|
||||
|
||||
2022-09-25 用阴阳无极八卦阵完成找食任务
|
||||
位于history\011目录,这是利用阴阳无极八卦阵算法来完成最开始的“找食”这个任务,即采用模拟细胞分裂再配合遗传算法,生成一个简单功能的神经网络,输入只有上下左右四种视觉细胞,输出只有上下左右四种运动细胞。
|
||||
为什么要使用阴阳无极八卦阵来生成神经网络,是因为它有几个特点:
|
||||
1.传统神经网络因为手工调优参数太多,被类比为”炼丹法“,而采用阴阳无极八卦阵之后,算法将只有固定的这一个,调参完全交给计算机,手工只需要设计基因和细胞行为即可,以不变应万变。只要有利于生存的脑结构,就会被筛选出来,结构即逻辑。
|
||||
2.有高效的信息存储方式(见先前8叉树的介绍),基因虽然是随机生成的,但是它采用树结构这种方式有非常高的信息压缩比,可以用少量的基因控制巨量细胞的生成。
|
||||
3.更贴近实际生物的神经网络生成原理。大自然就是采用分裂+遗传算法来生成脑神经网络的,理论上我们可以应该照抄这个模式来创造出高智能的神经网络。
|
||||
4.它的神经网络是三维的,结构组合方式是无穷的。同一个细胞可以由多个基因控制,一个基因可能控制零个或所有的细胞。
|
||||
下面是实际运行结果,最上面一层用4种颜色来表示眼睛细胞,其余的细胞参数如运动细胞、轴突方向、轴突长度等用不同大小、颜色的圆来表示:
|
||||
![result18](result18_yinyan_eatfood.gif)
|
||||
这个版本的目的是验证阴阳无极八卦阵算法的实用性和搭建初步框架。后面的任务将是进一步复杂化,生成有模式识别功能的神经网络三维结构。
|
||||
|
||||
|
||||
## 运行方式 | Run
|
||||
运行core或history各个子目录下的run.bat批处理文件即可启动运行,history下有多个子目录,按版本号顺序排列,存放着这个项目演化过程中的主要历史版本供演示。
|
||||
另外如果想要研究这个项目的早期版本,可以结合gitk命令和参考"版本提交记录.md"的介绍,用git reset命令回复到以前任一个版本,例如用:
|
||||
|
@ -11,6 +11,7 @@
|
||||
package com.gitee.drinkjava2.frog;
|
||||
|
||||
import static com.gitee.drinkjava2.frog.brain.Cells.GENE_NUMBERS;
|
||||
import static com.gitee.drinkjava2.frog.util.RandomUtils.percent;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
@ -20,8 +21,10 @@ import java.util.ArrayList;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import com.gitee.drinkjava2.frog.brain.Cells;
|
||||
import com.gitee.drinkjava2.frog.brain.Eye;
|
||||
import com.gitee.drinkjava2.frog.egg.Egg;
|
||||
import com.gitee.drinkjava2.frog.judge.TreeShapeJudge;
|
||||
import com.gitee.drinkjava2.frog.objects.Food;
|
||||
import com.gitee.drinkjava2.frog.objects.Material;
|
||||
import com.gitee.drinkjava2.frog.util.RandomUtils;
|
||||
import com.gitee.drinkjava2.frog.util.Tree8Util;
|
||||
@ -50,7 +53,7 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
}
|
||||
}
|
||||
|
||||
/** brain cells */
|
||||
/** brain cells,暂定一个空间只有一个细胞,以后可以考虑扩展为一个空间充许多个细胞,用多个三维数组表示,分别由各自的基因控制分裂 */
|
||||
public long[][][] cells = new long[Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE];
|
||||
public float[][][] energys = new float[Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE];
|
||||
|
||||
@ -91,11 +94,8 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
|
||||
public void initAnimal() { // 初始化animal,生成脑细胞是在这一步,这个方法是在当前屏animal生成之后调用,比方说有一千个青蛙分为500屏测试,每屏只生成2个青蛙的脑细胞,可以节约内存
|
||||
geneMutation(); //有小概率基因突变
|
||||
for (ArrayList<Integer> gene : genes) //基因多也要适当小扣点分,防止基因无限增长
|
||||
energy -= gene.size();
|
||||
createCellsFromGene(); //根据基因,分裂生成脑细胞
|
||||
//RainBowFishJudge.judge(this); //外界对是否长得象彩虹鱼打分
|
||||
TreeShapeJudge.judge(this);
|
||||
|
||||
}
|
||||
|
||||
private static final int MIN_ENERGY_LIMIT = Integer.MIN_VALUE + 5000;
|
||||
@ -111,39 +111,47 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
}
|
||||
|
||||
//如果改奖罚值,就可能出现缺色,这个要在基因变异算法(从上到下,从下到上)和环境本身奖罚合理性上下功夫
|
||||
public void awardAAAA() { changeEnergy(20);}
|
||||
public void awardAAAA() { changeEnergy(2000);}
|
||||
public void awardAAA() { changeEnergy(10);}
|
||||
public void awardAA() { changeEnergy(5);}
|
||||
public void awardA() { changeEnergy(2);}
|
||||
|
||||
public void penaltyAAAA() { changeEnergy(-20);}
|
||||
public void penaltyAAAA() { changeEnergy(-2000);}
|
||||
public void penaltyAAA() { changeEnergy(-10);}
|
||||
public void penaltyAA() { changeEnergy(-5);}
|
||||
public void penaltyA() { changeEnergy(-2);}
|
||||
public void kill() { this.alive = false; changeEnergy(-500000); Env.clearMaterial(x, y, animalMaterial); } //kill是最大的惩罚
|
||||
public void kill() { this.alive = false; changeEnergy(-5000000); Env.clearMaterial(x, y, animalMaterial); } //kill是最大的惩罚
|
||||
//@formatter:on
|
||||
|
||||
public boolean active() {// 这个active方法在每一步循环都会被调用,是脑思考的最小帧
|
||||
// 如果能量小于0、出界、与非食物的点重合则判死
|
||||
if (!alive) {
|
||||
energy = MIN_ENERGY_LIMIT; // 死掉的青蛙确保淘汰出局
|
||||
return false;
|
||||
}
|
||||
if (energy <= 0 || Env.outsideEnv(x, y) || Env.bricks[x][y] >= Material.KILL_ANIMAL) {
|
||||
kill();
|
||||
return false;
|
||||
}
|
||||
//energy -= 20;
|
||||
// 依次调用每个cell的active方法
|
||||
//for (Cell cell : cells)
|
||||
// cell.organ.active(this, cell);
|
||||
|
||||
this.energys[0][0][Env.BRAIN_ZSIZE - 1] = 10;
|
||||
|
||||
// if(Env.closeToEdge(this))
|
||||
// energys[0][0][0]=10;
|
||||
|
||||
Eye.active(this); //如看到食物,给顶层细胞赋能量
|
||||
Cells.active(this); //细胞之间互相传递能量
|
||||
|
||||
if (Food.foundAndAteFood(this.x, this.y)) { //如当前位置有食物就吃掉,并获得奖励
|
||||
this.awardAAAA();
|
||||
this.ateFood++;
|
||||
}
|
||||
return alive;
|
||||
}
|
||||
|
||||
public void show(Graphics g) {// 显示当前动物
|
||||
if (!alive)
|
||||
return;
|
||||
//g.drawImage(animalImage, x - 8, y - 8, 16, 16, null);// 减去坐标,保证嘴巴显示在当前x,y处
|
||||
g.drawImage(animalImage, x - 8, y - 8, 16, 16, null);// 减去坐标,保证嘴巴显示在当前x,y处
|
||||
}
|
||||
|
||||
/** Check if x,y,z out of animal's brain range */
|
||||
@ -152,14 +160,15 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
}
|
||||
|
||||
public void geneMutation() { //基因变异,注意这一个算法同时变异所有条基因,目前最多允许64条基因
|
||||
if(percent(50))
|
||||
for (int g = 0; g < GENE_NUMBERS; g++) {//随机新增阴节点基因
|
||||
if (RandomUtils.percent(10)) {
|
||||
if (percent(20)) {
|
||||
ArrayList<Integer> gene = genes.get(g);
|
||||
Tree8Util.knockNodesByGene(gene);//根据基因,把要敲除的8叉树节点作个标记,下面的算法保证阴节点基因只添加阳节点上
|
||||
int randomIndex = RandomUtils.nextInt(Tree8Util.keepNodeQTY);
|
||||
int count = -1;
|
||||
for (int i = 0; i < Tree8Util.NODE_QTY; i++) {
|
||||
if (Tree8Util.keep[i] >= 0) {
|
||||
if (Tree8Util.keep[i] > 0) {
|
||||
count++;
|
||||
if (count >= randomIndex && !gene.contains(-i)) {
|
||||
gene.add(-i);
|
||||
@ -169,16 +178,17 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(percent(50))
|
||||
for (int g = 0; g < GENE_NUMBERS; g++) {//随机新增阳节点基因
|
||||
if (RandomUtils.percent(5)) {
|
||||
if (RandomUtils.percent(20)) {
|
||||
ArrayList<Integer> gene = genes.get(g);
|
||||
Tree8Util.knockNodesByGene(gene);//根据基因,把要敲除的8叉树节点作个标记,下面的算法保证阳节点基因只添加在阴节点上
|
||||
int yinNodeQTY = Tree8Util.NODE_QTY - Tree8Util.keepNodeQTY; //阴节点总数
|
||||
int randomIndex = RandomUtils.nextInt(yinNodeQTY);
|
||||
int count = -1;
|
||||
for (int i = 0; i < yinNodeQTY; i++) {
|
||||
if (Tree8Util.keep[i] < 0) {
|
||||
if (Tree8Util.keep[i] <= 0) {
|
||||
count++;
|
||||
if (count >= randomIndex && !gene.contains(i)) {
|
||||
gene.add(i);
|
||||
@ -189,29 +199,9 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
}
|
||||
}
|
||||
|
||||
// for (int g = 0; g < GENE_NUMBERS; g++) {//随机变异将阳节点向上提升一级,相当于单个细胞的自底向上扩散式生长
|
||||
// if (RandomUtils.percent(3)) {
|
||||
// ArrayList<Integer> gene = genes.get(g);
|
||||
// int randomIndex = RandomUtils.nextInt(gene.size());
|
||||
// if (randomIndex > 0 && gene.get(randomIndex) > 0) {//如基因是阳基因,且节点不是顶节点
|
||||
// int size = Tree8Util.TREE8[randomIndex][0];
|
||||
// gene.remove(randomIndex); //先删除底层这个阳基因
|
||||
// for (int i = randomIndex - 1; i > 0; i--) {
|
||||
// if (Tree8Util.TREE8[i][0] > size) { //深度树只要大于size就是它的父节点
|
||||
// if (!gene.contains(i))
|
||||
// gene.add(i);
|
||||
// int x = gene.indexOf(-i);//如果有阴节点也删除
|
||||
// if (x > 0)
|
||||
// gene.remove(x);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
if(percent(50))
|
||||
for (int g = 0; g < GENE_NUMBERS; g++) {//随机变异删除一个基因,这样可以去除无用的拉圾基因,防止基因无限增大
|
||||
if (RandomUtils.percent(10)) {
|
||||
if (RandomUtils.percent(40)) {
|
||||
ArrayList<Integer> gene = genes.get(g);
|
||||
if (!gene.isEmpty())
|
||||
gene.remove(RandomUtils.nextInt(gene.size()));
|
||||
@ -225,7 +215,7 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
ArrayList<Integer> gene = genes.get(g);
|
||||
Tree8Util.knockNodesByGene(gene);//根据基因,把要敲除的8叉树节点作个标记
|
||||
for (int i = 0; i < Tree8Util.NODE_QTY; i++) {//再根据敲剩下的8叉树keep标记生成细胞参数
|
||||
if (Tree8Util.keep[i] >= 0) {
|
||||
if (Tree8Util.keep[i] > 0) {
|
||||
int[] node = Tree8Util.TREE8[i];
|
||||
if (node[0] == 1) {//如果node边长为1,即不可以再分裂了,就在三维空间对间数组的位置把当前基因geneMask置1
|
||||
cells[node[1]][node[2]][node[3]] = cells[node[1]][node[2]][node[3]] | geneMask; //在相应的细胞处把细胞参数位置1
|
||||
|
@ -132,15 +132,15 @@ public class Application {
|
||||
for (int i = 0; i < Cells.GENE_NUMBERS; i++) {
|
||||
JRadioButton geneRadio=new JRadioButton();
|
||||
geneRadio.setBounds(buttonXpos+300+i*16, Env.ENV_HEIGHT + 8, 20, 22);
|
||||
geneRadio.setSelected(true);
|
||||
geneRadio.setSelected(Cells.display_gene[i]);
|
||||
geneRadio.setName(""+i);
|
||||
ActionListener geneRadioAction = new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int i= Integer.parseInt(geneRadio.getName());
|
||||
if (geneRadio.isSelected())
|
||||
Env.display_gene[i]=true;
|
||||
Cells.display_gene[i]=true;
|
||||
else
|
||||
Env.display_gene[i]=false;
|
||||
Cells.display_gene[i]=false;
|
||||
}
|
||||
};
|
||||
geneRadio.addActionListener(geneRadioAction);
|
||||
|
@ -33,7 +33,7 @@ public class Env extends JPanel {
|
||||
|
||||
public static final int FROG_EGG_QTY = 100; // 每轮下n个青蛙蛋,可调,只有最优秀的前n个青蛙们才允许下蛋
|
||||
|
||||
public static final int FROG_PER_EGG = 4; // 每个青蛙蛋可以孵出几个青蛙
|
||||
public static final int FROG_PER_EGG = 6; // 每个青蛙蛋可以孵出几个青蛙
|
||||
|
||||
public static final int SCREEN = 1; // 分几屏测完
|
||||
|
||||
@ -45,7 +45,7 @@ public class Env extends JPanel {
|
||||
public static final boolean BORN_AT_RANDOM_PLACE = true;// 孵出青蛙落在地图上随机位置,而不是在蛋所在地
|
||||
|
||||
/** Frog's brain size */ // 脑细胞位于脑范围内,是个三维结构,在animal中用三维数组来表示
|
||||
public static final int BRAIN_CUBE_SIZE = 16; //脑立方边长大小,必须是2的幂数如4,8,16...,原因参见8叉树算法
|
||||
public static final int BRAIN_CUBE_SIZE = 4; //脑立方边长大小,必须是2的幂数如4,8,16...,原因参见8叉树算法
|
||||
|
||||
public static final int BRAIN_XSIZE = BRAIN_CUBE_SIZE; // 脑在X方向长度
|
||||
public static final int BRAIN_YSIZE = BRAIN_CUBE_SIZE; // 脑在Y方向长度
|
||||
@ -67,10 +67,10 @@ public class Env extends JPanel {
|
||||
public static final int FROG_BRAIN_DISP_WIDTH = 400; // Frog的脑图在屏幕上的显示大小,可调
|
||||
|
||||
/** Steps of one test round */
|
||||
public static final int STEPS_PER_ROUND = 20;// 每轮测试步数,可调
|
||||
public static final int STEPS_PER_ROUND = 200;// 每轮测试步数,可调
|
||||
public static int step;// 当前测试步数
|
||||
|
||||
public static final int FOOD_QTY = 1500; // 食物数量, 可调
|
||||
public static final int FOOD_QTY = 3000; // 食物数量, 可调
|
||||
|
||||
// 以下是程序内部变量,不要手工修改它们
|
||||
public static final int TOTAL_FROG_QTY = FROG_EGG_QTY * FROG_PER_EGG; // 蛇的总数
|
||||
@ -87,19 +87,15 @@ public class Env extends JPanel {
|
||||
|
||||
public static List<Egg> frog_eggs = new ArrayList<>(); // 这里存放新建或从磁盘载入上轮下的蛋,每个蛋可能生成几个青蛙,
|
||||
|
||||
public static EnvObject[] things = new EnvObject[]{};// 所有外界物体,如食物、字母测试工具都放在这个things里面
|
||||
public static EnvObject[] things = new EnvObject[]{Food.FOOD};// 所有外界物体,如食物、字母测试工具都放在这个things里面
|
||||
|
||||
public static boolean show_split_detail = false; //是否显示脑分裂的细节过程,即从一个细胞开始分裂分裂,而不是只显示分裂的最终结果
|
||||
|
||||
public static boolean[] display_gene = new boolean[Cells.GENE_NUMBERS]; //脑最多有64个基因,这里用来控制哪些基因需要显示在脑图上
|
||||
|
||||
static {
|
||||
Logger.info("唵缚悉波罗摩尼莎诃!"); // 杀生前先打印往生咒,见码云issue#IW4H8
|
||||
Logger.info("脑图快捷键: T:顶视 F:前视 L:左视 R:右视 X:斜视 方向键:剖视 空格:暂停 鼠标:缩放旋转平移");
|
||||
if (DELETE_FROG_EGGS)
|
||||
FrogEggTool.deleteEggs();
|
||||
for (int i = 0; i < display_gene.length; i++)
|
||||
display_gene[i] = true;
|
||||
}
|
||||
|
||||
public Env() {
|
||||
@ -263,8 +259,8 @@ public class Env extends JPanel {
|
||||
if (SHOW_SPEED > 0 && step % SHOW_SPEED != 0) // 用是否跳帧画图的方式来控制速度
|
||||
continue;
|
||||
|
||||
if (SHOW_SPEED < 0) // 如果speed小于0,人为加入延迟
|
||||
sleep(-SHOW_SPEED);
|
||||
if (SHOW_SPEED<30) // 如果speed为1,人为加入延迟
|
||||
sleep((30-SHOW_SPEED));
|
||||
|
||||
// 开始画虚拟环境和青蛙和蛇
|
||||
g.setColor(Color.white);
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.gitee.drinkjava2.frog.brain;
|
||||
|
||||
import static java.awt.Color.BLACK;
|
||||
import static com.gitee.drinkjava2.frog.brain.Cells.*;
|
||||
import static java.awt.Color.RED;
|
||||
import static java.awt.Color.WHITE;
|
||||
import static java.lang.Math.cos;
|
||||
@ -319,10 +320,10 @@ public class BrainPicture extends JPanel {
|
||||
ArrayList<Integer> gene = a.genes.get(geneIndex);
|
||||
Tree8Util.knockNodesByGene(gene);
|
||||
for (int j = 0; j < Tree8Util.NODE_QTY; j++) {
|
||||
if (Tree8Util.keep[j] >= 0) {
|
||||
if (Tree8Util.keep[j] > 0) {
|
||||
int[] node = Tree8Util.TREE8[j];
|
||||
int size = node[0];
|
||||
if (size == i && Env.display_gene[geneIndex]) {//如果允许显示的话, 显示当前层级的节点
|
||||
if (size == i && Cells.display_gene[geneIndex]) {//如果允许显示的话, 显示当前层级的节点
|
||||
setPicColor(ColorUtils.colorByCode(geneIndex));
|
||||
drawPoint(node[1] + size / 2, node[2] + size / 2, node[3] + size / 2, size * (0.5f - geneIndex * 0.05f));
|
||||
}
|
||||
@ -353,20 +354,46 @@ public class BrainPicture extends JPanel {
|
||||
for (int z = 0; z < Env.BRAIN_CUBE_SIZE; z++) {
|
||||
for (int y = Env.BRAIN_CUBE_SIZE - 1; y >= 0; y--) {
|
||||
for (int x = Env.BRAIN_CUBE_SIZE - 1; x >= 0; x--) {
|
||||
if (x >= xMask && y >= yMask && a.cells[x][y][z] != 0)
|
||||
long cell = a.cells[x][y][z];
|
||||
if ((cell & Cells.EXIST) == 0) //只显示有效的细胞点
|
||||
continue;
|
||||
if (a.energys[x][y][z] > 1) { //用大红色圆形画出能量大于1的细胞格
|
||||
setPicColor(Color.MAGENTA); //开始画出对应的细胞基因参数,用不同颜色直径圆表示
|
||||
drawCircle(x + 0.5f, y + 0.5f, z + 0.5f, 1.2f);
|
||||
}
|
||||
if (x >= xMask && y >= yMask && cell != 0)//画出细胞每个基因存在的细胞格子
|
||||
for (int geneIndex = 0; geneIndex < Cells.GENE_NUMBERS; geneIndex++) {
|
||||
if ((a.cells[x][y][z] & (1 << geneIndex)) != 0 && Env.display_gene[geneIndex]) {
|
||||
if ((cell & (1 << geneIndex)) != 0 && Cells.display_gene[geneIndex]) {
|
||||
setPicColor(ColorUtils.colorByCode(geneIndex)); //开始画出对应的细胞基因参数,用不同颜色直径圆表示
|
||||
drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, geneIndex == 0 ? 0.8f : 0.5f - geneIndex * 0.05f);
|
||||
}
|
||||
}
|
||||
if (((cell & ZT) > 0)) { //如有轴突基因,则从当前细胞到轴突端点画一条红线
|
||||
int x_ = (int) ((cell & ZTX) >> ZTX0);
|
||||
if (x_ == 0)
|
||||
x_ = -1;
|
||||
int y_ = (int) ((cell & ZTY) >> ZTY0);
|
||||
if (y_ == 0)
|
||||
y_ = -1;
|
||||
int z_ = (int) ((cell & ZTZ) >> ZTZ0);
|
||||
if (z_ == 0)
|
||||
z_ = -1;
|
||||
int zt_long = (int) ((cell & ZT_LONG) >> ZT_LONG0) + 1; //轴突长度, 大小为1~8
|
||||
int xx = x + x_ * zt_long;
|
||||
int yy = y + y_ * zt_long;
|
||||
int zz = z + z_ * zt_long;
|
||||
if (Env.insideBrain(xx, yy, zz)) {
|
||||
setPicColor(Color.RED);
|
||||
drawLine(x+.5f, y+.5f, z+.5f, xx+.5f, yy+.5f, zz+.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Eye.drawEye(this);//画眼睛
|
||||
|
||||
setPicColor(Color.BLACK);
|
||||
//BrainShapeJudge.show(this);//这行显示目标形状这个模子
|
||||
|
||||
drawCuboid(brain);// 把脑的框架画出来
|
||||
|
||||
setPicColor(BLACK); //把x,y,z坐标画出来
|
||||
|
@ -10,15 +10,131 @@
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.brain;
|
||||
|
||||
import com.gitee.drinkjava2.frog.Animal;
|
||||
import com.gitee.drinkjava2.frog.Env;
|
||||
import com.gitee.drinkjava2.frog.util.Logger;
|
||||
import com.gitee.drinkjava2.frog.util.RandomUtils;
|
||||
|
||||
/**
|
||||
* Cells代表不同的脑细胞参数,对应每个参数,细胞有不同的处理光子的行为
|
||||
* Cells代表不同的脑细胞参数,对应每个参数,用8叉树算法生成不同的细胞。
|
||||
* 每个脑细胞用一个long来存储,所以最多允许64个基因位, 有时一个参数由多个基因位决定。每个基因位都由一个单独的阴阳8叉树控制,多个基因就组成了一个8叉树阵列
|
||||
* 基因+分裂算法=结构
|
||||
* 基因+分裂算法+遗传算法=结构的进化
|
||||
* 这个类里定义每个基因位的掩码, 脑结构的所有参数,都要用基因来控制。开始时可以有常量、魔数,但以后都放到基因里去自动进化。
|
||||
*
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 10.0
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class Cells {
|
||||
public static int GENE_NUMBERS = 1; //目前有多少条基因,每个脑细胞用是一个long来存储,所以最多允许64条基因,每个基因控制一个细胞的参数
|
||||
|
||||
|
||||
public static int GENE_NUMBERS = 0;
|
||||
private static int zeros = 0;
|
||||
public static boolean[] display_gene = new boolean[64]; //脑最多有64个基因,这里用来控制哪些基因需要显示在脑图上
|
||||
|
||||
public static long EXIST = mask(1, true); // 细胞存在否,1为存在,0为不存在, true表示显示在脑图上
|
||||
public static long MOVE_UP = mask(1, true); //如此点为1,则此细胞如有能量,青蛙向上移动
|
||||
public static long MOVE_DOWN = mask(1, true); //如此点为1,则此细胞如有能量,青蛙向下移动
|
||||
public static long MOVE_LEFT = mask(1, true); //如此点为1,则此细胞如有能量,青蛙向左移动
|
||||
public static long MOVE_RIGHT = mask(1, true); //如此点为1,则此细胞如有能量,青蛙向右移动
|
||||
public static long ZT_LONG = mask(3, false); //轴突长度
|
||||
public static long ZT_LONG0 = zeros; //如果参数由多位组成,用同名+0变量表示有几个0,移位运算时用来去除0。下同
|
||||
public static long ZT = mask(1, true);//axon exist 轴突是否存在
|
||||
public static long ZTX = mask(1, false);//axon x offset, 轴突x方向, 轴突方向由x,y,z三个方向的参数组合决定
|
||||
public static long ZTX0 = zeros; //x方向暂定1位,如果2位也可以,角度更细,但出结果的时间会比较长
|
||||
public static long ZTY = mask(1, false); //轴突y方向
|
||||
public static long ZTY0 = zeros;
|
||||
public static long ZTZ = mask(1, false); //轴突z方向
|
||||
public static long ZTZ0 = zeros;
|
||||
public static long ZT_MINUS = mask(1, false);//细胞信号,1为正信号,0为负(抑制)信号
|
||||
|
||||
// public static long RANDOM_ACTIVE = mask(1, true);//这个基因控制细胞随机产生能量,对结果影响不大,会让静止的青蛙颤抖
|
||||
|
||||
// public static long ST_LONG = mask(2, false); //dendrite radius, 树突长度半径,待后继版本用到
|
||||
// public static long ST_LONG0 = zeros;
|
||||
// public static long HAPPY = mask(1, false); //吃食奖励信号,待后继版本用到
|
||||
|
||||
public static long mask(int n, boolean display) { //返回基因掩码,高位由n个1组成,低位是当前GENE_NUMBERS个0,这个方法执行后GENE_NUMBERS会加n
|
||||
for (int i = GENE_NUMBERS; i < GENE_NUMBERS + n; i++) {
|
||||
display_gene[i] = display;
|
||||
}
|
||||
|
||||
String one = "";
|
||||
String zero = "";
|
||||
for (int i = 1; i <= n; i++)
|
||||
one += "1";
|
||||
for (int i = 1; i <= GENE_NUMBERS; i++)
|
||||
zero += "0";
|
||||
zeros = GENE_NUMBERS;
|
||||
GENE_NUMBERS += n;
|
||||
if (GENE_NUMBERS >= 64) {//
|
||||
System.out.println("目前基因位数不能超过64");
|
||||
System.exit(-1);
|
||||
}
|
||||
return Long.parseLong(one + zero, 2); //将"111000"这种字符串转换为长整
|
||||
}
|
||||
|
||||
public static void active(Animal a) {//这个方法的功能是根据细胞的参数,在细胞间传输能量(即信息的载体)
|
||||
for (int z = Env.BRAIN_CUBE_SIZE - 1; z >= 0; z--)
|
||||
for (int y = Env.BRAIN_CUBE_SIZE - 1; y >= 0; y--)
|
||||
for (int x = Env.BRAIN_CUBE_SIZE - 1; x >= 0; x--) {
|
||||
long cell = a.cells[x][y][z];
|
||||
|
||||
if ((cell & EXIST) == 0) //如细胞不存在,
|
||||
continue;
|
||||
|
||||
// if ((cell & RANDOM_ACTIVE) > 0) //随机产生细胞能量,会让青蛙颤抖
|
||||
// if (RandomUtils.percent(5))
|
||||
// a.energys[x][y][z] = 1;
|
||||
|
||||
float e = a.energys[x][y][z];
|
||||
if (e > 0 && ((cell & ZT) > 0)) { //如有轴突基因,则当前细胞如存在能量,会输送到轴突端点处
|
||||
int x_ = (int) ((cell & ZTX) >> ZTX0); //把掩码转为坐标偏移量,因为暂定只有1位,所以只有1,-1
|
||||
if (x_ == 0)
|
||||
x_ = -1;
|
||||
int y_ = (int) ((cell & ZTY) >> ZTY0);
|
||||
if (y_ == 0)
|
||||
y_ = -1;
|
||||
int z_ = (int) ((cell & ZTZ) >> ZTZ0);
|
||||
if (z_ == 0)
|
||||
z_ = -1;
|
||||
int zt_long = (int) ((cell & ZT_LONG) >> ZT_LONG0) + 1; //轴突长度, 大小为1~8
|
||||
int xx = x + x_ * zt_long;
|
||||
int yy = y + y_ * zt_long;
|
||||
int zz = z + z_ * zt_long;
|
||||
if (Env.insideBrain(xx, yy, zz)) {
|
||||
if (a.energys[xx][yy][zz] < 10) {
|
||||
if ((cell & ZT_MINUS) > 0) //如果轴空是负信号
|
||||
a.energys[xx][yy][zz]--;
|
||||
else
|
||||
a.energys[xx][yy][zz]++;
|
||||
if (a.energys[x][y][z] > 0)
|
||||
a.energys[x][y][z]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
e = a.energys[x][y][z];
|
||||
if ((e > 0) && (z < Env.BRAIN_ZSIZE - 1)) { //如当前细胞有能量,且不和眼睛在同一层,且有移动细胞,则青蛙移动
|
||||
if ((cell & MOVE_UP) > 0) {//向上y是减,屏幕y的0点在上方
|
||||
a.energys[x][y][z] = 0;
|
||||
a.y++;
|
||||
}
|
||||
if ((cell & MOVE_DOWN) > 0) {
|
||||
a.energys[x][y][z] = 0;
|
||||
a.y--;
|
||||
}
|
||||
if ((cell & MOVE_LEFT) > 0) {
|
||||
a.energys[x][y][z] = 0;
|
||||
a.x--;
|
||||
}
|
||||
if ((cell & MOVE_RIGHT) > 0) {
|
||||
a.energys[x][y][z] = 0;
|
||||
a.x++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
76
core/src/main/java/com/gitee/drinkjava2/frog/brain/Eye.java
Normal file
76
core/src/main/java/com/gitee/drinkjava2/frog/brain/Eye.java
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.brain;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import com.gitee.drinkjava2.frog.Animal;
|
||||
import com.gitee.drinkjava2.frog.Env;
|
||||
import com.gitee.drinkjava2.frog.objects.Material;
|
||||
|
||||
/**
|
||||
* Eye, if found food then set cell energy at top level
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
public class Eye {
|
||||
|
||||
/** First eye can only see if food nearby at 4 directions */
|
||||
public static void active(Animal a) {// 眼睛只能观察上、下、左、右四个方向有没有食物,如发现食物,就将最上层的四个边的细胞激活成1能量
|
||||
int seeDist = 15; //眼睛能看多远
|
||||
for (int i = 1; i < seeDist; i++)
|
||||
if (Env.hasMaterial(a.x, a.y + i, Material.FOOD)) {//up
|
||||
for (int x = 1; x < Env.BRAIN_XSIZE; x++)
|
||||
a.energys[x][Env.BRAIN_YSIZE - 1][Env.BRAIN_ZSIZE - 1] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 1; i < seeDist; i++)
|
||||
if (Env.hasMaterial(a.x, a.y - i, Material.FOOD)) { //down
|
||||
for (int x = 0; x < Env.BRAIN_XSIZE - 1; x++)
|
||||
a.energys[x][0][Env.BRAIN_ZSIZE - 1] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 1; i < seeDist; i++)
|
||||
if (Env.hasMaterial(a.x - i, a.y, Material.FOOD)) { //left
|
||||
for (int y = 1; y < Env.BRAIN_YSIZE; y++)
|
||||
a.energys[0][y][Env.BRAIN_ZSIZE - 1] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 1; i < seeDist; i++)
|
||||
if (Env.hasMaterial(a.x + i, a.y, Material.FOOD)) {//right
|
||||
for (int y = 0; y < Env.BRAIN_YSIZE - 1; y++)
|
||||
a.energys[Env.BRAIN_XSIZE - 1][y][Env.BRAIN_ZSIZE - 1] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void drawEye(BrainPicture bp) {//在脑图中画出眼睛
|
||||
bp.setPicColor(Color.RED);
|
||||
for (int x = 1; x < Env.BRAIN_XSIZE; x++)
|
||||
bp.drawCircle(x + 0.5f, Env.BRAIN_YSIZE - 0.5f, Env.BRAIN_ZSIZE - 0.5f, 1);
|
||||
bp.setPicColor(Color.YELLOW);
|
||||
for (int x = 0; x < Env.BRAIN_XSIZE - 1; x++)
|
||||
bp.drawCircle(x + 0.5f, 0.5f, Env.BRAIN_ZSIZE - 0.5f, 1);
|
||||
bp.setPicColor(Color.BLUE);
|
||||
for (int y = 1; y < Env.BRAIN_YSIZE; y++)
|
||||
bp.drawCircle(0.5f, y + 0.5f, Env.BRAIN_ZSIZE - 0.5f, 1);
|
||||
bp.setPicColor(Color.GREEN);
|
||||
for (int y = 0; y < Env.BRAIN_YSIZE - 1; y++)
|
||||
bp.drawCircle(Env.BRAIN_XSIZE - 0.5f, y + 0.5f, Env.BRAIN_ZSIZE - 0.5f, 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -59,7 +59,17 @@ public class Egg implements Serializable {
|
||||
public Egg(Egg a, Egg b) {//两个蛋的基因混合, 生成一个新蛋
|
||||
x = a.x;
|
||||
y = a.y;
|
||||
genes.addAll(a.genes); //TODO: 两个蛋的基因混合
|
||||
genes.addAll(a.genes);
|
||||
if (RandomUtils.percent(20)) //插入蛋B的基因到A蛋中
|
||||
for (int i = 0; i < b.genes.size(); i++) {
|
||||
if (RandomUtils.percent(2)) {
|
||||
ArrayList<Integer> aGene = a.genes.get(i);
|
||||
ArrayList<Integer> bGene = b.genes.get(i);
|
||||
if (bGene.size() > 1) {//随机插入一个B的基因,不用担心基因越来越多,因为随机删除的速度大于增长的
|
||||
aGene.add(bGene.get(RandomUtils.nextInt(bGene.size())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ public class FrogEggTool {
|
||||
Env.frog_eggs.clear();
|
||||
for (int i = 0; i < Env.FROG_EGG_QTY; i++)
|
||||
Env.frog_eggs.add(new Egg(Env.frogs.get(i)));
|
||||
Logger.info("Fist frog energy={}, Last frog energy={}", first.energy, last.energy);
|
||||
Logger.info("Fist frog energy={}, gene size={}, Last frog energy={}", first.energy, getGeneSize(first), last.energy);
|
||||
if (Env.SAVE_EGGS_FILE) {
|
||||
FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "frog_eggs.ser");
|
||||
ObjectOutputStream so = new ObjectOutputStream(fo);
|
||||
@ -63,6 +63,16 @@ public class FrogEggTool {
|
||||
}
|
||||
}
|
||||
|
||||
private static String getGeneSize(Frog f) {//按genes类型汇总每种基因的个数
|
||||
StringBuilder sb=new StringBuilder("[");
|
||||
for (int i = 0; i < f.genes.size(); i++)
|
||||
sb.append(f.genes.get(i).size()).append(",");
|
||||
if(sb.length()>1)
|
||||
sb.setLength(sb.length()-1);
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static void sortFrogsOrderByEnergyDesc() {// 按能量多少给青蛙排序
|
||||
Collections.sort(Env.frogs, new Comparator<Animal>() {
|
||||
public int compare(Animal a, Animal b) {
|
||||
|
@ -1,84 +0,0 @@
|
||||
package com.gitee.drinkjava2.frog.judge;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.gitee.drinkjava2.frog.Animal;
|
||||
import com.gitee.drinkjava2.frog.Env;
|
||||
import com.gitee.drinkjava2.frog.brain.BrainPicture;
|
||||
import com.gitee.drinkjava2.frog.brain.Cells;
|
||||
import com.gitee.drinkjava2.frog.util.StringPixelUtils;
|
||||
|
||||
/**
|
||||
* RainBowFishJudge to judge if is a rainbow fish, judge method be called in animal's initAnimal method
|
||||
*
|
||||
* 这个类的judge方法在动物的初始化后被调用,根据脑细胞群的三维结构和参数来对动物进行奖罚,即加减它的能量值,这是一个临时类,只是用来检验细胞三维成形功能,以后可能改名或删除
|
||||
* 这个类的show方法在绘脑图时调用,在脑图里显示脑细胞群的三维形状和参数,用不同颜色直径的空心圆来表示不同参数,judge方法就像是一个模子,细胞长在这个模子里的有奖,否则扣分
|
||||
*/
|
||||
public class RainBowFishJudge {//NOSONAR
|
||||
private static int[] C = new int[]{0, 0, Env.BRAIN_CUBE_SIZE / 2}; //C是中心点
|
||||
private static boolean[][][] shape = new boolean[Env.BRAIN_XSIZE][Env.BRAIN_YSIZE][Env.BRAIN_ZSIZE];
|
||||
private static List<int[]> pointList = new ArrayList<>(); //pointList存放上面shape的所有有效点,用来加快显示循环而不用遍历三维数组
|
||||
static {
|
||||
putPixiel("🐟");
|
||||
}
|
||||
|
||||
public static void putPixiel(String str) {
|
||||
byte[][] c = StringPixelUtils.getStringPixels(Font.SANS_SERIF, Font.PLAIN, Env.BRAIN_CUBE_SIZE, str); //要把frog二维像素变成立体的三维点放到points里和pointsList里供使用
|
||||
int w = c.length;
|
||||
int h = c[0].length;
|
||||
for (int z = 0; z < 5; z++) {
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
if (c[x][y] > 0) {
|
||||
int[] p = new int[]{C[0] + x, C[1] + y + 2, C[2] + z};
|
||||
if (!Animal.outBrainRange(p[0], p[1], p[2])) {
|
||||
shape[p[0]][p[1]][p[2]] = true;
|
||||
pointList.add(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void judgeShape(Animal animal) {//检查animal的脑细胞是否位于brainShape的范围内
|
||||
for (int x = 0; x < Env.BRAIN_CUBE_SIZE; x++) {
|
||||
for (int y = 0; y < Env.BRAIN_CUBE_SIZE; y++) {
|
||||
for (int z = 0; z < Env.BRAIN_CUBE_SIZE; z++) {
|
||||
if ((animal.cells[x][y][z] & 1) != 0)
|
||||
if (shape[x][y][z]) {
|
||||
animal.awardAAAA();
|
||||
} else {
|
||||
animal.penaltyAAA();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void judgeColor(Animal animal) {//检查颜色与小鱼图像重合,且呈斑马纹色彩分布,是就加分,否则扣分
|
||||
int colorWidth = Env.BRAIN_CUBE_SIZE / Cells.GENE_NUMBERS; //每条彩带宽度
|
||||
for (int x = 0; x < Env.BRAIN_CUBE_SIZE; x++)
|
||||
for (int y = 0; y < Env.BRAIN_CUBE_SIZE; y++)
|
||||
for (int z = 0; z < Env.BRAIN_CUBE_SIZE; z++)
|
||||
for (int i = 1; i <= Cells.GENE_NUMBERS; i++)
|
||||
if ((animal.cells[x][y][z] & (1 << i)) != 0) //如果色彩存
|
||||
if ((animal.cells[x][y][z] & 1) != 0 && x >= (i - 1) * colorWidth && x < (i * colorWidth))
|
||||
animal.awardAA();
|
||||
else
|
||||
animal.penaltyA();
|
||||
}
|
||||
|
||||
public static void judge(Animal animal) {//检查animal的脑细胞是否位于brainShape的范围内
|
||||
judgeShape(animal);
|
||||
judgeColor(animal);
|
||||
}
|
||||
|
||||
public static void show(BrainPicture pic) {// 在脑图上显示当前形状
|
||||
for (int[] p : pointList)
|
||||
pic.drawCircle(p[0] + 0.5f, p[1] + 0.5f, p[2] + 0.5f, 1);
|
||||
}
|
||||
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
package com.gitee.drinkjava2.frog.judge;
|
||||
|
||||
import com.gitee.drinkjava2.frog.Animal;
|
||||
import com.gitee.drinkjava2.frog.Env;
|
||||
|
||||
/**
|
||||
* TreeShapeJudge to create a tree
|
||||
*/
|
||||
public class TreeShapeJudge {//NOSONAR
|
||||
|
||||
private static boolean hasCell(long[][][] cells, int x, int y, int z) { //检查指定位置是否有TREE_CELL
|
||||
if (Animal.outBrainRange(x, y, z))
|
||||
return false;
|
||||
return (cells[x][y][z] & 1) > 0;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
private static boolean hasCellAround(long[][][] cells, int x, int y, int z) {//检查四周是否有TREE_CELL
|
||||
if (hasCell(cells, x + 1, y, z))return true;
|
||||
if (hasCell(cells, x - 1, y, z))return true;
|
||||
if (hasCell(cells, x + 1, y+1, z))return true;
|
||||
if (hasCell(cells, x - 1, y+1, z))return true;
|
||||
if (hasCell(cells, x + 1, y-1, z))return true;
|
||||
if (hasCell(cells, x - 1, y-1, z))return true;
|
||||
if (hasCell(cells, x, y+1, z))return true;
|
||||
if (hasCell(cells, x, y-1, z))return true;
|
||||
return false;
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
public static void judge(Animal animal) {
|
||||
long[][][] cells = animal.cells;
|
||||
for (int x = 0; x < Env.BRAIN_CUBE_SIZE; x++)
|
||||
for (int y = 0; y < Env.BRAIN_CUBE_SIZE; y++)
|
||||
for (int z = 0; z <= Env.BRAIN_CUBE_SIZE - 2; z++) {
|
||||
long cell = cells[x][y][z];
|
||||
if ((cell & 1) > 0) {
|
||||
if ((z == 0 && x == Env.BRAIN_XSIZE / 2 && y == Env.BRAIN_YSIZE / 2) //如果在底部中心
|
||||
|| //或
|
||||
(!hasCell(cells, x, y, z - 1) // 正下方没有cell
|
||||
&& !hasCellAround(cells, x, y, z) //且周围没有cell
|
||||
&& hasCellAround(cells, x, y, z - 1) //且下方周围有cell
|
||||
))
|
||||
animal.awardAA();
|
||||
else
|
||||
animal.penaltyAA();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -33,6 +33,7 @@ import java.util.concurrent.BlockingQueue;
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class Logger {
|
||||
private static final int LOGGER_STYLE = 0; //风格设定, 0:不输出前缀, 1:输出时间、类、行号等前缀
|
||||
private static final String LEV_EL = "debug";
|
||||
private static final int LEVEL_INT;
|
||||
private static final BlockingQueue<String> LOG_LIST = new ArrayBlockingQueue<>(256);
|
||||
@ -123,6 +124,8 @@ public class Logger {
|
||||
}
|
||||
|
||||
private static String generateMsg(String levelStr, String msg, Object... params) {
|
||||
if(LOGGER_STYLE==0)
|
||||
return formatMsg(msg+ LINE_SEPARATOR, null, params);
|
||||
StackTraceElement stack = Thread.currentThread().getStackTrace()[4];
|
||||
String s = "{} [{}][{}#{} {}] - " + msg + LINE_SEPARATOR;
|
||||
Object[] args = new Object[5 + params.length];
|
||||
|
@ -29,7 +29,7 @@ public class Tree8Util {
|
||||
|
||||
public static int[][] TREE8 = new int[NODE_QTY][4]; //八叉数用数组表示,第一维是深度树的行号,第二维是一个整数数组,内容是深度树表示的八叉树细胞的size, x, y, z值
|
||||
|
||||
public static byte[] keep = new byte[NODE_QTY]; //这里临时记录树的敲除记录,大于等于0的值表示要keep, 负数节点表示要敲除
|
||||
public static byte[] keep = new byte[NODE_QTY]; //这里临时记录树的敲除记录,大于0的值表示要keep, 小于等于0表示要敲除
|
||||
|
||||
private static byte[] KEEP = new byte[NODE_QTY]; //这里保存初值为0的数组常量,可以用System.arraycopy(KEEP, 0, keep, 0, NODE_QTY)快速清空enable数组
|
||||
|
||||
@ -64,8 +64,8 @@ public class Tree8Util {
|
||||
|
||||
public static void knockNodesByGene(List<Integer> gene) {//根据基因,把要敲除的8叉树节点作敲除或保留标记
|
||||
System.arraycopy(KEEP, 0, keep, 0, NODE_QTY);//清空keep数组
|
||||
keepNodeQTY = NODE_QTY;
|
||||
for (int g : gene) {//g基因,用带符号的8叉数的行号表示,负数表示阴节点要敲除,0或正数表示是阳节点要保留
|
||||
keepNodeQTY = 0;
|
||||
for (int g : gene) {//g基因,用带符号的8叉数的行号表示,负数表示阴节点要敲除,正数表示是阳节点要保留
|
||||
int gLine = Math.abs(g); //基因对应节点的行号
|
||||
int size = Tree8Util.TREE8[gLine][0]; //size是基因对应节点的细胞立方体边长
|
||||
for (int line = gLine; line < Tree8Util.NODE_QTY; line++) {//从这个g节点开始,往下找节点
|
||||
@ -73,13 +73,13 @@ public class Tree8Util {
|
||||
break;
|
||||
else {//否则就是g的子节点
|
||||
if (g < 0) { //g是阴节点
|
||||
Tree8Util.keep[line]--;
|
||||
if (Tree8Util.keep[line] == -1) //如果正好是-1,表示这个节点从保留状态转为删除状态
|
||||
if (Tree8Util.keep[line] == 1) //如果是1,表示这个节点将从保留状态转为删除状态
|
||||
keepNodeQTY--;
|
||||
Tree8Util.keep[line]=0;
|
||||
} else if (g > 0) { //g是阳节点
|
||||
Tree8Util.keep[line]++;
|
||||
if (Tree8Util.keep[line] == 0) //如果正好是0,表示这个节点从删除状态又转回了保留状态
|
||||
if (Tree8Util.keep[line] == 0) //如果是0,表示这个节点将从删除状态转为保留状态
|
||||
keepNodeQTY++;
|
||||
Tree8Util.keep[line]=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
int randomIndex = RandomUtils.nextInt(Tree8Util.keepNodeQTY);
|
||||
int count = -1;
|
||||
for (int i = 0; i < Tree8Util.NODE_QTY; i++) {
|
||||
if (Tree8Util.keep[i] >= 0) {
|
||||
if (Tree8Util.keep[i] > 0) {
|
||||
count++;
|
||||
if (count >= randomIndex && !gene.contains(-i)) {
|
||||
gene.add(-i);
|
||||
@ -171,14 +171,14 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
}
|
||||
|
||||
for (int g = 0; g < GENE_NUMBERS; g++) {//随机新增阳节点基因
|
||||
if (RandomUtils.percent(5)) {
|
||||
if (RandomUtils.percent(10)) {
|
||||
ArrayList<Integer> gene = genes.get(g);
|
||||
Tree8Util.knockNodesByGene(gene);//根据基因,把要敲除的8叉树节点作个标记,下面的算法保证阳节点基因只添加在阴节点上
|
||||
int yinNodeQTY = Tree8Util.NODE_QTY - Tree8Util.keepNodeQTY; //阴节点总数
|
||||
int randomIndex = RandomUtils.nextInt(yinNodeQTY);
|
||||
int count = -1;
|
||||
for (int i = 0; i < yinNodeQTY; i++) {
|
||||
if (Tree8Util.keep[i] < 0) {
|
||||
if (Tree8Util.keep[i] <= 0) {
|
||||
count++;
|
||||
if (count >= randomIndex && !gene.contains(i)) {
|
||||
gene.add(i);
|
||||
@ -189,27 +189,6 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
}
|
||||
}
|
||||
|
||||
// for (int g = 0; g < GENE_NUMBERS; g++) {//随机变异将阳节点向上提升一级,相当于单个细胞的自底向上扩散式生长
|
||||
// if (RandomUtils.percent(3)) {
|
||||
// ArrayList<Integer> gene = genes.get(g);
|
||||
// int randomIndex = RandomUtils.nextInt(gene.size());
|
||||
// if (randomIndex > 0 && gene.get(randomIndex) > 0) {//如基因是阳基因,且节点不是顶节点
|
||||
// int size = Tree8Util.TREE8[randomIndex][0];
|
||||
// gene.remove(randomIndex); //先删除底层这个阳基因
|
||||
// for (int i = randomIndex - 1; i > 0; i--) {
|
||||
// if (Tree8Util.TREE8[i][0] > size) { //深度树只要大于size就是它的父节点
|
||||
// if (!gene.contains(i))
|
||||
// gene.add(i);
|
||||
// int x = gene.indexOf(-i);//如果有阴节点也删除
|
||||
// if (x > 0)
|
||||
// gene.remove(x);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
for (int g = 0; g < GENE_NUMBERS; g++) {//随机变异删除一个基因,这样可以去除无用的拉圾基因,防止基因无限增大
|
||||
if (RandomUtils.percent(10)) {
|
||||
ArrayList<Integer> gene = genes.get(g);
|
||||
@ -225,7 +204,7 @@ public abstract class Animal {// 这个程序大量用到public变量而不是ge
|
||||
ArrayList<Integer> gene = genes.get(g);
|
||||
Tree8Util.knockNodesByGene(gene);//根据基因,把要敲除的8叉树节点作个标记
|
||||
for (int i = 0; i < Tree8Util.NODE_QTY; i++) {//再根据敲剩下的8叉树keep标记生成细胞参数
|
||||
if (Tree8Util.keep[i] >= 0) {
|
||||
if (Tree8Util.keep[i] > 0) {
|
||||
int[] node = Tree8Util.TREE8[i];
|
||||
if (node[0] == 1) {//如果node边长为1,即不可以再分裂了,就在三维空间对间数组的位置把当前基因geneMask置1
|
||||
cells[node[1]][node[2]][node[3]] = cells[node[1]][node[2]][node[3]] | geneMask; //在相应的细胞处把细胞参数位置1
|
||||
|
@ -319,7 +319,7 @@ public class BrainPicture extends JPanel {
|
||||
ArrayList<Integer> gene = a.genes.get(geneIndex);
|
||||
Tree8Util.knockNodesByGene(gene);
|
||||
for (int j = 0; j < Tree8Util.NODE_QTY; j++) {
|
||||
if (Tree8Util.keep[j] >= 0) {
|
||||
if (Tree8Util.keep[j] > 0) {
|
||||
int[] node = Tree8Util.TREE8[j];
|
||||
int size = node[0];
|
||||
if (size == i && Env.display_gene[geneIndex]) {//如果允许显示的话, 显示当前层级的节点
|
||||
|
@ -18,7 +18,7 @@ package com.gitee.drinkjava2.frog.brain;
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class Cells {
|
||||
public static int GENE_NUMBERS = 1; //目前有多少条基因,每个脑细胞用是一个long来存储,所以最多允许64条基因,每个基因控制一个细胞的参数
|
||||
public static int GENE_NUMBERS = 4; //目前有多少条基因,每个脑细胞用是一个long来存储,所以最多允许64条基因,每个基因控制一个细胞的参数
|
||||
|
||||
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ public class FrogEggTool {
|
||||
Env.frog_eggs.clear();
|
||||
for (int i = 0; i < Env.FROG_EGG_QTY; i++)
|
||||
Env.frog_eggs.add(new Egg(Env.frogs.get(i)));
|
||||
Logger.info("Fist frog energy={}, Last frog energy={}", first.energy, last.energy);
|
||||
Logger.info("Fist frog energy={}, gene size={}, Last frog energy={}", first.energy, getGeneSize(first), last.energy);
|
||||
if (Env.SAVE_EGGS_FILE) {
|
||||
FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "frog_eggs.ser");
|
||||
ObjectOutputStream so = new ObjectOutputStream(fo);
|
||||
@ -63,6 +63,16 @@ public class FrogEggTool {
|
||||
}
|
||||
}
|
||||
|
||||
private static String getGeneSize(Frog f) {//按genes类型汇总每种基因的个数
|
||||
StringBuilder sb=new StringBuilder("[");
|
||||
for (int i = 0; i < f.genes.size(); i++)
|
||||
sb.append(f.genes.get(i).size()).append(",");
|
||||
if(sb.length()>1)
|
||||
sb.setLength(sb.length()-1);
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static void sortFrogsOrderByEnergyDesc() {// 按能量多少给青蛙排序
|
||||
Collections.sort(Env.frogs, new Comparator<Animal>() {
|
||||
public int compare(Animal a, Animal b) {
|
||||
|
@ -29,7 +29,7 @@ public class Tree8Util {
|
||||
|
||||
public static int[][] TREE8 = new int[NODE_QTY][4]; //八叉数用数组表示,第一维是深度树的行号,第二维是一个整数数组,内容是深度树表示的八叉树细胞的size, x, y, z值
|
||||
|
||||
public static byte[] keep = new byte[NODE_QTY]; //这里临时记录树的敲除记录,大于等于0的值表示要keep, 负数节点表示要敲除
|
||||
public static byte[] keep = new byte[NODE_QTY]; //这里临时记录树的敲除记录,大于0的值表示要keep, 小于等于0表示要敲除
|
||||
|
||||
private static byte[] KEEP = new byte[NODE_QTY]; //这里保存初值为0的数组常量,可以用System.arraycopy(KEEP, 0, keep, 0, NODE_QTY)快速清空enable数组
|
||||
|
||||
@ -64,8 +64,8 @@ public class Tree8Util {
|
||||
|
||||
public static void knockNodesByGene(List<Integer> gene) {//根据基因,把要敲除的8叉树节点作敲除或保留标记
|
||||
System.arraycopy(KEEP, 0, keep, 0, NODE_QTY);//清空keep数组
|
||||
keepNodeQTY = NODE_QTY;
|
||||
for (int g : gene) {//g基因,用带符号的8叉数的行号表示,负数表示阴节点要敲除,0或正数表示是阳节点要保留
|
||||
keepNodeQTY = 0;
|
||||
for (int g : gene) {//g基因,用带符号的8叉数的行号表示,负数表示阴节点要敲除,正数表示是阳节点要保留
|
||||
int gLine = Math.abs(g); //基因对应节点的行号
|
||||
int size = Tree8Util.TREE8[gLine][0]; //size是基因对应节点的细胞立方体边长
|
||||
for (int line = gLine; line < Tree8Util.NODE_QTY; line++) {//从这个g节点开始,往下找节点
|
||||
@ -73,13 +73,13 @@ public class Tree8Util {
|
||||
break;
|
||||
else {//否则就是g的子节点
|
||||
if (g < 0) { //g是阴节点
|
||||
Tree8Util.keep[line]--;
|
||||
if (Tree8Util.keep[line] == -1) //如果正好是-1,表示这个节点从保留状态转为删除状态
|
||||
if (Tree8Util.keep[line] == 1) //如果是1,表示这个节点将从保留状态转为删除状态
|
||||
keepNodeQTY--;
|
||||
Tree8Util.keep[line]=0;
|
||||
} else if (g > 0) { //g是阳节点
|
||||
Tree8Util.keep[line]++;
|
||||
if (Tree8Util.keep[line] == 0) //如果正好是0,表示这个节点从删除状态又转回了保留状态
|
||||
if (Tree8Util.keep[line] == 0) //如果是0,表示这个节点将从删除状态转为保留状态
|
||||
keepNodeQTY++;
|
||||
Tree8Util.keep[line]=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
201
history/011_yinyan_eatfood/LICENSE
Normal file
201
history/011_yinyan_eatfood/LICENSE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
11
history/011_yinyan_eatfood/README.md
Normal file
11
history/011_yinyan_eatfood/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
## 2022-09-25 阴阳无极八卦阵在初级炼丹法中的运用
|
||||
位于history\011目录,这是利用阴阳无极八卦阵算法来完成最开始的“找食”这个任务,即采用模拟细胞分裂再配合遗传算法,生成一个简单功能的神经网络,输入只有上下左右四种视觉细胞,输出只有上下左右四种运动细胞。
|
||||
为什么要使用阴阳无极八卦阵来生成神经网络,是因为它有几个优点:
|
||||
1.传统神经网络因为手工调优参数太多,如同炼丹一样复杂,常被类比为”炼丹法“,而采用阴阳无极八卦阵之后,调参这个工作可以完全交给计算机,手工只需要设计基因和细胞行为即可,以不变应万变,算法今后将不再是重点。脑结构交给计算机去生成,只要有利于生存的脑结构,就会被筛选出来,结构即逻辑。
|
||||
2.有高效的信息存储方式(见先前8叉树的介绍),基因虽然是随机生成的,但是它采用树结构这种方式是高度压缩的信息存储方式,可以用少量的基因控制巨量细胞的生成。
|
||||
3.更贴近实际生物的神经网络生成模式,大自然就是采用分裂+遗传算法来生成脑神经网络的,理论上我们可以照抄这个模式来创造出高度智能的神经网络。
|
||||
4.它的神经网络是三维的,没有传统的手工设计算法神经网格层数限制。同一个细胞可以有许多个基因同时控制,一个基因可能控制零到所有的细胞,组合方式是无穷的。
|
||||
|
||||
运行时最上面一层脑细胞用4种颜色来表示四个方向的眼睛细胞,其余的细胞参数如运动细胞、轴突方向、轴突长度等用不同大小、颜色的圆来表示:
|
||||
|
||||
这个版本的目的是验证阴阳无极八卦阵算法是否能生成简单神经网络。今后的任务将是进一步复杂化,利用阴阳无极八卦阵来生成有模式识别功能的神经网络三维结构。
|
1
history/011_yinyan_eatfood/maven_clean.bat
Normal file
1
history/011_yinyan_eatfood/maven_clean.bat
Normal file
@ -0,0 +1 @@
|
||||
mvn clean
|
1
history/011_yinyan_eatfood/maven_eclipse_clean.bat
Normal file
1
history/011_yinyan_eatfood/maven_eclipse_clean.bat
Normal file
@ -0,0 +1 @@
|
||||
mvn eclipse:clean
|
2
history/011_yinyan_eatfood/maven_eclipse_eclipse.bat
Normal file
2
history/011_yinyan_eatfood/maven_eclipse_eclipse.bat
Normal file
@ -0,0 +1,2 @@
|
||||
call mvn eclipse:eclipse
|
||||
call pause
|
102
history/011_yinyan_eatfood/pom.xml
Normal file
102
history/011_yinyan_eatfood/pom.xml
Normal file
@ -0,0 +1,102 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.gitee.drinkjava2</groupId>
|
||||
<artifactId>frog011</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>11.0</version>
|
||||
|
||||
<name>frog</name>
|
||||
<description>当前目标是由分裂算法来自动排列脑细胞和触突参数,以实现模式识别功能</description>
|
||||
<url>https://gitee.com/drinkjava2/jsqlbox/frog</url>
|
||||
|
||||
<issueManagement>
|
||||
<system>gitee Issue</system>
|
||||
<url>https://gitee.com/drinkjava2/jsqlbox/frog/issues</url>
|
||||
</issueManagement>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>The Apache Software License, Version 2.0</name>
|
||||
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<name>Yong Zhu</name>
|
||||
<email>yong9981@gmail.com</email>
|
||||
<url>https://gitee.com/drinkjava2/</url>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<scm>
|
||||
<connection>scm:git@gitee.com:drinkjava2/frog.git</connection>
|
||||
<developerConnection>scm:git@gitee.com:drinkjava2/frog.git</developerConnection>
|
||||
<url>git@gitee.com:drinkjava2/frog.git</url>
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
<!-- Release on Java8 -->
|
||||
<version.java>1.8</version.java>
|
||||
<version.javadoc>6</version.javadoc>
|
||||
<version.compiler-plugin>3.3</version.compiler-plugin>
|
||||
<version.war-plugin>2.6</version.war-plugin>
|
||||
<version.clean-plugin>3.0.0</version.clean-plugin>
|
||||
<version.resources-plugin>2.7</version.resources-plugin>
|
||||
<version.surefire-plugin>2.19</version.surefire-plugin>
|
||||
<version.jar-plugin>2.6</version.jar-plugin>
|
||||
<version.source-plugin>2.4</version.source-plugin>
|
||||
<version.javadoc-plugin>2.10.3</version.javadoc-plugin>
|
||||
<version.gpg-plugin>1.6</version.gpg-plugin>
|
||||
</properties>
|
||||
|
||||
|
||||
|
||||
<dependencies>
|
||||
<!--dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency-->
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${version.compiler-plugin}</version>
|
||||
<configuration>
|
||||
<source>${version.java}</source>
|
||||
<target>${version.java}</target>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addClasspath>true</addClasspath>
|
||||
<useUniqueVersions>false</useUniqueVersions>
|
||||
<classpathPrefix>lib/</classpathPrefix>
|
||||
<mainClass>com.gitee.drinkjava2.frog.Application</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
</profiles>
|
||||
|
||||
</project>
|
3
history/011_yinyan_eatfood/run.bat
Normal file
3
history/011_yinyan_eatfood/run.bat
Normal file
@ -0,0 +1,3 @@
|
||||
call mvn clean compile
|
||||
cd target\classes
|
||||
java -classpath ".;*" com.gitee.drinkjava2.frog.Application
|
2
history/011_yinyan_eatfood/run.sh
Normal file
2
history/011_yinyan_eatfood/run.sh
Normal file
@ -0,0 +1,2 @@
|
||||
mvn clean package
|
||||
java -jar target/frog-*.jar
|
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog;
|
||||
|
||||
import static com.gitee.drinkjava2.frog.brain.Cells.GENE_NUMBERS;
|
||||
import static com.gitee.drinkjava2.frog.util.RandomUtils.percent;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import com.gitee.drinkjava2.frog.brain.Cells;
|
||||
import com.gitee.drinkjava2.frog.brain.Eye;
|
||||
import com.gitee.drinkjava2.frog.egg.Egg;
|
||||
import com.gitee.drinkjava2.frog.objects.Food;
|
||||
import com.gitee.drinkjava2.frog.objects.Material;
|
||||
import com.gitee.drinkjava2.frog.util.RandomUtils;
|
||||
import com.gitee.drinkjava2.frog.util.Tree8Util;
|
||||
|
||||
/**
|
||||
* Animal is all artificial lives' father class
|
||||
* Animal only keep one copy of genes from egg, not store gene in cell
|
||||
* Animal是所有动物(青蛙、蛇等)的父类, animal是由蛋孵出来的,蛋里保存着脑细胞结构生成的基因, Animal只保存一份基因而不是每个细胞都保存一份基因,这是人工生命与实际生物的最大不同
|
||||
* 基因是一个list<list>结构, 每一条list代表一条由深度树方式存储的基因树,分表控制细胞的一个参数,当cell用长整数表示时最多可以表达支持64个参数
|
||||
*
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
public abstract class Animal {// 这个程序大量用到public变量而不是getter/setter,主要是为了编程方便和简洁,但缺点是编程者需要小心维护各个变量
|
||||
public static BufferedImage FROG_IMAGE;
|
||||
public static BufferedImage snakeImage;
|
||||
|
||||
public ArrayList<ArrayList<Integer>> genes = new ArrayList<>(); // 基因是多个数列,有点象多条染色体
|
||||
|
||||
static {
|
||||
try {
|
||||
FROG_IMAGE = ImageIO.read(new FileInputStream(Application.CLASSPATH + "frog.png"));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/** brain cells,暂定一个空间只有一个细胞,以后可以考虑扩展为一个空间充许多个细胞,用多个三维数组表示,分别由各自的基因控制分裂 */
|
||||
public long[][][] cells = new long[Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE];
|
||||
public float[][][] energys = new float[Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE][Env.BRAIN_CUBE_SIZE];
|
||||
|
||||
public int x; // animal在Env中的x坐标
|
||||
public int y; // animal在Env中的y坐标
|
||||
public long energy = 1000000000; // 青蛙的能量为0则死掉
|
||||
public boolean alive = true; // 设为false表示青蛙死掉了,将不参与计算和显示,以节省时间
|
||||
public int ateFood = 0; // 青蛙曾吃过的食物总数,下蛋时如果两个青蛙能量相等,可以比数量
|
||||
public int no; // 青蛙在Env.animals中的序号,从1开始, 会在运行期写到当前brick的最低位,可利用Env.animals.get(no-1)快速定位青蛙
|
||||
|
||||
public int animalMaterial;
|
||||
public Image animalImage;
|
||||
|
||||
public Animal(Egg egg) {// x, y 是虑拟环境的坐标
|
||||
for (int i = 0; i < GENE_NUMBERS; i++) {
|
||||
genes.add(new ArrayList<>());
|
||||
}
|
||||
int i = 0;
|
||||
for (ArrayList<Integer> gene : egg.genes)//动物的基因是蛋的基因的拷贝
|
||||
genes.get(i++).addAll(gene);
|
||||
i = 0;
|
||||
if (Env.BORN_AT_RANDOM_PLACE) { //是否随机出生在地图上?
|
||||
x = RandomUtils.nextInt(Env.ENV_WIDTH);
|
||||
y = RandomUtils.nextInt(Env.ENV_HEIGHT);
|
||||
} else {//否则出生成指定区域
|
||||
this.x = egg.x + RandomUtils.nextInt(80) - 40;
|
||||
this.y = egg.y + RandomUtils.nextInt(80) - 40;
|
||||
if (this.x < 0)
|
||||
this.x = 0;
|
||||
if (this.y < 0)
|
||||
this.y = 0;
|
||||
if (this.x >= (Env.ENV_WIDTH - 1))
|
||||
this.x = Env.ENV_WIDTH - 1;
|
||||
if (this.y >= (Env.ENV_HEIGHT - 1))
|
||||
this.y = Env.ENV_HEIGHT - 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void initAnimal() { // 初始化animal,生成脑细胞是在这一步,这个方法是在当前屏animal生成之后调用,比方说有一千个青蛙分为500屏测试,每屏只生成2个青蛙的脑细胞,可以节约内存
|
||||
geneMutation(); //有小概率基因突变
|
||||
createCellsFromGene(); //根据基因,分裂生成脑细胞
|
||||
|
||||
}
|
||||
|
||||
private static final int MIN_ENERGY_LIMIT = Integer.MIN_VALUE + 5000;
|
||||
private static final int MAX_ENERGY_LIMIT = Integer.MAX_VALUE - 5000;
|
||||
|
||||
//@formatter:off 下面几行是重要的奖罚方法,会经常调整或注释掉,集中放在一起,不要格式化为多行
|
||||
public void changeEnergy(int energy_) {//正数为奖励,负数为惩罚, energy大小是环境对animal唯一的奖罚,也是animal唯一的下蛋竞争标准
|
||||
energy += energy_;
|
||||
if (energy > MAX_ENERGY_LIMIT)
|
||||
energy = MAX_ENERGY_LIMIT;
|
||||
if (energy < MIN_ENERGY_LIMIT)
|
||||
energy = MIN_ENERGY_LIMIT;
|
||||
}
|
||||
|
||||
//如果改奖罚值,就可能出现缺色,这个要在基因变异算法(从上到下,从下到上)和环境本身奖罚合理性上下功夫
|
||||
public void awardAAAA() { changeEnergy(2000);}
|
||||
public void awardAAA() { changeEnergy(10);}
|
||||
public void awardAA() { changeEnergy(5);}
|
||||
public void awardA() { changeEnergy(2);}
|
||||
|
||||
public void penaltyAAAA() { changeEnergy(-2000);}
|
||||
public void penaltyAAA() { changeEnergy(-10);}
|
||||
public void penaltyAA() { changeEnergy(-5);}
|
||||
public void penaltyA() { changeEnergy(-2);}
|
||||
public void kill() { this.alive = false; changeEnergy(-5000000); Env.clearMaterial(x, y, animalMaterial); } //kill是最大的惩罚
|
||||
//@formatter:on
|
||||
|
||||
public boolean active() {// 这个active方法在每一步循环都会被调用,是脑思考的最小帧
|
||||
// 如果能量小于0、出界、与非食物的点重合则判死
|
||||
if (!alive) {
|
||||
return false;
|
||||
}
|
||||
if (energy <= 0 || Env.outsideEnv(x, y) || Env.bricks[x][y] >= Material.KILL_ANIMAL) {
|
||||
kill();
|
||||
return false;
|
||||
}
|
||||
|
||||
this.energys[0][0][Env.BRAIN_ZSIZE - 1] = 10;
|
||||
|
||||
// if(Env.closeToEdge(this))
|
||||
// energys[0][0][0]=10;
|
||||
|
||||
Eye.active(this); //如看到食物,给顶层细胞赋能量
|
||||
Cells.active(this); //细胞之间互相传递能量
|
||||
|
||||
if (Food.foundAndAteFood(this.x, this.y)) { //如当前位置有食物就吃掉,并获得奖励
|
||||
this.awardAAAA();
|
||||
this.ateFood++;
|
||||
}
|
||||
return alive;
|
||||
}
|
||||
|
||||
public void show(Graphics g) {// 显示当前动物
|
||||
if (!alive)
|
||||
return;
|
||||
g.drawImage(animalImage, x - 8, y - 8, 16, 16, null);// 减去坐标,保证嘴巴显示在当前x,y处
|
||||
}
|
||||
|
||||
/** Check if x,y,z out of animal's brain range */
|
||||
public static boolean outBrainRange(int x, int y, int z) {// 检查指定坐标是否超出animal脑空间界限
|
||||
return x < 0 || x >= Env.BRAIN_XSIZE || y < 0 || y >= Env.BRAIN_YSIZE || z < 0 || z >= Env.BRAIN_ZSIZE;
|
||||
}
|
||||
|
||||
public void geneMutation() { //基因变异,注意这一个算法同时变异所有条基因,目前最多允许64条基因
|
||||
if(percent(50))
|
||||
for (int g = 0; g < GENE_NUMBERS; g++) {//随机新增阴节点基因
|
||||
if (percent(20)) {
|
||||
ArrayList<Integer> gene = genes.get(g);
|
||||
Tree8Util.knockNodesByGene(gene);//根据基因,把要敲除的8叉树节点作个标记,下面的算法保证阴节点基因只添加阳节点上
|
||||
int randomIndex = RandomUtils.nextInt(Tree8Util.keepNodeQTY);
|
||||
int count = -1;
|
||||
for (int i = 0; i < Tree8Util.NODE_QTY; i++) {
|
||||
if (Tree8Util.keep[i] > 0) {
|
||||
count++;
|
||||
if (count >= randomIndex && !gene.contains(-i)) {
|
||||
gene.add(-i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(percent(50))
|
||||
for (int g = 0; g < GENE_NUMBERS; g++) {//随机新增阳节点基因
|
||||
if (RandomUtils.percent(20)) {
|
||||
ArrayList<Integer> gene = genes.get(g);
|
||||
Tree8Util.knockNodesByGene(gene);//根据基因,把要敲除的8叉树节点作个标记,下面的算法保证阳节点基因只添加在阴节点上
|
||||
int yinNodeQTY = Tree8Util.NODE_QTY - Tree8Util.keepNodeQTY; //阴节点总数
|
||||
int randomIndex = RandomUtils.nextInt(yinNodeQTY);
|
||||
int count = -1;
|
||||
for (int i = 0; i < yinNodeQTY; i++) {
|
||||
if (Tree8Util.keep[i] <= 0) {
|
||||
count++;
|
||||
if (count >= randomIndex && !gene.contains(i)) {
|
||||
gene.add(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(percent(50))
|
||||
for (int g = 0; g < GENE_NUMBERS; g++) {//随机变异删除一个基因,这样可以去除无用的拉圾基因,防止基因无限增大
|
||||
if (RandomUtils.percent(40)) {
|
||||
ArrayList<Integer> gene = genes.get(g);
|
||||
if (!gene.isEmpty())
|
||||
gene.remove(RandomUtils.nextInt(gene.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createCellsFromGene() {//根据基因生成细胞参数
|
||||
long geneMask = 1;
|
||||
for (int g = 0; g < GENE_NUMBERS; g++) {//动物有多条基因,一条基因控制一维细胞参数,最多有64维,也就是最多有64条基因
|
||||
ArrayList<Integer> gene = genes.get(g);
|
||||
Tree8Util.knockNodesByGene(gene);//根据基因,把要敲除的8叉树节点作个标记
|
||||
for (int i = 0; i < Tree8Util.NODE_QTY; i++) {//再根据敲剩下的8叉树keep标记生成细胞参数
|
||||
if (Tree8Util.keep[i] > 0) {
|
||||
int[] node = Tree8Util.TREE8[i];
|
||||
if (node[0] == 1) {//如果node边长为1,即不可以再分裂了,就在三维空间对间数组的位置把当前基因geneMask置1
|
||||
cells[node[1]][node[2]][node[3]] = cells[node[1]][node[2]][node[3]] | geneMask; //在相应的细胞处把细胞参数位置1
|
||||
}
|
||||
}
|
||||
}
|
||||
geneMask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
package com.gitee.drinkjava2.frog;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JRadioButton;
|
||||
import javax.swing.JSlider;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
|
||||
import com.gitee.drinkjava2.frog.brain.BrainPicture;
|
||||
import com.gitee.drinkjava2.frog.brain.Cells;
|
||||
|
||||
/**
|
||||
* Application's main method start the program
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class Application {
|
||||
|
||||
public static final String CLASSPATH;
|
||||
|
||||
static {
|
||||
String classpath = new File("").getAbsolutePath();
|
||||
int i = classpath.lastIndexOf("\\frog\\");
|
||||
if (i > 0)
|
||||
CLASSPATH = classpath.substring(0, i) + "\\frog\\";// windows
|
||||
else
|
||||
CLASSPATH = classpath + "/"; // UNIX
|
||||
}
|
||||
|
||||
public static JFrame mainFrame = new JFrame();
|
||||
public static Env env = new Env();
|
||||
public static BrainPicture brainPic = new BrainPicture(Env.ENV_WIDTH + 5, 0, Env.BRAIN_XSIZE, Env.FROG_BRAIN_DISP_WIDTH);
|
||||
public static ActionListener pauseAction;
|
||||
public static boolean selectFrog = true;
|
||||
|
||||
private static void checkIfShowBrainPicture(JButton button) {
|
||||
int y = Env.ENV_HEIGHT + 150;
|
||||
if (Env.SHOW_FIRST_ANIMAL_BRAIN) {
|
||||
button.setText("Hide brain");
|
||||
if (Env.FROG_BRAIN_DISP_WIDTH + 41 > y)
|
||||
y = Env.FROG_BRAIN_DISP_WIDTH + 41;
|
||||
mainFrame.setSize(Env.ENV_WIDTH + Env.FROG_BRAIN_DISP_WIDTH + 25, y);
|
||||
brainPic.requestFocus();
|
||||
} else {
|
||||
button.setText("Show brain");
|
||||
mainFrame.setSize(Env.ENV_WIDTH + 20, y);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
mainFrame.setLayout(null);
|
||||
mainFrame.setSize(Env.ENV_WIDTH + 200, Env.ENV_HEIGHT + 150); // 窗口大小
|
||||
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭时退出程序
|
||||
mainFrame.add(env); // 添加虚拟环境Panel
|
||||
mainFrame.add(brainPic); // 添加脑图Panel
|
||||
|
||||
JButton button = new JButton("Show brain");// 按钮,显示或隐藏脑图
|
||||
int buttonWidth = 100;
|
||||
int buttonHeight = 22;
|
||||
int buttonXpos = Env.ENV_WIDTH / 2 - buttonWidth / 2;
|
||||
button.setBounds(buttonXpos, Env.ENV_HEIGHT + 8, buttonWidth, buttonHeight);
|
||||
ActionListener al = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {//显示或隐藏脑图
|
||||
Env.SHOW_FIRST_ANIMAL_BRAIN = !Env.SHOW_FIRST_ANIMAL_BRAIN;
|
||||
checkIfShowBrainPicture(button);
|
||||
}
|
||||
};
|
||||
checkIfShowBrainPicture(button);
|
||||
button.addActionListener(al);
|
||||
mainFrame.add(button);
|
||||
|
||||
JButton stopButton = new JButton("Pause");// 暂停或继续按钮
|
||||
stopButton.setBounds(buttonXpos, Env.ENV_HEIGHT + 35, buttonWidth, buttonHeight);
|
||||
pauseAction = new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
Env.pause = !Env.pause;
|
||||
if (Env.pause) {
|
||||
stopButton.setText("Resume");
|
||||
} else {
|
||||
stopButton.setText("Pause");
|
||||
brainPic.requestFocus();
|
||||
}
|
||||
}
|
||||
};
|
||||
stopButton.addActionListener(pauseAction);
|
||||
mainFrame.add(stopButton);
|
||||
|
||||
// 速度条
|
||||
final JSlider speedSlider = new JSlider(1, 10, (int) Math.round(Math.pow(Env.SHOW_SPEED, 1.0/3)));
|
||||
speedSlider.setBounds(buttonXpos - 50, stopButton.getY() + 25, buttonWidth + 100, buttonHeight);
|
||||
ChangeListener slideAction = new ChangeListener() {
|
||||
@Override
|
||||
public void stateChanged(ChangeEvent e) {
|
||||
Env.SHOW_SPEED = speedSlider.getValue() * speedSlider.getValue() * speedSlider.getValue();
|
||||
brainPic.requestFocus();
|
||||
}
|
||||
};
|
||||
speedSlider.addChangeListener(slideAction);
|
||||
mainFrame.add(speedSlider);
|
||||
final JLabel label = new JLabel("Speed:");
|
||||
label.setBounds(buttonXpos - 90, stopButton.getY() + 23, 100, buttonHeight);
|
||||
mainFrame.add(label);
|
||||
|
||||
|
||||
|
||||
//是否把egg文件存盘
|
||||
JCheckBox saveFileCheckBox = new JCheckBox("Save egg file");
|
||||
saveFileCheckBox.setBounds(buttonXpos, Env.ENV_HEIGHT + 80, 120, 22);
|
||||
ActionListener saveAction = new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (saveFileCheckBox.isSelected())
|
||||
Env.SAVE_EGGS_FILE = true;
|
||||
else
|
||||
Env.SAVE_EGGS_FILE = false;
|
||||
}
|
||||
};
|
||||
saveFileCheckBox.addActionListener(saveAction);
|
||||
mainFrame.add(saveFileCheckBox);
|
||||
|
||||
//基因维数显示控制
|
||||
for (int i = 0; i < Cells.GENE_NUMBERS; i++) {
|
||||
JRadioButton geneRadio=new JRadioButton();
|
||||
geneRadio.setBounds(buttonXpos+300+i*16, Env.ENV_HEIGHT + 8, 20, 22);
|
||||
geneRadio.setSelected(Cells.display_gene[i]);
|
||||
geneRadio.setName(""+i);
|
||||
ActionListener geneRadioAction = new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int i= Integer.parseInt(geneRadio.getName());
|
||||
if (geneRadio.isSelected())
|
||||
Cells.display_gene[i]=true;
|
||||
else
|
||||
Cells.display_gene[i]=false;
|
||||
}
|
||||
};
|
||||
geneRadio.addActionListener(geneRadioAction);
|
||||
mainFrame.add(geneRadio);
|
||||
}
|
||||
|
||||
//是否显示分裂过程
|
||||
JCheckBox showSplitDetailCheckBox = new JCheckBox("Show split detail");
|
||||
showSplitDetailCheckBox.setBounds(buttonXpos+300, Env.ENV_HEIGHT + 40, 120, 22);
|
||||
ActionListener detailAction = new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (showSplitDetailCheckBox.isSelected())
|
||||
Env.show_split_detail = true;
|
||||
else
|
||||
Env.show_split_detail = false;
|
||||
}
|
||||
};
|
||||
showSplitDetailCheckBox.addActionListener(detailAction);
|
||||
mainFrame.add(showSplitDetailCheckBox);
|
||||
|
||||
mainFrame.setVisible(true);
|
||||
env.run();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,308 @@
|
||||
package com.gitee.drinkjava2.frog;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import com.gitee.drinkjava2.frog.brain.Cells;
|
||||
import com.gitee.drinkjava2.frog.egg.Egg;
|
||||
import com.gitee.drinkjava2.frog.egg.FrogEggTool;
|
||||
import com.gitee.drinkjava2.frog.objects.EnvObject;
|
||||
import com.gitee.drinkjava2.frog.objects.Food;
|
||||
import com.gitee.drinkjava2.frog.objects.Material;
|
||||
import com.gitee.drinkjava2.frog.util.Logger;
|
||||
import com.gitee.drinkjava2.frog.util.RandomUtils;
|
||||
|
||||
/**
|
||||
* Env is the living space of frog. draw it on JPanel
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class Env extends JPanel {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Speed of test */
|
||||
public static int SHOW_SPEED = 1000; // 测试速度,-1000~1000,可调, 数值越小,速度越慢
|
||||
|
||||
public static final int FROG_EGG_QTY = 100; // 每轮下n个青蛙蛋,可调,只有最优秀的前n个青蛙们才允许下蛋
|
||||
|
||||
public static final int FROG_PER_EGG = 6; // 每个青蛙蛋可以孵出几个青蛙
|
||||
|
||||
public static final int SCREEN = 1; // 分几屏测完
|
||||
|
||||
/** Delete eggs at beginning of each run */
|
||||
public static final boolean DELETE_FROG_EGGS = true;// 每次运行是否先删除以前保存的青蛙蛋文件,如果为false将加载旧蛋文件继续运行
|
||||
|
||||
public static boolean SAVE_EGGS_FILE = false; //从2021-11-23起,添加这个选项,允许不输出蛋文件到磁盘上
|
||||
|
||||
public static final boolean BORN_AT_RANDOM_PLACE = true;// 孵出青蛙落在地图上随机位置,而不是在蛋所在地
|
||||
|
||||
/** Frog's brain size */ // 脑细胞位于脑范围内,是个三维结构,在animal中用三维数组来表示
|
||||
public static final int BRAIN_CUBE_SIZE = 4; //脑立方边长大小,必须是2的幂数如4,8,16...,原因参见8叉树算法
|
||||
|
||||
public static final int BRAIN_XSIZE = BRAIN_CUBE_SIZE; // 脑在X方向长度
|
||||
public static final int BRAIN_YSIZE = BRAIN_CUBE_SIZE; // 脑在Y方向长度
|
||||
public static final int BRAIN_ZSIZE = BRAIN_CUBE_SIZE; // 脑在Z方向长度
|
||||
|
||||
/** SHOW first animal's brain structure */
|
||||
public static boolean SHOW_FIRST_ANIMAL_BRAIN = true; // 是否显示脑图在Env区的右侧
|
||||
|
||||
/** Draw first frog's brain after some steps */
|
||||
public static int DRAW_BRAIN_AFTER_STEPS = 0; // 以此值为间隔动态画出脑图,设为0则关闭这个动态脑图功能,只显示一个静态、不闪烁的脑图
|
||||
|
||||
/** Environment x width, unit: pixels */
|
||||
public static final int ENV_WIDTH = 400; // 虚拟环境的宽度, 可调
|
||||
|
||||
/** Environment y height, unit: pixels */
|
||||
public static final int ENV_HEIGHT = ENV_WIDTH; // 虚拟环境高度, 可调,通常取正方形
|
||||
|
||||
/** Frog's brain display width on screen, not important */
|
||||
public static final int FROG_BRAIN_DISP_WIDTH = 400; // Frog的脑图在屏幕上的显示大小,可调
|
||||
|
||||
/** Steps of one test round */
|
||||
public static final int STEPS_PER_ROUND = 200;// 每轮测试步数,可调
|
||||
public static int step;// 当前测试步数
|
||||
|
||||
public static final int FOOD_QTY = 3000; // 食物数量, 可调
|
||||
|
||||
// 以下是程序内部变量,不要手工修改它们
|
||||
public static final int TOTAL_FROG_QTY = FROG_EGG_QTY * FROG_PER_EGG; // 蛇的总数
|
||||
|
||||
public static final int FROG_PER_SCREEN = TOTAL_FROG_QTY / SCREEN; // 每屏显示几个青蛙,这个数值由其它常量计算得来
|
||||
|
||||
public static int current_screen = 0;
|
||||
|
||||
public static boolean pause = false; // 暂停按钮按下将暂停测试
|
||||
|
||||
public static int[][] bricks = new int[ENV_WIDTH][ENV_HEIGHT];// 组成环境的材料,见Material.java
|
||||
|
||||
public static List<Frog> frogs = new ArrayList<>(); // 这里存放所有待测的青蛙,可能分几次测完,由FROG_PER_SCREEN大小来决定
|
||||
|
||||
public static List<Egg> frog_eggs = new ArrayList<>(); // 这里存放新建或从磁盘载入上轮下的蛋,每个蛋可能生成几个青蛙,
|
||||
|
||||
public static EnvObject[] things = new EnvObject[]{Food.FOOD};// 所有外界物体,如食物、字母测试工具都放在这个things里面
|
||||
|
||||
public static boolean show_split_detail = false; //是否显示脑分裂的细节过程,即从一个细胞开始分裂分裂,而不是只显示分裂的最终结果
|
||||
|
||||
static {
|
||||
Logger.info("唵缚悉波罗摩尼莎诃!"); // 杀生前先打印往生咒,见码云issue#IW4H8
|
||||
Logger.info("脑图快捷键: T:顶视 F:前视 L:左视 R:右视 X:斜视 方向键:剖视 空格:暂停 鼠标:缩放旋转平移");
|
||||
if (DELETE_FROG_EGGS)
|
||||
FrogEggTool.deleteEggs();
|
||||
}
|
||||
|
||||
public Env() {
|
||||
super();
|
||||
this.setLayout(null);// 空布局
|
||||
this.setBounds(1, 1, ENV_WIDTH, ENV_HEIGHT);
|
||||
}
|
||||
|
||||
public static boolean insideBrain(int x, int y) {// 如果指定点在边界内
|
||||
return !(x < 0 || y < 0 || x >= BRAIN_XSIZE || y >= BRAIN_YSIZE);
|
||||
}
|
||||
|
||||
public static boolean insideBrain(int x, int y, int z) {// 如果指定点在边界内
|
||||
return !(x < 0 || y < 0 || z <= 0 || x >= BRAIN_XSIZE || y >= BRAIN_YSIZE || z >= BRAIN_ZSIZE);
|
||||
}
|
||||
|
||||
public static boolean insideBrain(float x, float y, float z) {// 如果指定点在边界内
|
||||
return !(x < 0 || y < 0 || z <= 0 || x >= BRAIN_XSIZE || y >= BRAIN_YSIZE || z >= BRAIN_ZSIZE);
|
||||
}
|
||||
|
||||
public static boolean insideEnv(int x, int y) {// 如果指定点在边界内
|
||||
return !(x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT);
|
||||
}
|
||||
|
||||
public static boolean outsideEnv(int x, int y) {// 如果指定点超出边界
|
||||
return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT;
|
||||
}
|
||||
|
||||
public static boolean closeToEdge(Animal a) {// 靠近边界? 离死不远了
|
||||
return a.x < 20 || a.y < 20 || a.x > (Env.ENV_WIDTH - 20) || a.y > (Env.ENV_HEIGHT - 20);
|
||||
}
|
||||
|
||||
public static boolean foundAnyThingOrOutEdge(int x, int y) {// 如果指定点看到任意东西或超出边界,返回true
|
||||
return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT || Env.bricks[x][y] != 0;
|
||||
}
|
||||
|
||||
public static boolean foundFrogOrOutEdge(int x, int y) {// 如果指定点看到青蛙或超出边界,返回true
|
||||
if (x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT)
|
||||
return true;// 如果出界返回true
|
||||
if ((Env.bricks[x][y] & Material.FROG_TAG) > 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void setMaterial(int x, int y, int material) {
|
||||
if (Env.insideEnv(x, y))
|
||||
Env.bricks[x][y] = Env.bricks[x][y] | material;
|
||||
}
|
||||
|
||||
public static boolean hasMaterial(int x, int y, int material) {
|
||||
if (!Env.insideEnv(x, y))
|
||||
return false;
|
||||
return (Env.bricks[x][y] & material) > 0;
|
||||
}
|
||||
|
||||
public static void clearMaterial(int x, int y, int material) {
|
||||
if (Env.insideEnv(x, y))
|
||||
Env.bricks[x][y] = Env.bricks[x][y] & ~material;
|
||||
}
|
||||
|
||||
private void rebuildFrogs() {// 根据蛙蛋重新孵化出蛙
|
||||
frogs.clear();
|
||||
for (int i = 0; i < frog_eggs.size(); i++) {// 创建青蛙,每个蛋生成n个蛙,并随机取一个别的蛋作为精子
|
||||
int loop = FROG_PER_EGG;
|
||||
if (frog_eggs.size() > 20) { // 如果数量多,进行一些优化,让排名靠前的Egg多孵出青蛙
|
||||
if (i < FROG_PER_EGG)// 0,1,2,3
|
||||
loop = FROG_PER_EGG + 1;
|
||||
if (i >= (frog_eggs.size() - FROG_PER_EGG))
|
||||
loop = FROG_PER_EGG - 1;
|
||||
}
|
||||
for (int j = 0; j < loop; j++) {
|
||||
Egg zygote = new Egg(frog_eggs.get(i), frog_eggs.get(RandomUtils.nextInt(frog_eggs.size())));
|
||||
Frog f = new Frog(zygote);
|
||||
frogs.add(f);
|
||||
f.no = frogs.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void drawWorld(Graphics g) {
|
||||
int brick;
|
||||
for (int x = 0; x < ENV_WIDTH; x++)
|
||||
for (int y = 0; y < ENV_HEIGHT; y++) {
|
||||
brick = bricks[x][y];
|
||||
if (brick != 0) {
|
||||
g.setColor(Material.color(brick));
|
||||
if ((brick & Material.FOOD) > 0) {
|
||||
g.fillRoundRect(x, y, 4, 4, 2, 2); //食物只有一个点太小,画大一点
|
||||
} else
|
||||
g.drawLine(x, y, x, y); // only 1 point
|
||||
}
|
||||
}
|
||||
g.setColor(Color.BLACK);
|
||||
}
|
||||
|
||||
static final NumberFormat format100 = NumberFormat.getPercentInstance();
|
||||
static {
|
||||
format100.setMaximumFractionDigits(2);
|
||||
}
|
||||
|
||||
private String foodAtedCount() {// 统计吃食总数等
|
||||
int maxFound = 0;
|
||||
for (Frog f : frogs)
|
||||
if (f.ateFood > maxFound)
|
||||
maxFound = f.ateFood;
|
||||
return new StringBuilder("吃食率:").append(format100.format(Food.food_ated * 1.00 / FOOD_QTY)).append(", 平均: ").append(Food.food_ated * 1.0f / FROG_PER_SCREEN).append(",最多:").append(maxFound)
|
||||
.toString();
|
||||
}
|
||||
|
||||
public static void checkIfPause() {
|
||||
if (pause)
|
||||
do {
|
||||
Application.brainPic.drawBrainPicture();
|
||||
Application.brainPic.requestFocus();
|
||||
sleep(100);
|
||||
} while (pause);
|
||||
}
|
||||
|
||||
public static void sleep(long millis) {
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static Animal getShowAnimal() {
|
||||
return frogs.get(current_screen * FROG_PER_SCREEN);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
FrogEggTool.loadFrogEggs(); // 从磁盘加载蛙egg,或新建一批egg
|
||||
Image buffImg = createImage(this.getWidth(), this.getHeight());
|
||||
Graphics g = buffImg.getGraphics();
|
||||
long time0;// 计时用
|
||||
int round = 1;
|
||||
do {
|
||||
rebuildFrogs(); // 根据蛙蛋重新孵化出蛙,注意基因变异有可能在孵化过程中发生
|
||||
for (current_screen = 0; current_screen < SCREEN; current_screen++) {// 分屏测试,每屏FROG_PER_SCREEN个蛙
|
||||
time0 = System.currentTimeMillis();
|
||||
for (EnvObject thing : things) // 创建食物、陷阱等物体
|
||||
thing.build();
|
||||
boolean allDead = false;
|
||||
for (int j = 0; j < FROG_PER_SCREEN; j++) {
|
||||
Frog f = frogs.get(current_screen * FROG_PER_SCREEN + j);
|
||||
f.initAnimal(); // 初始化器官延迟到这一步,是因为脑细胞太占内存,而且当前屏测完后会清空
|
||||
}
|
||||
for (step = 0; step < STEPS_PER_ROUND; step++) {
|
||||
for (EnvObject thing : things)// 调用食物、陷阱等物体的动作
|
||||
thing.active();
|
||||
if (allDead)
|
||||
break; // 青蛙全死光了就直接跳到下一轮,以节省时间
|
||||
allDead = true;
|
||||
for (int j = 0; j < FROG_PER_SCREEN; j++) {
|
||||
Frog f = frogs.get(current_screen * FROG_PER_SCREEN + j);
|
||||
if (f.active())// 调用青蛙的Active方法,并返回是否还活着
|
||||
allDead = false;
|
||||
}
|
||||
|
||||
if (SHOW_SPEED > 0 && step % SHOW_SPEED != 0) // 用是否跳帧画图的方式来控制速度
|
||||
continue;
|
||||
|
||||
if (SHOW_SPEED<30) // 如果speed为1,人为加入延迟
|
||||
sleep((30-SHOW_SPEED));
|
||||
|
||||
// 开始画虚拟环境和青蛙和蛇
|
||||
g.setColor(Color.white);
|
||||
g.fillRect(0, 0, this.getWidth(), this.getHeight()); // 先清空虚拟环境
|
||||
g.setColor(Color.BLACK);
|
||||
drawWorld(g);// 画整个虚拟环境
|
||||
for (int j = 0; j < FROG_PER_SCREEN; j++) { // 显示青蛙
|
||||
Frog f = frogs.get(current_screen * FROG_PER_SCREEN + j);
|
||||
f.show(g);
|
||||
}
|
||||
|
||||
if (SHOW_FIRST_ANIMAL_BRAIN) {// 在showAnimal上画一个红圈
|
||||
Animal showAnimal = getShowAnimal();
|
||||
if (showAnimal != null) {
|
||||
g.setColor(Color.red);
|
||||
g.drawArc(showAnimal.x - 15, showAnimal.y - 15, 30, 30, 0, 360);
|
||||
g.setColor(Color.BLACK);
|
||||
}
|
||||
}
|
||||
if (DRAW_BRAIN_AFTER_STEPS > 0 && step % DRAW_BRAIN_AFTER_STEPS == 0)
|
||||
Application.brainPic.drawBrainPicture();
|
||||
Graphics g2 = this.getGraphics();
|
||||
g2.drawImage(buffImg, 0, 0, this);
|
||||
}
|
||||
if (SHOW_FIRST_ANIMAL_BRAIN)
|
||||
Application.brainPic.drawBrainPicture();
|
||||
checkIfPause();
|
||||
for (int j = 0; j < FROG_PER_SCREEN; j++) {
|
||||
Frog f = frogs.get(current_screen * FROG_PER_SCREEN + j);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder("Round: ");
|
||||
sb.append(round).append(", screen:").append(current_screen).append(", speed:").append(Env.SHOW_SPEED).append(", ").append(", 用时: ").append(System.currentTimeMillis() - time0)
|
||||
.append("ms, ");
|
||||
sb.append(foodAtedCount());
|
||||
|
||||
Application.mainFrame.setTitle(sb.toString());
|
||||
for (EnvObject thing : things)// 去除食物、陷阱等物体
|
||||
thing.destory();
|
||||
}
|
||||
round++;
|
||||
FrogEggTool.layEggs(); //能量高的青蛙才有权下蛋
|
||||
} while (true);
|
||||
}
|
||||
|
||||
}
|
@ -8,25 +8,22 @@
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.util;
|
||||
package com.gitee.drinkjava2.frog;
|
||||
|
||||
import com.gitee.drinkjava2.frog.egg.Egg;
|
||||
import com.gitee.drinkjava2.frog.objects.Material;
|
||||
|
||||
/**
|
||||
* Cube has x,y,z value
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 2021-11-07
|
||||
* Frog is child class of Animal, Frog's name is Sam
|
||||
* Frog是Animal的一个子类
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public class Cube {
|
||||
public int x;//x,y,z是cube的左下前点坐标
|
||||
public int y;
|
||||
public int z;
|
||||
public int size;//size是cube的边长
|
||||
public class Frog extends Animal {
|
||||
|
||||
public Cube(int x, int y, int z, int size) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.size = size;
|
||||
public Frog(Egg egg) {
|
||||
super(egg);
|
||||
animalMaterial = Material.FROG_TAG;
|
||||
animalImage = Animal.FROG_IMAGE;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,475 @@
|
||||
package com.gitee.drinkjava2.frog.brain;
|
||||
|
||||
import static java.awt.Color.BLACK;
|
||||
import static com.gitee.drinkjava2.frog.brain.Cells.*;
|
||||
import static java.awt.Color.RED;
|
||||
import static java.awt.Color.WHITE;
|
||||
import static java.lang.Math.cos;
|
||||
import static java.lang.Math.round;
|
||||
import static java.lang.Math.sin;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import com.gitee.drinkjava2.frog.Animal;
|
||||
import com.gitee.drinkjava2.frog.Application;
|
||||
import com.gitee.drinkjava2.frog.Env;
|
||||
import com.gitee.drinkjava2.frog.util.ColorUtils;
|
||||
import com.gitee.drinkjava2.frog.util.Tree8Util;
|
||||
|
||||
/**
|
||||
* BrainPicture show first frog's brain structure, for debug purpose only
|
||||
*
|
||||
* 这个类用来画出脑图,这不是一个关键类,对脑的运行逻辑无影响,但有了脑图后可以直观地看出脑的3维结构,进行有针对性的改进
|
||||
* 可以用鼠标进行平移、缩放、旋转,以及t、f、l、r,x五个键来选择顶视、前视、左视、右视、斜视这5个方向的视图,以及空格暂停、方向键调整切面
|
||||
* 鼠标的动作定义在MouseAction类中。
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class BrainPicture extends JPanel {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final float D90 = (float) (Math.PI / 2);
|
||||
|
||||
Color picColor = RED;
|
||||
int brainDispWidth; // screen display piexls width
|
||||
float scale; // brain scale
|
||||
int xOffset = 0; // brain display x offset compare to screen
|
||||
int yOffset = 0; // brain display y offset compare to screen
|
||||
float xAngle = D90 * .8f; // brain rotate on x axis
|
||||
float yAngle = D90 / 4; // brain rotate on y axis
|
||||
float zAngle = 0;// brain rotate on z axis
|
||||
int xMask = -1;// x Mask
|
||||
int yMask = -1;// y Mask
|
||||
BufferedImage buffImg;
|
||||
Graphics g;
|
||||
String note;
|
||||
public KeyAdapter keyAdapter;
|
||||
|
||||
public BrainPicture(int x, int y, float brainWidth, int brainDispWidth) {
|
||||
super();
|
||||
this.setLayout(null);// 空布局
|
||||
this.brainDispWidth = brainDispWidth;
|
||||
scale = 0.5f * brainDispWidth / brainWidth;
|
||||
this.setBounds(x, y, brainDispWidth + 1, brainDispWidth + 1);
|
||||
buffImg = new BufferedImage(Env.FROG_BRAIN_DISP_WIDTH, Env.FROG_BRAIN_DISP_WIDTH, BufferedImage.TYPE_INT_RGB);
|
||||
g = buffImg.getGraphics();
|
||||
MouseAction act = new MouseAction(this);
|
||||
this.addMouseListener(act); // 添加鼠标动作监听
|
||||
this.addMouseWheelListener(act);// 添加鼠标滚轮动作监听
|
||||
this.addMouseMotionListener(act);// 添加鼠标移动动作监听
|
||||
|
||||
keyAdapter = new KeyAdapter() {// 处理t,f,l,r,x键盘命令
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
switch (e.getKeyCode()){
|
||||
case KeyEvent.VK_UP:// Y切面向上
|
||||
yMask++;
|
||||
if (yMask > Env.BRAIN_YSIZE)
|
||||
yMask = Env.BRAIN_YSIZE;
|
||||
break;
|
||||
case KeyEvent.VK_DOWN:// Y切面向下
|
||||
yMask--;
|
||||
if (yMask < 0)
|
||||
yMask = 0;
|
||||
break;
|
||||
case KeyEvent.VK_LEFT:// x切面向左
|
||||
xMask--;
|
||||
if (xMask < 0)
|
||||
xMask = 0;
|
||||
break;
|
||||
case KeyEvent.VK_RIGHT:// x切面向右
|
||||
xMask++;
|
||||
if (xMask > Env.BRAIN_XSIZE)
|
||||
xMask = Env.BRAIN_XSIZE;
|
||||
break;
|
||||
case ' ':// 暂停及继续
|
||||
Application.pauseAction.actionPerformed(null);
|
||||
break;
|
||||
case 'T':// 顶视
|
||||
xAngle = 0;
|
||||
yAngle = 0;
|
||||
zAngle = 0;
|
||||
break;
|
||||
case 'F':// 前视
|
||||
xAngle = D90;
|
||||
yAngle = 0;
|
||||
zAngle = 0;
|
||||
break;
|
||||
case 'L':// 左视
|
||||
xAngle = D90;
|
||||
yAngle = D90;
|
||||
zAngle = 0;
|
||||
break;
|
||||
case 'R':// 右视
|
||||
xAngle = D90;
|
||||
yAngle = -D90;
|
||||
zAngle = 0;
|
||||
break;
|
||||
case 'X':// 斜视
|
||||
xAngle = D90 * .8f;
|
||||
yAngle = D90 / 4;
|
||||
zAngle = 0;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
};
|
||||
addKeyListener(keyAdapter);
|
||||
this.setFocusable(true);
|
||||
}
|
||||
|
||||
public void drawCuboid(Cuboid c) {// 在脑图上画一个长立方体框架,视角是TopView
|
||||
drawCuboid(c.x, c.y, c.z, c.xe, c.ye, c.ze);
|
||||
}
|
||||
|
||||
public void drawCuboid(float x, float y, float z, float xe, float ye, float ze) {// 在脑图上画一个长立方体框架,视角是TopView
|
||||
drawLine(x, y, z, x + xe, y, z);// 画立方体的下面边
|
||||
drawLine(x + xe, y, z, x + xe, y + ye, z);
|
||||
drawLine(x + xe, y + ye, z, x, y + ye, z);
|
||||
drawLine(x, y + ye, z, x, y, z);
|
||||
|
||||
drawLine(x, y, z, x, y, z + ze);// 画立方体的中间边
|
||||
drawLine(x + xe, y, z, x + xe, y, z + ze);
|
||||
drawLine(x + xe, y + ye, z, x + xe, y + ye, z + ze);
|
||||
drawLine(x, y + ye, z, x, y + ye, z + ze);
|
||||
|
||||
drawLine(x, y, z + ze, x + xe, y, z + ze);// 画立方体的上面边
|
||||
drawLine(x + xe, y, z + ze, x + xe, y + ye, z + ze);
|
||||
drawLine(x + xe, y + ye, z + ze, x, y + ye, z + ze);
|
||||
drawLine(x, y + ye, z + ze, x, y, z + ze);
|
||||
}
|
||||
|
||||
/*-
|
||||
画线,固定以top视角的角度,所以只需要从x1,y1画一条到x2,y2的直线
|
||||
绕 x 轴旋转 θ
|
||||
x, y.cosθ-zsinθ, y.sinθ+z.cosθ
|
||||
|
||||
绕 y 轴旋转 θ
|
||||
z.sinθ+x.cosθ, y, z.cosθ-x.sinθ
|
||||
|
||||
绕 z 轴旋转 θ
|
||||
x.cosθ-y.sinθ, x.sinθ+y.consθ, z
|
||||
-*/
|
||||
public void drawLine(float px1, float py1, float pz1, float px2, float py2, float pz2) {
|
||||
double x1 = px1 - Env.BRAIN_XSIZE / 2;
|
||||
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的,显示时要正过来
|
||||
double z1 = pz1 - Env.BRAIN_ZSIZE / 2;
|
||||
double x2 = px2 - Env.BRAIN_XSIZE / 2;
|
||||
double y2 = -py2 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的,显示时要正过来
|
||||
double z2 = pz2 - Env.BRAIN_ZSIZE / 2;
|
||||
x1 = x1 * scale;
|
||||
y1 = y1 * scale;
|
||||
z1 = z1 * scale;
|
||||
x2 = x2 * scale;
|
||||
y2 = y2 * scale;
|
||||
z2 = z2 * scale;
|
||||
double x, y, z;
|
||||
y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
|
||||
z = y1 * sin(xAngle) + z1 * cos(xAngle);
|
||||
y1 = y;
|
||||
z1 = z;
|
||||
|
||||
x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
|
||||
// z = z1 * cos(yAngle) - x1 * sin(yAngle);
|
||||
x1 = x;
|
||||
// z1 = z;
|
||||
|
||||
x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
|
||||
y = x1 * sin(zAngle) + y1 * cos(zAngle);
|
||||
x1 = x;
|
||||
y1 = y;
|
||||
|
||||
y = y2 * cos(xAngle) - z2 * sin(xAngle);// 绕x轴转
|
||||
z = y2 * sin(xAngle) + z2 * cos(xAngle);
|
||||
y2 = y;
|
||||
z2 = z;
|
||||
|
||||
x = z2 * sin(yAngle) + x2 * cos(yAngle);// 绕y轴转
|
||||
// z = z2 * cos(yAngle) - x2 * sin(yAngle);
|
||||
x2 = x;
|
||||
// z2 = z;
|
||||
|
||||
x = x2 * cos(zAngle) - y2 * sin(zAngle);// 绕z轴转
|
||||
y = x2 * sin(zAngle) + y2 * cos(zAngle);
|
||||
x2 = x;
|
||||
y2 = y;
|
||||
|
||||
g.setColor(picColor);
|
||||
g.drawLine((int) round(x1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset, (int) round(y1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset, (int) round(x2) + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset,
|
||||
(int) round(y2) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset);
|
||||
}
|
||||
|
||||
/** 画点,固定以top视角的角度,所以只需要在x1,y1位置画一个点 */
|
||||
public void drawPoint(float px1, float py1, float pz1, float r) {
|
||||
double x1 = px1 - Env.BRAIN_XSIZE / 2;
|
||||
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的,显示时要正过来
|
||||
double z1 = pz1 - Env.BRAIN_ZSIZE / 2;
|
||||
x1 = x1 * scale;
|
||||
y1 = y1 * scale;
|
||||
z1 = z1 * scale;
|
||||
double x, y, z;
|
||||
y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
|
||||
z = y1 * sin(xAngle) + z1 * cos(xAngle);
|
||||
y1 = y;
|
||||
z1 = z;
|
||||
|
||||
x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
|
||||
// z = z1 * cos(yAngle) - x1 * sin(yAngle);
|
||||
x1 = x;
|
||||
// z1 = z;
|
||||
|
||||
x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
|
||||
y = x1 * sin(zAngle) + y1 * cos(zAngle);
|
||||
x1 = x;
|
||||
y1 = y;
|
||||
|
||||
g.setColor(picColor);
|
||||
g.fillOval(round((float) x1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset - r * scale * .5f), round((float) y1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset - r * scale * .5f), round(r * scale),
|
||||
round(r * scale));
|
||||
}
|
||||
|
||||
/** 画一个圆 */
|
||||
public void drawCircle(float px1, float py1, float pz1, float r) {//这个方法实际和上面的一样的,只是改成了drawOval
|
||||
double x1 = px1 - Env.BRAIN_XSIZE / 2;
|
||||
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的,显示时要正过来
|
||||
double z1 = pz1 - Env.BRAIN_ZSIZE / 2;
|
||||
x1 = x1 * scale;
|
||||
y1 = y1 * scale;
|
||||
z1 = z1 * scale;
|
||||
double x, y, z;
|
||||
y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
|
||||
z = y1 * sin(xAngle) + z1 * cos(xAngle);
|
||||
y1 = y;
|
||||
z1 = z;
|
||||
|
||||
x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
|
||||
// z = z1 * cos(yAngle) - x1 * sin(yAngle);
|
||||
x1 = x;
|
||||
// z1 = z;
|
||||
|
||||
x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
|
||||
y = x1 * sin(zAngle) + y1 * cos(zAngle);
|
||||
x1 = x;
|
||||
y1 = y;
|
||||
|
||||
g.setColor(picColor);
|
||||
g.drawOval(round((float) x1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset - r * scale * .5f), round((float) y1 + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset - r * scale * .5f), round(r * scale),
|
||||
round(r * scale));
|
||||
}
|
||||
|
||||
public void drawText(float px1, float py1, float pz1, String text, float textSize) {
|
||||
double x1 = px1 - Env.BRAIN_XSIZE / 2;
|
||||
double y1 = -py1 + Env.BRAIN_YSIZE / 2;// 屏幕的y坐标是反的,显示时要正过来
|
||||
double z1 = pz1 - Env.BRAIN_ZSIZE / 2;
|
||||
x1 = x1 * scale;
|
||||
y1 = y1 * scale;
|
||||
z1 = z1 * scale;
|
||||
double x, y, z;
|
||||
y = y1 * cos(xAngle) - z1 * sin(xAngle);// 绕x轴转
|
||||
z = y1 * sin(xAngle) + z1 * cos(xAngle);
|
||||
y1 = y;
|
||||
z1 = z;
|
||||
|
||||
x = z1 * sin(yAngle) + x1 * cos(yAngle);// 绕y轴转
|
||||
// z = z1 * cos(yAngle) - x1 * sin(yAngle);
|
||||
x1 = x;
|
||||
// z1 = z;
|
||||
|
||||
x = x1 * cos(zAngle) - y1 * sin(zAngle);// 绕z轴转
|
||||
y = x1 * sin(zAngle) + y1 * cos(zAngle);
|
||||
x1 = x;
|
||||
y1 = y;
|
||||
|
||||
g.setColor(picColor);
|
||||
g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, (int) round(textSize * scale)));
|
||||
g.drawString(text, (int) round(x1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + xOffset, (int) round(y1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset);
|
||||
|
||||
}
|
||||
|
||||
private static Cuboid brain = new Cuboid(0, 0, 0, Env.BRAIN_XSIZE, Env.BRAIN_YSIZE, Env.BRAIN_ZSIZE);
|
||||
|
||||
public void drawBrainPicture() {// 在这个方法里进行动物的三维脑结构的绘制,蛇是青蛙的子类,所以也可以当参数传进来
|
||||
if (!Env.SHOW_FIRST_ANIMAL_BRAIN)
|
||||
return;
|
||||
if (Env.show_split_detail)
|
||||
drawSplitDetail();
|
||||
else
|
||||
drawBrainStructure();
|
||||
}
|
||||
|
||||
public void drawSplitDetail() {// 在这个方法里绘制脑细胞分裂的显示步聚,即从一个细胞开始分裂成最终脑结构的每一步
|
||||
Animal a = Env.getShowAnimal(); // 第一个青蛙或蛇
|
||||
|
||||
for (int i = Env.BRAIN_CUBE_SIZE; i >= 1; i /= 2) {
|
||||
g.setColor(WHITE);// 先清空旧图, g是buffImg,绘在内存中
|
||||
g.fillRect(0, 0, brainDispWidth, brainDispWidth);
|
||||
g.setColor(BLACK); // 画边框
|
||||
g.drawRect(0, 0, brainDispWidth, brainDispWidth);
|
||||
|
||||
for (int geneIndex = 0; geneIndex < Cells.GENE_NUMBERS; geneIndex++) {
|
||||
ArrayList<Integer> gene = a.genes.get(geneIndex);
|
||||
Tree8Util.knockNodesByGene(gene);
|
||||
for (int j = 0; j < Tree8Util.NODE_QTY; j++) {
|
||||
if (Tree8Util.keep[j] > 0) {
|
||||
int[] node = Tree8Util.TREE8[j];
|
||||
int size = node[0];
|
||||
if (size == i && Cells.display_gene[geneIndex]) {//如果允许显示的话, 显示当前层级的节点
|
||||
setPicColor(ColorUtils.colorByCode(geneIndex));
|
||||
drawPoint(node[1] + size / 2, node[2] + size / 2, node[3] + size / 2, size * (0.5f - geneIndex * 0.05f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
g.setColor(BLACK);
|
||||
drawCuboid(brain);// 把脑的框架画出来
|
||||
this.getGraphics().drawImage(buffImg, 0, 0, this);// 利用缓存避免画面闪烁,这里输出缓存图片
|
||||
if (!Env.show_split_detail)
|
||||
return;
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void drawBrainStructure() {// 在这个方法里进行动物的三维脑结构的绘制,蛇是青蛙的子类,所以也可以当参数传进来
|
||||
Animal a = Env.getShowAnimal(); // 显示第一个青蛙或蛇
|
||||
if (a == null || !a.alive)
|
||||
return;
|
||||
g.setColor(WHITE);// 先清空旧图, g是buffImg,绘在内存中
|
||||
g.fillRect(0, 0, brainDispWidth, brainDispWidth);
|
||||
g.setColor(BLACK); // 画边框
|
||||
g.drawRect(0, 0, brainDispWidth, brainDispWidth);
|
||||
|
||||
for (int z = 0; z < Env.BRAIN_CUBE_SIZE; z++) {
|
||||
for (int y = Env.BRAIN_CUBE_SIZE - 1; y >= 0; y--) {
|
||||
for (int x = Env.BRAIN_CUBE_SIZE - 1; x >= 0; x--) {
|
||||
long cell = a.cells[x][y][z];
|
||||
if ((cell & Cells.EXIST) == 0) //只显示有效的细胞点
|
||||
continue;
|
||||
if (a.energys[x][y][z] > 1) { //用大红色圆形画出能量大于1的细胞格
|
||||
setPicColor(Color.MAGENTA); //开始画出对应的细胞基因参数,用不同颜色直径圆表示
|
||||
drawCircle(x + 0.5f, y + 0.5f, z + 0.5f, 1.2f);
|
||||
}
|
||||
if (x >= xMask && y >= yMask && cell != 0)//画出细胞每个基因存在的细胞格子
|
||||
for (int geneIndex = 0; geneIndex < Cells.GENE_NUMBERS; geneIndex++) {
|
||||
if ((cell & (1 << geneIndex)) != 0 && Cells.display_gene[geneIndex]) {
|
||||
setPicColor(ColorUtils.colorByCode(geneIndex)); //开始画出对应的细胞基因参数,用不同颜色直径圆表示
|
||||
drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, geneIndex == 0 ? 0.8f : 0.5f - geneIndex * 0.05f);
|
||||
}
|
||||
}
|
||||
if (((cell & ZT) > 0)) { //如有轴突基因,则从当前细胞到轴突端点画一条红线
|
||||
int x_ = (int) ((cell & ZTX) >> ZTX0);
|
||||
if (x_ == 0)
|
||||
x_ = -1;
|
||||
int y_ = (int) ((cell & ZTY) >> ZTY0);
|
||||
if (y_ == 0)
|
||||
y_ = -1;
|
||||
int z_ = (int) ((cell & ZTZ) >> ZTZ0);
|
||||
if (z_ == 0)
|
||||
z_ = -1;
|
||||
int zt_long = (int) ((cell & ZT_LONG) >> ZT_LONG0) + 1; //轴突长度, 大小为1~8
|
||||
int xx = x + x_ * zt_long;
|
||||
int yy = y + y_ * zt_long;
|
||||
int zz = z + z_ * zt_long;
|
||||
if (Env.insideBrain(xx, yy, zz)) {
|
||||
setPicColor(Color.RED);
|
||||
drawLine(x+.5f, y+.5f, z+.5f, xx+.5f, yy+.5f, zz+.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Eye.drawEye(this);//画眼睛
|
||||
|
||||
setPicColor(Color.BLACK);
|
||||
drawCuboid(brain);// 把脑的框架画出来
|
||||
|
||||
setPicColor(BLACK); //把x,y,z坐标画出来
|
||||
drawText(Env.BRAIN_CUBE_SIZE, 0, 0, "x", 2);
|
||||
drawText(0, Env.BRAIN_CUBE_SIZE, 0, "y", 2);
|
||||
drawText(0, 0, Env.BRAIN_CUBE_SIZE, "z", 2);
|
||||
setPicColor(RED);
|
||||
drawLine(0, 0, 0, Env.BRAIN_CUBE_SIZE, 0, 0);
|
||||
drawLine(0, 0, 0, 0, Env.BRAIN_CUBE_SIZE, 0);
|
||||
drawLine(0, 0, 0, 0, 0, Env.BRAIN_CUBE_SIZE);
|
||||
|
||||
g.setColor(Color.black);
|
||||
if (note != null) // 全局注释
|
||||
g.drawString(note, 30, 55);
|
||||
this.getGraphics().drawImage(buffImg, 0, 0, this);// 利用缓存避免画面闪烁,这里输出缓存图片
|
||||
}
|
||||
|
||||
public static void setNote(String note) {
|
||||
Application.brainPic.note = note;
|
||||
}
|
||||
|
||||
// getters & setters
|
||||
public float getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
public void setScale(float scale) {
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
public float getxAngle() {
|
||||
return xAngle;
|
||||
}
|
||||
|
||||
public void setxAngle(float xAngle) {
|
||||
this.xAngle = xAngle;
|
||||
}
|
||||
|
||||
public float getyAngle() {
|
||||
return yAngle;
|
||||
}
|
||||
|
||||
public void setyAngle(float yAngle) {
|
||||
this.yAngle = yAngle;
|
||||
}
|
||||
|
||||
public float getzAngle() {
|
||||
return zAngle;
|
||||
}
|
||||
|
||||
public void setzAngle(float zAngle) {
|
||||
this.zAngle = zAngle;
|
||||
}
|
||||
|
||||
public void setPicColor(Color color) {
|
||||
this.picColor = color;
|
||||
}
|
||||
|
||||
public Color getPicColor() {
|
||||
return picColor;
|
||||
}
|
||||
|
||||
public int getxOffset() {
|
||||
return xOffset;
|
||||
}
|
||||
|
||||
public void setxOffset(int xOffset) {
|
||||
this.xOffset = xOffset;
|
||||
}
|
||||
|
||||
public int getyOffset() {
|
||||
return yOffset;
|
||||
}
|
||||
|
||||
public void setyOffset(int yOffset) {
|
||||
this.yOffset = yOffset;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.brain;
|
||||
|
||||
import com.gitee.drinkjava2.frog.Animal;
|
||||
import com.gitee.drinkjava2.frog.Env;
|
||||
import com.gitee.drinkjava2.frog.util.Logger;
|
||||
import com.gitee.drinkjava2.frog.util.RandomUtils;
|
||||
|
||||
/**
|
||||
* Cells代表不同的脑细胞参数,对应每个参数,用8叉树算法生成不同的细胞。
|
||||
* 每个脑细胞用一个long来存储,所以最多允许64个基因位, 有时一个参数由多个基因位决定。每个基因位都由一个单独的阴阳8叉树控制,多个基因就组成了一个8叉树阵列
|
||||
* 基因+分裂算法=结构
|
||||
* 基因+分裂算法+遗传算法=结构的进化
|
||||
* 这个类里定义每个基因位的掩码, 脑结构的所有参数,都要用基因来控制。开始时可以有常量、魔数,但以后都放到基因里去自动进化。
|
||||
*
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 10.0
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class Cells {
|
||||
public static int GENE_NUMBERS = 0;
|
||||
private static int zeros = 0;
|
||||
public static boolean[] display_gene = new boolean[64]; //脑最多有64个基因,这里用来控制哪些基因需要显示在脑图上
|
||||
|
||||
public static long EXIST = mask(1, true); // 细胞存在否,1为存在,0为不存在, true表示显示在脑图上
|
||||
public static long MOVE_UP = mask(1, true); //如此点为1,则此细胞如有能量,青蛙向上移动
|
||||
public static long MOVE_DOWN = mask(1, true); //如此点为1,则此细胞如有能量,青蛙向下移动
|
||||
public static long MOVE_LEFT = mask(1, true); //如此点为1,则此细胞如有能量,青蛙向左移动
|
||||
public static long MOVE_RIGHT = mask(1, true); //如此点为1,则此细胞如有能量,青蛙向右移动
|
||||
public static long ZT_LONG = mask(3, false); //轴突长度
|
||||
public static long ZT_LONG0 = zeros; //如果参数由多位组成,用同名+0变量表示有几个0,移位运算时用来去除0。下同
|
||||
public static long ZT = mask(1, true);//axon exist 轴突是否存在
|
||||
public static long ZTX = mask(1, false);//axon x offset, 轴突x方向, 轴突方向由x,y,z三个方向的参数组合决定
|
||||
public static long ZTX0 = zeros; //x方向暂定1位,如果2位也可以,角度更细,但出结果的时间会比较长
|
||||
public static long ZTY = mask(1, false); //轴突y方向
|
||||
public static long ZTY0 = zeros;
|
||||
public static long ZTZ = mask(1, false); //轴突z方向
|
||||
public static long ZTZ0 = zeros;
|
||||
public static long ZT_MINUS = mask(1, false);//细胞信号,1为正信号,0为负(抑制)信号
|
||||
|
||||
// public static long RANDOM_ACTIVE = mask(1, true);//这个基因控制细胞随机产生能量,对结果影响不大,会让静止的青蛙颤抖
|
||||
|
||||
// public static long ST_LONG = mask(2, false); //dendrite radius, 树突长度半径,待后继版本用到
|
||||
// public static long ST_LONG0 = zeros;
|
||||
// public static long HAPPY = mask(1, false); //吃食奖励信号,待后继版本用到
|
||||
|
||||
public static long mask(int n, boolean display) { //返回基因掩码,高位由n个1组成,低位是当前GENE_NUMBERS个0,这个方法执行后GENE_NUMBERS会加n
|
||||
for (int i = GENE_NUMBERS; i < GENE_NUMBERS + n; i++) {
|
||||
display_gene[i] = display;
|
||||
}
|
||||
|
||||
String one = "";
|
||||
String zero = "";
|
||||
for (int i = 1; i <= n; i++)
|
||||
one += "1";
|
||||
for (int i = 1; i <= GENE_NUMBERS; i++)
|
||||
zero += "0";
|
||||
zeros = GENE_NUMBERS;
|
||||
GENE_NUMBERS += n;
|
||||
if (GENE_NUMBERS >= 64) {//
|
||||
System.out.println("目前基因位数不能超过64");
|
||||
System.exit(-1);
|
||||
}
|
||||
return Long.parseLong(one + zero, 2); //将"111000"这种字符串转换为长整
|
||||
}
|
||||
|
||||
public static void active(Animal a) {//这个方法的功能是根据细胞的参数,在细胞间传输能量(即信息的载体)
|
||||
for (int z = Env.BRAIN_CUBE_SIZE - 1; z >= 0; z--)
|
||||
for (int y = Env.BRAIN_CUBE_SIZE - 1; y >= 0; y--)
|
||||
for (int x = Env.BRAIN_CUBE_SIZE - 1; x >= 0; x--) {
|
||||
long cell = a.cells[x][y][z];
|
||||
|
||||
if ((cell & EXIST) == 0) //如细胞不存在,
|
||||
continue;
|
||||
|
||||
// if ((cell & RANDOM_ACTIVE) > 0) //随机产生细胞能量,会让青蛙颤抖
|
||||
// if (RandomUtils.percent(5))
|
||||
// a.energys[x][y][z] = 1;
|
||||
|
||||
float e = a.energys[x][y][z];
|
||||
if (e > 0 && ((cell & ZT) > 0)) { //如有轴突基因,则当前细胞如存在能量,会输送到轴突端点处
|
||||
int x_ = (int) ((cell & ZTX) >> ZTX0); //把掩码转为坐标偏移量,因为暂定只有1位,所以只有1,-1
|
||||
if (x_ == 0)
|
||||
x_ = -1;
|
||||
int y_ = (int) ((cell & ZTY) >> ZTY0);
|
||||
if (y_ == 0)
|
||||
y_ = -1;
|
||||
int z_ = (int) ((cell & ZTZ) >> ZTZ0);
|
||||
if (z_ == 0)
|
||||
z_ = -1;
|
||||
int zt_long = (int) ((cell & ZT_LONG) >> ZT_LONG0) + 1; //轴突长度, 大小为1~8
|
||||
int xx = x + x_ * zt_long;
|
||||
int yy = y + y_ * zt_long;
|
||||
int zz = z + z_ * zt_long;
|
||||
if (Env.insideBrain(xx, yy, zz)) {
|
||||
if (a.energys[xx][yy][zz] < 10) {
|
||||
if ((cell & ZT_MINUS) > 0) //如果轴空是负信号
|
||||
a.energys[xx][yy][zz]--;
|
||||
else
|
||||
a.energys[xx][yy][zz]++;
|
||||
if (a.energys[x][y][z] > 0)
|
||||
a.energys[x][y][z]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
e = a.energys[x][y][z];
|
||||
if ((e > 0) && (z < Env.BRAIN_ZSIZE - 1)) { //如当前细胞有能量,且不和眼睛在同一层,且有移动细胞,则青蛙移动
|
||||
if ((cell & MOVE_UP) > 0) {//向上y是减,屏幕y的0点在上方
|
||||
a.energys[x][y][z] = 0;
|
||||
a.y++;
|
||||
}
|
||||
if ((cell & MOVE_DOWN) > 0) {
|
||||
a.energys[x][y][z] = 0;
|
||||
a.y--;
|
||||
}
|
||||
if ((cell & MOVE_LEFT) > 0) {
|
||||
a.energys[x][y][z] = 0;
|
||||
a.x--;
|
||||
}
|
||||
if ((cell & MOVE_RIGHT) > 0) {
|
||||
a.energys[x][y][z] = 0;
|
||||
a.x++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.brain;
|
||||
|
||||
/**
|
||||
* Cuboid represents a rectangular prism 3d zone in brain
|
||||
*
|
||||
* Cuboid是一个长方体,通常用来表示脑内器官的形状
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 2.0.2
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class Cuboid {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public float x;// x,y,z是长方体的左下角坐标
|
||||
public float y;
|
||||
public float z;
|
||||
public float xe;// xe,ye,ze分别是长方体三边长
|
||||
public float ye;
|
||||
public float ze;
|
||||
|
||||
public Cuboid() {
|
||||
// 空构造器不能省
|
||||
}
|
||||
|
||||
public Cuboid(float x, float y, float z, float xe, float ye, float ze) {// 用x,y,z,r来构造
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.xe = xe;
|
||||
this.ye = ye;
|
||||
this.ze = ze;
|
||||
}
|
||||
|
||||
public Cuboid(Cuboid c) {// 用另一个Cuboid来构造
|
||||
this.x = c.x;
|
||||
this.y = c.y;
|
||||
this.z = c.z;
|
||||
this.xe = c.xe;
|
||||
this.ye = c.ye;
|
||||
this.ze = c.ze;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.brain;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
import com.gitee.drinkjava2.frog.Animal;
|
||||
import com.gitee.drinkjava2.frog.Env;
|
||||
import com.gitee.drinkjava2.frog.objects.Material;
|
||||
|
||||
/**
|
||||
* Eye, if found food then set cell energy at top level
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
public class Eye {
|
||||
|
||||
/** First eye can only see if food nearby at 4 directions */
|
||||
public static void active(Animal a) {// 眼睛只能观察上、下、左、右四个方向有没有食物,如发现食物,就将最上层的四个边的细胞激活成1能量
|
||||
int seeDist = 15; //眼睛能看多远
|
||||
for (int i = 1; i < seeDist; i++)
|
||||
if (Env.hasMaterial(a.x, a.y + i, Material.FOOD)) {//up
|
||||
for (int x = 1; x < Env.BRAIN_XSIZE; x++)
|
||||
a.energys[x][Env.BRAIN_YSIZE - 1][Env.BRAIN_ZSIZE - 1] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 1; i < seeDist; i++)
|
||||
if (Env.hasMaterial(a.x, a.y - i, Material.FOOD)) { //down
|
||||
for (int x = 0; x < Env.BRAIN_XSIZE - 1; x++)
|
||||
a.energys[x][0][Env.BRAIN_ZSIZE - 1] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 1; i < seeDist; i++)
|
||||
if (Env.hasMaterial(a.x - i, a.y, Material.FOOD)) { //left
|
||||
for (int y = 1; y < Env.BRAIN_YSIZE; y++)
|
||||
a.energys[0][y][Env.BRAIN_ZSIZE - 1] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 1; i < seeDist; i++)
|
||||
if (Env.hasMaterial(a.x + i, a.y, Material.FOOD)) {//right
|
||||
for (int y = 0; y < Env.BRAIN_YSIZE - 1; y++)
|
||||
a.energys[Env.BRAIN_XSIZE - 1][y][Env.BRAIN_ZSIZE - 1] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void drawEye(BrainPicture bp) {//在脑图中画出眼睛
|
||||
bp.setPicColor(Color.RED);
|
||||
for (int x = 1; x < Env.BRAIN_XSIZE; x++)
|
||||
bp.drawCircle(x + 0.5f, Env.BRAIN_YSIZE - 0.5f, Env.BRAIN_ZSIZE - 0.5f, 1);
|
||||
bp.setPicColor(Color.YELLOW);
|
||||
for (int x = 0; x < Env.BRAIN_XSIZE - 1; x++)
|
||||
bp.drawCircle(x + 0.5f, 0.5f, Env.BRAIN_ZSIZE - 0.5f, 1);
|
||||
bp.setPicColor(Color.BLUE);
|
||||
for (int y = 1; y < Env.BRAIN_YSIZE; y++)
|
||||
bp.drawCircle(0.5f, y + 0.5f, Env.BRAIN_ZSIZE - 0.5f, 1);
|
||||
bp.setPicColor(Color.GREEN);
|
||||
for (int y = 0; y < Env.BRAIN_YSIZE - 1; y++)
|
||||
bp.drawCircle(Env.BRAIN_XSIZE - 0.5f, y + 0.5f, Env.BRAIN_ZSIZE - 0.5f, 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
package com.gitee.drinkjava2.frog.brain;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.event.MouseWheelListener;
|
||||
|
||||
/**
|
||||
* MouseAction
|
||||
*
|
||||
* 这个类用来处理脑图BrainPicture上的鼠标动作,有平移、旋转、缩放三种
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 2.0.2
|
||||
*/
|
||||
public class MouseAction implements MouseListener, MouseWheelListener, MouseMotionListener {
|
||||
private BrainPicture brainPic;
|
||||
private int buttonPressed = 0;
|
||||
private int x;
|
||||
private int y;
|
||||
|
||||
public MouseAction(BrainPicture brainPic) {
|
||||
this.brainPic = brainPic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {// 记录当前鼠标点
|
||||
if (e.getButton() == 1)// 旋转
|
||||
buttonPressed = 1;
|
||||
else if (e.getButton() == 2)// 缩放
|
||||
buttonPressed = 2;
|
||||
else
|
||||
buttonPressed = 0;
|
||||
x = e.getPoint().x;
|
||||
y = e.getPoint().y;
|
||||
brainPic.requestFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
buttonPressed = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved(MouseWheelEvent e) {// 缩放
|
||||
if (e.getWheelRotation() < 0) {
|
||||
brainPic.scale *= 1.1;
|
||||
brainPic.xOffset *= 1.1;
|
||||
brainPic.yOffset *= 1.1;
|
||||
} else {
|
||||
brainPic.scale /= 1.1;
|
||||
brainPic.xOffset /= 1.1;
|
||||
brainPic.yOffset /= 1.1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {// 旋转
|
||||
if (buttonPressed == 1) {
|
||||
if (e.getX() > x && e.getY() > y)
|
||||
brainPic.zAngle -= .00f;
|
||||
else if (e.getX() < x && e.getY() < y)
|
||||
brainPic.zAngle += .00f;
|
||||
else {
|
||||
if (e.getX() > x)
|
||||
brainPic.yAngle += .02f;
|
||||
if (e.getX() < x)
|
||||
brainPic.yAngle -= .02f;
|
||||
if (e.getY() > y)
|
||||
brainPic.xAngle -= .02f;
|
||||
if (e.getY() < y)
|
||||
brainPic.xAngle += .02f;
|
||||
}
|
||||
x = e.getX();
|
||||
y = e.getY();
|
||||
}
|
||||
if (buttonPressed == 2) {// 平移
|
||||
if (e.getX() > x)
|
||||
brainPic.xOffset += 6;
|
||||
if (e.getX() < x)
|
||||
brainPic.xOffset -= 6;
|
||||
if (e.getY() > y)
|
||||
brainPic.yOffset += 6;
|
||||
if (e.getY() < y)
|
||||
brainPic.yOffset -= 6;
|
||||
x = e.getX();
|
||||
y = e.getY();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) { // do nothing
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.egg;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.gitee.drinkjava2.frog.Animal;
|
||||
import com.gitee.drinkjava2.frog.Env;
|
||||
import com.gitee.drinkjava2.frog.util.RandomUtils;
|
||||
|
||||
/**
|
||||
* Egg is the static structure description of brain cells
|
||||
*
|
||||
* 蛋存在的目的是为了以最小的字节数串行化存储脑细胞,它是海量脑细胞的生成算法描述,而不是脑细胞本身
|
||||
* 蛋和基因的关系:基因是一种语言,相当于染色体,不存在坐标位置。蛋则是基因的载体,有x,y坐标,表示在虚拟环境中蛋存在的位置。
|
||||
*
|
||||
* 另外青蛙本身也是基因的载体,所以青蛙里有一个gene属性
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
public class Egg implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public int x; // 蛋的x位置
|
||||
public int y; // 蛋的y位置
|
||||
|
||||
// gene record the 8-tree structure of brain cells
|
||||
// 基因是随机生成的8叉树数据结构,和实际生物每个细胞都要保存一份基因不同,程序中每个脑细胞并不需要保存基因的副本,这样可以极大地减少内存占用
|
||||
public ArrayList<ArrayList<Integer>> genes = new ArrayList<>();
|
||||
|
||||
public Egg() {// 无中生有,创建一个蛋,先有蛋,后有蛙
|
||||
x = RandomUtils.nextInt(Env.ENV_WIDTH);
|
||||
y = RandomUtils.nextInt(Env.ENV_HEIGHT);
|
||||
}
|
||||
|
||||
/** Create egg from animal */
|
||||
public Egg(Animal a) { // 下蛋,每个器官会创建自已的副本或变异,可以是0或多个
|
||||
x = a.x;
|
||||
y = a.y;
|
||||
for (ArrayList<Integer> gene : a.genes) {//下蛋就是把动物的基因拷贝到新蛋里,并有可能变异
|
||||
ArrayList<Integer> g = new ArrayList<>();
|
||||
g.addAll(gene);
|
||||
genes.add(g);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a egg by join 2 eggs, x+y=zygote 模拟X、Y 染色体合并,两个蛋生成一个新的蛋
|
||||
*/
|
||||
public Egg(Egg a, Egg b) {//两个蛋的基因混合, 生成一个新蛋
|
||||
x = a.x;
|
||||
y = a.y;
|
||||
genes.addAll(a.genes);
|
||||
if (RandomUtils.percent(20)) //插入蛋B的基因到A蛋中
|
||||
for (int i = 0; i < b.genes.size(); i++) {
|
||||
if (RandomUtils.percent(2)) {
|
||||
ArrayList<Integer> aGene = a.genes.get(i);
|
||||
ArrayList<Integer> bGene = b.genes.get(i);
|
||||
if (bGene.size() > 1) {//随机插入一个B的基因,不用担心基因越来越多,因为随机删除的速度大于增长的
|
||||
aGene.add(bGene.get(RandomUtils.nextInt(bGene.size())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright 2018 the original author or authors.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.egg;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import com.gitee.drinkjava2.frog.Animal;
|
||||
import com.gitee.drinkjava2.frog.Application;
|
||||
import com.gitee.drinkjava2.frog.Env;
|
||||
import com.gitee.drinkjava2.frog.Frog;
|
||||
import com.gitee.drinkjava2.frog.util.LocalFileUtils;
|
||||
import com.gitee.drinkjava2.frog.util.Logger;
|
||||
|
||||
/**
|
||||
* FrogEggTool save/load frog eggs to file
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class FrogEggTool {
|
||||
|
||||
/**
|
||||
* Frogs which have higher energy lay eggs
|
||||
*
|
||||
* 利用Java串行机制存盘。 能量多(也就是吃的更多)的Frog下蛋并存盘, 以进行下一轮测试,能量少的Frog被淘汰,没有下蛋的资格。
|
||||
* 用能量的多少来简化生存竟争模拟,每次下蛋数量固定为EGG_QTY个
|
||||
*/
|
||||
public static void layEggs() {
|
||||
sortFrogsOrderByEnergyDesc();
|
||||
Frog first = Env.frogs.get(0);
|
||||
Frog last = Env.frogs.get(Env.frogs.size() - 1);
|
||||
try {
|
||||
Env.frog_eggs.clear();
|
||||
for (int i = 0; i < Env.FROG_EGG_QTY; i++)
|
||||
Env.frog_eggs.add(new Egg(Env.frogs.get(i)));
|
||||
Logger.info("Fist frog energy={}, gene size={}, Last frog energy={}", first.energy, getGeneSize(first), last.energy);
|
||||
if (Env.SAVE_EGGS_FILE) {
|
||||
FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "frog_eggs.ser");
|
||||
ObjectOutputStream so = new ObjectOutputStream(fo);
|
||||
so.writeObject(Env.frog_eggs);
|
||||
so.close();
|
||||
Logger.info(". Saved {} eggs to file '{}frog_eggs.ser'", Env.frog_eggs.size(), Application.CLASSPATH);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Logger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getGeneSize(Frog f) {//按genes类型汇总每种基因的个数
|
||||
StringBuilder sb=new StringBuilder("[");
|
||||
for (int i = 0; i < f.genes.size(); i++)
|
||||
sb.append(f.genes.get(i).size()).append(",");
|
||||
if(sb.length()>1)
|
||||
sb.setLength(sb.length()-1);
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static void sortFrogsOrderByEnergyDesc() {// 按能量多少给青蛙排序
|
||||
Collections.sort(Env.frogs, new Comparator<Animal>() {
|
||||
public int compare(Animal a, Animal b) {
|
||||
if (a.energy > b.energy)
|
||||
return -1;
|
||||
else if (a.energy == b.energy)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void deleteEggs() {
|
||||
Logger.info("Delete exist egg file: '{}frog_eggs.ser'", Application.CLASSPATH);
|
||||
LocalFileUtils.deleteFile(Application.CLASSPATH + "frog_eggs.ser");
|
||||
}
|
||||
|
||||
/**
|
||||
* 从磁盘读入一批frog Egg
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void loadFrogEggs() {
|
||||
boolean errorfound = false;
|
||||
try {
|
||||
FileInputStream eggsFile = new FileInputStream(Application.CLASSPATH + "frog_eggs.ser");
|
||||
ObjectInputStream eggsInputStream = new ObjectInputStream(eggsFile);
|
||||
Env.frog_eggs = (List<Egg>) eggsInputStream.readObject();
|
||||
Logger.info("Loaded " + Env.frog_eggs.size() + " eggs from file '" + Application.CLASSPATH
|
||||
+ "frog_eggs.ser" + "'.\n");
|
||||
eggsInputStream.close();
|
||||
} catch (Exception e) {
|
||||
errorfound = true;
|
||||
}
|
||||
if (errorfound) {
|
||||
Env.frog_eggs.clear();
|
||||
for (int j = 0; j < Env.FROG_EGG_QTY; j++) {
|
||||
Egg egg = new Egg();
|
||||
Env.frog_eggs.add(egg);
|
||||
}
|
||||
Logger.info("Fail to load frog egg file '" + Application.CLASSPATH + "frog_eggs.ser" + "', created "
|
||||
+ Env.frog_eggs.size() + " eggs to do test.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/* Copyright 2018-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.objects;
|
||||
|
||||
/**
|
||||
* EnvObject means some virtual object in Env
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
public interface EnvObject {
|
||||
|
||||
public void build(); // 在Env中创建本身物体,指改变Env.bricks数组元素为本身物体的组成材料。只在每屏测试前调用一次
|
||||
|
||||
public void destory();// 从Env中清除本身物体,只在每屏测试完成后调用一次
|
||||
|
||||
public void active(); // 每个步长都会调用一次这个方法
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/* Copyright 2018-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.objects;
|
||||
|
||||
import static com.gitee.drinkjava2.frog.Env.ENV_HEIGHT;
|
||||
import static com.gitee.drinkjava2.frog.Env.ENV_WIDTH;
|
||||
import static com.gitee.drinkjava2.frog.Env.FOOD_QTY;
|
||||
|
||||
import com.gitee.drinkjava2.frog.Env;
|
||||
import com.gitee.drinkjava2.frog.util.RandomUtils;
|
||||
|
||||
/**
|
||||
* Food randomly scatter on Env
|
||||
* 食物
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
public enum Food implements EnvObject {
|
||||
FOOD; //FOOD是一个枚举型单例,整个环境只允许有一个FOOD实例
|
||||
|
||||
public static int food_ated = 0;
|
||||
|
||||
@Override
|
||||
public void build() {
|
||||
food_ated = 0;
|
||||
for (int i = 0; i < FOOD_QTY; i++) { // 随机位置生成食物
|
||||
int x = RandomUtils.nextInt(ENV_WIDTH);
|
||||
int y = RandomUtils.nextInt(ENV_HEIGHT);
|
||||
if (!Env.hasMaterial(x, y, Material.FOOD)) {
|
||||
Env.setMaterial(x, y, Material.FOOD); //在环境里标记上FOOD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destory() {
|
||||
food_ated=0;
|
||||
for (int x = 0; x < ENV_WIDTH; x++) // 清除食物
|
||||
for (int y = 0; y < ENV_HEIGHT; y++) {
|
||||
Env.clearMaterial(x, y, Material.FOOD);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void active() {
|
||||
//食物除了被吃,它自己没有什么活动
|
||||
}
|
||||
|
||||
public static boolean foundAndAteFood(int x, int y) {// 如果x,y有食物,将其清0,返回true
|
||||
if (Env.hasMaterial(x, y, Material.FOOD)) {
|
||||
food_ated++;
|
||||
Env.clearMaterial(x, y, Material.FOOD);//在环境里清除FOOD
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/* Copyright 2018-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.objects;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Material store material types
|
||||
*
|
||||
* 虚拟环境中每个点由一个int代表,多个材料可以同时出现在同一个点,每种材料用int中的一个bit位来表示,
|
||||
* 小于等于16384的位数用来标记青蛙序号,可利用Env.frogs.get(no-1)获取青蛙对象,其它各种材料用整数中其它位来表示
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
public class Material {// NOSONAR
|
||||
|
||||
public static final int FROG_TAG = 0b11111111111111; // 16383 小于等于16384的位数用来标记青蛙序号,可利用Env.frogs.get(no-1)快速定位青蛙
|
||||
|
||||
private static int material = FROG_TAG + 1; // 大于16384用来作为各种材料的标记
|
||||
|
||||
public static final int FOOD = nextMaterial();
|
||||
public static final int SNAKE = nextMaterial(); // 蛇的图形
|
||||
public static final int KILL_ANIMAL = nextMaterial(); // if>=KILLFROG will kill animal
|
||||
public static final int BRICK = nextMaterial();// brick will kill frog
|
||||
public static final int TRAP = nextMaterial(); // trap will kill frog
|
||||
|
||||
private static int nextMaterial() {// 每次将material左移1位
|
||||
material = material << 1;
|
||||
if (material < 0)
|
||||
throw new IllegalArgumentException("Material out of maximum range");
|
||||
return material;
|
||||
}
|
||||
|
||||
public static Color color(int material) {
|
||||
if ((material & TRAP) > 0)
|
||||
return Color.LIGHT_GRAY;
|
||||
else
|
||||
return Color.BLACK;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/* Copyright 2018-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.util;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* Color Utilities used in this project
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
public class ColorUtils {
|
||||
|
||||
private static final Color[] rainbow = new Color[]{Color.GRAY, Color.GREEN, Color.RED, Color.BLUE, Color.YELLOW, Color.ORANGE, Color.MAGENTA, Color.CYAN};
|
||||
|
||||
private static int nextColor = 0;
|
||||
|
||||
private ColorUtils() {// default private constr
|
||||
}
|
||||
|
||||
public static int nextColorCode() {
|
||||
return nextColor++;
|
||||
}
|
||||
|
||||
public static Color nextRainbowColor() {// 返回下一个彩虹色
|
||||
if (nextColor == rainbow.length)
|
||||
nextColor = 0;
|
||||
return rainbow[nextColor++];
|
||||
}
|
||||
|
||||
public static Color colorByCode(int i) {// 数值取模后返回一个固定彩虹色
|
||||
return rainbow[i % rainbow.length];
|
||||
}
|
||||
|
||||
public static Color rainbowColor(float i) { // 根据数值大小范围,在8种彩虹色中取值
|
||||
if (i <= 20)
|
||||
return Color.GRAY;
|
||||
if (i <= 30)
|
||||
return Color.BLACK;
|
||||
if (i <= 50)
|
||||
return Color.RED;
|
||||
return Color.MAGENTA;
|
||||
}
|
||||
|
||||
public static Color grayColor(float f) { // 根据数值大小范围0~1000,返回一个灰度色,越大越黑
|
||||
if (f > 1000)
|
||||
f = 1000;
|
||||
int i1 = 255 - (int) Math.round(f * .255);
|
||||
int i2 = 200 - (int) Math.round(f * .200);
|
||||
int i3 = 150 - (int) Math.round(f * .150);
|
||||
return new Color(i1, i2, i3);
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
/* Copyright 2018-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.util;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Local File Utilities used in this project
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
public class LocalFileUtils {
|
||||
|
||||
private LocalFileUtils() {
|
||||
// default constructor
|
||||
}
|
||||
|
||||
public static boolean deleteFile(String fileFullPath) {
|
||||
File file = new File(fileFullPath);
|
||||
return file.delete(); // NOSONAR
|
||||
}
|
||||
|
||||
public static void writeFile(String fileFullPath, byte[] byteArry) {
|
||||
File file = new File(fileFullPath);
|
||||
if (!file.getParentFile().exists())
|
||||
file.getParentFile().mkdirs();
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(file);
|
||||
fos.write(byteArry);
|
||||
fos.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
try {
|
||||
try {
|
||||
fos.flush();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeFile(String fileFullPath, String text, String encoding) {
|
||||
File file = new File(fileFullPath);
|
||||
if (!file.getParentFile().exists())
|
||||
file.getParentFile().mkdirs();
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(file);
|
||||
byte[] bytes;
|
||||
bytes = text.getBytes(encoding);
|
||||
fos.write(bytes);
|
||||
fos.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
try {
|
||||
try {
|
||||
fos.flush();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String readFile(String fileFullPath, String encoding) {
|
||||
InputStream inputStream;
|
||||
try {
|
||||
inputStream = new FileInputStream(new File(fileFullPath));
|
||||
} catch (FileNotFoundException e1) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int length;
|
||||
while ((length = inputStream.read(buffer)) != -1)
|
||||
result.write(buffer, 0, length);
|
||||
String string = result.toString(encoding);
|
||||
return string;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void appendFile(String fileName, String content) {
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(fileName, true);
|
||||
fos.write(content.getBytes());
|
||||
fos.write("\r\n".getBytes());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (fos != null) {
|
||||
try {
|
||||
try {
|
||||
fos.flush();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
/**
|
||||
* Usually a logger tool is used like below:
|
||||
* Logger log = LoggerFactory.getLogger(Xxxx.class);
|
||||
* log.info("some msg");
|
||||
*
|
||||
* But to simplify, in this project directly use static method:
|
||||
* Logger.info("some msg");
|
||||
*
|
||||
* @Description: 简版控制台日志打印,从码云上合并来,见 https://gitee.com/drinkjava2/frog/pulls/4
|
||||
* @author 栾成翔
|
||||
* @Date: 2021/12/07
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class Logger {
|
||||
private static final int LOGGER_STYLE = 0; //风格设定, 0:不输出前缀, 1:输出时间、类、行号等前缀
|
||||
private static final String LEV_EL = "debug";
|
||||
private static final int LEVEL_INT;
|
||||
private static final BlockingQueue<String> LOG_LIST = new ArrayBlockingQueue<>(256);
|
||||
private static final SimpleDateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
|
||||
private static final OutputStream OUTPUT_STREAM = System.out;
|
||||
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
|
||||
private static final String DELIM_STR = "{}";
|
||||
private static final String TAB = "\tat";
|
||||
private static final Map<String, Integer> LEVEL_MAP = new HashMap<>();
|
||||
|
||||
static {
|
||||
LEVEL_MAP.put("DEBUG", 1);
|
||||
LEVEL_MAP.put("INFO", 2);
|
||||
LEVEL_MAP.put("WARN", 2);
|
||||
LEVEL_MAP.put("ERROR", 2);
|
||||
LEVEL_INT = LEVEL_MAP.get(LEV_EL.toUpperCase());
|
||||
new Thread(() -> {
|
||||
while (true) {
|
||||
try {
|
||||
outPutConsole(LOG_LIST.take());
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public static void debug(String msg) {
|
||||
printLog(LEVEL_MAP.get("DEBUG"), msg);
|
||||
}
|
||||
|
||||
public static void debug(String msg, Object params) {
|
||||
printLog(LEVEL_MAP.get("DEBUG"), msg, params);
|
||||
}
|
||||
|
||||
public static void debug(String msg, Object... params) {
|
||||
printLog(LEVEL_MAP.get("DEBUG"), msg, params);
|
||||
}
|
||||
|
||||
public static void info(String msg) {
|
||||
printLog(LEVEL_MAP.get("INFO"), msg);
|
||||
}
|
||||
|
||||
public static void info(String msg, Object params) {
|
||||
printLog(LEVEL_MAP.get("INFO"), msg, params);
|
||||
}
|
||||
|
||||
public static void info(String msg, Object... params) {
|
||||
printLog(LEVEL_MAP.get("INFO"), msg, params);
|
||||
}
|
||||
|
||||
public static void warn(String msg) {
|
||||
printLog(LEVEL_MAP.get("WARN"), msg);
|
||||
}
|
||||
|
||||
public static void warn(String msg, Object params) {
|
||||
printLog(LEVEL_MAP.get("WARN"), msg, params);
|
||||
}
|
||||
|
||||
public static void warn(String msg, Object... params) {
|
||||
printLog(LEVEL_MAP.get("WARN"), msg, params);
|
||||
}
|
||||
|
||||
public static void error(String msg) {
|
||||
printLog(LEVEL_MAP.get("ERROR"), msg);
|
||||
}
|
||||
|
||||
public static void error(String msg, Object params) {
|
||||
printLog(LEVEL_MAP.get("ERROR"), msg, params);
|
||||
}
|
||||
|
||||
public static void error(String msg, Object... params) {
|
||||
printLog(LEVEL_MAP.get("ERROR"), msg, params);
|
||||
}
|
||||
|
||||
public static void error(Object param) {
|
||||
printLog(LEVEL_MAP.get("ERROR"), "", param);
|
||||
}
|
||||
|
||||
private static void printLog(int levelInt, String msg, Object... params) {
|
||||
try {
|
||||
if (levelInt >= LEVEL_INT) {
|
||||
LOG_LIST.put(generateMsg(getLevelStr(levelInt), msg, params));
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static String generateMsg(String levelStr, String msg, Object... params) {
|
||||
if(LOGGER_STYLE==0)
|
||||
return formatMsg(msg+ LINE_SEPARATOR, null, params);
|
||||
StackTraceElement stack = Thread.currentThread().getStackTrace()[4];
|
||||
String s = "{} [{}][{}#{} {}] - " + msg + LINE_SEPARATOR;
|
||||
Object[] args = new Object[5 + params.length];
|
||||
args[0] = FORMAT.format(System.currentTimeMillis());
|
||||
args[1] = levelStr;
|
||||
args[2] = stack.getClassName();
|
||||
args[3] = stack.getMethodName();
|
||||
args[4] = stack.getLineNumber();
|
||||
|
||||
Throwable throwable = null;
|
||||
if (params.length > 0) {
|
||||
final Object lastEntry = params[params.length - 1];
|
||||
if (lastEntry instanceof Throwable) {
|
||||
throwable = (Throwable) lastEntry;
|
||||
System.arraycopy(params, 0, args, 5, params.length - 1);
|
||||
} else {
|
||||
System.arraycopy(params, 0, args, 5, params.length);
|
||||
}
|
||||
}
|
||||
return formatMsg(s, throwable, args);
|
||||
}
|
||||
|
||||
private static String formatMsg(String msg, Throwable throwable, Object... params) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int s;
|
||||
int i = 0;
|
||||
for (Object o : params) {
|
||||
s = msg.indexOf(DELIM_STR, i);
|
||||
if (s > -1) {
|
||||
sb.append(msg, i, s).append(o);
|
||||
i = s + 2;
|
||||
}
|
||||
}
|
||||
sb.append(msg, i, msg.length());
|
||||
if (null != throwable) {
|
||||
sb.append(throwable).append(LINE_SEPARATOR);
|
||||
StackTraceElement[] stack = throwable.getStackTrace();
|
||||
for (StackTraceElement element : stack) {
|
||||
sb.append(TAB).append(element).append(LINE_SEPARATOR);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static void outPutConsole(String msg) {
|
||||
try {
|
||||
OUTPUT_STREAM.write(msg.getBytes(StandardCharsets.UTF_8));
|
||||
OUTPUT_STREAM.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getLevelStr(int levelInt) {
|
||||
switch (levelInt) {
|
||||
case 1:
|
||||
return "DEBUG";
|
||||
case 2:
|
||||
return "INFO";
|
||||
case 3:
|
||||
return "WARN";
|
||||
case 4:
|
||||
return "ERROR";
|
||||
default:
|
||||
throw new IllegalStateException("Level " + levelInt + " is unknown.");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/* Copyright 2018-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.util;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Random Utilities used in this project
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
public class RandomUtils {
|
||||
|
||||
private RandomUtils() {
|
||||
}
|
||||
|
||||
private static final Random rand = new Random();
|
||||
|
||||
public static int nextInt(int i) {//返回随机整数,最小为0,最大为n-1
|
||||
if(i==0)
|
||||
return 0;
|
||||
return rand.nextInt(i);
|
||||
}
|
||||
|
||||
public static int nextNegOrPosInt(int n) {//返回随机整数,最小为-(n-1),最大为n-1
|
||||
int x = nextInt(n);
|
||||
if (percent(50))
|
||||
return x;
|
||||
return -x;
|
||||
}
|
||||
|
||||
public static float nextFloat() {
|
||||
return rand.nextFloat();
|
||||
}
|
||||
|
||||
public static boolean percent(float percent) {// 有百分这percent的机率为true
|
||||
return rand.nextFloat() * 100 < percent;
|
||||
}
|
||||
|
||||
public static int vary(int v, int percet) {
|
||||
if (percent(percet))
|
||||
return vary(v);
|
||||
return v;
|
||||
}
|
||||
|
||||
public static int vary(int v) {// 随机有大概率小变异,小概率大变异,极小概率极大变异
|
||||
if (percent(40))
|
||||
v += v * .04 * (nextFloat() - 0.5); // v=v+-.04
|
||||
if (percent(10))
|
||||
v += v * .103 * (nextFloat() - 0.5); // v=v+-0.1
|
||||
else if (percent(5))
|
||||
v += v * 1 * (nextFloat() - 0.5); // v=v+-0.4
|
||||
else if (percent(2))
|
||||
v += v * 4 * (nextFloat() - 0.5); // v=v+-2
|
||||
else if (percent(1f))
|
||||
v += v * 8 * (nextFloat() - 0.5); // v=v+-6
|
||||
return v;
|
||||
}
|
||||
|
||||
public static float vary(float v) {// 随机有大概率小变异,小概率大变异,极小概率极大变异
|
||||
if (percent(40))
|
||||
v += v * .04 * (nextFloat() - 0.5); // v=v+-.04
|
||||
if (percent(10))
|
||||
v += v * .103 * (nextFloat() - 0.5); // v=v+-0.1
|
||||
else if (percent(5))
|
||||
v += v * 1 * (nextFloat() - 0.5); // v=v+-0.4
|
||||
else if (percent(2))
|
||||
v += v * 4 * (nextFloat() - 0.5); // v=v+-2
|
||||
else if (percent(1f))
|
||||
v += v * 8 * (nextFloat() - 0.5); // v=v+-6
|
||||
return v;
|
||||
}
|
||||
|
||||
public static int varyInLimit(int v, int from, int to) {// 让返回值在from和to之间随机变异
|
||||
int i = vary(v);
|
||||
if (i < from)
|
||||
i = from;
|
||||
if (i > to)
|
||||
i = to;
|
||||
return i;
|
||||
}
|
||||
|
||||
public static float varyInLimit(float v, float from, float to) {// 让返回值在from和to之间随机变异
|
||||
float i = vary(v);
|
||||
if (i < from)
|
||||
i = from;
|
||||
if (i > to)
|
||||
i = to;
|
||||
return i;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/* Copyright 2018-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.util;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* StringPixelUtils used to get pixel array from a given string
|
||||
*
|
||||
* 根据给定的字体和字符串,返回它的像素点阵,lettersMap[0][0]是左下角素
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 2.0.2
|
||||
*/
|
||||
public class StringPixelUtils {
|
||||
private static final Map<String, byte[][]> lettersMap = new HashMap<>();//cache
|
||||
|
||||
public static byte[][] getSanserif10Pixels(String s) {
|
||||
return getStringPixels(Font.SANS_SERIF, Font.PLAIN, 10, s);
|
||||
}
|
||||
|
||||
public static byte[][] getSanserif12Pixels(String s) {
|
||||
return getStringPixels(Font.SANS_SERIF, Font.PLAIN, 12, s);
|
||||
}
|
||||
|
||||
public static byte[][] getSanserifItalic10Pixels(String s) {
|
||||
return getStringPixels(Font.SANS_SERIF, Font.ITALIC, 10, s);
|
||||
}
|
||||
|
||||
/* 在内存 BufferedImage里输出文本并获取它的像素点 */
|
||||
public static byte[][] getStringPixels(String fontName, int fontStyle, int fontSize, String s) {
|
||||
String key = new StringBuilder(fontName).append("_").append(fontStyle).append("_").append(fontSize).append("_")
|
||||
.append(s).toString();
|
||||
if (lettersMap.containsKey(key))
|
||||
return lettersMap.get(key);
|
||||
Font font = new Font(fontName, fontStyle, fontSize);
|
||||
|
||||
BufferedImage bi = new BufferedImage(fontSize * 10, fontSize * 50, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics g = bi.getGraphics();
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
g2d.setFont(font);
|
||||
FontMetrics fm = g2d.getFontMetrics();
|
||||
int strHeight = fm.getAscent() + fm.getDescent() - 1;
|
||||
int strWidth = fm.stringWidth(s);
|
||||
g2d.drawString(s, 0, fm.getAscent() - fm.getLeading() -1);
|
||||
|
||||
int ystart;//改进:在命令行和eclipse下会有不同的空行,所以要用ystart和yend来限定只获取有效象素行数
|
||||
loop1: for (ystart = 0; ystart < strHeight; ystart++)
|
||||
for (int x = 0; x < strWidth; x++) {
|
||||
if (bi.getRGB(x, ystart) == -1)
|
||||
break loop1;
|
||||
}
|
||||
|
||||
int yend;
|
||||
loop2: for (yend = strHeight; yend >= 0; yend--)
|
||||
for (int x = 0; x < strWidth; x++) {
|
||||
if (bi.getRGB(x, yend) == -1)
|
||||
break loop2;
|
||||
}
|
||||
|
||||
byte[][] b = new byte[strWidth][yend-ystart+1];
|
||||
for (int y = ystart; y <= yend; y++)
|
||||
for (int x = 0; x < strWidth; x++)
|
||||
if (bi.getRGB(x, y ) == -1)
|
||||
b[x][yend-y] = 1;
|
||||
else
|
||||
b[x][yend-y] = 0;
|
||||
lettersMap.put(key, b);
|
||||
return b;
|
||||
}
|
||||
|
||||
/*- 这个是测试输出,平时不需要用
|
||||
public static void main(String[] args) {
|
||||
System.out.println("===============");
|
||||
byte[][] c = getStringPixels(Font.SANS_SERIF, Font.PLAIN, 12, "FROG");
|
||||
int w = c.length;
|
||||
int h = c[0].length;
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
if (c[x][h - y - 1] > 0)
|
||||
System.out.print("*");
|
||||
else
|
||||
System.out.print(" ");
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
System.out.println("===============");
|
||||
}
|
||||
*/
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/* Copyright 2018-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
|
||||
* applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
* OF ANY KIND, either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the License.
|
||||
*/
|
||||
package com.gitee.drinkjava2.frog.util;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.gitee.drinkjava2.frog.Env;
|
||||
|
||||
/**
|
||||
* Tree8Util used to store a pre-order Traversal tree array to speed
|
||||
*
|
||||
* 这里缓存着一个前序排列的八叉树用来在细胞生成时加快速度和简化运算,关于树结构可用深度树数组来表达的知识可以参见这里:https://my.oschina.net/drinkjava2/blog/1818631
|
||||
*
|
||||
* @author Yong Zhu
|
||||
* @since 1.0
|
||||
*/
|
||||
public class Tree8Util {
|
||||
|
||||
//EIGHT_TREE store a pre-order Traversal tree array
|
||||
public static final int NODE_QTY = calculateNodeSize(Env.BRAIN_CUBE_SIZE);
|
||||
|
||||
public static int[][] TREE8 = new int[NODE_QTY][4]; //八叉数用数组表示,第一维是深度树的行号,第二维是一个整数数组,内容是深度树表示的八叉树细胞的size, x, y, z值
|
||||
|
||||
public static byte[] keep = new byte[NODE_QTY]; //这里临时记录树的敲除记录,大于0的值表示要keep, 小于等于0表示要敲除
|
||||
|
||||
private static byte[] KEEP = new byte[NODE_QTY]; //这里保存初值为0的数组常量,可以用System.arraycopy(KEEP, 0, keep, 0, NODE_QTY)快速清空enable数组
|
||||
|
||||
public static int keepNodeQTY = NODE_QTY; //这里临时记录需keep的节点总数,好用来继续敲除,初始值是全部节点
|
||||
|
||||
private static int index = 0;
|
||||
static {
|
||||
tree8Split(0, 0, 0, Env.BRAIN_CUBE_SIZE);
|
||||
}
|
||||
|
||||
static int calculateNodeSize(int n) {//计算8叉树全展开的总节点数
|
||||
if (n == 1)
|
||||
return 1;
|
||||
return n * n * n + calculateNodeSize(n / 2);
|
||||
}
|
||||
|
||||
//if cube can split, then split it to 8 small cubes
|
||||
private static void tree8Split(int x, int y, int z, int size) {//如立方体可分裂,就继续递归分裂成8个
|
||||
TREE8[index++] = new int[]{size, x, y, z}; //这里size类似于深度树中的level,只不过是size从大到小,level是从小到大,原理一样
|
||||
if (size == 1)
|
||||
return;
|
||||
int half = size / 2;//每个细胞可以分裂成8个size为原来1/2的小细胞
|
||||
tree8Split(x, y, z, half);
|
||||
tree8Split(x + half, y, z, half);
|
||||
tree8Split(x, y + half, z, half);
|
||||
tree8Split(x + half, y + half, z, half);
|
||||
tree8Split(x, y, z + half, half);
|
||||
tree8Split(x + half, y, z + half, half);
|
||||
tree8Split(x, y + half, z + half, half);
|
||||
tree8Split(x + half, y + half, z + half, half);
|
||||
}
|
||||
|
||||
public static void knockNodesByGene(List<Integer> gene) {//根据基因,把要敲除的8叉树节点作敲除或保留标记
|
||||
System.arraycopy(KEEP, 0, keep, 0, NODE_QTY);//清空keep数组
|
||||
keepNodeQTY = 0;
|
||||
for (int g : gene) {//g基因,用带符号的8叉数的行号表示,负数表示阴节点要敲除,正数表示是阳节点要保留
|
||||
int gLine = Math.abs(g); //基因对应节点的行号
|
||||
int size = Tree8Util.TREE8[gLine][0]; //size是基因对应节点的细胞立方体边长
|
||||
for (int line = gLine; line < Tree8Util.NODE_QTY; line++) {//从这个g节点开始,往下找节点
|
||||
if (line > gLine && Tree8Util.TREE8[line][0] >= size) //如果除了第一个节点外,边长大于等于size,说明节点不是g的子节点,退出
|
||||
break;
|
||||
else {//否则就是g的子节点
|
||||
if (g < 0) { //g是阴节点
|
||||
if (Tree8Util.keep[line] == 1) //如果是1,表示这个节点将从保留状态转为删除状态
|
||||
keepNodeQTY--;
|
||||
Tree8Util.keep[line]=0;
|
||||
} else if (g > 0) { //g是阳节点
|
||||
if (Tree8Util.keep[line] == 0) //如果是0,表示这个节点将从删除状态转为保留状态
|
||||
keepNodeQTY++;
|
||||
Tree8Util.keep[line]=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
BIN
result18_yinyan_eatfood.gif
Normal file
BIN
result18_yinyan_eatfood.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 179 KiB |
Loading…
Reference in New Issue
Block a user