diff --git a/3d-model.gif b/3d-model.gif new file mode 100644 index 0000000..4156cdf Binary files /dev/null and b/3d-model.gif differ diff --git a/README.md b/README.md index bbe0a10..45bef15 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ ## Frog | 人工生命 +(English introduction please see "README_EN.md") 这是一个人工生命试验项目,最终目标是创建“有自我意识表现”的模拟生命体,技术架构基于02年提出的 [一个人工脑模型](一个人工脑模型.md)。 这个项目永远没有结束的时候,开始于模拟一个简单的生命体,然后是青蛙、狗......, 结束于有“自我意识表现”的人工脑,或者说,结束于被机器人代替人类的那一天。 @@ -9,7 +10,7 @@ 从单细胞进化到多细胞、从青蛙进化到人类,这是一个漫长的、随机的进化过程,但在超级电脑上跑可能只要几天时间,就可能得到一个相当不错的脑模型。当然电脑速度越快、容量越大、环境模拟的越真实,则优胜夯汰后形成的脑结构就越复杂,错的脑模型都被自然淘汰掉了。从算法着手搭建,还是从模拟环境着手自动进化,这是创建人工生命的两个大方向,第一个方向有可能走到死胡同里,因为它不具备算法自改进、变异、遗传(算法的压缩)功能,当脑模型复杂到一定地步,可能会超出人脑能理解的范畴。模拟环境方式的难点则在于环境本身必须足够复杂、正确。而且必须循序渐进,与脑的进化同步,如果把一群青蛙扔到猴子的模拟环境中,则所有青蛙都会被自然淘汰掉,项目就无法进行下去了,另一个困难是电脑必须非常快,因为它是用串行方式模拟并行,不断试错前进的过程。 目前的项目只是搭建了一个框架,语言为Java,利用Swing作图环境,构建一个虚拟环境、并模拟一群草履虫的优胜夯汰,来获取一个具备自进化功能的人工生命体,具体脑(即电脑生成的神经网络)的生成、进化算法还需要以后逐渐加入。欢迎有对神经网络感兴趣的同学加入这个实验项目,大家一起来玩,这个项目不需要多少数学知识,重在实践。 ## 短期目标 | Sort-term Goals -目前它的第一个初步目标是:造出一个真正意义上的人工生命:草履虫。它必须具备以下前四个特点: +目前它的第一个初步目标是:造出一个真正意义上的人工生命:草履虫(备注:基本上已完成)。它必须具备以下前四个特点: * 脑结构由电脑生成:神经网络由电脑算法生成,但是电脑算法仅限于模拟环境,而不是直接参与搭建神经网络,就好象大自然只负责拍死不合格的生命,它从不主动参与设计大脑。 * 脑结构可遗传:类似于生物的DNA,电脑生成的脑结构(神经网络),可通过简单的算法规则描述,并且此算法规则可以压缩成较短的片段存储,并参与到下一代草履虫的构建。 * 脑结构可变异:算法规则可以变异,下一代生成的草履虫在脑结构上与上一代总体相似,但存在部分变异。 @@ -31,7 +32,7 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什 ## 技术细节和构思 * 通过数组来模拟神经网络,用串行的循环来模拟并行芯片运作方式。用Frog的能量多少来衡量是否将它淘汰还是允许它产生后代(下蛋)参与下一轮的测试,因为这个项目的目的是获取智能体,与一般的生命游戏还是有区别的,并不是适者生存就结束了,而是必须完成一系列程序员设定好的目标,一步步进化,直到表现出自我意识现象为止。脑模型的生成算法通过简单的神经元连接完成,原则上不允行出现任何形式的硬编码(除模式识别外),因为硬编码可能会破坏“随机变异”这一生命特性。为简单起见,暂不考虑引入GPU图形芯片进行加速。 -* 更多的杂七八拉的一些想法和构思放在“开发思路.md”、“一个人工脑模型.md”等文里。 +* 更多的杂乱的一些想法和构思放在“开发思路.md”、“一个人工脑模型.md”等文里。 ## 项目要实现的短期和长远目标 * 脑模型和虚拟环境的初步搭建 [脑模型刚开始搭建。虚拟环境已完成,点击run.bat可以查看演示] @@ -66,12 +67,21 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什 ![resut3](https://gitee.com/drinkjava2/frog/raw/master/result3.gif) 2019-06-26 找食效率太低,又改回到4.12的用连接数量代替权值这个逻辑,人为设计的算法居然比不过随机连接。Pain器官的加入没有提高找食效率,必须与感光细胞合用才能知道是哪个边界,急需引入记忆功能。 2019-06-28 为了让青蛙看到边界,又加了个新的眼睛,它是一个可自进化的nxn点阵的眼睛,将来会取代只有四个象素点(但能看得远)的老眼睛。到目前为止,依然还没有进行模式识别和记忆功能开发。另外脑图可以动态显示了,用一个红圈标记出被动态跟踪显示的青蛙。 +2019-07-28 +有以下改动:1.在Env区中间加了一个陷阱区Trap,以增加趣味性,自然选择的结果是青蛙会自动绕开陷阱区。2.增加一个Active器官,它的作用是一直保持激活,发现比Hungry器官驱动更能提高找食效率。3.增加一个Chance器官,它的作用是引入随机扰动,打破青蛙有时候围着一个食物打转就是吃不着的死循环。目前进食奖励信号没用到,白白浪费了。 +另外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) +这个模型的最顶层表示眼睛的感光细胞(或任意输入输出细胞),同时也是思维区,红色表示一个长条的图形,兰色表示一个三角图形,如果这两个图形经常有规律地同时出现,就会把它们共有的节点撑大,见紫色的节点,当红色图形单独出现,就会强烈激活紫色节点,然后紫色节点的信号反向传播,就会激活三角图形,反之亦然。这就同时解释了模式识别和记忆(或者说回忆)功能的的原理。一个节点可以被多个感光细胞共享,所以它的存储能力是很强的。而且可能这个原理比较符合生物脑结构。当然,实际编程时,虚拟神经元不一定要排成正立方三角,而可能通过胡乱排放,大致上过得去就行了,也许能乱拳打死老师傅,最终要靠电脑自动随机的排放,然后用优胜劣汰来筛选。目前有个难点是这个记忆功能在思维区成像是如何有条不紊地大体上按串行进行工作的,这个问题先放一放。 ## 版权 | License [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) ## 期望 | Futures -欢迎发issue提出更好的意见或加入开发组,尤其欢迎能接触到超级计算机的同学加入,随着虚拟环境的复杂度和神经元数量增多,对电脑速度要求会越来越高。 +欢迎发issue提出建意或加入开发组,尤其欢迎能接触到超级计算机的同学加入,随着神经元数量增多,对电脑的速度要求会越来越高,很快将达到台式机性能瓶颈,只能通过拖长运行时间来换取大样本数量了。 +另外本项目正式宣布开启哭穷模式,比提交一个pull request还能帮助这个项目开发的,莫过于提交一个红包了,您的赞助将实实在在地转化成我(或其它开发者)的项目开发时间,本项目将建立赞助者名单及收支明细账。 ## 作者其它开源项目 | Other Projects - [Java持久层工具 jSqlBox](https://gitee.com/drinkjava2/jSqlBox) @@ -81,4 +91,5 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什 ## 关注我 | About Me [Github](https://github.com/drinkjava2) -[码云](https://gitee.com/drinkjava2) +[码云](https://gitee.com/drinkjava2) +微信:yong99819981(如想长期关注本项目、交流信息,或想参与具体项目开发的,请留言加入"人工生命群",如果只是想临时私聊也可以加我好友后再删掉,我不介意) \ No newline at end of file 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 e14a362..34e8ab5 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/Env.java +++ b/core/src/main/java/com/github/drinkjava2/frog/Env.java @@ -10,8 +10,10 @@ import java.util.Random; import javax.swing.JPanel; +import com.github.drinkjava2.frog.brain.group.RandomConnectGroup; import com.github.drinkjava2.frog.egg.Egg; import com.github.drinkjava2.frog.egg.EggTool; +import com.github.drinkjava2.frog.util.RandomUtils; /** * Env is the living space of frog. draw it on JPanel @@ -22,7 +24,7 @@ import com.github.drinkjava2.frog.egg.EggTool; @SuppressWarnings("serial") public class Env extends JPanel { /** Speed of test */ - public static int SHOW_SPEED = 5; // 测试速度,-1000~1000,可调, 数值越小,速度越慢 + public static int SHOW_SPEED = 20; // 测试速度,-1000~1000,可调, 数值越小,速度越慢 /** Delete eggs at beginning of each run */ public static final boolean DELETE_EGGS = true;// 每次运行是否先删除保存的蛋 @@ -40,7 +42,7 @@ public class Env extends JPanel { 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 = 300; // Frog的脑图在屏幕上的显示大小,可调 + public static final int FROG_BRAIN_DISP_WIDTH = 400; // Frog的脑图在屏幕上的显示大小,可调 /** Steps of one test round */ public static final int STEPS_PER_ROUND = 2000;// 每轮测试步数,可调 @@ -58,6 +60,10 @@ public class Env extends JPanel { private static final boolean[][] foods = new boolean[ENV_WIDTH][ENV_HEIGHT];// 食物数组定义 + private static final int TRAP_WIDTH = 350; // 陷阱高, 0~200 + + private static final int TRAP_HEIGHT = 10; // 陷阱宽, 0~200 + public List frogs = new ArrayList<>(); public List eggs; @@ -86,8 +92,17 @@ public class Env extends JPanel { return !(x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT) && Env.foods[x][y]; } - public static boolean foundFoodOrOutEdge(int x, int y) {// 如果指定点看到食物或超出边界 - return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT || Env.foods[x][y]; + public static boolean closeToEdge(Frog f) {// 青蛙靠近边界? 离死不远了 + return f.x < 20 || f.y < 20 || f.x > (Env.ENV_WIDTH - 20) || f.y > (Env.ENV_HEIGHT - 20); + } + + public static boolean inTrap(int x, int y) {// 如果指定点看到食物 + return x >= ENV_WIDTH / 2 - TRAP_WIDTH / 2 && x <= ENV_WIDTH / 2 + TRAP_WIDTH / 2 + && y >= ENV_HEIGHT / 2 - TRAP_HEIGHT / 2 && y <= ENV_HEIGHT / 2 + TRAP_HEIGHT / 2; + } + + public static boolean foundAnyThing(int x, int y) {// 如果指定点看到食物或超出边界 + return x < 0 || y < 0 || x >= ENV_WIDTH || y >= ENV_HEIGHT || Env.foods[x][y] || inTrap(x, y); } public static boolean foundAndDeleteFood(int x, int y) {// 如果x,y有食物,将其清0,返回true @@ -131,6 +146,14 @@ public class Env extends JPanel { } } + private void drawTrap(Graphics g) {// 所有走到陷阱边沿上的的青蛙都死掉 + g.fillRect(ENV_HEIGHT / 2 - TRAP_WIDTH / 2, ENV_HEIGHT / 2 - TRAP_HEIGHT / 2, TRAP_WIDTH, TRAP_HEIGHT); + g.setColor(Color.white); + g.fillRect(ENV_HEIGHT / 2 - TRAP_WIDTH / 2 + 3, ENV_HEIGHT / 2 - TRAP_HEIGHT / 2 + 3, TRAP_WIDTH - 6, + TRAP_HEIGHT - 6); + g.setColor(Color.black); + } + static final NumberFormat format100 = NumberFormat.getPercentInstance(); static { format100.setMaximumFractionDigits(2); @@ -154,10 +177,6 @@ public class Env extends JPanel { } } - public static boolean closeToEdge(Frog f) {// 青蛙靠近边界? 离死不远了 - return f.x < 20 || f.y < 20 || f.x > (Env.WIDTH - 20) || f.y > (Env.HEIGHT - 20); - } - public void run() throws InterruptedException { EggTool.loadEggs(this); // 从磁盘加载egg,或新建一批egg int round = 1; @@ -183,6 +202,13 @@ public class Env extends JPanel { if (frog.active(this)) allDead = false; + for (Frog frog : frogs) + if (frog.alive && RandomUtils.percent(0.2f)) {// 有很小的机率在青蛙活着时就创建新的器官 + RandomConnectGroup newConGrp = new RandomConnectGroup(); + newConGrp.initFrog(frog); + frog.organs.add(newConGrp); + } + if (SHOW_SPEED > 0 && i % SHOW_SPEED != 0) // 画青蛙会拖慢速度 continue; @@ -197,13 +223,16 @@ public class Env extends JPanel { frog.show(g); if (firstFrog.alive) { // 开始显示第一个Frog的动态脑图 - g.setColor(Color.red); - g.drawArc(firstFrog.x - 15, firstFrog.y - 15, 30, 30, 0, 360); - g.setColor(Color.BLACK); + if (Application.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 (DRAW_BRAIN_AFTER_STEPS > 0 && i % DRAW_BRAIN_AFTER_STEPS == 0) Application.brainPic.drawBrainPicture(firstFrog); } + drawTrap(g); drawFood(g); Graphics g2 = this.getGraphics(); g2.drawImage(buffImg, 0, 0, this); @@ -213,7 +242,7 @@ public class Env extends JPanel { EggTool.layEggs(this); t2 = System.currentTimeMillis(); Application.mainFrame.setTitle("Frog test round: " + round++ + ", 找食效率:" + foodFoundPercent() - + ", time used: " + (t2 - t1) + " ms, first frog x=" + firstFrog.x + ", y=" + firstFrog.y); + + ", time used: " + (t2 - t1) + " ms"); } 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 7fae915..f9d91f3 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/Frog.java +++ b/core/src/main/java/com/github/drinkjava2/frog/Frog.java @@ -40,8 +40,9 @@ public class Frog { public int x; // frog在Env中的x坐标 public int y; // frog在Env中的y坐标 - public long energy = 1000000; // 青蛙的能量为0则死掉 + public long energy = 100000; // 青蛙的能量为0则死掉 public boolean alive = true; // 设为false表示青蛙死掉了,将不参与计算和显示,以节省时间 + public int ateFood = 0; static Image frogImg; static { @@ -62,19 +63,14 @@ public class Frog { } public boolean active(Env v) { - if (Env.outsideEnv(x, y)) - alive = false; - energy -= 20; - if (!alive || energy < 0) {// 如果能量小于0则死 + if (!alive || energy < 0 || Env.outsideEnv(x, y) || Env.inTrap(x, y)) {// 如果能量小于0则死 energy -= 100; // 死掉的青蛙也要消耗能量,保证淘汰出局 alive = false; return false; } - - for (Organ o : organs) { // 调用每个Organ的active方法 - // energy -= o.organWasteEnergy; // 器官不是越多越好,每增加一个器官,要多消耗一点能量,通过这个方法防止器官无限增多 + energy -= 20; + for (Organ o : organs) o.active(this); - } return alive; } 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 1a1ea08..44de23f 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 @@ -26,6 +26,11 @@ import com.github.drinkjava2.frog.Frog; public class BrainPicture extends JPanel { private float brainWidth; // real brain width private int brainDispWidth; // screen display width + private Color color = Color.BLACK; + + public void setColor(Color c) { + color = c; + } public BrainPicture(int x, int y, float brainWidth, int brainDispWidth) { super(); @@ -35,7 +40,8 @@ public class BrainPicture extends JPanel { this.setBounds(x, y, brainDispWidth + 1, brainDispWidth + 1); } - public void drawZone(Graphics g, Zone z) { + public void drawZone( Zone z) {Graphics g = this.getGraphics(); + g.setColor(color); float rate = brainDispWidth / brainWidth; int x = Math.round(z.x * rate); int y = Math.round(z.y * rate); @@ -43,14 +49,16 @@ public class BrainPicture extends JPanel { g.drawRect(x - radius, y - radius, radius * 2, radius * 2); } - public void drawCircle(Graphics g, Zone z) { + public void drawCircle( Zone z) {Graphics g = this.getGraphics(); + g.setColor(color); float rate = brainDispWidth / brainWidth; int x = Math.round(z.x * rate); int y = Math.round(z.y * rate); g.drawArc(x - 5, y - 5, 10, 10, 0, 360); } - public void fillZone(Graphics g, Zone z) { + public void fillZone( Zone z) {Graphics g = this.getGraphics(); + g.setColor(color); float rate = brainDispWidth / brainWidth; int x = Math.round(z.x * rate); int y = Math.round(z.y * rate); @@ -58,7 +66,9 @@ public class BrainPicture extends JPanel { g.fillRect(x - radius, y - radius, radius * 2, radius * 2); } - public void drawLine(Graphics g, Zone z1, Zone z2) { + public void drawLine(Zone z1, Zone z2) { + Graphics g = this.getGraphics(); + g.setColor(color); float rate = brainDispWidth / brainWidth; int x1 = Math.round(z1.x * rate); int y1 = Math.round(z1.y * rate); @@ -67,7 +77,8 @@ public class BrainPicture extends JPanel { g.drawLine(x1, y1, x2, y2); } - public void drawText(Graphics g, Zone z, String text) { + public void drawText( Zone z, String text) {Graphics g = this.getGraphics(); + g.setColor(color); float rate = brainDispWidth / brainWidth; int x = Math.round(z.x * rate); int y = Math.round(z.y * rate); @@ -113,4 +124,5 @@ public class BrainPicture extends JPanel { for (Organ organ : frog.organs) organ.drawOnBrainPicture(frog, this); // each organ draw itself } + } 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 4168151..c26da8f 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 @@ -11,8 +11,8 @@ package com.github.drinkjava2.frog.brain; import java.awt.Color; -import java.awt.Graphics; +import com.github.drinkjava2.frog.Application; import com.github.drinkjava2.frog.Frog; /** @@ -27,7 +27,8 @@ public class Organ extends Zone { private static final long serialVersionUID = 1L; public String name; // 显示在脑图上的器官名称,可选 public long fat = 0; // 如果活跃多,fat值高,则保留(及变异)的可能性大,反之则很可能丢弃掉 - //public float organWasteEnergy = 0.05f; // 器官在每个测试循环中需要消耗青蛙多少能量,可以通过调节这个参数抑制器官数量无限增长 + // public float organWasteEnergy = 0.05f; // + // 器官在每个测试循环中需要消耗青蛙多少能量,可以通过调节这个参数抑制器官数量无限增长 public float organActiveEnergy = 1; // 输出器官激活需要消耗每个脑细胞多少能量 public float organOutputEnergy = 2; // 感觉器官激活会给每个脑细胞增加多少能量 public boolean initilized; // 通过这个标记判断是否需要手工给定它的参数初值 @@ -64,11 +65,12 @@ public class Organ extends Zone { /** Child class can override this method to drawing picture */ public void drawOnBrainPicture(Frog f, BrainPicture pic) {// 把自已这个器官在脑图上显示出来,子类可以重写这个方法 - Graphics g = pic.getGraphics();// border - g.setColor(Color.BLACK); // 缺省是黑色 - pic.drawZone(g, this); + if (!Application.SHOW_FIRST_FROG_BRAIN) + return; + pic.setColor(Color.BLACK); // 缺省是黑色 + pic.drawZone(this); if (this.name != null) - pic.drawText(g, this, String.valueOf(this.name)); + pic.drawText(this, String.valueOf(this.name)); } /** Only call once when frog created , Child class can override this method */ diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/group/RandomConnectGroup.java b/core/src/main/java/com/github/drinkjava2/frog/brain/group/RandomConnectGroup.java index 814fe91..ed223df 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/group/RandomConnectGroup.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/group/RandomConnectGroup.java @@ -11,7 +11,6 @@ package com.github.drinkjava2.frog.brain.group; import java.awt.Color; -import java.awt.Graphics; import com.github.drinkjava2.frog.Env; import com.github.drinkjava2.frog.Frog; @@ -49,7 +48,7 @@ public class RandomConnectGroup extends Group { public void initFrog(Frog f) { if (!initilized) { initilized = true; - //organWasteEnergy=.05f; + // organWasteEnergy=.05f; x = Env.FROG_BRAIN_WIDTH / 2; y = Env.FROG_BRAIN_WIDTH / 2; r = Env.FROG_BRAIN_WIDTH / 2; @@ -83,19 +82,18 @@ public class RandomConnectGroup extends Group { } @Override - public void drawOnBrainPicture(Frog f,BrainPicture pic) {// 把自已这个器官在脑图上显示出来 - Graphics g = pic.getGraphics();// border + public void drawOnBrainPicture(Frog f, BrainPicture pic) {// 把自已这个器官在脑图上显示出来 if (fat <= 0) - g.setColor(Color.LIGHT_GRAY); // 没用到? 灰色 + pic.setColor(Color.LIGHT_GRAY); // 没用到? 灰色 else - g.setColor(Color.red); // 用到了?红色 - pic.drawZone(g, this); - pic.drawLine(g, inputZone, outputZone); - pic.drawZone(g, inputZone); - pic.fillZone(g, outputZone); + pic.setColor(Color.red); // 用到了?红色 + pic.drawLine(inputZone, outputZone); + pic.drawZone(this); + pic.drawZone(inputZone); + pic.fillZone(outputZone); if (fat > 0) { - g.setColor(Color.red); - pic.drawCircle(g, outputZone); // 如果胖了,表示激活过了,下次下蛋少不了这一组 + pic.setColor(Color.red); + pic.drawCircle(outputZone); // 如果胖了,表示激活过了,下次下蛋少不了这一组 } } diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Active.java b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Active.java new file mode 100644 index 0000000..6724647 --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Active.java @@ -0,0 +1,47 @@ +/* + * 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.brain.organ; + +import com.github.drinkjava2.frog.Frog; +import com.github.drinkjava2.frog.brain.Cell; +import com.github.drinkjava2.frog.brain.Input; +import com.github.drinkjava2.frog.brain.Organ; + +/** + * Active always keep active + * + * 这个器官永远激活 + */ +public class Active extends Organ {//以前的实验发现添加一个始终激活的区比用Hungry来驱动更能提高找食效率 + + private static final long serialVersionUID = 1L; + + @Override + public void initFrog(Frog f) { + if (!initilized) { + initilized = true; + organOutputEnergy = 2; + } + } + + @Override + public void active(Frog f) { + for (Cell cell : f.cells) { + if (cell.energy > 0) + cell.energy--; + if (cell.energy < Cell.MAX_ENERGY_LIMIT) + for (Input input : cell.inputs) + if (input.nearby(this)) // if input zone near by happy zone + cell.energy += organOutputEnergy; + } + } + +} diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Chance.java b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Chance.java new file mode 100644 index 0000000..8527363 --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Chance.java @@ -0,0 +1,62 @@ +/* + * 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.brain.organ; + +import com.github.drinkjava2.frog.Frog; +import com.github.drinkjava2.frog.brain.Cell; +import com.github.drinkjava2.frog.brain.Input; +import com.github.drinkjava2.frog.brain.Organ; +import com.github.drinkjava2.frog.util.RandomUtils; + +/** + * Chance is a random number generator + * + * 这个器官是一个随机数发生器,用来打乱青蛙的思维,防止它围着一个食物打转出不来 + */ +public class Chance extends Organ { // 至于这个器官能不能被选中,是另外一回事,听天由命了 + private static final long serialVersionUID = 1L; + public int percent; // 初始化的机率为5% + + @Override + public void initFrog(Frog f) { + if (!initilized) { + initilized = true; + percent = 5; + } + } + + @Override + public Organ[] vary() { + if (RandomUtils.percent(5)) { + percent = percent + 1 - 2 * RandomUtils.nextInt(2); + if (percent < 1) + percent = 1; + if (percent > 98) + percent = 98; + } + return new Organ[] { this }; + } + + @Override + public void active(Frog f) { + if (RandomUtils.percent(percent)) {// 如果靠近边界,痛苦信号生成 + for (Cell cell : f.cells) { + if (cell.energy > 0) + cell.energy--; + if (cell.energy < Cell.MAX_ENERGY_LIMIT) + for (Input input : cell.inputs) + if (input.nearby(this)) // if input zone nearby this zone + cell.energy += 30; + } + } + } + +} 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/Eat.java index bbf5015..cf97cec 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/Eat.java @@ -23,8 +23,9 @@ public class Eat extends Organ {// Eat这个类将食物转化为能量,能量 @Override public void active(Frog f) { if (Env.foundAndDeleteFood(f.x, f.y)) { + f.ateFood++; // 所有的硬编码都是bug,包括这个1000 - f.energy += 1000;// 如果青蛙的坐标与食物重合,吃掉food,能量境加 + f.energy += 1000;// 如果青蛙的坐标与食物重合,吃掉food,能量境加 // 能量境加青蛙感觉不到,但是Happy区激活青蛙能感觉到,因为Happy区是一个脑器官 diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Eye.java b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Eye.java index be135b1..43c8645 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Eye.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Eye.java @@ -10,6 +10,7 @@ */ package com.github.drinkjava2.frog.brain.organ; +import com.github.drinkjava2.frog.Application; import com.github.drinkjava2.frog.Env; import com.github.drinkjava2.frog.Frog; import com.github.drinkjava2.frog.brain.BrainPicture; @@ -17,27 +18,31 @@ import com.github.drinkjava2.frog.brain.Cell; import com.github.drinkjava2.frog.brain.Input; import com.github.drinkjava2.frog.brain.Organ; import com.github.drinkjava2.frog.brain.Zone; +import com.github.drinkjava2.frog.util.RandomUtils; /** - * Eye is an organ can see environment, and active brain cells which inputs are - * located in eye range + * Eye can only see 4 direction * * @author Yong Zhu * @since 1.0 */ -public class Eye extends Organ {// Eye类需要重构,目前只有4个感光细胞,不够,Eye要改成Group的子类,Eye只负责感光细胞的排列,感光细胞自已负责变异 +public class Eye extends Organ {// 这个Eye是老版的眼睛,只能看到四个方向,但它的调节距离会自动随机调整到一个最佳值,这就是随机试错算法的一个应用 private static final long serialVersionUID = 1L; + public int seeDistance; // 眼睛能看到的距离 @Override public void initFrog(Frog f) { // 仅在Frog生成时这个方法会调用一次 if (!initilized) { initilized = true; organOutputEnergy = 30; + seeDistance = 8; } } @Override public void drawOnBrainPicture(Frog f, BrainPicture pic) {// 把自已这个器官在脑图上显示出来 + if (!Application.SHOW_FIRST_FROG_BRAIN) + return; super.drawOnBrainPicture(f, pic); float qRadius = r / 4; float q3Radius = (float) (r * .75); @@ -45,14 +50,21 @@ public class Eye extends Organ {// Eye类需要重构,目前只有4个感光 Zone seeDown = new Zone(x, y - q3Radius, qRadius); Zone seeLeft = new Zone(x - q3Radius, y, qRadius); Zone seeRight = new Zone(x + q3Radius, y, qRadius); - pic.drawZone(pic.getGraphics(), seeUp); - pic.drawZone(pic.getGraphics(), seeDown); - pic.drawZone(pic.getGraphics(), seeLeft); - pic.drawZone(pic.getGraphics(), seeRight); + pic.drawZone(seeUp); + pic.drawZone(seeDown); + pic.drawZone(seeLeft); + pic.drawZone(seeRight); } @Override public Organ[] vary() { + if (RandomUtils.percent(5)) { + seeDistance = seeDistance + 1 - 2 * RandomUtils.nextInt(2); + if (seeDistance < 1) + seeDistance = 1; + if (seeDistance > 50) + seeDistance = 50; + } return new Organ[] { this }; } @@ -72,29 +84,28 @@ public class Eye extends Organ {// Eye类需要重构,目前只有4个感光 boolean foodAtLeft = false; boolean foodAtRight = false; - int seeDist = 10; - for (int i = 1; i < seeDist; i++) + for (int i = 1; i < seeDistance; i++) if (Env.foundFood(f.x, f.y + i)) { seeFood = true; foodAtUp = true; break; } - for (int i = 1; i < seeDist; i++) + for (int i = 1; i < seeDistance; i++) if (Env.foundFood(f.x, f.y - i)) { seeFood = true; foodAtDown = true; break; } - for (int i = 1; i < seeDist; i++) + for (int i = 1; i < seeDistance; i++) if (Env.foundFood(f.x - i, f.y)) { seeFood = true; foodAtLeft = true; break; } - for (int i = 1; i < seeDist; i++) + for (int i = 1; i < seeDistance; i++) if (Env.foundFood(f.x + i, f.y)) { seeFood = true; foodAtRight = true; diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Happy.java b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Happy.java index ded35c5..ad52bae 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Happy.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Happy.java @@ -10,7 +10,11 @@ */ package com.github.drinkjava2.frog.brain.organ; +import java.awt.Color; + +import com.github.drinkjava2.frog.Application; import com.github.drinkjava2.frog.Frog; +import com.github.drinkjava2.frog.brain.BrainPicture; import com.github.drinkjava2.frog.brain.Cell; import com.github.drinkjava2.frog.brain.Input; import com.github.drinkjava2.frog.brain.Organ; @@ -22,6 +26,23 @@ public class Happy extends Organ { // Happy器官是进食后的产生的快感 private static final long serialVersionUID = 1L; public float happy = 0; // happy初始值为0, 进食后将由eat器官增加happy值 + @Override + public void drawOnBrainPicture(Frog f, BrainPicture pic) {// 把自已这个器官在脑图上显示出来 + if (!Application.SHOW_FIRST_FROG_BRAIN) + return; + if (happy > 0) { + pic.setColor(Color.red); + pic.fillZone(this); + } else { + pic.setColor(Color.white); + pic.fillZone(this); + pic.setColor(Color.BLACK); + pic.drawZone(this); + } + if (this.name != null) + pic.drawText(this, String.valueOf(this.name)); + } + @Override public void active(Frog f) { if (happy > 0) { diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Hungry.java b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Hungry.java index 3b1477e..ee51b61 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Hungry.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Hungry.java @@ -10,7 +10,11 @@ */ package com.github.drinkjava2.frog.brain.organ; +import java.awt.Color; + +import com.github.drinkjava2.frog.Application; import com.github.drinkjava2.frog.Frog; +import com.github.drinkjava2.frog.brain.BrainPicture; import com.github.drinkjava2.frog.brain.Cell; import com.github.drinkjava2.frog.brain.Input; import com.github.drinkjava2.frog.brain.Organ; @@ -25,11 +29,27 @@ public class Hungry extends Organ { public void initFrog(Frog f) { // 仅在Frog生成时这个方法会调用一次,缺省啥也不干,通常用于Organ类的初始化 if (!initilized) { initilized = true; - //organWasteEnergy = 20f; + // organWasteEnergy = 20f; organOutputEnergy = 2; } } + @Override + public void drawOnBrainPicture(Frog f, BrainPicture pic) {// 把自已这个器官在脑图上显示出来 + if (!Application.SHOW_FIRST_FROG_BRAIN) + return; + if (f.energy < 10000) { + pic.fillZone(this); + } else { + pic.setColor(Color.white); + pic.fillZone(this); + pic.setColor(Color.BLACK); + pic.drawZone(this); + } + if (this.name != null) + pic.drawText(this, String.valueOf(this.name)); + } + @Override public Organ[] vary() { // if (RandomUtils.percent(20)) // 有20机率权重变化 diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/NewEye.java b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/NewEye.java index 2d7d40c..d9459ed 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/NewEye.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/NewEye.java @@ -10,6 +10,7 @@ */ package com.github.drinkjava2.frog.brain.organ; +import com.github.drinkjava2.frog.Application; import com.github.drinkjava2.frog.Env; import com.github.drinkjava2.frog.Frog; import com.github.drinkjava2.frog.brain.BrainPicture; @@ -26,9 +27,9 @@ import com.github.drinkjava2.frog.util.RandomUtils; * @author Yong Zhu * @since 1.0 */ -public class NewEye extends Organ {// 这个眼睛有nxn个感光细胞,可以看到青蛙周围nxn网络内有没有食物 +public class NewEye extends Organ {// 这个新版的眼睛有nxn个感光细胞,可以看到青蛙周围nxn网络内有没有食物 private static final long serialVersionUID = 1L; - public int n = 3; // 眼睛有n x n个感光细胞,缺省是3x3点阵,会随机自动变异(加1或减1,最小是1) + public int n = 3; // 眼睛有n x n个感光细胞, 用随机试错算法自动变异(加1或减1,最小是3x3) @Override public void initFrog(Frog f) { // 仅在Frog生成时这个方法会调用一次,缺省啥也不干,通常用于Organ类的初始化 @@ -40,6 +41,8 @@ public class NewEye extends Organ {// 这个眼睛有nxn个感光细胞,可以 @Override public void drawOnBrainPicture(Frog f, BrainPicture pic) {// 把自已这个器官在脑图上显示出来 + if (!Application.SHOW_FIRST_FROG_BRAIN) + return; super.drawOnBrainPicture(f, pic); float r2 = r / n; // r2是每个感光细胞的半径 float x0 = x - r; @@ -47,10 +50,10 @@ public class NewEye extends Organ {// 这个眼睛有nxn个感光细胞,可以 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { Zone cell = new Zone(x0 + i * 2 * r2 + r2, y0 + j * 2 * r2 + r2, r2); - if (Env.foundFoodOrOutEdge(f.x - n / 2 + i, f.y - n / 2 + j)) - pic.fillZone(pic.getGraphics(), cell); + if (Env.foundAnyThing(f.x - n / 2 + i, f.y - n / 2 + j)) + pic.fillZone(cell); else - pic.drawZone(pic.getGraphics(), cell); + pic.drawZone(cell); } } } @@ -74,7 +77,7 @@ public class NewEye extends Organ {// 这个眼睛有nxn个感光细胞,可以 float y0 = y - r; // x0,y0是眼睛的左上角 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { - if (Env.foundFoodOrOutEdge(f.x - n / 2 + i, f.y - n / 2 + j)) { + if (Env.foundAnyThing(f.x - n / 2 + i, f.y - n / 2 + j)) { Zone eyeCell = new Zone(x0 + i * 2 * r2 + r2, y0 + j * 2 * r2 + r2, r2); for (Cell cell : f.cells) for (Input input : cell.inputs) diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Pain.java b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Pain.java index c799f1b..bac4b18 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Pain.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Pain.java @@ -10,14 +10,18 @@ */ package com.github.drinkjava2.frog.brain.organ; +import java.awt.Color; + +import com.github.drinkjava2.frog.Application; import com.github.drinkjava2.frog.Env; import com.github.drinkjava2.frog.Frog; +import com.github.drinkjava2.frog.brain.BrainPicture; import com.github.drinkjava2.frog.brain.Cell; import com.github.drinkjava2.frog.brain.Input; import com.github.drinkjava2.frog.brain.Organ; /** - * Pain zone active after some bad thingg happen like close to edge, hurt... + * Pain zone active after some bad thing happen like close to edge, hurt... * * 痛是一种惩罚,表示青蛙做错了什么,但是又不至严重到判其死亡的地步 */ @@ -29,16 +33,25 @@ public class Pain extends Organ { // Pain器官目前激活的条件是离边境 public void initFrog(Frog f) { if (!initilized) { initilized = true; - organOutputEnergy = 2; + organOutputEnergy = 5; } } - // @Override - // public Organ[] vary() { - // if (RandomUtils.percent(20)) // 有20机率权重变化 - // organOutputEnergy = RandomUtils.vary(organOutputEnergy); - // return new Organ[] { this }; - // } + @Override + public void drawOnBrainPicture(Frog f, BrainPicture pic) {// 把自已这个器官在脑图上显示出来 + if (!Application.SHOW_FIRST_FROG_BRAIN) + return; + if (Env.closeToEdge(f)) { + pic.fillZone(this); + } else { + pic.setColor(Color.white); + pic.fillZone(this); + pic.setColor(Color.BLACK); + pic.drawZone(this); + } + if (this.name != null) + pic.drawText(this, String.valueOf(this.name)); + } @Override public void active(Frog f) { @@ -48,7 +61,7 @@ public class Pain extends Organ { // Pain器官目前激活的条件是离边境 cell.energy--; if (cell.energy < Cell.MAX_ENERGY_LIMIT) for (Input input : cell.inputs) - if (input.nearby(this)) // if input zone near by happy zone + if (input.nearby(this)) // if input zone nearby this zone cell.energy += organOutputEnergy; } } diff --git a/core/src/main/java/com/github/drinkjava2/frog/egg/CellGroup.java b/core/src/main/java/com/github/drinkjava2/frog/egg/CellGroup.java deleted file mode 100644 index 6768e40..0000000 --- a/core/src/main/java/com/github/drinkjava2/frog/egg/CellGroup.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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; - -public class CellGroup { -} 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 37832a8..ac5128c 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 @@ -17,7 +17,8 @@ import java.util.List; import com.github.drinkjava2.frog.Frog; import com.github.drinkjava2.frog.brain.Organ; import com.github.drinkjava2.frog.brain.group.Group; -import com.github.drinkjava2.frog.brain.group.RandomConnectGroup; +import com.github.drinkjava2.frog.brain.organ.Active; +import com.github.drinkjava2.frog.brain.organ.Chance; import com.github.drinkjava2.frog.brain.organ.Eat; import com.github.drinkjava2.frog.brain.organ.Eye; import com.github.drinkjava2.frog.brain.organ.Happy; @@ -41,9 +42,9 @@ import com.github.drinkjava2.frog.util.RandomUtils; * @since 1.0 */ public class Egg implements Serializable { - // 但为了缩短时间,这个程序随机生成的联结将只落在固定的器官上而不是漫天撒网(见4.12提交),这是程序的优化,实现的逻辑和随机漫天撒网定是相同的。 - // 但是这个优化带来的问题是这个硬编码逻辑不能拷贝到将来的分形结构里去,而且下面这个 FIXED_ORGAN_QTY必须每次手工设定 - public static int FIXED_ORGAN_QTY = 9; + // 为了缩短时间,这个程序随机生成的联结将只落在固定的器官上而不是漫天撒网(见4.12提交),这是程序的优化,实现的逻辑和随机漫天撒网定是相同的。 + // 但是这个优化带来的问题是这是一个硬编码逻辑,不利于器官的优胜劣汰, 而且下面这个 FIXED_ORGAN_QTY必须每次手工设定,以后需要重构这块的代码 + public static int FIXED_ORGAN_QTY = 11; private static final long serialVersionUID = 1L; @@ -53,20 +54,21 @@ public class Egg implements Serializable { public Egg() {// 无中生有,创建一个蛋,先有蛋,后有蛙 organs.add(new Happy().setXYRN(600, 700, 60, "Happy")); // Happy必须第一个加入 - organs.add(new Hungry().setXYRN(300, 100, 100, "Hungry")); + organs.add(new Hungry().setXYRN(300, 100, 60, "Hungry")); organs.add(new MoveUp().setXYRN(800, 100, 60, "Up")); organs.add(new MoveDown().setXYRN(800, 400, 60, "Down")); organs.add(new MoveLeft().setXYRN(700, 250, 60, "Left")); organs.add(new MoveRight().setXYRN(900, 250, 60, "Right")); organs.add(new Eye().setXYRN(100, 300, 100, "Eye")); organs.add(new NewEye().setXYRN(200, 700, 200, "NewEye")); - organs.add(new Pain().setXYRN(800, 700, 60, "Pain")); // 痛苦在靠近边界时触发 + organs.add(new Pain().setXYRN(800, 700, 60, "Pain")); // 痛苦在靠近边界时触发 + organs.add(new Active().setXYRN(500, 100, 60, "Active")); // 永远激活 + organs.add(new Chance().setXYRN(650, 100, 60, "Chance")); // 永远激活 - // Pain对提高找食效率没有帮助,将来要和记忆功能一起加入,我们的目标:不出界,吃光所有食物 + // 以上为11个, 就是FIXED_ORGAN_QTY值 organs.add(new Eat().setXYRN(0, 0, 0, "Eat")); // EAT不是感觉或输出器官,没有位置和大小 - addRandomConnectionGroups(); } /** Create egg from frog */ @@ -74,12 +76,6 @@ public class Egg implements Serializable { for (Organ organ : frog.organs) for (Organ newOrgan : organ.vary()) organs.add(newOrgan); - addRandomConnectionGroups(); - } - - private void addRandomConnectionGroups() {// 每次下蛋时新建5个RandomConnectGroup实例 - for (int i = 0; i < 5; i++) - organs.add(new RandomConnectGroup()); } /** diff --git a/core/src/main/java/com/github/drinkjava2/frog/egg/EggTool.java b/core/src/main/java/com/github/drinkjava2/frog/egg/EggTool.java index 7686c0d..4dffcdd 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/egg/EggTool.java +++ b/core/src/main/java/com/github/drinkjava2/frog/egg/EggTool.java @@ -24,6 +24,8 @@ import com.github.drinkjava2.frog.Application; import com.github.drinkjava2.frog.Env; import com.github.drinkjava2.frog.Frog; import com.github.drinkjava2.frog.brain.Organ; +import com.github.drinkjava2.frog.brain.organ.Chance; +import com.github.drinkjava2.frog.brain.organ.Eye; import com.github.drinkjava2.frog.util.FrogFileUtils; /** @@ -53,14 +55,14 @@ public class EggTool { + org.organActiveEnergy + ", outputEnergy=" + org.organOutputEnergy); } - System.out.print("First frog has " + first.organs.size() + " organs, energy=" + first.energy); - System.out.print(", Last frog has " + last.organs.size() + " organs, energy=" + last.energy); + System.out.println("1st frog has " + first.organs.size() + " organs, energy=" + first.energy + ", seeDist=" + + ((Eye) first.organs.get(6)).seeDistance + ", chance=" + ((Chance) first.organs.get(10)).percent); + System.out.println("Last frog has " + last.organs.size() + " organs, energy=" + last.energy); try { List newEggs = new ArrayList<>(); for (int i = 0; i < Env.EGG_QTY; i++) newEggs.add(new Egg(env.frogs.get(i))); - System.out.print(", organs =" + newEggs.get(0).organs.size() + ", "); FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "eggs.ser"); ObjectOutputStream so = new ObjectOutputStream(fo); @@ -68,8 +70,8 @@ public class EggTool { so.close(); env.eggs = newEggs; - System.out.println( - ", Saved " + env.eggs.size() + " eggs to file '" + Application.CLASSPATH + "eggs.ser" + "'"); + System.out + .println("Saved " + env.eggs.size() + " eggs to file '" + Application.CLASSPATH + "eggs.ser" + "'"); } catch (IOException e) { System.out.println(e); } @@ -88,6 +90,24 @@ public class EggTool { }); } + // private static void sortFrogsOrderByEnergyDesc(Env env) {// + // 按吃到食物数量、剩余能量多少给青蛙排序 + // Collections.sort(env.frogs, new Comparator() { + // public int compare(Frog a, Frog b) { + // if (a.ateFood > b.ateFood) + // return -1; + // else if (a.ateFood == b.ateFood) { + // // if (a.energy > b.energy) + // // return -1; + // // if (a.energy < b.energy) + // // return 1; + // return 0; + // } else + // return 1; + // } + // }); + // } + public static void deleteEggs() { System.out.println("Delete exist egg file: '" + Application.CLASSPATH + "eggs.ser'"); FrogFileUtils.deleteFile(Application.CLASSPATH + "eggs.ser"); diff --git a/core/src/main/java/com/github/drinkjava2/frog/env/CellGroup.java b/core/src/main/java/com/github/drinkjava2/frog/env/CellGroup.java deleted file mode 100644 index 8f253df..0000000 --- a/core/src/main/java/com/github/drinkjava2/frog/env/CellGroup.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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.env; - -public class CellGroup { -} 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 3ca8449..60ecdd5 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 @@ -47,8 +47,8 @@ public class RandomUtils { } - public static boolean percent(int percent) { - return rand.nextInt(100) < percent; + public static boolean percent(float percent) { + return rand.nextFloat() * 100 < percent; } diff --git a/result4.gif b/result4.gif new file mode 100644 index 0000000..b0817ce Binary files /dev/null and b/result4.gif differ diff --git a/开发思路.md b/开发思路.md index 759999a..190482c 100644 --- a/开发思路.md +++ b/开发思路.md @@ -3,6 +3,7 @@ =======以下是杂七八拉的一些想法,想到什么就记下来========== +* 到达台式机性能瓶颈后,如果找不到快的超级计算机,只能通过存盘多个文件,按文件分组,人为地拉长测试时间来换取大样本数量,也就是说,同一个环境里的Frog数量可以很少,这样对于单个测试来说速度可以接受,也不会撑爆内存。当然了,开发体验就差了。 * 判断Frog胜出,可以不用能量,而用吃了多少个食物来判断,一个测试周期吃的多的胜出,用能量多少是不公平的,因为吃的多的,有可能因为脑细胞或器官多,消耗的能量也多,最后剩下的能量反而不如那些不运动或死掉的Frog。 * 将来训练者和生物体可以对话,表现形式为弹出一个24x24点阵图形,每次只能弹出一种图形。训练者由人或电脑操纵,生物体则可以任意自主行动和说话(输出任意图形),训练者和生物体具有相似权限的输出(开始阶段输出图形仅限于100个汉字和数字),行动仅限于说话、移动、打击、保存食物、拿出食物。 * 训练者在生物体模拟正确或行为(输出文字或图形,行走,吃,睡等)正确后,给予食物奖励。训练者在生物体说话或行为错误时,不给予奖励或给予打击惩罚。 @@ -28,7 +29,215 @@ =======以下是码云上评论的备份,抄在下面,防止万一码云挂掉以前的评论丢失========== +drinkjava2owner3 days ago + +看来JQ暂时是搞不完了。下面先清理一下这个项目,有些垃圾类要删掉。网格形式的模式识别先不急,先把奖励信号利用上,目前奖励信号被白白浪费了。要改成每次吃到食物之后,近期活跃过的所有神经元的fat值增加,就好象训兽师每次在海豹完成一个动作后,就给它条鱼吃一样,吃完鱼之后,海豹就会把刚才的动作记得更牢。另外相应地,动态生成随机连接(目前是RandomConnectionGroup),也改成每隔几步step之后就动态生成一些,而不是等青蛙死掉后再由它的后代去生成,由后代生成新的随机联接虽然可以体现优胜劣汰,但是太滞后了,根本无法利用上宝贵的奖励信号。创造性思维就是将不相干的神经元联系起来,在这里具体就是随机产生新的联接,然后由食物奖励来强化(保留)。 Copy URL +5177524_longfer +LongFer3 days ago + +我觉得项目很好,请问大佬怎么加群呢 +Copy URL +920504_drinkjava2 +drinkjava2owner3 days ago + +如果想长期关注这个研发方向,请加我微信yong99819981并留言人工生命群,谢谢! +Copy URL +someome +someome6 days ago + +大神可以了解一下深度强化学习和OpenAI gym,感觉模拟大脑神经元和生物进化的思路是一条歪路。生命的本质无非就是复制和变异,实现是很简单的。最重要的是人类的意识和思维,这也是人工智能这个学科的最终目的。深度强化学习是目前最有可能取得突破的方向领域,大神可以关注一下这方面的信息。“意识从来就不存在,意识只是一种现象”我不同意这个观点。我的观点是“意识是一种状态,对过去和现在的记忆的自我感觉的一种状态”。其实几百年前笛卡尔就已经解决了意识是什么的问题。是的,就是笛卡尔的哲学命题“我思故我在”。 +Copy URL +920504_drinkjava2 +drinkjava2owner6 days ago + +模拟大脑的进化是一种手段,指望让电脑来自动生成复杂的脑结构,这个有投机成份,能不能成功有点靠运气,所以这个项目也不排除人为参与设计,允许吸收其它算法如深度强化学习(这个我是弱项,因为我是外行,等我有时间一定学习,或其它人也可以参与改进这个项目),编程者也需要较高的编程技巧,一条路走不通再试另一条。 至于是不是歪路并不重要,只要能逮着耗子就是好猫。 +关于意识是什么的问题,这个项目的看法是认为讨论意识本质之类的话题是无意义的,纯属浪费时间,"杯子"、“自行车”、"意识"、"智能"、“勇气”这些都不是存在的实物,只是人类语言中对一类现象的归纳而已。这个项目只从程序能实现的功能来判断它是否足够"智能",足够有用,直到能够实现解决一些现实问题,例如模拟动物实现一些复杂的工作如模拟一只狗来实现垃圾分类,当然,如这个项目开头所说,"有用"只是暂时的,最终它的目标是要造出有自我意识表现的通用人工智能。 +Copy URL +920504_drinkjava2 +drinkjava2owner3 days ago + +这个OpenAI项目,我查了一下,它的目标和这个项目的目标是完全一致的,就是造出一个通用的人工智能。看来国外已经认识到,单纯通过算法来解决开放性的复杂问题(如自动驾驶、翻译等),是一条走不通的路,最终人工智能的解决方案是"通用"智能,一个模型能解决所有问题,也就是说能造出最终智力表现超出人类的机器人。关于如何防止人工智能反制人类,相应地他们的看法就是“更多人拥有同样的能力来达到相互制衡”,这个观点也与我的观点有点接近,只不过没我这么明确彻底地倒向"投降派",人工智能研发不能被阻止,但可以通过人工智能立法保护人工智能人权、防止人类伤害机器人等方式防止人类被灭绝。 +另外OpenAI最终实现途径和Frog在算法逻辑上可能是等同的,都需要电脑来生成脑结构,而不是人来搭建。不同的是Frog给出了具体的研发路线和考核目标,每一步人工生命的进展,都是可以考核评价的,从低等生命的行为一直模拟到高等生命的行为表现就行了。 +Copy URL +heychina +heychina14 days ago + +伟大的目标,大佬,我想加入开发团队,贡献自己的一点力量. +Copy URL +920504_drinkjava2 +drinkjava2owner13 days ago + +谢谢你及最近好多同学的点赞,看来大家都对人工生命这个研发方向很感兴趣。但最近关注这个项目的请耐心等待一段时间,不光因为我最近没时间,而是因为这个项目架构方面会有极大调整(添加模式识别和记忆功能,见评论),这可能需要较长的编码时间,我一般会在有青蛙的行为有明显改进时才提交到码云,防止同学们down下来却看不出什么名堂,一头雾水。当然了,如果有同学自认为思路和编码能力较强的,也可以试着加入模式识别和记忆功能,争取能走在我的前面。目前的目标有两个:1。青蛙不能出界 2。青蛙要吃光所有食物。第一个目标青蛙必须看到并识别出边界的存在,第二个目标要求青蛙的眼睛能进化到看到屏幕上的任一点。 +Copy URL +筑梦前行 +筑梦前行16 days ago + +目标远大,我辈学习之榜样! +Copy URL +小仔 +小仔18 days ago + +太棒了,持续关注大佬 +Copy URL + +drinkjava2owner24 days ago + +这个项目消停两天,这一两周要集中精力完成jSqlBox的分布式事务。 +Copy URL +920504_drinkjava2 +drinkjava2owner25 days ago + +手机收到了,如果大家只是想临时私聊的可以加我微信yong99819981,聊完删掉好友即可。如果有想加入开发团队或长期关注这个项目的,可以留言加入"人工生命群"。 +Copy URL +妖孽 +妖孽26 days ago + +持续关注中 +Copy URL +920504_drinkjava2 +drinkjava2owner26 days ago + +谢谢关注!但这个项目快不起来,一方面作者本人是个外行,另一方面它可能是走在了无人区(至少从这个外行的眼里看来),“外行”+“无人区”注定了它举步为艰,随时卡壳。 这个项目唯一的亮点可能就是作者本人坚信这条路能一直走到头的信心了。现在的神经网络研究要么信心不足,不觉得从模拟蚂蚁脑、青蛙脑可以一直走到模拟人脑。要么就是信心足过了头,连蚂蚁脑都没搞明白,就要上高大上的人脑模拟项目(欧洲人脑项目)。 +Copy URL +920504_drinkjava2 +drinkjava2owner28 days ago + +随机联结只是演示了"会自主运动觅食“的微生物可以简单地通过随机进化中产生,但不能解释模式识别和记忆功能的产生。下面要开始另一种脑细胞分布模型的尝试了,可能要完全推翻目前随机联结这个架构,而且似乎更符合实际生物的脑结构,这就是网状结构: +打比方说,目前如果一个眼睛有100个象素点,分别对应A,B,C,D....等感光细胞,另外有上、下、左、右四个运动细胞。可以假设每个感光细胞收到光信号后,会象一个波源发生器一样向四周的脑细胞传递信号,越远的细胞收到的信号越弱,如果两个或多个感光细胞的信号同时到达远处的一个细胞,则形成波峰,如果多个波峰同时激活,这几个波峰从波的角度来说,可以看成是独立的信号源,于是又会在更远处形成波峰,于是不同形状的图形就会被大脑归类于一个个特点的波峰激活区,这就是模式识别的基本原理了。 一个波峰形成后会以反指数曲线形式消退,在此期间如果有个别波到达,会很容易再次激活,即使只是图像(或其它内、外信号)的局部信号,也可能使这个波峰激活到很高的值,这就是记忆的基本原理了。如果某个感觉细胞的输入转辗到达了运动细胞,可以说是一种天生的本能反射,如果这个本能反射链被加强或削弱,例如被脑内进食奖励区兴奋(多巴胺产生会加强最近的触突联接)、痛觉信号(可能产生强烈负信号),或是被脑内其它波峰的信号覆盖,那么这种后天形成的信号-运动反应,可以称为后天的条件反射。 对于电脑模拟来说,只需要构造一个模拟波形传播的网装结构即可,一个节点可以接受多个方向的波,也可以向多个方向发送波,这就要求它具备多个输入、输出触突(也可以是电脑虚拟触突),以及对应的奖惩调节机制即可,激活多的脑区,在下次遗传时把网格变异成更密一点就可以了,以体现用进废退。这就是下面要进行的工作的大概思路,这是一个整体化的解决方案。 +Copy URL +920504_drinkjava2 +drinkjava2owner27 days ago + +与波的发散形成多个波峰相反,多个波峰激活会形成脑内的思维区成像(多个波峰激活会在原波源处成像,还有一种可能是在反侧镜像处成像),脑内的思维区就是人脑的CPU快速缓存区,它永远不停地被周围的波干扰,生成各种图像(或声音等),思维区内容永不停止地在变幻,思维成像区驱动着其它脑区,反过来,其它脑区又在思维成像区形成新的图像,这就是大脑工作的流程,在做梦时这个流程更清晰,因为没有了外部信号输入,思维成像区永远不会是空白,所以大脑永远不会当机。 +波峰的激活会在思维区成像,但是这个成像是模糊的,这就是为什么大脑中永远不能想象出一幅高清画面的根源(脑部变异者除外)。 +现在的问题是,思维区是位于感光细胞区和大脑存贮细胞区之间的,还是之后? 换句话说,视觉光信号是先到达思维成像区神经元还是先到达波峰区神经元? 从波的成像象度来说,个人倾向于前者(因为镜像这个条件很难满足,它要求波峰位于同一个平面上),也就是说外部信号必须先经过思维成像区之后,再传递给波峰(大脑的存贮细胞),在回忆时,波峰的信号必须原路逆向返回到思维成像区。这就需要与视觉、听觉信号相关的脑内神经元的信号必须是双向传播的。但我google了一下,生物神经元只能单向传播信号,如果是这样,就只能通过两个相反方向的神经元来模拟一个双向传导功能,这是个疑问。先把这个问题放下,对于这个电脑模拟项目来说,先考虑直接上双向,因为目标是找食,并不需要全盘照搬生物底层机制。 +Copy URL +920504_drinkjava2 +drinkjava2owner26 days ago + +当然了,这里的“波”只是个比喻,实际编程时是不可能也没必要模拟波在360度所有角度上的传播的,只能用n(可能少到1、2条)条放射线分布在一个小于180度的扇面上来近似代表波的传播路径,甚至可以用"横5格,竖2格"之类的网格比率来简化射线斜率的传播方向,两个射线的交点就是一个脑细胞存贮单元。而且可以用信号向右(水平方向的分量)传播表示波的扩张,向左表示波峰到原点的逆向信号传播。这适用于单维信号的输入和存贮,二维的(图像)输入还要再想想。 +另外,神经元如果处在波的传播链中间,应该也具有波的叠加特性,即使一个神经元已被激活,当另一个信号到达时,它也应当具备将这个信号中继给下一级神经元的能力。 所以处于中点的神经元其饱和值很高(通过用进废退原则进化得来),处于信号末端的神经元饱和值低。 +Copy URL +920504_drinkjava2 +drinkjava2owner26 days ago + +痛苦、愉悦感觉细胞本身也可以视作一个波源,简单说,可以视为图像的一个象素点,和视觉信号发生干涉,在大脑里形成波峰。于是每当看到特定的钉子、刀、针等图像时,这些波峰区被激活,信号再逆向传回到信号源后会激活痛苦成像区(或者说痛苦感受区)。 痛苦区激活可能会回忆到缩手区(缩手区是一个运动细胞,但同时也是一个波输出信号发生源),当这个过程持续足够长或这个回忆检索收集到的信号足够强,就有可能超过缩手区运动细胞的执行阀值,真的作出缩手运动。类似地,看到蛋糕图像会激活愉悦区,愉悦区可能会回忆到伸手区,当蛋糕足够大或在我面前晃动时间足够长时,蛋糕就被抢走了。蛋糕吃到嘴后,大脑会分泌多巴胺奖励所有最近活跃过的脑细胞,好让下次的抢蛋糕反射链发生得更流畅一点。 +Copy URL +920504_drinkjava2 +drinkjava2owner29 days ago + +yeah!满300赞了,谢谢最后一位点赞的同学。 +Copy URL +萧萧雨声 +萧萧雨声29 days ago + +非常有创意的项目,代码中使用的随机数是普通的伪随机数,如果有必要可以考虑真随机数,这里有个网站可以获取真随机数https://www.random.org +Copy URL + +Copy URL +920504_drinkjava2 +drinkjava2owner29 days ago + +谢谢提醒,不过神经网络应该不在乎伪随机数还是真随机数的,因为从它的需求来看,伪还是真随机数起到的作用是一样的,因为它不象密码一样需要防着人家去破解,只是需要一个均匀分布的随机概率而已。 +Copy URL +920504_drinkjava2 +drinkjava2owner30 days ago + +加了个新的眼睛,用nxn点阵形式代表,脑图也可以动态显示了。蝼蚁尚且贪生,青蛙到了边界就不走了,往生咒加上了。 +Copy URL +920504_drinkjava2 +drinkjava2ownera month ago + +找食效率太低,又改回到用连接数量代替权值这个逻辑,看起来舒服多了。权值这种人为设计的算法居然比不过随机试错,失败。 +Copy URL +920504_drinkjava2 +drinkjava2ownera month ago + +猜测:大脑的结构可能是一个分形结构,在宏观上具备的记忆、信号输入和模式识别、条件反射等功能和结构,在微观上也具有相似的结构,也就是说只需要设计出一套脑细胞排布算法就可以了,每一个低层的脑结构就是高一层脑结构的分形式复制,在活跃度高的节点上,分形式遗传变异复制发生的概率高(用进废退),最终形成一个复杂的树状脑结构。这个猜测的意义在于如果能够完成基本的青蛙脑的设计,完成基本的找食、分辨天敌(需要增加感光细胞)等功能,更复杂的如人脑就不用再去单独设计了,利用计算机的虚拟环境训练就可以自动让这个青蛙脑进化成更复杂的人脑了。算法是一样的,只是脑的总细胞数量和分形层数不一样而已。在蛋(Egg)里,只保存着一套算法,和一棵分形树的每个节点。打个比方来说,用最好的条件和环境来训练一群狗、一群猴子、一群恐龙,最终几十万年后它们都会进化成和人一样聪明,因为这些动物的受精卵里保存的脑的进化方案是一样的。 +另外现在这个版本的找食效率不如4.12的提交,这可能是因为权值虽然可以简化模型,但悬殊巨大的权值可能抑制了新连接的建立,正在调试将4.12的逻辑照抄到RandomConnectionGroup中去,增加细胞数量,弱化权值自动调整范围。等到引入记忆器官和利用上 Happy器官的奖励信号之后再说。目前这个青蛙的任务很明确:1.遇到边界要掉头,而不是出界或顺着边界往下溜 2.发现并吃光Env中的所有食物。 第一个任务必须引入记忆功能,第二个任务必须进化出感光细胞非常多的眼睛,因为如果测试环境中只有一个食物和一个青蛙时,如果青蛙感光细胞很少就会根本看不到这个食物而饿死。 +Copy URL +920504_drinkjava2 +drinkjava2ownera month ago + +当然,如果食物太多,眼睛的感光细胞可能不会进化出很多,例如矿井里的有一种老鼠眼睛基本看不到,不是因为大自然觉得即然用不到眼睛,就让它退化吧,而是因为有了眼睛的老鼠需要消耗更多的食物,在生存竞争中被淘汰。所以环境决定了生物的形态,环境决定了脑的进化方向。 +Copy URL +1320504_fzwise +码瘾少年a month ago + +nice job,这个想法我之前就想过,随机才是王道,再复杂的逻辑写出来的人工智能只是人思维的规律总结,算不上智能 +Copy URL +xinyi +xinyia month ago + +求加微信xx17610115570 +Copy URL +920504_drinkjava2 +drinkjava2ownera month ago + +报歉手机坏了,正在等网购的手机到,等拿到手再加你,顺便也会把微信号挂在"关注我"栏里面。这几天可以在这里发评论或私信,我每天都会登录码云看看的。 +Copy URL +天崖 +天崖a month ago + +忍不住推荐一个视频:https://www.bilibili.com/video/av54874176/。或者说是推荐这个up主。他的系列视频讲了一些神经网络和人工智能学习机制的科普,我觉得讲得太棒了。而且里面关于“意识是客观现象”的观点与楼主不谋而合。 +Copy URL +920504_drinkjava2 +drinkjava2ownera month ago + +受教了,才知道草履虫的纤毛能感觉到外界输入,up主的生物知识很渊博。我是根据任务来假设生物必须具备某种信号处理能力,而生物学家可以直接从内因来解释生物为什么能实现这个任务。 +Copy URL + +drinkjava2ownera month ago + +加了个“初学者入门介绍“,方便Java零基础的人看源码。 +Copy URL +Master_H +Master_Ha month ago + +厉害 +Copy URL +Jackchars +Jackcharsa month ago + +看着就牛逼哄哄 +Copy URL +妖孽 +妖孽a month ago + +大佬牛逼啊 +Copy URL +920504_drinkjava2 +drinkjava2ownera month ago + +微信号(yong99819981),但正在换手机,请过两天再加。这两天只是想聊天的请发在这里或私信。 +Copy URL +1489318_lnsooxd +LnsooXDa month ago + +怎么加入你? +Copy URL +920504_drinkjava2 +drinkjava2ownera month ago + +开了个微信"人工生命群”,可以在那聊。我没有QQ,你也可以直接在这里评论或发issue、私信。 +Copy URL +1727136_sunziren +sunzirena month ago + +老弟,你QQ多少,我对你这个项目很感兴趣,咱们应该有的聊的 +Copy URL +jdkhome +jdkhomea month ago + +带我一个 +Copy URL +920504_drinkjava2 +drinkjava2ownera month ago + +开了个微信"人工生命群”,可以在那聊。我没有QQ,你也可以直接在这里评论或发issue、私信。 + +Copy URL 143517_vebai /vebaia day ago diff --git a/版本提交记录.md b/版本提交记录.md index 3d73bee..b511993 100644 --- a/版本提交记录.md +++ b/版本提交记录.md @@ -46,12 +46,14 @@ 主要做了一些清理,将所有器官移到单独的类里,删除OrganDesc类。将一些类(如Applicaton移到根包下)移到不同的包下。这个版本是比较大的一个重构,最大的进步是将算法当成一个器官引入,当然,这个版本只存在一个随机连接两端的算法,以后会扩充。 另外,顺手加上了Happy和Pain两个器官,分别对应进食愉快感和痛苦感,后者在靠近边界时激发。观查它的表现,果然不出所料,痛苦感立即生效,有一些Frog移动到边界后就不再前进,而是顺着边界溜下去了,不傻,但是Happy器官没有生效,这也很显然,因为Happy属于进食反射链的一部分,在没有记忆器官(算法)引入之前,是没有途径使用上进食奖励信号的。 -### 2019-06-13, Commit: Happy & Pain -主要做了一些清理,将所有器官移到单独的类里,删除OrganDesc类。将一些类(如Applicaton移到根包下)移到不同的包下。这个版本是比较大的一个重构,最大的进步是将算法当成一个器官引入,当然,这个版本只存在一个随机连接两端的算法,以后会扩充。 -另外,顺手加上了Happy和Pain两个器官,分别对应进食愉快感和痛苦感,后者在靠近边界时激发。观查它的表现,果然不出所料,痛苦感立即生效,有一些Frog移动到边界后就不再前进,而是顺着边界溜下去了,不傻,但是Happy器官没有生效,这也很显然,因为Happy属于进食反射链的一部分,在没有记忆器官(算法)引入之前,是没有途径使用上进食奖励信号的。 - ### 2019-06-26, Commit: Back to many connections 找食效率太低,又改回到4.12的用连接数量代替权值这个逻辑,权值这种人为设计的算法居然比不过随机试错,失败。先暂时去掉Pain器官,Pain的加入并没有提高找食效率,必须与感光细胞合用才能知道是哪个方向的边界,下个版本急需引入记忆功能,也就是说要将感光细胞的活跃和痛苦器官的活跃关联起来。 ### 2019-06-28, Commit: New eye & dynamic show brain 为了更方便青蛙看到边界,又加了个新的眼睛,它是一个可自进化的nxn点阵的眼睛,将来会取代只有四个象素点(但能看得远)的老眼睛。到目前为止,依然还没有进行模式识别和记忆功能的开发。另外脑图可以动态显示了,用一个红圈标记出被动态跟踪显示的青蛙。另外每次运行前打印往生咒,以示对生命的尊重。 +### 2019-07-28, Commit: Trap & Active & Chance +这还是一个常规版本,建立在随机连接、优胜劣汰基础上。主要有以下改动: +1. 在Env区中间加了一个陷阱区Trap,以增加趣味性,青蛙如果走到陷阱区就死掉,结果自然选择的结果是青蛙会绕开陷阱区。 +2. 青蛙增加一个Active器官,它的作用是一直保持激活,如果有神经元触突位于这个区就会驱动神经元兴奋,这个器官经实践证明比Hungry器官驱动更能提高找食效率。 +3. 青蛙增加一个Chance器官,它的作用是引入随机扰动,打破青蛙有时候围着一个食物打转就是吃不着的死循环。 +从当前这个版本可以看出,实际上青蛙是有一定的记忆能力的,连接就=记忆,只不过没有模式识别能力,以后的工作将以模式识别为重点,基本原理是见note中提到的仿照全息存储原理,在思维区逆向成像。因为逆向成像的限制,以后的版本,所有的器官会被移到脑图的同一侧,不再是随意分布在脑图上了,这将是一个比较明显的改动。当然随机连接这个算法看起来比较有用,以后还是可能保留的。 \ No newline at end of file