From 830b83165b524a2aaae8f1171522336dc63ae2d5 Mon Sep 17 00:00:00 2001 From: Yong Zhu Date: Wed, 3 Jun 2020 07:59:07 -0600 Subject: [PATCH] Work on add snake --- README.md | 10 +- core/run.bat | 3 +- .../github/drinkjava2/frog/Application.java | 43 ++++- .../java/com/github/drinkjava2/frog/Env.java | 175 +++++++++++++----- .../java/com/github/drinkjava2/frog/Frog.java | 22 ++- .../drinkjava2/frog/brain/BrainPicture.java | 6 +- .../github/drinkjava2/frog/brain/Organ.java | 2 +- .../github/drinkjava2/frog/brain/Zone.java | 11 ++ .../drinkjava2/frog/brain/organ/Line.java | 46 +++-- .../frog/brain/organ/{Eat.java => Mouth.java} | 4 +- .../com/github/drinkjava2/frog/egg/Egg.java | 27 +-- .../egg/{EggTool.java => FrogEggTool.java} | 72 ++++--- .../drinkjava2/frog/egg/SnakeEggTool.java | 128 +++++++++++++ .../github/drinkjava2/frog/objects/Food.java | 57 +++++- .../drinkjava2/frog/objects/Material.java | 31 +++- .../drinkjava2/frog/objects/SeeSaw.java | 93 ---------- .../github/drinkjava2/frog/objects/Trap.java | 52 ------ .../github/drinkjava2/frog/snake/Snake.java | 49 +++++ .../frog/snake/brain/organ/SnakeEyes.java | 102 ++++++++++ .../frog/snake/brain/organ/SnakeMouth.java | 31 ++++ ...FrogFileUtils.java => LocalFileUtils.java} | 6 +- .../drinkjava2/frog/util/RandomUtils.java | 43 +---- history/001_first_version/run.bat | 3 +- history/002_first_eye/run.bat | 3 +- history/003_trap/run.bat | 3 +- history/003a_legs/run.bat | 3 +- history/003b_simple/run.bat | 3 +- history/004_seasaw/run.bat | 3 +- history/005_letter_test/run.bat | 3 +- snake.png | Bin 0 -> 1000 bytes 捐款记录.md | 10 +- 版本提交记录.md | 5 +- 32 files changed, 706 insertions(+), 343 deletions(-) rename core/src/main/java/com/github/drinkjava2/frog/brain/organ/{Eat.java => Mouth.java} (87%) rename core/src/main/java/com/github/drinkjava2/frog/egg/{EggTool.java => FrogEggTool.java} (52%) create mode 100644 core/src/main/java/com/github/drinkjava2/frog/egg/SnakeEggTool.java delete mode 100644 core/src/main/java/com/github/drinkjava2/frog/objects/SeeSaw.java delete mode 100644 core/src/main/java/com/github/drinkjava2/frog/objects/Trap.java create mode 100644 core/src/main/java/com/github/drinkjava2/frog/snake/Snake.java create mode 100644 core/src/main/java/com/github/drinkjava2/frog/snake/brain/organ/SnakeEyes.java create mode 100644 core/src/main/java/com/github/drinkjava2/frog/snake/brain/organ/SnakeMouth.java rename core/src/main/java/com/github/drinkjava2/frog/util/{FrogFileUtils.java => LocalFileUtils.java} (97%) create mode 100644 snake.png diff --git a/README.md b/README.md index 1487055..ca20bdd 100644 --- a/README.md +++ b/README.md @@ -56,13 +56,13 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什 ## 目前进展和成绩 2019.03.11 虚拟环境已建好,可以模拟低等生命的遗传、繁殖、变异、进化现象,但只能往一个方向运动,相当于一个最简单的单细胞生物,还不具备视觉能力,不具备主动找食能力。 运行run.bat可以查看演示(需要安装Java8和Maven)。 -![result1](https://gitee.com/drinkjava2/frog/raw/master/result1.gif) +![result1](result1.gif) 另外每步演示的结果(egg)会存盘在根目根目录下,名为egg.ser,可以删除这个文件以从头开始新的测试。因为还没涉及脑模型的搭建,可以看到有些青蛙跑得飞快,这是自然选择的结果,因为跑在最前面的吃得多。 一些重要的测试参数如显示区大小、是否每次测试要删除保存的蛋等,请参见Env.java中开头的常量设定,可以手工修改进行不同参数的测试。 2019.03.21 添加了脑图,改进随机运动模式为Hungry区驱动。从脑图上可以直观地观察脑结构,方便调试。 2019.04.01 改进脑图的显示bug, 每一次生成Frog时添加随机神经元,并简单实现"卵+精子->受精卵"算法,以促进种群多样性。 2019-04-12 添加一个简单的眼睛(只有四个感光细胞),自然选择的结果是眼睛被选中,但是和运动区短路了,谈不上智能。但有眼睛后找食效率明显提高了,见下图: -![resut2](https://gitee.com/drinkjava2/frog/raw/master/result2.gif) +![resut2](result2.gif) 2019-06-13 做了一些重构清理,加上了Happy和Pain两个器官,分别对应进食奖励和痛苦感,后者在靠近边界时激发。观查它的表现,痛苦感生效了,一些Frog跑到边界后就不再前进,而是顺着边界溜下去了,但是Happy器官没有生效,这也很显然,因为Happy属于复杂的进食条件反射链的一部分,在没有记忆器官(算法)引入之前,再怎么优胜劣汰也是没办法用上进食奖励信号的。见下图: ![resut3](https://gitee.com/drinkjava2/frog/raw/master/result3.gif) 2019-06-26 找食效率太低,又改回到4.12的用连接数量代替权值这个逻辑,人为设计的算法居然比不过随机连接。Pain器官的加入没有提高找食效率,必须与感光细胞合用才能知道是哪个边界,急需引入记忆功能。 @@ -71,11 +71,11 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什 另外Chance和Eye类里也再次运用了随机试错原理去确定关键参数,效果还不错,有兴趣的可以看一看源码。 ![resut4](https://gitee.com/drinkjava2/frog/raw/master/result4.gif) 另外发现青蛙其实是有记忆能力的,因为连接本身就是一种记忆,只不过它没有复杂的模式识别能力,例如给个蛇的图片它就认不出来。以后的工作将以模式识别为重点(当然随机连接看起来很有用,以后还可能保留),基本原理是见note中提到的仿照波传播及全息存储原理,在思维区逆向成像。而且脑可能改成三维结构,并根据逆向成像原理,要将所有输入输出器官全移到三维结构的同一侧(即思维区)。这将会是一个非常大的改动,下面我简单画了一个3D示意图来说明我想象中的这个模式识别和记忆的原理,至于对不对还需要实验来验证: -![3d-model](https://gitee.com/drinkjava2/frog/raw/master/3d-model.gif) +![3d-model](3d-model.gif) 这个模型的最顶层表示眼睛的感光细胞(或任意输入输出细胞),同时也是思维区,红色表示一个长条的图形,兰色表示一个三角图形,如果这两个图形经常有规律地同时出现,就会把它们共有的节点撑大,见紫色的节点,当红色图形单独出现,就会强烈激活紫色节点,然后紫色节点的信号反向传播,就会激活三角图形,反之亦然。这就同时解释了模式识别和记忆(或者说回忆)功能的的原理。一个节点可以被多个感光细胞共享,所以它的存储能力是很强的。而且可能这个原理比较符合生物脑结构。当然,实际编程时,虚拟神经元不一定要排成正立方三角,而可能通过胡乱排放,大致上过得去就行了,也许能乱拳打死老师傅,最终要靠电脑自动随机的排放,然后用优胜劣汰来筛选。目前有个难点是这个记忆功能在思维区成像是如何有条不紊地大体上按串行进行工作的,这个问题先放一放。 2019-08-04 更新了一个分组测试功能,如果测试青蛙数量太多,可以分批来测试,每轮测试最少的青蛙数量可以少到只有一个,这是用时间来换空间。 2019-08-05 有了分组测试功能后,顺手加上了一个青蛙走跷跷板自动平衡的演示,它每次只出场一个青蛙, 每轮包括100场测试,大约跑90多轮半个小时(电脑慢)后,出现了下面的画面: -![result5](https://gitee.com/drinkjava2/frog/raw/master/result5_seesaw.gif) +![result5](result5_seesaw.gif) 这个版本的目的是为了增加一点趣味性,显得青蛙还是有点"用处"的,省得让人以为这个项目不务正业,青蛙只会找食。这个版本青蛙的脑结构和找食版的青蛙基本相同,区别只是在于环境不同,也就是说它的表现随着环境而变化,这符合"通用人工智能"的概念,即信号感受器官是统一的(通常是眼睛),但能根据不同的环境完成不同的任务。走跷跷板演示是最后一个2维脑的版本,今后这个项目将沉寂一段较长时间,我将致力于将青蛙脑重构为3D金字塔形脑结构(见上文),因为这个项目的缺点已经很明显,它不具备对2维图像的模式识别能力,用随机试错的方式只能处理非常简单的、信号在视网膜的固定区域出现的图像信号。 青蛙的找食效率以及走跷跷板平衡的能力都没有优化到顶点,一些构想中的复杂的器官如“与门”、“或门”(不要怀疑大自然能否进化出这些复杂器官)等都没加上,器官的用进废退、奖励信号的利用都没反映,但我认为这些还不关键,目前最急迫的任务应该是先进行3D脑结构建模,让青蛙能具备2维图形的模式识别(和回忆)功能,这个大的架构重构是它能处理复杂图像信息的立足之本,它的图像识别能力和通常的用上千张图片来训练识别一个图片这种工作模式完全不同,它是一种通用的,可自动分类识别所有图像的模式,更符合动物脑的工作模式,记住并回忆出某个图像(或任意输入信号场景的组合),可能只需要这种场景重复出现过几次即可,它是一种无外界信号判定,自动分类的识别模式。 2019-09-09 开始3D脑的构建,任务又回到原点:找食,从静止的青蛙要能进化到吃光所有食物。目前只是搭建空的3D框架,还未涉及3D脑模型编程。新的工作存放在core3d目录,原有的旧core目录保留,相应地批处理文件也分为普通版run.bat和3d版run3d.bat,蛋文件也分为普通版eggs.ser和3d版eggs3d.ser。 @@ -88,7 +88,7 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什 2019-11-16 模式识别功能更新 上次提交有个大bug,有多个字母出现时将不能区分,这次提交更正过来。到此为止,基本完成了模式识别的原理验证过程,即如果字母的象素点与训练图片的重点合越多,则听力区收到的反向红色光子数就越多,这是一个简单、直观的模式识别方法,以后可以通过将声音分成多个小区编码,并统计每个区收到多少反向的光子总数来判断是哪个字母图像输入。原理验证比较枯燥,但这个模式识别功能是无法绕过去的,一旦原理被证实,以后就可以有意地引导或者说设计青蛙向这个方向进化,而不是由手工来搭建包含模式识别功能的脑模型,因为一来要减少手工的干预,硬编码越少越好,尽量利用随机变异、生存竟争这个电脑工具,二来这个原理不光是模式识别要用到,其它信号处理(如快感、痛觉信号与行为信号之间的关联)都要用到类似的细胞级逻辑,因为我一直在强调“任意两个时间上相关的信号,大脑总会将它们关联起来,这是条件反射行为建立的基础”。 另外,这次更新加强了暂停功能,可以在脑图任一时刻暂停,并加上了脑图的剖面显示。所有脑图快捷键有: T:顶视 F:前视 L:左视 R:右视 X:斜视 方向键:剖视 空格:暂停 鼠标操作:缩放旋转平移 -![result6](https://gitee.com/drinkjava2/frog/raw/master/result6_letter.gif) +![result6](result6_letter.gif) 2019-11-26 优化了一下程序,用"对酒当歌人生几何"8个汉字来进行模式识别原理演示,但容错性依然没有,变形、变位后的文字识别率很差。以后要考虑借签算法中的侧抑制、卷积、分层等原理来提高它的容错性,用图形化模拟的方式来实现。总体上算法和图形化模拟是两条路,算法通常可以用模拟的方式来表达,但不是所有模拟都可以归纳成算法,因为模拟(或者说软件本身)有时会非常复杂,不容易总结出规律。也就是说模拟的表现力比算法更强,但模拟的缺点是资源消耗大。 2019-12-27 开始设立history目录,给主要的版本直接在history目录下创建副本,以方便运行。在history\003a_legs目录下(依然是2维脑)尝试给青蛙加两条腿,看它能不能自动学会走路。一条腿位于下方,负责左右移动,一条腿位于右侧,负责上下移动,每条腿有抬腿、落腿、转动和相应的感觉细胞。只有当腿落下且转动,而且另一条脚抬起来时青蛙才会位移,具体什么时候抬腿、什么时候转动腿完全由随机数决定。经过一段时间的生存汰淘之后,青蛙会进化出会利用两条腿走路了,但需要的时间非常长,约几个小时之后才达到最高吃食率50%左右,走路风格也比较诡异,是小碎步而不是大踏步。但至少这是青蛙第一次利用两条腿来走路,还是有点意义的,这证明生命进化中就算神经元随机排布,进化出眼睛和腿也是非常简单自然的事。 2020-05-04 在进行3维脑改造过程中,发现找食率很低,发现自己也看不懂以前的程序怎么编的了,所以在history目录下又添加一个003b_simple目录,把2维脑简化一下,去掉不重要的器官,好仔细分析它的逻辑。 diff --git a/core/run.bat b/core/run.bat index ab1bab3..2684987 100644 --- a/core/run.bat +++ b/core/run.bat @@ -1,4 +1,3 @@ call mvn clean compile cd target\classes -java -classpath ".;*" com.github.drinkjava2.frog.Application -@pause \ No newline at end of file +java -classpath ".;*" com.github.drinkjava2.frog.Application \ No newline at end of file diff --git a/core/src/main/java/com/github/drinkjava2/frog/Application.java b/core/src/main/java/com/github/drinkjava2/frog/Application.java index b698116..993a138 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/Application.java +++ b/core/src/main/java/com/github/drinkjava2/frog/Application.java @@ -4,9 +4,12 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; +import javax.swing.ButtonGroup; 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; @@ -37,6 +40,7 @@ public class Application { public static BrainPicture brainPic = new BrainPicture(Env.ENV_WIDTH + 5, 0, Env.FROG_BRAIN_XSIZE, Env.FROG_BRAIN_DISP_WIDTH); public static ActionListener pauseAction; + public static boolean selectFrog = true; static private void checkIfShowBrainPicture(JButton button) { if (Env.SHOW_FIRST_FROG_BRAIN) { @@ -63,13 +67,26 @@ public class Application { int buttonWidth = 100; int buttonHeight = 22; int buttonXpos = Env.ENV_WIDTH / 2 - buttonWidth / 2; - button.setBounds(buttonXpos, Env.ENV_HEIGHT + 8, buttonWidth, buttonHeight); + // select frog or snake 显示青蛙或蛇的脑图 + JRadioButton radioFrog = new JRadioButton("Frog"); + radioFrog.setBounds(buttonXpos + buttonWidth + 10, Env.ENV_HEIGHT + 8, 50, buttonHeight); + radioFrog.addActionListener(e -> selectFrog = radioFrog.isSelected()); + JRadioButton radioSnake = new JRadioButton("Snake"); + + button.setBounds(buttonXpos, Env.ENV_HEIGHT + 8, buttonWidth, buttonHeight); ActionListener al = new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { Env.SHOW_FIRST_FROG_BRAIN = !Env.SHOW_FIRST_FROG_BRAIN; checkIfShowBrainPicture(button); + if (Env.SHOW_FIRST_FROG_BRAIN && Env.SNAKE_MODE) { + radioFrog.setVisible(true); + radioSnake.setVisible(true); + } else { + radioFrog.setVisible(false); + radioSnake.setVisible(false); + } } }; @@ -77,6 +94,15 @@ public class Application { button.addActionListener(al); mainFrame.add(button); + radioSnake.setBounds(buttonXpos + buttonWidth + 60, Env.ENV_HEIGHT + 8, 80, buttonHeight); + radioSnake.addActionListener(e -> selectFrog = radioFrog.isSelected()); + ButtonGroup btnGroup = new ButtonGroup(); + btnGroup.add(radioFrog); + btnGroup.add(radioSnake); + radioFrog.setSelected(true); + mainFrame.add(radioFrog); + mainFrame.add(radioSnake); + JButton stopButton = new JButton("Pause");// 按钮,暂停或继续 stopButton.setBounds(buttonXpos, Env.ENV_HEIGHT + 35, buttonWidth, buttonHeight); pauseAction = new ActionListener() { @@ -109,6 +135,21 @@ public class Application { label.setBounds(buttonXpos - 90, stopButton.getY() + 23, 100, buttonHeight); mainFrame.add(label); + JCheckBox snakeModeCkBox = new JCheckBox("Snake Mode"); + snakeModeCkBox.setBounds(buttonXpos, speedSlider.getY() + 25, 120, buttonHeight); + snakeModeCkBox.addActionListener(e -> { + Env.SNAKE_MODE = snakeModeCkBox.isSelected(); + if (Env.SHOW_FIRST_FROG_BRAIN && Env.SNAKE_MODE) { + radioFrog.setVisible(true); + radioSnake.setVisible(true); + } else { + radioFrog.setVisible(false); + radioSnake.setVisible(false); + } + }); + snakeModeCkBox.setSelected(true); + mainFrame.add(snakeModeCkBox); + mainFrame.setVisible(true); env.run(); } diff --git a/core/src/main/java/com/github/drinkjava2/frog/Env.java b/core/src/main/java/com/github/drinkjava2/frog/Env.java index 4e7c05f..22ba28d 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/Env.java +++ b/core/src/main/java/com/github/drinkjava2/frog/Env.java @@ -10,10 +10,12 @@ import java.util.List; import javax.swing.JPanel; import com.github.drinkjava2.frog.egg.Egg; -import com.github.drinkjava2.frog.egg.EggTool; +import com.github.drinkjava2.frog.egg.FrogEggTool; +import com.github.drinkjava2.frog.egg.SnakeEggTool; import com.github.drinkjava2.frog.objects.EnvObject; import com.github.drinkjava2.frog.objects.Food; import com.github.drinkjava2.frog.objects.Material; +import com.github.drinkjava2.frog.snake.Snake; import com.github.drinkjava2.frog.util.RandomUtils; /** @@ -28,15 +30,15 @@ public class Env extends JPanel { public static int SHOW_SPEED = 10; // 测试速度,-1000~1000,可调, 数值越小,速度越慢 /** Delete eggs at beginning of each run */ - public static final boolean DELETE_EGGS = true;// 每次运行是否先删除保存的蛋 + public static final boolean DELETE_FROG_EGGS = true;// 每次运行是否先删除保存的青蛙蛋 - public static final int EGG_QTY = 25; // 每轮下n个蛋,可调,只有最优秀的前n个青蛙们才允许下蛋 + public static final int FROG_EGG_QTY = 25; // 每轮下n个青蛙蛋,可调,只有最优秀的前n个青蛙们才允许下蛋 - public static final int FROG_PER_EGG = 4; // 每个蛋可以孵出几个青蛙 + public static final int FROG_PER_EGG = 4; // 每个青蛙蛋可以孵出几个青蛙 public static final int SCREEN = 1; // 分几屏测完 - public static final int FROG_PER_SCREEN = EGG_QTY * FROG_PER_EGG / SCREEN; // 每屏上显示几个青蛙,这个数值由上面三个参数计算得来 + public static final int FROG_PER_SCREEN = FROG_EGG_QTY * FROG_PER_EGG / SCREEN; // 每屏上显示几个青蛙,这个数值由上面三个参数计算得来 /** Frog's brain size is a 3D array of Cell */ // 脑空间是个三维Cell数组,为节约内存,仅在用到数组元素时才去初始化这维,按需分配内存 public static final int FROG_BRAIN_XSIZE = 1000; // frog的脑在X方向长度 @@ -63,24 +65,42 @@ public class Env extends JPanel { public static int step;// 当前测试步数 public static final int FOOD_QTY = 1500; // 食物数量, 可调 + public static boolean FOOD_CAN_MOVE = false; // 食物是否可以移动,眼花 // 以下是程序内部变量,不要手工修改它们 public static boolean pause = false; // 暂停按钮按下将暂停测试 - public static byte[][] bricks = new byte[ENV_WIDTH][ENV_HEIGHT];// 组成环境的材料,见Material.java + public static int[][] bricks = new int[ENV_WIDTH][ENV_HEIGHT];// 组成环境的材料,见Material.java public static List frogs = new ArrayList<>(); // 这里存放所有待测的青蛙,可能分几次测完,由FROG_PER_SCREEN大小来决定 - public static List eggs = new ArrayList<>(); // 这里存放新建或从磁盘载入上轮下的蛋,每个蛋可能生成几个青蛙, + public static List frog_eggs = new ArrayList<>(); // 这里存放新建或从磁盘载入上轮下的蛋,每个蛋可能生成几个青蛙, public static EnvObject[] things = new EnvObject[] { new Food() };// 所有外界物体,如食物、字母测试工具都放在这个things里面 + // =========以下是与蛇相关的常量和变量=========== + + public static final boolean DELETE_SNAKE_EGGS = true;// 每次运行是否先删除保存的蛇蛋 + + public static boolean SNAKE_MODE = true; // 是否加小蛇加进来吃青蛙? + + public static final int SNAKE_EGG_QTY = 10; // 每轮下n个蛇蛋,可调,只有最优秀的前n个蛇们才允许下蛋 + + public static final int SNAKE_PER_EGG = 4; // 每个蛇蛋可以孵出几个蛇 + + public static final int SNAKE_PER_SCREEN = SNAKE_EGG_QTY * SNAKE_PER_EGG / SCREEN; // 每屏上显示几个蛇,这个数值由上面参数计算得来 + + public static List snakes = new ArrayList<>(); // 这里存放所有待测的蛇,可能分几次测完,由FROG_PER_SCREEN大小来决定 + + public static List snake_eggs = new ArrayList<>(); // 这里存放新建或从磁盘载入上轮下的蛋,每个蛋可能生成几个蛇 + static { System.out.println("唵缚悉波罗摩尼莎诃!"); // 杀生前先打印往生咒,见码云issue#IW4H8 System.out.println("脑图快捷键: T:顶视 F:前视 L:左视 R:右视 X:斜视 方向键:剖视 空格:暂停 鼠标:缩放旋转平移"); - if (DELETE_EGGS) - EggTool.deleteEggs(); - + if (DELETE_FROG_EGGS) + FrogEggTool.deleteEggs(); + if (DELETE_SNAKE_EGGS) + SnakeEggTool.deleteEggs(); } public Env() { @@ -105,41 +125,79 @@ public class Env extends JPanel { return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT || Env.bricks[x][y] >= Material.VISIBLE; } + public static boolean foundFrog(int x, int y) {// TODO:优化寻找青蛙的速度,不要用循环 如果指定点看到青蛙或超出边界,返回true + if (x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT) + return true; + for (Frog f : frogs) + if (f.alive && f.x == x && f.y == y) { + return true; + } + return false; + } + public static boolean foundAndAteFood(int x, int y) {// 如果x,y有食物,将其清0,返回true - if (insideEnv(x, y) && Env.bricks[x][y] == Material.FOOD) { + if (insideEnv(x, y) && Env.bricks[x][y] >= Material.FOOD && Env.bricks[x][y] <= Material.FLY4) { + Food.food_ated++; bricks[x][y] = 0; return true; } return false; } - private void rebuildFrogs() { + public static boolean foundAndAteFrog(int x, int y) {// TODO:优化寻找青蛙的速度,不要用循环 如果x,y有青蛙,将其杀死,返回true + for (Frog f : frogs) + if (f.alive && f.x == x && f.y == y) { + f.alive = false; + return true; + } + return false; + } + + private void rebuildFrogs() {// 根据蛙蛋重新孵化出蛙 frogs.clear(); - for (int i = 0; i < eggs.size(); i++) {// 创建青蛙,每个蛋生成n个蛙,并随机取一个别的蛋作为精子 + for (int i = 0; i < frog_eggs.size(); i++) {// 创建青蛙,每个蛋生成n个蛙,并随机取一个别的蛋作为精子 int loop = FROG_PER_EGG; - if (eggs.size() > 20) { // 如果数量多,进行一些优化,让排名靠前的Egg多孵出青蛙 + if (frog_eggs.size() > 20) { // 如果数量多,进行一些优化,让排名靠前的Egg多孵出青蛙 if (i < FROG_PER_EGG)// 0,1,2,3 loop = FROG_PER_EGG + 1; - if (i >= (eggs.size() - FROG_PER_EGG)) + if (i >= (frog_eggs.size() - FROG_PER_EGG)) loop = FROG_PER_EGG - 1; } for (int j = 0; j < loop; j++) { - Egg zygote = new Egg(eggs.get(i), eggs.get(RandomUtils.nextInt(eggs.size()))); + Egg zygote = new Egg(frog_eggs.get(i), frog_eggs.get(RandomUtils.nextInt(frog_eggs.size()))); frogs.add(new Frog(RandomUtils.nextInt(ENV_WIDTH), RandomUtils.nextInt(ENV_HEIGHT), zygote)); } } } + private void rebuildSnakes() {// 根据蛇蛋重新孵化出蛇 + snakes.clear(); + for (int i = 0; i < snake_eggs.size(); i++) {// 创建蛇,每个蛋生成n个蛇,并随机取一个别的蛋作为精子 + int loop = SNAKE_PER_EGG; + if (snake_eggs.size() > 20) { // 如果数量多,进行一些优化,让排名靠前的Egg多孵出青蛙 + if (i < SNAKE_PER_EGG)// 0,1,2,3 + loop = SNAKE_PER_EGG + 1; + if (i >= (snake_eggs.size() - SNAKE_PER_EGG)) + loop = SNAKE_PER_EGG - 1; + } + for (int j = 0; j < loop; j++) { + Egg zygote = new Egg(snake_eggs.get(i), snake_eggs.get(RandomUtils.nextInt(snake_eggs.size()))); + snakes.add(new Snake(RandomUtils.nextInt(ENV_WIDTH), RandomUtils.nextInt(ENV_HEIGHT), zygote)); + } + } + } + private void drawWorld(Graphics g) { - byte brick; + 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) - g.fillRoundRect(x, y, 4, 4, 2, 2); // show food bigger - else + if (brick >= Material.FOOD && brick <= Material.FLY4) { + g.fillRoundRect(x, y, 4, 4, 2, 2); // 点模式 食物只有一个点太小,画大一点 + // g.drawString(String.valueOf(brick - Material.FOOD), x, y); // 数字雨模式 + } else g.drawLine(x, y, x, y); // only 1 point } } @@ -151,23 +209,13 @@ public class Env extends JPanel { format100.setMaximumFractionDigits(2); } - private static int foodFoundAmount() {// 统计找食数等 - int leftfood = 0; - for (int x = 0; x < ENV_WIDTH; x++) - for (int y = 0; y < ENV_HEIGHT; y++) - if (bricks[x][y] == Material.FOOD) - leftfood++; - return FOOD_QTY - leftfood; - } - private String foodFoundCountText() {// 统计找食数等 - int foodFound = foodFoundAmount(); int maxFound = 0; for (Frog f : frogs) if (f.ateFood > maxFound) maxFound = f.ateFood; - return new StringBuilder("找食率:").append(format100.format(foodFound * 1.00 / FOOD_QTY)).append(", 平均: ") - .append(foodFound * 1.0f / FROG_PER_SCREEN).append(",最多:").append(maxFound).toString(); + 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(Frog f) { @@ -190,24 +238,37 @@ public class Env extends JPanel { } public void run() { - EggTool.loadEggs(); // 从磁盘加载egg,或新建一批egg + FrogEggTool.loadFrogEggs(); // 从磁盘加载蛙egg,或新建一批egg + if (SNAKE_MODE) + SnakeEggTool.loadSnakeEggs(); // 从磁盘加载蛇egg,或新建一批egg Image buffImg = createImage(this.getWidth(), this.getHeight()); Graphics g = buffImg.getGraphics(); long time0;// 计时用 int round = 1; do { rebuildFrogs(); + if (SNAKE_MODE) + rebuildSnakes(); for (int screen = 0; screen < SCREEN; screen++) {// 分屏测试,每屏FROG_PER_SCREEN个蛙 time0 = System.currentTimeMillis(); for (EnvObject thing : things) // 创建食物、陷阱等物体 thing.build(); boolean allDead = false; Frog firstFrog = frogs.get(screen * FROG_PER_SCREEN); + Snake firstSnake = null; + for (int j = 0; j < FROG_PER_SCREEN; j++) { Frog f = frogs.get(screen * FROG_PER_SCREEN + j); f.initFrog(); // 初始化器官延迟到这一步,是因为脑细胞太占内存,而且当前屏测完后会清空 } - + if (SNAKE_MODE && !snakes.isEmpty()) { + firstSnake = snakes.get(screen * SNAKE_PER_SCREEN); + for (int j = 0; j < SNAKE_PER_SCREEN; j++) { + Snake s = snakes.get(screen * SNAKE_PER_SCREEN + j); + s.initFrog(); // 初始化器官延迟到这一步,是因为脑细胞太占内存,而且当前屏测完后会清空 + } + } + Frog showFrog = Application.selectFrog ? firstFrog : firstSnake; for (step = 0; step < STEPS_PER_ROUND; step++) { for (EnvObject thing : things)// 调用食物、陷阱等物体的动作 thing.active(screen); @@ -219,36 +280,46 @@ public class Env extends JPanel { if (f.active(this))// 调用青蛙的Active方法,并返回是否还活着 allDead = false; } + if (SNAKE_MODE && !snakes.isEmpty()) + for (int j = 0; j < SNAKE_PER_SCREEN; j++) { + Snake s = snakes.get(screen * SNAKE_PER_SCREEN + j); + s.active(this);// snake唯一作用就是吃小蛇 + } - if (SHOW_SPEED > 0 && step % SHOW_SPEED != 0) // 用画青蛙的方式来拖慢速度 + if (SHOW_SPEED > 0 && step % SHOW_SPEED != 0) // 用是否跳帧画图的方式来控制速度 continue; if (SHOW_SPEED < 0) // 如果speed小于0,人为加入延迟 sleep(-SHOW_SPEED); - // 开始画青蛙 + // 开始画虚拟环境和青蛙和蛇 g.setColor(Color.white); - g.fillRect(0, 0, this.getWidth(), this.getHeight()); + g.fillRect(0, 0, this.getWidth(), this.getHeight()); // 先清空虚拟环境 g.setColor(Color.BLACK); - drawWorld(g); - for (int j = 0; j < FROG_PER_SCREEN; j++) { + drawWorld(g);// 画整个虚拟环境 + for (int j = 0; j < FROG_PER_SCREEN; j++) { // 显示青蛙 Frog f = frogs.get(screen * FROG_PER_SCREEN + j); f.show(g); } - - if (firstFrog.alive) { // 开始显示第一个Frog的动态脑图 - if (SHOW_FIRST_FROG_BRAIN) { - g.setColor(Color.red); - g.drawArc(firstFrog.x - 15, firstFrog.y - 15, 30, 30, 0, 360); - g.setColor(Color.BLACK); + if (SNAKE_MODE && !snakes.isEmpty()) + for (int j = 0; j < SNAKE_PER_SCREEN; j++) { // 显示蛇 + Snake s = snakes.get(screen * SNAKE_PER_SCREEN + j); + s.show(g); } - if (DRAW_BRAIN_AFTER_STEPS > 0 && step % DRAW_BRAIN_AFTER_STEPS == 0) - Application.brainPic.drawBrainPicture(firstFrog); + + if (SHOW_FIRST_FROG_BRAIN && showFrog != null) { + g.setColor(Color.red); + g.drawArc(showFrog.x - 15, showFrog.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(showFrog); Graphics g2 = this.getGraphics(); g2.drawImage(buffImg, 0, 0, this); } - Application.brainPic.drawBrainPicture(firstFrog); + // System.out.println(showFrog.debugInfo());// 打印输出Frog调试内容 + if (SHOW_FIRST_FROG_BRAIN) + Application.brainPic.drawBrainPicture(showFrog); checkIfPause(firstFrog); for (int j = 0; j < FROG_PER_SCREEN; j++) { Frog f = frogs.get(screen * FROG_PER_SCREEN + j); @@ -262,7 +333,13 @@ public class Env extends JPanel { thing.destory(); } round++; - EggTool.layEggs(); + FrogEggTool.layEggs(); + if (SNAKE_MODE) { + if (snakes.isEmpty()) + SnakeEggTool.loadSnakeEggs(); + else + SnakeEggTool.layEggs(); + } } while (true); } diff --git a/core/src/main/java/com/github/drinkjava2/frog/Frog.java b/core/src/main/java/com/github/drinkjava2/frog/Frog.java index 073896e..881925c 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/Frog.java +++ b/core/src/main/java/com/github/drinkjava2/frog/Frog.java @@ -74,8 +74,9 @@ public class Frog {// 这个程序大量用到public变量而不是getter/setter public void addRandomLines() {// 有一定机率在器官间生成随机的神经连线 if (alive && RandomUtils.percent(0.2f)) {// 有很小的机率在青蛙活着时就创建新的器官 Line line = new Line(); - organs.add(line); + line.initilized = false; line.initFrog(this); + organs.add(line); } } @@ -93,7 +94,7 @@ public class Frog {// 这个程序大量用到public变量而不是getter/setter // 依次调用每个cell的active方法,这是写在organ类里的方法,因为同一个器官的cell具有相同的行为 for (Cell cell : cells) cell.organ.active(this, cell); - addRandomLines(); + addRandomLines(); // 随机添加神经连线, 这是一个硬编码, 目前一个连线对应一个器官,待改进 return alive; } @@ -117,4 +118,21 @@ public class Frog {// 这个程序大量用到public变量而不是getter/setter || z >= Env.FROG_BRAIN_ZSIZE; } + /** Print debug info */ + public String debugInfo() {// 输出Frog调试内容 + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < organs.size(); i++) { + Organ o = organs.get(i); + if (o != null) { + sb.append("organ(" + i + ")=" + o.getClass()).append("\r"); + if (Line.class.equals(o.getClass())) { + Line l = (Line) o; + sb.append(l.inputZone.debugInfo()).append("\r"); + sb.append(l.outputZone.debugInfo()).append("\r"); + } + } + } + return sb.toString(); + } + } diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/BrainPicture.java b/core/src/main/java/com/github/drinkjava2/frog/brain/BrainPicture.java index 90f8a81..3931fdf 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/BrainPicture.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/BrainPicture.java @@ -313,10 +313,8 @@ public class BrainPicture extends JPanel { private static Cuboid brain = new Cuboid(0, 0, 0, Env.FROG_BRAIN_XSIZE, Env.FROG_BRAIN_YSIZE, Env.FROG_BRAIN_ZSIZE); - public void drawBrainPicture(Frog f) {// 在这个方法里进行青蛙三维脑结构的绘制 - if (!f.alive) - return; - if (!Env.SHOW_FIRST_FROG_BRAIN) + public void drawBrainPicture(Frog f) {// 在这个方法里进行青蛙或蛇的三维脑结构的绘制,蛇是青蛙的子类,所以也可以当参数传进来 + if (!Env.SHOW_FIRST_FROG_BRAIN || f == null || !f.alive) return; g.setColor(WHITE);// 先清空旧图 g.fillRect(0, 0, brainDispWidth, brainDispWidth); diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/Organ.java b/core/src/main/java/com/github/drinkjava2/frog/brain/Organ.java index 329db20..f19894d 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/Organ.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/Organ.java @@ -94,7 +94,7 @@ public class Organ extends Zone { try { newOrgan = this.getClass().newInstance(); } catch (Exception e) { - throw new UnknownError("Can not make new Organ copy for " + this); + throw new UnknownError("Can not make new organ copy for " + this); } copyXYZR(this, newOrgan); newOrgan.name = this.name; diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/Zone.java b/core/src/main/java/com/github/drinkjava2/frog/brain/Zone.java index e50adc0..997501b 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/Zone.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/Zone.java @@ -58,6 +58,13 @@ public class Zone implements Serializable { // zone 代表脑空间中的一块 this.r = z.r; } + public Zone(Zone a, Zone b) {// 用两个Zone来构造,新的zone位于两个zone的中间 + this.x = (a.x + b.x) / 2; + this.y = (a.y + b.y) / 2; + this.z = (a.z + b.z) / 2 ; + this.r = (a.r + b.r) / 2; + } + public boolean nearby(Zone o) { if (o == null) return false; @@ -97,4 +104,8 @@ public class Zone implements Serializable { // zone 代表脑空间中的一块 this.r = r; } + public String debugInfo() { + return new StringBuilder().append("zone x=").append(x).append(", y=").append(y).append(", z=").append(z) + .append(", r=").append(r).toString(); + } } diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Line.java b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Line.java index fd14ec3..953ce2f 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Line.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Line.java @@ -22,16 +22,17 @@ import com.github.drinkjava2.frog.util.RandomUtils; /** * Line * - * 这是一个随机方式连接两端的Organ,它是从旧版的RandomConnectGroup改造过来,这是一种最简单的神经元排列方式, + * 这是一个随机方式连接两端的Organ,它是从旧版的RandomConnectGroup改造过来,这是一种最简单的神经元排列方式 * * @author Yong Zhu * @since 1.0 */ -public class Line extends Organ { +public class Line extends Organ { private static final long serialVersionUID = 1L; public Zone inputZone; // 输入触突区 public Zone outputZone; // 输出触突区 + public Zone bodyZone; // 输出触突区 @Override public boolean allowBorrow() { // 是否允许在精子中将这个器官借出 @@ -41,18 +42,38 @@ public class Line extends Organ { @Override public void initFrog(Frog f) { if (!initilized) { - initilized = true; - inputZone= RandomUtils.randomZoneInOrgans(f); + initilized = true; + inputZone = RandomUtils.randomZoneInOrgans(f); outputZone = RandomUtils.randomZoneInOrgans(f); - } + bodyZone = new Zone(inputZone, outputZone); + } this.fat = 0;// 每次fat清0,因为遗传下来的fat不为0 - Cell c=new Cell(); - c.input= inputZone; - c.output=outputZone; - c.organ=this; + Cell c = new Cell(); + c.input = inputZone; + c.output = outputZone; + c.body = bodyZone; + c.organ = this; f.cells.add(c); } + /** Line如果input是另一个line的body,吸收能量, Line如果output是另一个line的body,放出能量 */ + public void active(Frog f, Cell c) { + if (RandomUtils.percent(95)) //这个会严重影响速度,所以降低它的机率 + return; + for (Cell cell : f.cells) { + if (cell.energy > organActiveEnergy) + if (c.input.nearby(cell.body)) { + c.organ.fat++; + cell.energy -= organActiveEnergy; + c.energy += organActiveEnergy; + } + if (c.energy >= organOutputEnergy && c.output.nearby(cell.body)) { + c.energy -= organOutputEnergy; + cell.energy += organOutputEnergy; + } + } + } + @Override public Organ[] vary() { organOutputEnergy = RandomUtils.varyInLimit(organOutputEnergy, -3, 3); @@ -71,9 +92,10 @@ public class Line extends Organ { else if (organOutputEnergy <= 0) pic.setPicColor(Color.BLUE); else - pic.setPicColor(Color.red); // 用到了?红色 - pic.drawLine(inputZone, outputZone); - pic.drawZone(this); + pic.setPicColor(Color.red); // 用到了?红色 + pic.drawLine(inputZone, bodyZone); + pic.drawLine(bodyZone, outputZone); + pic.drawZone(bodyZone); pic.setPicColor(Color.red); } diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Eat.java b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Mouth.java similarity index 87% rename from core/src/main/java/com/github/drinkjava2/frog/brain/organ/Eat.java rename to core/src/main/java/com/github/drinkjava2/frog/brain/organ/Mouth.java index 0c160f5..4a77b2d 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Eat.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Mouth.java @@ -15,9 +15,9 @@ import com.github.drinkjava2.frog.Frog; import com.github.drinkjava2.frog.brain.Organ; /** - * Eat food at current x, y position + * Mouth eat food at current x, y position */ -public class Eat extends Organ {// Eat这个类将食物转化为能量,能量小于0,则青蛙死掉 +public class Mouth extends Organ {// Mouth这个类将食物转化为能量,能量小于0,则青蛙死掉 private static final long serialVersionUID = 1L; @Override diff --git a/core/src/main/java/com/github/drinkjava2/frog/egg/Egg.java b/core/src/main/java/com/github/drinkjava2/frog/egg/Egg.java index 7795844..b6e9ec4 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/egg/Egg.java +++ b/core/src/main/java/com/github/drinkjava2/frog/egg/Egg.java @@ -16,16 +16,6 @@ import java.util.List; import com.github.drinkjava2.frog.Frog; import com.github.drinkjava2.frog.brain.Organ; -import com.github.drinkjava2.frog.brain.organ.Active; -import com.github.drinkjava2.frog.brain.organ.Eat; -import com.github.drinkjava2.frog.brain.organ.Eyes.SeeDown; -import com.github.drinkjava2.frog.brain.organ.Eyes.SeeLeft; -import com.github.drinkjava2.frog.brain.organ.Eyes.SeeRight; -import com.github.drinkjava2.frog.brain.organ.Eyes.SeeUp; -import com.github.drinkjava2.frog.brain.organ.MoveDown; -import com.github.drinkjava2.frog.brain.organ.MoveLeft; -import com.github.drinkjava2.frog.brain.organ.MoveRight; -import com.github.drinkjava2.frog.brain.organ.MoveUp; import com.github.drinkjava2.frog.util.RandomUtils; /** @@ -41,24 +31,9 @@ import com.github.drinkjava2.frog.util.RandomUtils; public class Egg implements Serializable { private static final long serialVersionUID = 1L; - public static int FIXED_ORGAN_QTY = 9; - public List organs = new ArrayList<>();// NOSONAR - public Egg() {// 无中生有,创建一个蛋,先有蛋,后有蛙 - organs.add(new MoveUp().setXYZRN(800, 100, 500, 60, "Up")); - organs.add(new MoveDown().setXYZRN(800, 400, 500, 60, "Down")); - organs.add(new MoveLeft().setXYZRN(700, 250, 500, 60, "Left")); - organs.add(new MoveRight().setXYZRN(900, 250, 500, 60, "Right")); - organs.add(new SeeUp().setXYZRN(200, 300 + 90, 500, 40, "SeeUp")); - organs.add(new SeeDown().setXYZRN(200, 300 - 90, 500, 40, "SeeDown")); - organs.add(new SeeLeft().setXYZRN(200 - 90, 300, 500, 40, "SeeLeft")); - organs.add(new SeeRight().setXYZRN(200 + 90, 300, 500, 40, "SeeRight")); - organs.add(new Active().setXYZRN(500, 600, 500, 40, "Active")); // 永远激活 - // 以上数量就是FIXED_ORGAN_QTY值 - - organs.add(new Eat().setXYZRN(0, 0, 0, 0, null)); // EAT不是感觉或输出器官,没有位置和大小 - + public Egg() {// 无中生有,创建一个蛋,先有蛋,后有蛙 } /** Create egg from frog */ diff --git a/core/src/main/java/com/github/drinkjava2/frog/egg/EggTool.java b/core/src/main/java/com/github/drinkjava2/frog/egg/FrogEggTool.java similarity index 52% rename from core/src/main/java/com/github/drinkjava2/frog/egg/EggTool.java rename to core/src/main/java/com/github/drinkjava2/frog/egg/FrogEggTool.java index 04101d7..31222cc 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/egg/EggTool.java +++ b/core/src/main/java/com/github/drinkjava2/frog/egg/FrogEggTool.java @@ -22,7 +22,17 @@ import java.util.List; import com.github.drinkjava2.frog.Application; import com.github.drinkjava2.frog.Env; import com.github.drinkjava2.frog.Frog; -import com.github.drinkjava2.frog.util.FrogFileUtils; +import com.github.drinkjava2.frog.brain.organ.Active; +import com.github.drinkjava2.frog.brain.organ.Mouth; +import com.github.drinkjava2.frog.brain.organ.MoveDown; +import com.github.drinkjava2.frog.brain.organ.MoveLeft; +import com.github.drinkjava2.frog.brain.organ.MoveRight; +import com.github.drinkjava2.frog.brain.organ.MoveUp; +import com.github.drinkjava2.frog.brain.organ.Eyes.SeeDown; +import com.github.drinkjava2.frog.brain.organ.Eyes.SeeLeft; +import com.github.drinkjava2.frog.brain.organ.Eyes.SeeRight; +import com.github.drinkjava2.frog.brain.organ.Eyes.SeeUp; +import com.github.drinkjava2.frog.util.LocalFileUtils; /** * EggTool save eggs to disk @@ -30,7 +40,7 @@ import com.github.drinkjava2.frog.util.FrogFileUtils; * @author Yong Zhu * @since 1.0 */ -public class EggTool { +public class FrogEggTool { /** * Frogs which have higher energy lay eggs @@ -39,25 +49,22 @@ public class EggTool { * 用能量的多少来简化生存竟争模拟,每次下蛋数量固定为EGG_QTY个 */ public static void layEggs() { - + sortFrogsOrderByEnergyDesc(); -// for (Frog frog : Env.frogs) { -// Lines LINES=(Lines) frog.organs.get(10); -// System.out.println(frog.energy+":"+LINES.lines[0]); -// } Frog first = Env.frogs.get(0); Frog last = Env.frogs.get(Env.frogs.size() - 1); try { - Env.eggs.clear(); - for (int i = 0; i < Env.EGG_QTY; i++) - Env.eggs.add(new Egg(Env.frogs.get(i))); - FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "eggs.ser"); + Env.frog_eggs.clear(); + for (int i = 0; i < Env.FROG_EGG_QTY; i++) + Env.frog_eggs.add(new Egg(Env.frogs.get(i))); + FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "frog_eggs.ser"); ObjectOutputStream so = new ObjectOutputStream(fo); - so.writeObject(Env.eggs); + so.writeObject(Env.frog_eggs); so.close(); System.out.print("Fist frog has " + first.organs.size() + " organs, energy=" + first.energy); System.out.println(", Last frog has " + last.organs.size() + " organs, energy=" + last.energy); - System.out.println("Saved " + Env.eggs.size() + " eggs to file '" + Application.CLASSPATH + "eggs.ser'"); + System.out.println( + "Saved " + Env.frog_eggs.size() + " eggs to file '" + Application.CLASSPATH + "frog_eggs.ser'"); } catch (IOException e) { System.out.println(e); } @@ -77,32 +84,45 @@ public class EggTool { } public static void deleteEggs() { - System.out.println("Delete exist egg file: '" + Application.CLASSPATH + "eggs.ser'"); - FrogFileUtils.deleteFile(Application.CLASSPATH + "eggs.ser"); + System.out.println("Delete exist egg file: '" + Application.CLASSPATH + "frog_eggs.ser'"); + LocalFileUtils.deleteFile(Application.CLASSPATH + "frog_eggs.ser"); } /** - * 从磁盘读入一批Egg + * 从磁盘读入一批frog Egg */ @SuppressWarnings("unchecked") - public static void loadEggs() { + public static void loadFrogEggs() { boolean errorfound = false; try { - FileInputStream eggsFile = new FileInputStream(Application.CLASSPATH + "eggs.ser"); + FileInputStream eggsFile = new FileInputStream(Application.CLASSPATH + "frog_eggs.ser"); ObjectInputStream eggsInputStream = new ObjectInputStream(eggsFile); - Env.eggs = (List) eggsInputStream.readObject(); - System.out.println( - "Loaded " + Env.eggs.size() + " eggs from file '" + Application.CLASSPATH + "eggs.ser" + "'.\n"); + Env.frog_eggs = (List) eggsInputStream.readObject(); + System.out.println("Loaded " + Env.frog_eggs.size() + " eggs from file '" + Application.CLASSPATH + + "frog_eggs.ser" + "'.\n"); eggsInputStream.close(); } catch (Exception e) { errorfound = true; } if (errorfound) { - Env.eggs.clear(); - for (int j = 0; j < Env.EGG_QTY; j++) - Env.eggs.add(new Egg()); - System.out.println("Fail to load egg file at path '" + Application.CLASSPATH + "', created " - + Env.eggs.size() + " eggs to do test.\n"); + Env.frog_eggs.clear(); + for (int j = 0; j < Env.FROG_EGG_QTY; j++) { + Egg egg = new Egg(); + float r = 40; + egg.organs.add(new Mouth().setXYZRN(0, 0, 0, 0, "Eat")); // Mouth不是感觉或输出器官,没有位置和大小 + egg.organs.add(new Active().setXYZRN(500, 600, 500, r, "Active")); // 永远激活 + egg.organs.add(new MoveUp().setXYZRN(800, 100, 500, r, "Up")); + egg.organs.add(new MoveDown().setXYZRN(800, 400, 500, r, "Down")); + egg.organs.add(new MoveLeft().setXYZRN(700, 250, 500, r, "Left")); + egg.organs.add(new MoveRight().setXYZRN(900, 250, 500, r, "Right")); + egg.organs.add(new SeeUp().setXYZRN(200, 300 + 90, 500, r, "SeeUp")); + egg.organs.add(new SeeDown().setXYZRN(200, 300 - 90, 500, r, "SeeDown")); + egg.organs.add(new SeeLeft().setXYZRN(200 - 90, 300, 500, r, "SeeLeft")); + egg.organs.add(new SeeRight().setXYZRN(200 + 90, 300, 500, r, "SeeRight")); + Env.frog_eggs.add(egg); + } + System.out.println("Fail to load frog egg file '" + Application.CLASSPATH + "frog_eggs.ser" + "', created " + + Env.frog_eggs.size() + " eggs to do test."); } } diff --git a/core/src/main/java/com/github/drinkjava2/frog/egg/SnakeEggTool.java b/core/src/main/java/com/github/drinkjava2/frog/egg/SnakeEggTool.java new file mode 100644 index 0000000..b36f508 --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/egg/SnakeEggTool.java @@ -0,0 +1,128 @@ +/* + * 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.github.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.Collections; +import java.util.Comparator; +import java.util.List; + +import com.github.drinkjava2.frog.Application; +import com.github.drinkjava2.frog.Env; +import com.github.drinkjava2.frog.brain.organ.Active; +import com.github.drinkjava2.frog.brain.organ.MoveDown; +import com.github.drinkjava2.frog.brain.organ.MoveLeft; +import com.github.drinkjava2.frog.brain.organ.MoveRight; +import com.github.drinkjava2.frog.brain.organ.MoveUp; +import com.github.drinkjava2.frog.snake.Snake; +import com.github.drinkjava2.frog.snake.brain.organ.SnakeEyes; +import com.github.drinkjava2.frog.snake.brain.organ.SnakeMouth; +import com.github.drinkjava2.frog.util.LocalFileUtils; + +/** + * EggTool save eggs to disk + * + * @author Yong Zhu + * @since 1.0 + */ +public class SnakeEggTool { + + /** + * Snakes which have higher energy lay eggs + * + * 利用Java串行机制存盘。 能量多(也就是吃的更多)的Snake下蛋并存盘, 以进行下一轮测试,能量少的Snake被淘汰,没有下蛋的资格。 + * 用能量的多少来简化生存竟争模拟,每次下蛋数量固定为EGG_QTY个 + */ + public static void layEggs() { + if (!Env.SNAKE_MODE) + return; + sortSnakesOrderByEnergyDesc(); + Snake first = Env.snakes.get(0); + Snake last = Env.snakes.get(Env.snakes.size() - 1); + try { + Env.snake_eggs.clear(); + for (int i = 0; i < Env.SNAKE_EGG_QTY; i++) + Env.snake_eggs.add(new Egg(Env.snakes.get(i))); + FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "snake_eggs.ser"); + ObjectOutputStream so = new ObjectOutputStream(fo); + so.writeObject(Env.snake_eggs); + so.close(); + System.out.print("Fist snake has " + first.organs.size() + " organs, energy=" + first.energy); + System.out.println(", Last snake has " + last.organs.size() + " organs, energy=" + last.energy); + System.out.println( + "Saved " + Env.snake_eggs.size() + " eggs to file '" + Application.CLASSPATH + "snake_eggs.ser'"); + } catch (IOException e) { + System.out.println(e); + } + } + + private static void sortSnakesOrderByEnergyDesc() {// 按能量多少给青蛙排序 + Collections.sort(Env.snakes, new Comparator() { + public int compare(Snake a, Snake b) { + if (a.energy > b.energy) + return -1; + else if (a.energy == b.energy) + return 0; + else + return 1; + } + }); + } + + public static void deleteEggs() { + System.out.println("Delete exist egg file: '" + Application.CLASSPATH + "snake_eggs.ser'"); + LocalFileUtils.deleteFile(Application.CLASSPATH + "snake_eggs.ser"); + } + + /** + * 从磁盘读入一批snake Egg + */ + @SuppressWarnings("unchecked") + public static void loadSnakeEggs() { + boolean errorfound = false; + try { + FileInputStream eggsFile = new FileInputStream(Application.CLASSPATH + "snake_eggs.ser"); + ObjectInputStream eggsInputStream = new ObjectInputStream(eggsFile); + Env.snake_eggs = (List) eggsInputStream.readObject(); + System.out.println("Loaded " + Env.snake_eggs.size() + " eggs from file '" + Application.CLASSPATH + + "snake_eggs.ser" + "'.\n"); + eggsInputStream.close(); + } catch (Exception e) { + errorfound = true; + } + if (errorfound) { + Env.snake_eggs.clear(); + for (int j = 0; j < Env.SNAKE_EGG_QTY; j++) { + Egg egg = new Egg(); + float r = 40; + egg.organs.add(new SnakeMouth().setXYZRN(0, 0, 0, 0, "Eat")); // SnakeMouth不是感觉或输出器官,没有位置和大小 + egg.organs.add(new Active().setXYZRN(500, 600, 500, 5, "Active")); // 永远激活 + egg.organs.add(new MoveUp().setXYZRN(800, 100, 500, r, "Up")); + egg.organs.add(new MoveDown().setXYZRN(800, 400, 500, r, "Down")); + egg.organs.add(new MoveLeft().setXYZRN(700, 250, 500, r, "Left")); + egg.organs.add(new MoveRight().setXYZRN(900, 250, 500, r, "Right")); + egg.organs.add(new SnakeEyes.SeeUp().setXYZRN(200, 300 + 90, 500, r, "SeeUp")); + egg.organs.add(new SnakeEyes.SeeDown().setXYZRN(200, 300 - 90, 500, r, "SeeDown")); + egg.organs.add(new SnakeEyes.SeeLeft().setXYZRN(200 - 90, 300, 500, r, "SeeLeft")); + egg.organs.add(new SnakeEyes.SeeRight().setXYZRN(200 + 90, 300, 500, r, "SeeRight")); + Env.snake_eggs.add(egg); + } + System.out.println("Fail to load snake egg file '" + Application.CLASSPATH + "snake_eggs.ser" + + "', created " + Env.snake_eggs.size() + " eggs to do test."); + } + + } + +} diff --git a/core/src/main/java/com/github/drinkjava2/frog/objects/Food.java b/core/src/main/java/com/github/drinkjava2/frog/objects/Food.java index 7489171..ae06c32 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/objects/Food.java +++ b/core/src/main/java/com/github/drinkjava2/frog/objects/Food.java @@ -15,6 +15,7 @@ import static com.github.drinkjava2.frog.Env.ENV_WIDTH; import static com.github.drinkjava2.frog.Env.FOOD_QTY; import static com.github.drinkjava2.frog.Env.bricks; +import com.github.drinkjava2.frog.Env; import com.github.drinkjava2.frog.util.RandomUtils; /** @@ -24,25 +25,73 @@ import com.github.drinkjava2.frog.util.RandomUtils; * @since 1.0 */ public class Food implements EnvObject { + public static int food_ated = 0; @Override public void build() { - for (int i = 0; i < FOOD_QTY; i++) // 生成食物 - bricks[RandomUtils.nextInt(ENV_WIDTH)][RandomUtils.nextInt(ENV_HEIGHT)] = Material.FOOD; + food_ated = 0; + if (!Env.FOOD_CAN_MOVE) { + for (int i = 0; i < FOOD_QTY; i++) // 生成食物 + bricks[RandomUtils.nextInt(ENV_WIDTH)][RandomUtils.nextInt(ENV_HEIGHT)] = Material.FOOD; + return; + } + for (int i = 0; i < FOOD_QTY / 4; i++) // 生成苍蝇1 + bricks[RandomUtils.nextInt(ENV_WIDTH)][RandomUtils.nextInt(ENV_HEIGHT)] = Material.FLY1; + for (int i = 0; i < FOOD_QTY / 4; i++) // 生成苍蝇2 + bricks[RandomUtils.nextInt(ENV_WIDTH)][RandomUtils.nextInt(ENV_HEIGHT)] = Material.FLY2; + for (int i = 0; i < FOOD_QTY / 4; i++) // 生成苍蝇3 + bricks[RandomUtils.nextInt(ENV_WIDTH)][RandomUtils.nextInt(ENV_HEIGHT)] = Material.FLY3; + for (int i = 0; i < FOOD_QTY / 4; i++) // 生成苍蝇4 + bricks[RandomUtils.nextInt(ENV_WIDTH)][RandomUtils.nextInt(ENV_HEIGHT)] = Material.FLY4; } @Override public void destory() { for (int i = 0; i < ENV_WIDTH; i++) {// 清除食物 for (int j = 0; j < ENV_HEIGHT; j++) - if (bricks[i][j] == Material.FOOD) + if (bricks[i][j] >= Material.FOOD && bricks[i][j] <= Material.FLY4) bricks[i][j] = 0; } } @Override public void active(int screen) { - // Food do not have any active + if (RandomUtils.percent(96)) + return; + for (int i = 1; i < ENV_WIDTH; i++) {// 水平移动FLY + for (int j = 1; j < ENV_HEIGHT; j++) { + if (bricks[i][j] == Material.FLY1) { + bricks[i - 1][j] = Material.FLY1; + bricks[i][j] = 0; + } + if (bricks[i][j] == Material.FLY2) { + bricks[i][j - 1] = Material.FLY2; + bricks[i][j] = 0; + } + } + } + + for (int i = ENV_WIDTH - 2; i > 0; i--) {// 上下移动FLY + for (int j = ENV_HEIGHT - 2; j > 0; j--) { + if (bricks[i][j] == Material.FLY3) { + bricks[i + 1][j] = Material.FLY3; + bricks[i][j] = 0; + } + if (bricks[i][j] == Material.FLY4) { + bricks[i][j + 1] = Material.FLY4; + bricks[i][j] = 0; + } + } + } + + for (int i = 0; i < ENV_WIDTH; i++) { + bricks[i][0] = 0; + bricks[i][ENV_HEIGHT - 1] = 0; + } + for (int i = 0; i < ENV_HEIGHT; i++) { + bricks[0][i] = 0; + bricks[ENV_WIDTH - 1][i] = 0; + } } } diff --git a/core/src/main/java/com/github/drinkjava2/frog/objects/Material.java b/core/src/main/java/com/github/drinkjava2/frog/objects/Material.java index b80fb61..45fa7e6 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/objects/Material.java +++ b/core/src/main/java/com/github/drinkjava2/frog/objects/Material.java @@ -15,24 +15,35 @@ import java.awt.Color; /** * Material store material types * - * 用不同的数字常量代表虚拟环境中不同的组成材料,0为空,小于10的不可见,大于20的将杀死在同一位置出现的青蛙,例如砖头和青蛙不可以重叠出现在同一位置 + * 用不同的数字常量代表虚拟环境中不同的材料,0为空,每个材料用整数中的一位表示, 所以一个整数中可以表达15种不同的材料,并且这些材料可以同时出现 * * @author Yong Zhu * @since 1.0 */ public class Material { - public static final byte NO = 0; // nothing - public static final byte SEESAW_BASE = 1; // 1~9 is invisible to frog + private static int origin = 1; - public static final byte VISIBLE = 10; // if>=10 will visible to frog - public static final byte FOOD = VISIBLE + 1; - public static final byte SEESAW = VISIBLE + 2; + private static int next() {// 每次将origin左移1位 + origin = origin << 1; + if (origin < 0) + throw new RuntimeException(""); + return origin; + } - public static final byte KILLFROG = 20; // if>=20 will kill frog - public static final byte BRICK = KILLFROG + 1;// brick will kill frog - public static final byte TRAP = KILLFROG + 2; // trap will kill frog + public static final int NO = 0; // nothing + public static final int VISIBLE = next(); // if visible to frog + public static final int SEESAW = next(); + public static final int FOOD = next(); + public static final int FLY1 = next();// FLY1苍蝇是一种会移动的Food + public static final int FLY2 = next();// FLY2苍蝇是一种会移动的Food + public static final int FLY3 = next();// FLY3苍蝇是一种会移动的Food + public static final int FLY4 = next();// FLY4苍蝇是一种会移动的Food - public static Color color(byte material) { + public static final int KILLFROG = next(); // if>=KILLFROG will kill frog + public static final int BRICK = next();// brick will kill frog + public static final int TRAP = next(); // trap will kill frog + + public static Color color(int material) { if (material == TRAP) return Color.LIGHT_GRAY; else diff --git a/core/src/main/java/com/github/drinkjava2/frog/objects/SeeSaw.java b/core/src/main/java/com/github/drinkjava2/frog/objects/SeeSaw.java deleted file mode 100644 index ca1f212..0000000 --- a/core/src/main/java/com/github/drinkjava2/frog/objects/SeeSaw.java +++ /dev/null @@ -1,93 +0,0 @@ -/* 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.github.drinkjava2.frog.objects; - -import static com.github.drinkjava2.frog.Env.ENV_HEIGHT; -import static com.github.drinkjava2.frog.Env.ENV_WIDTH; -import static com.github.drinkjava2.frog.Env.bricks; - -import com.github.drinkjava2.frog.Env; -import com.github.drinkjava2.frog.Frog; -import com.github.drinkjava2.frog.util.RandomUtils; - -/** - * This is a seesaw to train frog's balance - * - * @author Yong Zhu - * @since 2.0.1 - */ -public class SeeSaw implements EnvObject { - private static final int LEGNTH = 300; - private static final int CENTER_X = Env.ENV_WIDTH / 2; - private static final int CENTER_Y = Env.ENV_HEIGHT / 2; - - private double angle = 0;// -PI/4 to PI/4 - private double leftWeight = 0; - private double rightWeight = 0; - - @Override - public void build() { - angle = 0; - } - - @Override - public void destory() { - // do nothing - } - - @Override - public void active(int screen) { - for (int i = 0; i < ENV_WIDTH; i++) {// 清除食物 - for (int j = 0; j < ENV_HEIGHT; j++) - if (bricks[i][j] == Material.SEESAW) - bricks[i][j] = 0; - } - - if (RandomUtils.percent(2)) - leftWeight = RandomUtils.nextFloat() * 3; - if (RandomUtils.percent(2)) - rightWeight = RandomUtils.nextFloat() * 3; - Frog f = Env.frogs.get(screen); - - if (f.x < (CENTER_X - LEGNTH / 2) || f.x > (CENTER_X + LEGNTH / 2)) - f.energy -= 100000; // 如果走出跷跷板外则扣分,出局 - double left = leftWeight - (f.x - CENTER_X); - double right = rightWeight + (f.x - CENTER_X); - // right - left need in -100 to +100 - angle = angle + (right - left) * Math.PI * .000001; - if (angle > Math.PI / 6) { - angle = Math.PI / 6; - f.energy -= 200; - } - if (angle < -Math.PI / 6) { - angle = -Math.PI / 6; - f.energy -= 200; - } - f.y = CENTER_Y + (int) Math.round((f.x - CENTER_X) * Math.tan(angle)); - f.energy -= Math.abs(angle) * 180; // 角度越大,扣分越多 - int x; - int y; - for (int l = -LEGNTH / 2; l <= LEGNTH / 2; l++) { - x = (int) Math.round(l * Math.cos(angle)); - y = (int) Math.round(l * Math.sin(angle)); - Env.bricks[CENTER_X + x][CENTER_Y + y] = Material.SEESAW; - } - - // 画底座 - for (int i = 1; i < 10; i++) { - Env.bricks[CENTER_X - i][CENTER_Y + i] = Material.SEESAW_BASE; - Env.bricks[CENTER_X + i][CENTER_Y + i] = Material.SEESAW_BASE; - } - for (int i = -10; i < 10; i++) - Env.bricks[CENTER_X + i][CENTER_Y + 10] = Material.SEESAW_BASE; - - } -} diff --git a/core/src/main/java/com/github/drinkjava2/frog/objects/Trap.java b/core/src/main/java/com/github/drinkjava2/frog/objects/Trap.java deleted file mode 100644 index 05ce6f4..0000000 --- a/core/src/main/java/com/github/drinkjava2/frog/objects/Trap.java +++ /dev/null @@ -1,52 +0,0 @@ -/* 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.github.drinkjava2.frog.objects; - -import static com.github.drinkjava2.frog.Env.ENV_HEIGHT; -import static com.github.drinkjava2.frog.Env.ENV_WIDTH; -import static com.github.drinkjava2.frog.Env.bricks; - -import com.github.drinkjava2.frog.Frog; - -/** - * Trap will kill all frogs inside of it, if frog's position has material and - * it's trap, frog will die - * - * @author Yong Zhu - * @since 2019-08-05 - */ -@SuppressWarnings("all") -public class Trap implements EnvObject { - private static final int X1 = ENV_WIDTH / 2 - 350 / 2; // 陷阱左上角 - private static final int Y1 = ENV_HEIGHT / 2 - 20 / 2; // 陷阱左上角 - private static final int X2 = ENV_WIDTH / 2 + 350 / 2; // 陷阱右下角 - private static final int Y2 = ENV_HEIGHT / 2 + 20 / 2; // 陷阱右下角 - - @Override - public void build() { - for (int x = X1; x <= X2; x++) - for (int y = Y1; y <= Y2; y++) - bricks[x][y] = Material.TRAP; - } - - @Override - public void destory() { - for (int x = X1; x <= X2; x++) - for (int y = Y1; y <= Y2; y++) - bricks[x][y] = 0; - } - - @Override - public void active(int screen) { - - } - -} diff --git a/core/src/main/java/com/github/drinkjava2/frog/snake/Snake.java b/core/src/main/java/com/github/drinkjava2/frog/snake/Snake.java new file mode 100644 index 0000000..fb2f90e --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/snake/Snake.java @@ -0,0 +1,49 @@ +/* + * 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.github.drinkjava2.frog.snake; + +import java.awt.Graphics; +import java.awt.Image; +import java.io.FileInputStream; + +import javax.imageio.ImageIO; + +import com.github.drinkjava2.frog.Application; +import com.github.drinkjava2.frog.Frog; +import com.github.drinkjava2.frog.egg.Egg; + +/** + * Snake has similar brain like Frog, snake eat frog
+ * 蛇是青蛙的子类,区别是: 蛇只能看到青蛙,并将其当作一个单个象素点的食物, 青蛙能看到真的食物(Food)和蛇 + * + * @since 1.0 + */ +public class Snake extends Frog { + static Image snakeImg; + static { + try { + snakeImg = ImageIO.read(new FileInputStream(Application.CLASSPATH + "snake.png")); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public Snake(int x, int y, Egg egg) { + super(x, y, egg); + } + + @Override + public void show(Graphics g) {// 显示蛇的图象 + if (!alive) + return; + g.drawImage(snakeImg, x - 16, y - 5, 18, 18, null);// 减去坐标,保证蛇嘴巴显示在当前x,y处 + } +} diff --git a/core/src/main/java/com/github/drinkjava2/frog/snake/brain/organ/SnakeEyes.java b/core/src/main/java/com/github/drinkjava2/frog/snake/brain/organ/SnakeEyes.java new file mode 100644 index 0000000..86617e3 --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/snake/brain/organ/SnakeEyes.java @@ -0,0 +1,102 @@ +/* + * 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.github.drinkjava2.frog.snake.brain.organ; + +import com.github.drinkjava2.frog.Env; +import com.github.drinkjava2.frog.Frog; +import com.github.drinkjava2.frog.brain.Organ; +import com.github.drinkjava2.frog.util.RandomUtils; + +/** + * SnakeEyes can only see 4 direction's frog + * + * 蛇的眼睛看不到food, 只能看到青蛙,也就是说它把青蛙当成食物 + * + * @author Yong Zhu + * @since 1.0 + */ +public class SnakeEyes { + + public static class SeeUp extends Organ {// 只能看到上方青蛙 + private static final long serialVersionUID = 1L; + public int seeDistance; // 眼睛能看到的距离 + + @Override + public void initFrog(Frog f) { // 仅在Snake生成时这个方法会调用一次 + if (!initilized) { + initilized = true; + seeDistance = 8; + } + } + + @Override + public Organ[] vary() { + seeDistance = RandomUtils.varyInLimit(seeDistance, 5, 20); + if (RandomUtils.percent(5)) { // 可视距离有5%的机率变异 + seeDistance = seeDistance + 1 - 2 * RandomUtils.nextInt(2); + if (seeDistance < 1) + seeDistance = 1; + if (seeDistance > 50) + seeDistance = 50; + } + return new Organ[] { this }; + } + + @Override + public void active(Frog f) { + for (int i = 1; i < seeDistance; i++) + if (Env.foundAnyThing(f.x, f.y + i)) { + activeInput(f, 30); + return; + } + } + } + + public static class SeeDown extends SeeUp {// 只能看到下方青蛙 + private static final long serialVersionUID = 1L; + + @Override + public void active(Frog f) { + for (int i = 1; i < seeDistance; i++) + if (Env.foundAnyThing(f.x, f.y - i)) { + activeInput(f, 30); + return; + } + } + } + + public static class SeeLeft extends SeeUp {// 只能看到左方青蛙 + private static final long serialVersionUID = 1L; + + @Override + public void active(Frog f) { + for (int i = 1; i < seeDistance; i++) + if (Env.foundAnyThing(f.x - i, f.y)) { + activeInput(f, 30); + return; + } + } + } + + public static class SeeRight extends SeeUp {// 只能看到右方青蛙 + private static final long serialVersionUID = 1L; + + @Override + public void active(Frog f) { + for (int i = 1; i < seeDistance; i++) + if (Env.foundAnyThing(f.x + i, f.y)) { + activeInput(f, 30); + return; + } + } + } + +} diff --git a/core/src/main/java/com/github/drinkjava2/frog/snake/brain/organ/SnakeMouth.java b/core/src/main/java/com/github/drinkjava2/frog/snake/brain/organ/SnakeMouth.java new file mode 100644 index 0000000..06d41be --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/snake/brain/organ/SnakeMouth.java @@ -0,0 +1,31 @@ +/* + * 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.github.drinkjava2.frog.snake.brain.organ; + +import com.github.drinkjava2.frog.Env; +import com.github.drinkjava2.frog.Frog; +import com.github.drinkjava2.frog.brain.Organ; + +/** + * SnakeMouth eat frog at current x, y position (snake's mouth postion) + */ +public class SnakeMouth extends Organ {// SnakeMouth这个类将青蛙作为食物转化为能量,能量小于0,则蛇死掉 + private static final long serialVersionUID = 1L; + + @Override + public void active(Frog f) { + if (Env.foundAndAteFrog(f.x, f.y)) { + f.ateFood++; + f.energy += 1000;// 如果蛇的坐标与青蛙重合,吃掉food,能量境加 + } + } + +} diff --git a/core/src/main/java/com/github/drinkjava2/frog/util/FrogFileUtils.java b/core/src/main/java/com/github/drinkjava2/frog/util/LocalFileUtils.java similarity index 97% rename from core/src/main/java/com/github/drinkjava2/frog/util/FrogFileUtils.java rename to core/src/main/java/com/github/drinkjava2/frog/util/LocalFileUtils.java index 16f1999..8b466d6 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/util/FrogFileUtils.java +++ b/core/src/main/java/com/github/drinkjava2/frog/util/LocalFileUtils.java @@ -19,14 +19,14 @@ import java.io.IOException; import java.io.InputStream; /** - * File Utilities used in this project + * Local File Utilities used in this project * * @author Yong Zhu * @since 1.0 */ -public class FrogFileUtils { +public class LocalFileUtils { - private FrogFileUtils() { + private LocalFileUtils() { // default constructor } diff --git a/core/src/main/java/com/github/drinkjava2/frog/util/RandomUtils.java b/core/src/main/java/com/github/drinkjava2/frog/util/RandomUtils.java index be42bbb..7208538 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/util/RandomUtils.java +++ b/core/src/main/java/com/github/drinkjava2/frog/util/RandomUtils.java @@ -10,16 +10,12 @@ */ package com.github.drinkjava2.frog.util; -import static com.github.drinkjava2.frog.Env.FROG_BRAIN_XSIZE; -import static com.github.drinkjava2.frog.Env.FROG_BRAIN_YSIZE; -import static com.github.drinkjava2.frog.Env.FROG_BRAIN_ZSIZE; - import java.util.Random; import com.github.drinkjava2.frog.Frog; -import com.github.drinkjava2.frog.brain.Cuboid; +import com.github.drinkjava2.frog.brain.Organ; import com.github.drinkjava2.frog.brain.Zone; -import com.github.drinkjava2.frog.egg.Egg; +import com.github.drinkjava2.frog.brain.organ.Line; /** * Random Utilities used in this project @@ -48,38 +44,19 @@ public class RandomUtils { public static Zone randomZoneInZone(Zone o) { // 在一个区内随机取一个小小区 return new Zone(o.x - o.r + o.r * 2 * rand.nextFloat(), o.y - o.r + o.r * 2 * rand.nextFloat(), - o.z - o.r + o.r * 2 * rand.nextFloat(), o.r * rand.nextFloat() * .04f); + o.z /*- o.r + o.r * 2 * rand.nextFloat()*/, o.r * rand.nextFloat() * .04f); } /** Return a random zone inside of frog's random organ */ public static Zone randomZoneInOrgans(Frog f) { if (f.organs == null || f.organs.size() == 0) - throw new IllegalArgumentException("Can not call randomPosInRandomOrgan method when frog has no organ"); - return randomZoneInZone(f.organs.get(RandomUtils.nextInt(Egg.FIXED_ORGAN_QTY))); - } - - /** Randomly create a Cuboid inside of brain space */ - public static Cuboid randomCuboid() {// 随机生成一个位于脑空间内的立方体 - Cuboid c = new Cuboid(); - c.x = nextInt(FROG_BRAIN_XSIZE) - FROG_BRAIN_XSIZE / 4;// 为了多产生贴边的立方体,超出边界的被裁切 - if (c.x < 0) - c.x = 0; - c.y = nextInt(FROG_BRAIN_YSIZE) - FROG_BRAIN_YSIZE / 4; - if (c.y < 0) - c.y = 0; - c.z = nextInt(FROG_BRAIN_ZSIZE) - FROG_BRAIN_ZSIZE / 4; - if (c.z < 0) - c.z = 0; - c.xe = 1 + nextInt(FROG_BRAIN_XSIZE); // 立方体任一个边长至少是1 - if (c.xe > (FROG_BRAIN_XSIZE - c.x))// 超出边界的被裁切 - c.xe = FROG_BRAIN_XSIZE - c.x; - c.ye = 1 + nextInt(FROG_BRAIN_YSIZE); - if (c.ye > (FROG_BRAIN_YSIZE - c.y)) - c.ye = FROG_BRAIN_YSIZE - c.y; - c.ze = 1 + nextInt(FROG_BRAIN_ZSIZE); - if (c.ze > (FROG_BRAIN_ZSIZE - c.z)) - c.ze = FROG_BRAIN_ZSIZE - c.z; - return c; + throw new IllegalArgumentException("Can not call randomPosInRandomOrgan method when has no organ"); + Organ o = f.organs.get(1 + RandomUtils.nextInt(f.organs.size() - 1)); // 跳过第一个器官 + if (o instanceof Line) { + return randomZoneInZone(((Line) o).bodyZone); + } else { + return randomZoneInZone(o); + } } public static int vary(int v, int percet) { diff --git a/history/001_first_version/run.bat b/history/001_first_version/run.bat index fa4fed9..9000f92 100644 --- a/history/001_first_version/run.bat +++ b/history/001_first_version/run.bat @@ -1,4 +1,3 @@ call mvn clean compile cd target\classes -java -classpath ".;*" com.github.drinkjava2.frog.env.Application -@pause \ No newline at end of file +java -classpath ".;*" com.github.drinkjava2.frog.env.Application \ No newline at end of file diff --git a/history/002_first_eye/run.bat b/history/002_first_eye/run.bat index fa4fed9..9000f92 100644 --- a/history/002_first_eye/run.bat +++ b/history/002_first_eye/run.bat @@ -1,4 +1,3 @@ call mvn clean compile cd target\classes -java -classpath ".;*" com.github.drinkjava2.frog.env.Application -@pause \ No newline at end of file +java -classpath ".;*" com.github.drinkjava2.frog.env.Application \ No newline at end of file diff --git a/history/003_trap/run.bat b/history/003_trap/run.bat index ab1bab3..2684987 100644 --- a/history/003_trap/run.bat +++ b/history/003_trap/run.bat @@ -1,4 +1,3 @@ call mvn clean compile cd target\classes -java -classpath ".;*" com.github.drinkjava2.frog.Application -@pause \ No newline at end of file +java -classpath ".;*" com.github.drinkjava2.frog.Application \ No newline at end of file diff --git a/history/003a_legs/run.bat b/history/003a_legs/run.bat index ab1bab3..2684987 100644 --- a/history/003a_legs/run.bat +++ b/history/003a_legs/run.bat @@ -1,4 +1,3 @@ call mvn clean compile cd target\classes -java -classpath ".;*" com.github.drinkjava2.frog.Application -@pause \ No newline at end of file +java -classpath ".;*" com.github.drinkjava2.frog.Application \ No newline at end of file diff --git a/history/003b_simple/run.bat b/history/003b_simple/run.bat index ab1bab3..2684987 100644 --- a/history/003b_simple/run.bat +++ b/history/003b_simple/run.bat @@ -1,4 +1,3 @@ call mvn clean compile cd target\classes -java -classpath ".;*" com.github.drinkjava2.frog.Application -@pause \ No newline at end of file +java -classpath ".;*" com.github.drinkjava2.frog.Application \ No newline at end of file diff --git a/history/004_seasaw/run.bat b/history/004_seasaw/run.bat index ab1bab3..2684987 100644 --- a/history/004_seasaw/run.bat +++ b/history/004_seasaw/run.bat @@ -1,4 +1,3 @@ call mvn clean compile cd target\classes -java -classpath ".;*" com.github.drinkjava2.frog.Application -@pause \ No newline at end of file +java -classpath ".;*" com.github.drinkjava2.frog.Application \ No newline at end of file diff --git a/history/005_letter_test/run.bat b/history/005_letter_test/run.bat index ab1bab3..2684987 100644 --- a/history/005_letter_test/run.bat +++ b/history/005_letter_test/run.bat @@ -1,4 +1,3 @@ call mvn clean compile cd target\classes -java -classpath ".;*" com.github.drinkjava2.frog.Application -@pause \ No newline at end of file +java -classpath ".;*" com.github.drinkjava2.frog.Application \ No newline at end of file diff --git a/snake.png b/snake.png new file mode 100644 index 0000000000000000000000000000000000000000..ba9c77f48fb709dbabfcb208748f2834609d29c7 GIT binary patch literal 1000 zcmV>P)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZuu6)F zVFTwm1|x2127mx!B*tqmet-RMyseUfn}wa>KM*o8GBGf{`^oTEfR%xnk&%J%A0q=m z01@S)z=J&uTtGuufd=rha5C_-aWOFPGc!ni{>RX=^AiJ;rZNLS0HGLk@b!)VZ+?7c z`1S7(gBG7OgT9~~BS`$m-`@;B{`_Jv71v;>)ed0LG>{t@&EHV3mE_c2yW2! zrx*VhTv!Tr`mcY#fdDV+!@d<=#{3JiaMVby+hGgyw9k(uGsuWt-OJp5P<0tg_c&5zFhXJ=vsbN>GS z#~{fe$f(RC##pZ#%<%QkPln?k?ttY!16{`pjIBx6cQ9P|@CYN#00a=zqDRLVf@Mq@ zY(&+-24$RG`2X#%FaJOO{K6o_&I3#%5J%58O=b84^xCEO4;eoF_=@2ofB<6RVr6CE zXXRv6;SvR>lS>~TG6=KrFn$Jx4J*()tjx?{g`QG+jQ@ZZaWJzoG+tQ4@a)@r6juQR z5R)voD40>D6TqkeOgpc?eFF1+r41SX0>ccLa2XCfz54&fkB|R(fQgZrfr;VCua68r zfJp=y00a;V2QU^s{{8WvpP2)gUYHpEF(NGDV`OLe`2QzE@%d#8)>0ba$N(jfL}gnB zF%CWyg8%}EW!b$W3^(3BVvuCu{(tx5O9oz6PKG`2um5)u)MRuK)nr)n>O8|o#-9v3 zo?ikd33e7%pf~jycvv_XkqrU}AeMHM2!@K|iy8g^h1q~%V$QG105Sw5*<~8T`0EVA z|Fa+NGjOs1Q}o||3`r{X3`T+qjOc+45I|sCrd{9hUujdp|JeOg|APV%Bt|L*2rvN3 WLQUj(qUH$z0000