diff --git a/README.md b/README.md index e675569..84da02b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ 这个项目永远没有结束的时候,开始于模拟一个简单的生命体,然后是青蛙、狗......, 结束于有“自我意识表现”的人工脑,或者说,结束于被机器人代替人类的那一天。 ## 缘起 | Origin -目前人工智能的进展已经比较完美地解决了模式识别这块的难题,人脸识别、语音识别已经不弱于人类的水平,而这是我在二十年前感到最困惑的一块,因为底子差和当时的电脑速度慢。模式识别解决了,剩下的问题就简单多了,目前距离人工意识的诞生只差临门一脚了,就是如何在识别的基础上“理解”这些识别的内容并与人类形成交互的反馈。所以这个项目的重点不在于模式识别,而是在利用模式识别的成果基础上,训练神经网络形成条件反射,表现出高等动物才具有的条形反射行为,最终表现为"拥有自我意识"的行为。根据“意识不是一种存在,而是一种现象”原理,如果最终一个系统表现出具有自我意识的行为,即可认为它也是人,应该获得人权。目前有些人工智能的研究目的是想让人工智能解决一些复杂的人类社会方面的问题如机器翻译等,则是完全错误的目标,不可能成功,因为如果一个系统不能表现出自我意识,它就不能与人类交流,也就不可能具有解决这些问题的能力,表现出来的现象就是通常说的"机器不犯错,一旦犯错就是大错"。另一方面,如果一个系统表现出具有自我意识的行为,它就完全有能力解决世界上所有难题,包括改进它的自身和淘汰人类(因为他是先进生产力的代表)。所以人工智能的研究重点应该放在人工生命的构建和论理研究,而不是期待短期收益,指望人类可以一直享受人工智能的大餐是很危险的。模式识别和深度学习的成果只是人工生命的踮脚石和一块路标而已。人工智能的“有用”的应用,很可能只是短暂的一段过渡期而已,不用高兴得太早,也许都是白忙,给机器人作嫁衣而已,当然,深度学习的成果在将来还是有用的,生物体从来不能象计算机那样对某个技能反复训练上千万次,达到史无前例的覆盖度,既使在机器人时代,也是一个有用的技术。 +目前人工智能的进展已经比较完美地解决了模式识别这块的难题,人脸识别、语音识别已经不弱于人类的水平,而这是我在二十年前感到最困惑的一块,因为底子差和当时的电脑速度慢。模式识别解决了,剩下的问题就简单多了,目前距离人工意识的诞生只差临门一脚了,就是如何在识别的基础上“理解”这些识别的内容并与人类形成交互的反馈。所以这个项目的重点不在于模式识别,而是在利用模式识别的成果基础上,训练神经网络形成条件反射,表现出高等动物才具有的条形反射行为,最终表现为"拥有自我意识"的行为。根据“意识不是一种存在,而是一种现象”原理,如果最终一个系统表现出具有自我意识的行为,即可认为它也是人,应该获得人权。目前有些人工智能的研究目的是想让人工智能解决一些复杂的人类社会方面的问题如机器翻译等,则是完全错误的目标,不可能成功,因为如果一个系统不能表现出自我意识,它就不能与人类交流,也就不可能具有解决这些问题的能力,表现出来的现象就是通常说的"机器不犯错,一旦犯错就是大错"。另一方面,如果一个系统表现出具有自我意识的行为,它就完全有能力解决世界上所有难题,包括改进它的自身和淘汰人类(因为他是先进生产力的代表)。所以人工智能的研究重点应该放在人工生命的构建和伦理研究,而不是期待短期收益,指望人类可以一直享受人工智能的大餐是很危险的。模式识别和深度学习的成果只是人工生命的踮脚石和一块路标而已。人工智能的“有用”的应用,很可能只是短暂的一段过渡期而已,不用高兴得太早,也许都是白忙,给机器人作嫁衣而已,当然,深度学习的成果在将来还是有用的,生物体从来不能象计算机那样对某个技能反复训练上千万次,达到史无前例的覆盖度,既使在机器人时代,也是一个有用的技术。 简单来说,这个项目的目的是试验和探索神经网络开发的另一个方向,即以实验为导向,模拟生命进化的过程,按照优胜夯汰、随机变异、用进废退这三大原则,一步一步地搭建出从低等到复杂的人工生命体,除了模式识别的成果可以部分引用,原则上不需要很多的数学知识,因为它是由实验为驱动,而不是由算法着手来搭建神经网络。目前神经网络研究重点在于模式识别和算法,但对系统赋予主动性关注不够。 从单细胞进化到多细胞、从青蛙进化到人类,这是一个漫长的、随机的进化过程,但在超级电脑上跑可能只要几天时间,就可能得到一个相当不错的脑模型。当然电脑速度越快、容量越大、环境模拟的越真实,则优胜夯汰后形成的脑结构就越复杂,错的脑模型都被自然淘汰掉了。从算法着手搭建,还是从模拟环境着手自动进化,这是创建人工生命的两个大方向,第一个方向有可能走到死胡同里,因为它不具备算法自改进、变异、遗传(算法的压缩)功能,当脑模型复杂到一定地步,可能会超出人脑能理解的范畴。模拟环境方式的难点则在于环境本身必须足够复杂、正确。而且必须循序渐进,与脑的进化同步,如果把一群青蛙扔到猴子的模拟环境中,则所有青蛙都会被自然淘汰掉,项目就无法进行下去了,另一个困难是电脑必须非常快,因为它是用串行方式模拟并行,不断试错前进的过程。 目前的项目只是搭建了一个框架,语言为Java,利用Swing作图环境,构建一个虚拟环境、并模拟一群草履虫的优胜夯汰,来获取一个具备自进化功能的人工生命体,具体脑(即电脑生成的神经网络)的生成、进化算法还需要以后逐渐加入。欢迎有对神经网络感兴趣的同学加入这个实验项目,大家一起来玩,这个项目不需要多少数学知识,重在实践。 diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/Env.java b/core3d/src/main/java/com/github/drinkjava2/frog/Env.java index efd8fff..7a0bc50 100644 --- a/core3d/src/main/java/com/github/drinkjava2/frog/Env.java +++ b/core3d/src/main/java/com/github/drinkjava2/frog/Env.java @@ -11,11 +11,10 @@ import javax.swing.JPanel; import com.github.drinkjava2.frog.egg.Egg; import com.github.drinkjava2.frog.egg.EggTool; +import com.github.drinkjava2.frog.objects.EnvObject; import com.github.drinkjava2.frog.objects.LetterTester; import com.github.drinkjava2.frog.objects.Material; -import com.github.drinkjava2.frog.objects.EnvObject; import com.github.drinkjava2.frog.util.RandomUtils; -import com.github.drinkjava2.frog.util.StringPixelUtils; /** * Env is the living space of frog. draw it on JPanel @@ -39,10 +38,10 @@ public class Env extends JPanel { public static final int FROG_PER_SCREEN = EGG_QTY * FROG_PER_EGG / SCREEN; // 每屏上显示几个青蛙,这个数值由上面三个参数计算得来 - /** Frog's brain size is a 3D array of Room */ // 脑空间是个三维Room数组,为节约内存,仅在用到数组元素时才去初始化这维,按需分配内存 + /** Frog's brain size is a 3D array of Cell */ // 脑空间是个三维Cell数组,为节约内存,仅在用到数组元素时才去初始化这维,按需分配内存 public static final int FROG_BRAIN_XSIZE = 30; // frog的脑在X方向长度 public static final int FROG_BRAIN_YSIZE = 20; // frog的脑在Y方向长度 - public static final int FROG_BRAIN_ZSIZE = 20; // frog的脑在Z方向长度 + public static final int FROG_BRAIN_ZSIZE = 25; // frog的脑在Z方向长度 /** SHOW first frog's brain structure */ public static boolean SHOW_FIRST_FROG_BRAIN = true; // 是否显示脑图在Env区的右侧 @@ -60,7 +59,7 @@ public class Env extends JPanel { public static final int FROG_BRAIN_DISP_WIDTH = 600; // Frog的脑图在屏幕上的显示大小,可调 /** Steps of one test round */ - public static final int STEPS_PER_ROUND = 2000;// 每轮测试步数,可调 + public static final int STEPS_PER_ROUND = 100;// 每轮测试步数,可调 public static int step;// 当前测试步数 public static final int FOOD_QTY = 100; // 食物数量, 可调 @@ -76,7 +75,7 @@ public class Env extends JPanel { public static EnvObject[] things = new EnvObject[] { new LetterTester() };// 所有外界物体,如食物、字母测试工具都放在这个things里面 - static { + static { System.out.println("唵缚悉波罗摩尼莎诃!"); // 杀生前先打印往生咒,见码云issue#IW4H8 if (DELETE_EGGS) EggTool.deleteEggs(); @@ -242,7 +241,7 @@ public class Env extends JPanel { Application.brainPic.drawBrainPicture(firstFrog); for (int j = 0; j < FROG_PER_SCREEN; j++) { Frog f = frogs.get(screen * FROG_PER_SCREEN + j); - f.rooms = null; // 清空frog脑细胞所占用的内存 + f.cells = null; // 清空frog脑细胞所占用的内存 } Application.mainFrame.setTitle(new StringBuilder("Round: ").append(round).append(", screen:") .append(screen).append(", ").append(foodFoundCountText()).append(", 用时: ") diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/Frog.java b/core3d/src/main/java/com/github/drinkjava2/frog/Frog.java index 03476a4..9397345 100644 --- a/core3d/src/main/java/com/github/drinkjava2/frog/Frog.java +++ b/core3d/src/main/java/com/github/drinkjava2/frog/Frog.java @@ -20,23 +20,23 @@ import javax.imageio.ImageIO; import com.github.drinkjava2.frog.brain.Cuboid; import com.github.drinkjava2.frog.brain.Organ; -import com.github.drinkjava2.frog.brain.Room; +import com.github.drinkjava2.frog.brain.Cell; import com.github.drinkjava2.frog.egg.Egg; import com.github.drinkjava2.frog.objects.Material; /** - * Frog = organs + rooms
- * rooms = brain cells + photons
+ * Frog = organs + cells
+ * cells = brain cells + photons
* organs = cell parameters + cell actions * - * 青蛙脑由器官播种出的细胞组成,器官Organ会播种出各种脑细胞填充在一个rooms三维数组代表的空间中,每个room里可以存在多个脑细胞和光子,光子是信息的载体,永远不停留。 + * 青蛙脑由器官播种出的细胞组成,器官Organ会播种出各种脑细胞填充在一个cells三维数组代表的空间中,每个cell里可以存在多个脑细胞和光子,光子是信息的载体,永远不停留。 * * @author Yong Zhu * @since 1.0 */ public class Frog { - /** brain rooms */ - public Room[][][] rooms;// 一开始不要初始化,只在调用getRoom方法时才初始化相关维以节约内存 + /** brain cells */ + public Cell[][][] cells;// 一开始不要初始化,只在调用getCell方法时才初始化相关维以节约内存 /** organs */ public List organs = new ArrayList<>(); @@ -65,7 +65,7 @@ public class Frog { public void initFrog() {// 仅在测试之前调用这个方法初始化frog以节约内存,测试完成后要清空units释放内存 try { - rooms = new Room[Env.FROG_BRAIN_XSIZE][][]; // 为了节约内存,先只初始化三维数组的x维,另两维用到时再分配 + cells = new Cell[Env.FROG_BRAIN_XSIZE][][]; // 为了节约内存,先只初始化三维数组的x维,另两维用到时再分配 } catch (OutOfMemoryError e) { System.out.println("OutOfMemoryError found for frog, force it die."); this.alive = false; @@ -89,22 +89,28 @@ public class Frog { if (!alive) return; for (int x = o.x; x < o.x + o.xe; x++) - for (int y = o.y; y < o.y + o.ye; y++) - for (int z = o.z; z < o.z + o.ze; z++) - getRoom(x, y, z).setActive(active); + if (cells[x] != null) + for (int y = o.y; y < o.y + o.ye; y++) + if (cells[x][y] != null) + for (int z = o.z; z < o.z + o.ze; z++) + if (cells[x][y][z] != null) + getOrCreateCell(x, y, z).setActive(active); } - /** Calculate organ activity by add all organ rooms' active value together */ - public float getCuboidActiveTotalValue(Cuboid o) {// 遍历长方体区域所在room,将它们的激活值汇总返回 + /** Calculate organ activity by add all organ cells' active value together */ + public float getCuboidActiveTotalValue(Cuboid o) {// 遍历长方体区域所在cell,将它们的激活值汇总返回 float activity = 0; for (int x = o.x; x < o.x + o.xe; x++) for (int y = o.y; y < o.y + o.ye; y++) for (int z = o.z; z < o.z + o.ze; z++) - activity += this.getRoom(x, y, z).getActive(); + activity += this.getOrCreateCell(x, y, z).getActive(); return activity; } + private int activeNo = 0; + public boolean active(Env v) {// 这个active方法在每一步循环都会被调用,是脑思考的最小帧 + activeNo++; // 如果能量小于0、出界、与非食物的点重合则判死 if (!alive || energy < 0 || Env.outsideEnv(x, y) || Env.bricks[x][y] >= Material.KILLFROG) { energy -= 100; // 死掉的青蛙也要消耗能量,确保淘汰出局 @@ -115,12 +121,17 @@ public class Frog { for (Organ o : organs) o.active(this); // 调用每个器官的active方法, 通常只用于执行器官的外界信息输入、动作输出,脑细胞的遍历不是在这一步 - // 这里是最关键的脑细胞主循环,脑细胞负责捕获和发出光子,光子则沿它的矢量方向每次自动走一格,如果下一格是真空(即数组room元素未初始化)会继续走下去并衰减(为减少运算),直到能量为0 + // 这里是最关键的脑细胞主循环,脑细胞负责捕获和发送光子,光子则沿它的矢量方向每次自动走一格,如果下一格是真空(即cell未初始化)会继续走下去并衰减直到为0(为减少运算) + for (int i = 0; i < Env.FROG_BRAIN_XSIZE; i++) - for (int j = 0; j < Env.FROG_BRAIN_YSIZE; j++) - for (int k = 0; k < Env.FROG_BRAIN_ZSIZE; k++) { - //TODO 脑细胞主循环 - } + if (cells[i] != null) + for (int j = 0; j < Env.FROG_BRAIN_YSIZE; j++) + if (cells[i][j] != null) + for (int k = 0; k < Env.FROG_BRAIN_ZSIZE; k++) { + Cell cell = cells[i][j][k]; + if (cell != null && cell.getActions() != null) + cell.execute(this, activeNo, i, j, k);// 调用cell的方法来进行这个运算 + } return alive; } @@ -130,23 +141,32 @@ public class Frog { g.drawImage(frogImg, x - 8, y - 8, 16, 16, null); } - /** Check if room exist */ - public boolean existRoom(int x, int y, int z) {// 检查指定坐标room是否存在 - return rooms[x] != null && rooms[x][y] != null && rooms[x][y][z] != null; + /** Check if cell exist */ + public Cell getCell(int x, int y, int z) {// 返回指定脑ssf坐标的cell ,如果不存在,返回null + if (cells[x] == null || cells[x][y] == null) + return null; + return cells[x][y][z]; } - /** Get a room in position (x,y,z), if not exist, create a new one */ - public Room getRoom(int x, int y, int z) {// 获取指定坐标的Room,如果为空,则在指定位置新建Room - if (rooms[x] == null) - rooms[x] = new Room[Env.FROG_BRAIN_YSIZE][]; - if (rooms[x][y] == null) - rooms[x][y] = new Room[Env.FROG_BRAIN_ZSIZE]; - if (rooms[x][y][z] == null) { - Room unit = new Room(); - rooms[x][y][z] = unit; - return unit; - } else - return rooms[x][y][z]; + /** Get a cell in position (x,y,z), if not exist, create a new one */ + public Cell getOrCreateCell(int x, int y, int z) {// 获取指定坐标的Cell,如果为空,则在指定位置新建Cell + if (outBrainBound(x, y, z)) + return null; + if (cells[x] == null) + cells[x] = new Cell[Env.FROG_BRAIN_YSIZE][]; + if (cells[x][y] == null) + cells[x][y] = new Cell[Env.FROG_BRAIN_ZSIZE]; + Cell cell = cells[x][y][z]; + if (cell == null) { + cell = new Cell(); + cells[x][y][z] = cell; + } + return cell; } + /** Check if x,y,z out of frog's brain bound */ + public static boolean outBrainBound(int x, int y, int z) {// 检查指定坐标是否超出frog脑空间界限 + return x < 0 || x >= Env.FROG_BRAIN_XSIZE || y < 0 || y >= Env.FROG_BRAIN_YSIZE || z < 0 + || z >= Env.FROG_BRAIN_ZSIZE; + } } diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/brain/CellAction.java b/core3d/src/main/java/com/github/drinkjava2/frog/brain/Action.java similarity index 52% rename from core3d/src/main/java/com/github/drinkjava2/frog/brain/CellAction.java rename to core3d/src/main/java/com/github/drinkjava2/frog/brain/Action.java index bf0b460..5a0c1da 100644 --- a/core3d/src/main/java/com/github/drinkjava2/frog/brain/CellAction.java +++ b/core3d/src/main/java/com/github/drinkjava2/frog/brain/Action.java @@ -11,21 +11,18 @@ package com.github.drinkjava2.frog.brain; /** - * CellAction defines cell action + * Action is the action of cell, one cell can have multiple actions * - * CellAction的实现类只有一个act方法,它会根据细胞器官所属的类型作为不同的行为 + * Action是细胞的行为,一个细胞Cell可以拥用多个action * * @author Yong Zhu * @since 2.0.2 */ -public interface CellAction { +public class Action { + public Organ organ; // 细胞属于哪个器官 + + public Action(Organ organ) {// Action不保存在蛋里,不需要定义空构造器 + this.organ = organ; + } - /** - * Each cell's act method will be called once at each loop step - * - * act方法是只有锥器官才具备的方法,在每个测试步长中act方法都会被调用一次,这个方法针对不同的细胞类型有不同的行为逻辑,这是硬 - * 编码,所以要准备多套不同的行为(可以参考动物脑细胞的活动逻辑),然后抛给电脑去随机筛选,不怕多。 - * - */ - public void act(Cell cell, int x, int y, int z); } diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/brain/BrainPicture.java b/core3d/src/main/java/com/github/drinkjava2/frog/brain/BrainPicture.java index a4e96fc..36de168 100644 --- a/core3d/src/main/java/com/github/drinkjava2/frog/brain/BrainPicture.java +++ b/core3d/src/main/java/com/github/drinkjava2/frog/brain/BrainPicture.java @@ -1,14 +1,8 @@ package com.github.drinkjava2.frog.brain; import static java.awt.Color.BLACK; -import static java.awt.Color.BLUE; -import static java.awt.Color.CYAN; -import static java.awt.Color.GREEN; -import static java.awt.Color.MAGENTA; -import static java.awt.Color.ORANGE; import static java.awt.Color.RED; import static java.awt.Color.WHITE; -import static java.awt.Color.YELLOW; //import static java.awt.BLUE; import static java.lang.Math.cos; import static java.lang.Math.round; @@ -16,29 +10,35 @@ import static java.lang.Math.sin; import java.awt.Color; import java.awt.Graphics; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import javax.swing.JPanel; import com.github.drinkjava2.frog.Env; import com.github.drinkjava2.frog.Frog; +import com.github.drinkjava2.frog.util.ColorUtils; /** * BrainPicture show first frog's brain structure, for debug purpose only * * 这个类用来画出脑图,这不是一个关键类,对脑的运行逻辑无影响,但有了脑图后可以直观地看出脑的3维结构,进行有针对性的改进 + * 可以用鼠标进行平移、缩放、旋转,以及t、f、l、r,x五个键来选择顶视、前视、左视、右视、斜视这5个方向的视图 * * @author Yong Zhu * @since 1.0 */ @SuppressWarnings("all") public class BrainPicture extends JPanel { + private static final float d90 = (float) (Math.PI / 2); + Color picColor = RED; int brainDispWidth; // screen display piexls width float scale; // brain scale int xOffset = 0; // brain display x offset compare to screen int yOffset = 0; // brain display y offset compare to screen - float xAngle = (float) (Math.PI / 2.5); // brain rotate on x axis - float yAngle = -(float) (Math.PI / 8); // brain rotate on y axis + float xAngle = d90 * .8f; // brain rotate on x axis + float yAngle = d90 / 4; // brain rotate on y axis float zAngle = 0;// brain rotate on z axis public BrainPicture(int x, int y, float brainWidth, int brainDispWidth) { @@ -48,9 +48,42 @@ public class BrainPicture extends JPanel { scale = 0.7f * brainDispWidth / brainWidth; this.setBounds(x, y, brainDispWidth + 1, brainDispWidth + 1); MouseAction act = new MouseAction(this); - this.addMouseListener(act); - this.addMouseWheelListener(act); - this.addMouseMotionListener(act); + this.addMouseListener(act); // 添加鼠标动作监听 + this.addMouseWheelListener(act);// 添加鼠标滚轮动作监听 + this.addMouseMotionListener(act);// 添加鼠标移动动作监听 + this.setFocusable(true); + addKeyListener(new KeyAdapter() {// 处理t,f,l,r,x键盘命令 + public void keyPressed(KeyEvent e) { + switch (e.getKeyCode()) { + case 'T':// 顶视 + xAngle = 0; + yAngle = 0; + zAngle = 0; + break; + case 'F':// 前视 + xAngle = d90; + yAngle = 0; + zAngle = 0; + break; + case 'L':// 左视 + xAngle = d90; + yAngle = d90; + zAngle = 0; + break; + case 'R':// 右视 + xAngle = d90; + yAngle = -d90; + zAngle = 0; + break; + case 'X':// 斜视 + xAngle = d90 * .8f; + yAngle = d90 / 4; + zAngle = 0; + break; + default: + } + } + }); } public void drawCuboid(Cuboid c) {// 在脑图上画一个长立方体框架,视角是TopView @@ -78,8 +111,8 @@ public class BrainPicture extends JPanel { } public void drawCone(Cone c) {// 在脑图上画一个锥体,视角是TopView - drawLine(c.x1, c.y1, c.z1, c.x2, c.y2, c.z2);// 画锥体的中心线 - //TODO 画出锥体的上下面 + drawLine(c.x1, c.y1, c.z1, c.x2, c.y2, c.z2);// 画锥体的中心线 + // TODO 画出锥体的上下面 } /*- @@ -145,11 +178,16 @@ public class BrainPicture extends JPanel { (int) round(y2) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset); } - /** 画出Room的中心点 */ - public void drawRoomCenter(float x, float y, float z) { + /** 画出cell的中心点,通常用来显示器官的激活区 */ + public void drawCellCenter(float x, float y, float z) { drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, (int) Math.max(1, Math.round(scale * .7))); } + /** 画出cell的中心小点,通常用来显示光子 */ + public void drawCellSmallCenter(float x, float y, float z) { + drawPoint(x + 0.5f, y + 0.5f, z + 0.5f, (int) Math.max(1, Math.round(scale * .15))); + } + /** 画点,固定以top视角的角度,所以只需要在x1,y1位置画一个点 */ public void drawPoint(float px1, float py1, float pz1, int diameter) { double x1 = px1 - Env.FROG_BRAIN_XSIZE / 2; @@ -180,33 +218,6 @@ public class BrainPicture extends JPanel { (int) round(y1) + Env.FROG_BRAIN_DISP_WIDTH / 2 + yOffset - diameter / 2, diameter, diameter); } - private static final Color[] rainbow = new Color[] { RED, ORANGE, YELLOW, GREEN, CYAN, BLUE, MAGENTA }; - private static int nextColor = 0; - - public static Color nextRainbowColor() { - if (nextColor == rainbow.length) - nextColor = 0; - return rainbow[nextColor++]; - } - - public static Color rainbowColor(float i) { - if (i == 0) - return BLACK; - if (i == 1) - return RED; - if (i <= 3) - return ORANGE; - if (i <= 10) - return YELLOW; - if (i <= 20) - return GREEN; - if (i <= 50) - return CYAN; - if (i <= 100) - return BLUE; - return MAGENTA; - } - 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) {// 在这个方法里进行青蛙三维脑结构的绘制 @@ -229,14 +240,20 @@ public class BrainPicture extends JPanel { drawLine(0, 0, 0, 0, 1, 0); drawLine(0, 0, 0, 0, 0, 1); - for (int x = 0; x < Env.FROG_BRAIN_XSIZE; x++) { - if (f.rooms[x] != null) + for (int x = 0; x < Env.FROG_BRAIN_XSIZE; x++) {// 开始画整个脑空间的光子和激活点阵图 + if (f.cells[x] != null) for (int y = 0; y < Env.FROG_BRAIN_YSIZE; y++) { - if (f.rooms[x][y] != null) + if (f.cells[x][y] != null) for (int z = 0; z < Env.FROG_BRAIN_ZSIZE; z++) { - if (f.existRoom(x, y, z) && f.getRoom(x, y, z).getActive() > 0) { - setPicColor(rainbowColor(f.getRoom(x, y, z).getActive())); - drawRoomCenter(x, y, z); + Cell cell = f.getCell(x, y, z); + if (cell != null) { + if (cell.getActive() > 0) { + setPicColor(ColorUtils.rainbowColor(cell.getActive())); + drawCellCenter(x, y, z); + } else if (cell.getPhotonQty() > 0) { + setPicColor(ColorUtils.colorByCode(cell.getColor())); + drawCellSmallCenter(x, y, z); + } } } } diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/brain/Cell.java b/core3d/src/main/java/com/github/drinkjava2/frog/brain/Cell.java index 9949eda..7f3ae23 100644 --- a/core3d/src/main/java/com/github/drinkjava2/frog/brain/Cell.java +++ b/core3d/src/main/java/com/github/drinkjava2/frog/brain/Cell.java @@ -10,35 +10,136 @@ */ package com.github.drinkjava2.frog.brain; +import java.util.Arrays; + +import com.github.drinkjava2.frog.Frog; + /** - * Cell is the basic unit of frog's brain - * - * Cell这个类只保存很少的信息,可节约内存,它的触突分布参数、对信号(即光子)的处理行为由orgran中定义的各项细胞参数来决定。 - * Cell的排布由器官来完成,一个器官通常会撒布一群相同类型的细胞。 - * - * synapses字段比较特殊,不一定每个细胞会用到,取决于细胞的类型。常用的一种用法是取最活跃的几个光子输入信号的方向,建立几个对应其方向的动态触突, - * 以后只要有任一个触突有信号,其它的触突就发送信号,这样两个或多个不同方向的信息就被关联起来了,这就是体全息存贮逆向成像的基础,是自然规律为什么会 - * 沉淀在人脑中 的基石,因为任意有相关性的信号,只要反复或同时发生,总会有脑细胞位于这两个信号之间,将它们这个关联关系保存下来。 - * 这个synapse是动态生成的,不是在细胞诞生时生成的,所以更宝贵。 + * Cell is the smallest unit of brain space, a Cell can have many actions and + * photons * - * Organ类中也可能让细胞产生一些无状态的触突(保存在Organ类模板中调用),区别在于后者只能进行一些信号传导、转折、发散、聚焦等比较单调刻板的功能, - * 不具备智能性。例如要模拟体全息存贮现象,既可以利用Cell中的动态触突,也可以利用Organ类中固定的触突,但后者对信号的输入角度有严格要求,处理信 - * 息量有限,即使细胞位于两个信号的交点(驻点),也不一定能接收到信号;而利用动态触突,则可以确保360度无死角地建立两个或多个重复信号之间的关联。 + * Cell是脑的最小空间单元,可以存在多个行为(Action)和光子(Photon),脑是由frog中的cells三维数组组成,但不是每一维都初始化过 * * @author Yong Zhu - * @since 2.0.2 + * @since 1.0 */ -public class Cell {// Cell是脑神经元,将来脑里会有上亿个脑细胞,为节约内存,不重要的、与细胞状态无关的参数都存放在Organ类中去了。 +public class Cell { + /** Active of current cell */ + private float active = 0; // 这个cell的激活程度,允许是负值,它反映了在这个小立方体里所有光子的能量汇总值 + + private Action[] actions = null; + + private Photon[] photons = null; + + private int color;// Cell的颜色取最后一次被添加的光子的颜色,颜色不重要,但能方便观察 + + private int photonQty = 0; + + public Action[] getActions() {// 为了节约内存,仅在访问actions时创建它的实例 + if (actions == null) + actions = new Action[] {}; + return actions; + } + + public Photon[] getPhotons() {// 为了节约内存,仅在访问photons时创建它的实例 + if (photons == null) + photons = new Photon[] {}; + return photons; + } + + public void addAction(Action cell) {// 每个Cell可以存在多个行为,通常只在青蛙初始化器官时调用这个方法 + if (actions == null) + actions = new Action[] {}; + actions = Arrays.copyOf(actions, actions.length + 1); + actions[actions.length - 1] = cell; + } - public Cell(Organ organ) {// Cell不保存在蛋里,不需要定义空构造器 - this.organ = organ; + public void addPhoton(Photon p) {// 每个cell空间可以存在多个光子 + if (p == null) + return; + p.energy *= .78; + if (p.energy < 0.1) + return; + photonQty++; + color = p.color; // Cell的颜色取最后一次被添加的光子的颜色 + if (photons == null) + photons = new Photon[] {};// 创建数组 + else + for (int i = 0; i < photons.length; i++) { // 找空位插入 + if (photons[i] == null || photons[i].energy < 0.1) { + photons[i] = p; + return; // 如找到就插入,返回 + } + } + photons = Arrays.copyOf(photons, photons.length + 1);// 否则追加新光子到未尾 + photons[photons.length - 1] = p; } - /** energy of cell, energy got from food */ - public float energy = 0; // 每个细胞当前的能量值 + public void removePhoton(int i) {// 删第几个光子 + if (photons[i] != null) { + photons[i] = null; + photonQty--; + } + } + + /** Photon always walk */ + public void photonWalk(Frog f, Photon p) { // 光子自已会走到下一格,如果下一格为空,继续走,直到能量耗尽或出界 + if (p.energy < 0.1) + return;// 能量小的光子直接扔掉 + if (p.outBrainBound()) + return; //// 出界的光子直接扔掉 + p.x += p.mx; + p.y += p.my; + p.z += p.mz; + int rx = Math.round(p.x); + int ry = Math.round(p.y); + int rz = Math.round(p.z); + if (Frog.outBrainBound(rx, ry, rz)) + return;// 出界直接扔掉 + Cell cell = f.getCell(rx, ry, rz); + if (cell != null) { + cell.addPhoton(p); + } else { + // p.energy *= .6;// 真空中也要乘一个衰减系数,防止它走太远,占用计算资源 + photonWalk(f, p);// 递归,一直走下去,直到遇到cell或出界 + } + } + + /** Move photons and call cell's execute method */ + public void execute(Frog f, int activeNo, int x, int y, int z) {// 主运行方法,进行实际的脑细经元的行为和光子移动 + if (actions != null) + for (Action action : actions) + CellActions.act(f, activeNo, this, action, x, y, z); // 调用每个细胞的act方法,处理掉所在cell的光子 + // 剩下的光子自已会走到下一格,光子自己是会走的,而且是直线传播 + if (photons != null) + for (int i = 0; i < photons.length; i++) { + Photon p = photons[i]; + if (p == null || p.activeNo == activeNo)// 同一轮新产生的光子或处理过的光子不再走了 + continue; + p.activeNo = activeNo; + removePhoton(i);// 原来的位置的先清除,去除它的Java对象引用 + photonWalk(f, p); // 让光子自已往下走 + } + } + + public float getActive() {// 获取cell的激活度 + return active; + } - /** Organ index in egg */ - public Organ organ; // 细胞属于哪个器官 + public void setActive(float active) {// 设cell的激活度 + this.active = active; + } + + public int getPhotonQty() {// 获取cell里的总光子数 + return photonQty; + } + + public int getColor() { + return color; + } + + public void setColor(int color) { + this.color = color; + } - public Synapse[] synapses; // 动态触突, 详见上面解说,通常是只在最活跃的几个光子输入信号的来源方向上建立动态触突 } diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/brain/CellActions.java b/core3d/src/main/java/com/github/drinkjava2/frog/brain/CellActions.java index 2403b49..9506a3d 100644 --- a/core3d/src/main/java/com/github/drinkjava2/frog/brain/CellActions.java +++ b/core3d/src/main/java/com/github/drinkjava2/frog/brain/CellActions.java @@ -11,11 +11,12 @@ package com.github.drinkjava2.frog.brain; import com.github.drinkjava2.frog.Frog; +import com.github.drinkjava2.frog.util.RandomUtils; /** * CellActions have many cell action stored * - * CellActions登记了许多硬编码的脑细胞活动单例,用act方法来调用这些活动,type参数来区分调用哪个单例的方法 + * CellActions写死了许多硬编码的脑细胞活动,用act方法来调用这些活动,type参数来区分调用哪个单例的方法 * * @author Yong Zhu * @since 2.0.2 @@ -25,7 +26,7 @@ public class CellActions { /*- * Each cell's act method will be called once at each loop step * - * act方法是只有锥器官才具备的方法,在每个测试步长中act方法都会被调用一次,这个方法针对不同的细胞类型有不同的行为逻辑,这是硬 + * 在每个测试步长中act方法都会被调用一次,这个方法针对不同的细胞类型有不同的行为逻辑,这是硬 * 编码,所以要准备多套不同的行为(可以参考动物脑细胞的活动逻辑),然后抛给电脑去随机筛选,不怕多。 * * 举例来说,以下是一些假想中的脑细胞行为: @@ -36,10 +37,29 @@ public class CellActions { * 一对多,拆分,入射光子被拆分成多个光子,发散角与器官相关 * 多对一,聚合,入射光子被触突捕获 */ - public void act(Frog f, int type, Cell cell, int x, int y, int z) { - switch (type) { //添加细胞的行为,这是硬编码 - case Organ.EYE: - + public static void act(Frog f, int actionNo, Cell cell, Action action, int x, int y, int z) { + Organ o = action.organ; + switch (o.type) { // 添加细胞的行为,这是硬编码 + case Organ.EYE: // 如果是视网膜细胞,它的行为是将Cell的激活值转化为向右的多个光子发散出去,模拟波源 + if (cell.getActive() > 0 && RandomUtils.percent(30)) { + for (float yy = -0.3f; yy <= 0.3f; yy += 0.1) {// 形成一个扇面向右发送 + for (float zz = -0.3f; zz <= 0.3f; zz += 0.1) { + cell.addPhoton(new Photon(o.color, x, y, z, 1.0f, yy, zz, 100f)); + } + } + } + break; + case Organ.EAR: // 如果是听力细胞,它的行为是将cell的激活能量转化为向下的多个光子发散出去,模拟波源 + if (cell.getActive() > 0 && RandomUtils.percent(30)) { + for (float xx = -0.3f; xx <= 0.3f; xx += 0.13) {// 形成一个扇面向下发送 + for (float yy = -0.3f; yy <= 0.3f; yy += 0.13) { + cell.addPhoton(new Photon(o.color, x, y, z, xx, yy, -1, 100f)); + } + } + } + + break; + case Organ.DYNAMIC:// 如果是动态细胞,它的行为是。。。比较复杂,一言难尽。 break; default: diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/brain/Cone.java b/core3d/src/main/java/com/github/drinkjava2/frog/brain/Cone.java index b8d5ba6..fb93c15 100644 --- a/core3d/src/main/java/com/github/drinkjava2/frog/brain/Cone.java +++ b/core3d/src/main/java/com/github/drinkjava2/frog/brain/Cone.java @@ -55,8 +55,14 @@ public class Cone implements Shape { } @Override - public void fillCells(Frog f, Organ o) { + public void fillCellsWithAction(Frog f, Organ o) { // TODO 待添加Cone形器官播种脑细胞的代码 } + @Override + public void createCells(Frog f, Organ o) { + // TODO 待添加Cone形器官createCells的代码 + + } + } diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/brain/Cuboid.java b/core3d/src/main/java/com/github/drinkjava2/frog/brain/Cuboid.java index 4e0351a..d7e66af 100644 --- a/core3d/src/main/java/com/github/drinkjava2/frog/brain/Cuboid.java +++ b/core3d/src/main/java/com/github/drinkjava2/frog/brain/Cuboid.java @@ -59,12 +59,20 @@ public class Cuboid implements Shape { } @Override - public void fillCells(Frog f, Organ o) { + public void fillCellsWithAction(Frog f, Organ o) { for (int i = x; i < x + xe; i++)// 这是具体的播种脑细胞代码,先忽略密度分布等参数 for (int j = y; j < y + ye; j++) for (int k = z; k < z + ze; k++) { - f.getRoom(i, j, k).addCell(new Cell(o)); + Cell cell = f.getOrCreateCell(i, j, k); + if (cell != null) + cell.addAction(new Action(o)); } } + public void createCells(Frog f, Organ o) { + for (int i = x; i < x + xe; i++) + for (int j = y; j < y + ye; j++) + for (int k = z; k < z + ze; k++) + f.getOrCreateCell(i, j, k); + } } diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/brain/Organ.java b/core3d/src/main/java/com/github/drinkjava2/frog/brain/Organ.java index 1028635..2c96030 100644 --- a/core3d/src/main/java/com/github/drinkjava2/frog/brain/Organ.java +++ b/core3d/src/main/java/com/github/drinkjava2/frog/brain/Organ.java @@ -25,8 +25,8 @@ import com.github.drinkjava2.frog.util.RandomUtils; * 器官是脑的一部分,多个器官在脑内可以允许部分或完全重叠出现在同一脑内位置,器官都是可以变异的, 器官负责在青蛙脑生成时播种脑细胞 * 器官是可串行化的,所有器官都会保存在蛋里面 * - * 器官是一种外形为锥圆柱体的脑内区,它的作用是在它的形状范围内播种脑细胞, 这是第一个也是最重要的脑细胞播种器官,它的数 - * 量、形状、大小、角度、位置、神经元分布方式,以及神经元的内部参数可以随机生成和变异, 并由生存竟争来淘汰筛选。 + * 器官是一种外形为锥圆柱体或长方体的脑内区,它的作用是在它的形状范围内播种脑细胞, + * 它的数量、形状、大小、角度、位置、神经元分布方式,以及神经元的内部参数可以随机生成和变异, 并由生存竟争来淘汰筛选。 * * 器官可以组合成复杂的网络结构或曲折的信号传导路径,例如一个圆柱形神经传导器官,可以变异为由两个圆柱状传导器官首尾相接,然后这两个器官各 * 自变异,就有可能形成弯的传导路径或更复杂的网络结构。看起来复杂,但大自然可以做到比这更复杂的进化逻辑,先假设大自然是万能的,只要是有用的 @@ -54,13 +54,15 @@ public class Organ implements Serializable, Cloneable {// 因为要保存在蛋 private static final long serialVersionUID = 1L; // 以下是各种器官类型,每个神经元都属于一个器官,每个器官都有一个type类型参数 - public static final int EYE = 1;// 眼细胞,会根据room激活度产生发散到各个方向的光子 - public static final int EAR = 2;// 耳细胞,类似眼细胞,不同点是为了简化,脑内听觉区和输入区混用一个区,所以它也可吸收光子,倒过来激活room + public static final int EMPTY = 0;// 空细胞,不处理光子 + public static final int EYE = 1;// 眼细胞,会根据cell激活度产生发散到各个方向的光子 + public static final int EAR = 2;// 耳细胞,类似眼细胞,不同点是为了简化,脑内听觉区和输入区混用一个区,所以它也可吸收光子,倒过来激活cell public static final int CORE = 3; // 什么触突都没有,光溜溜的细胞,但它也有可能根据r半径来中转光子 public static final int DYNAMIC = 4; // 只有动态触突的细胞,它忽略静态触突参数 public static final int STATIC = 5; // 只有静态触突的细胞,它忽略动态触突参数 public static final int MIX = 6; // 同时具有静态和动态触突的细胞 public static final int TYPE_QTY = 7;// 所有的type都是预先写好在这里的,自动生成的type也只能在写好的type里选一个 + public int color = 1;// 这个不重要,表示它生成的光子的显示在脑图中的颜色号,见ColorUtils public float fat = 0;// 细胞活跃多,则fat值大,如果fat值很低,则这个器官被丢弃的可能性加大,这个值很重要,它使得孤岛器官被淘汰 public boolean allowVary;// 是否允许变异,有一些器官是手工创建的,在项目初级阶段禁止它们参与变异和生存竟争。 @@ -73,7 +75,7 @@ public class Organ implements Serializable, Cloneable {// 因为要保存在蛋 public Shape shape; // 器官的形状,不同的形状要写出不同的播种行为 - public float cellDistance; // 细胞播种间隔,每隔多少个room放一个细胞 + public float cellDistance; // 细胞播种间隔,每隔多少个cell放一个action public float centerDensityRate; // 中心相对于边沿的细胞播种密度比,为1时为均匀分布 @@ -142,7 +144,9 @@ public class Organ implements Serializable, Cloneable {// 因为要保存在蛋 /** Only call once when frog created , Child class can override this method */ public void init(Frog f) { // 在青蛙生成时会调用这个方法,进行一些初始化,通常是根据参数来播种脑细胞 - // 这里是器官播种脑细胞的具体代码,对于手工生成的器官,可以重写这个方法,对于自动生成的器官,必须根据type和shape等来播种,要写死在这里 + // 里是器官播种脑细胞的具体代码,对于手工生成的器官,也可以重写这个方法,对于自动生成的器官,必须根据type和shape等来播种,要写死在这里 + if (shape != null) + shape.fillCellsWithAction(f, this); // 先均匀播种脑细胞试试 } /** each step will call Organ's active methodd */ @@ -156,7 +160,7 @@ public class Organ implements Serializable, Cloneable {// 因为要保存在蛋 return;// 如果没有形状,就不画 if (!Env.SHOW_FIRST_FROG_BRAIN || !f.alive) // 如果不允许画或青蛙死了,就直接返回 return; - pic.setPicColor(Color.LIGHT_GRAY); // 缺省是黑色 + pic.setPicColor(Color.LIGHT_GRAY); // 缺省是灰色 shape.drawOnBrainPicture(pic); } diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/brain/Photon.java b/core3d/src/main/java/com/github/drinkjava2/frog/brain/Photon.java index e4e1a77..65fd4b0 100644 --- a/core3d/src/main/java/com/github/drinkjava2/frog/brain/Photon.java +++ b/core3d/src/main/java/com/github/drinkjava2/frog/brain/Photon.java @@ -10,28 +10,46 @@ */ package com.github.drinkjava2.frog.brain; +import com.github.drinkjava2.frog.Env; + /** * Photon has direction and strength * - * 用光子来代表信息传递的载体,这是一个矢量,具有方向和能量,能量可以为负值,x,y,z值表示单位向量(长度为1)的三个坐标轴值 + * 用光子来代表信息传递的载体,这是一个矢量,具有方向和能量,能量可以为负值,x,y,z值表示它的脑空间的坐标值,mx,my,mz表示每次移动多少 * 光子永远在移动,直到被吸收转化为Cell的能量贮存或出界 * * @author Yong Zhu * @since 2.0.2 */ public class Photon { - public float x;// 用单位向量的形式表示矢量方向,x,y,z的平方和必须为1 + public float x; public float y; public float z; + public float mx; + public float my; + public float mz; public float energy; + public int color;// 每个光子都有自已的颜色,与产生光子的器官的颜色来决定,颜色不重要,但能方便观察 + public int activeNo;// 每一轮循环都有一个编号,光子走一格后就加上这个编号,同一个循环如果遇到相同编号的光子就不跳过,防止光子被一直赶着走多步 public Photon() { // 缺省构造器 } - public Photon(float x, float y, float z, float energy) { + public Photon(int color, float x, float y, float z, float mx, float my, float mz, float energy) { this.x = x; this.y = y; this.z = z; + this.mx = mx; + this.my = my; + this.mz = mz; this.energy = energy; + this.color = color; + } + + /** Check if x,y,z out of frog's brain bound */ + public boolean outBrainBound() {// 检查指定坐标是否超出frog脑空间界限 + return x < 0 || x >= Env.FROG_BRAIN_XSIZE || y < 0 || y >= Env.FROG_BRAIN_YSIZE || z < 0 + || z >= Env.FROG_BRAIN_ZSIZE; } + } diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/brain/Room.java b/core3d/src/main/java/com/github/drinkjava2/frog/brain/Room.java deleted file mode 100644 index 636dcfd..0000000 --- a/core3d/src/main/java/com/github/drinkjava2/frog/brain/Room.java +++ /dev/null @@ -1,75 +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.brain; - -import java.util.Arrays; - -/** - * Room is the smallest unit of brain space, a room can have 0~n cells and 0~n - * photons - * - * Room是脑的最小空间单元,里面可以存放多个脑细胞(Cell)和光子(Photon),脑是由frog中的rooms三维数组组成,但不是每一维都初始化过 - * 以前Room名为Cube, 现改名为Room - * - * @author Yong Zhu - * @since 1.0 - */ -public class Room { - /** Activity of current room */ - private float active = 0; // 这个立方体的激活程度,允许是负值,它反映了在这个小立方体里所有光子的能量汇总值,room总是随时间自动衰减 - - private Cell[] cells = null; - - private Photon[] photons = null; - - public Cell[] getCells() {// 为了节约内存,仅在访问cells时创建它的实例 - if (cells == null) - cells = new Cell[] {}; - return cells; - } - - public Photon[] getPhotons() {// 为了节约内存,仅在访问photons时创建它的实例 - if (photons == null) - photons = new Photon[] {}; - return photons; - } - - public void addCell(Cell cell) {// 每个方格空间可以存在多个脑细胞 - if (cells == null) - cells = new Cell[] {}; - cells = Arrays.copyOf(cells, cells.length + 1); - cells[cells.length - 1] = cell; - } - - public void addPhoton(Photon p) {// 每个方格空间可以存在多个光子 - if (photons == null) - photons = new Photon[] {}; - for (Photon old : photons) - if (old.energy < 0.01 && p.energy > -0.01) {// 如果能量没有了,用新的代替空位 - old.x = p.x; - old.y = p.y; - old.z = p.z; - old.energy = p.energy; - return; - } - photons = Arrays.copyOf(photons, photons.length + 1);// 否则追加新光子到未尾 - photons[cells.length - 1] = p; - } - - public float getActive() { - return active; - } - - public void setActive(float active) { - this.active = active; - } - -} diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/brain/Shape.java b/core3d/src/main/java/com/github/drinkjava2/frog/brain/Shape.java index 249c1a3..baf92c9 100644 --- a/core3d/src/main/java/com/github/drinkjava2/frog/brain/Shape.java +++ b/core3d/src/main/java/com/github/drinkjava2/frog/brain/Shape.java @@ -24,7 +24,9 @@ import com.github.drinkjava2.frog.Frog; */ public interface Shape extends Serializable { /* Draw self on brain picture */ - public void drawOnBrainPicture(BrainPicture pic); //把自己在脑图上画出来 - - public void fillCells(Frog f, Organ o); //根据给定organ的参数,在shape所代表的脑区内播种脑细胞 + public void drawOnBrainPicture(BrainPicture pic); // 把自己在脑图上画出来 + + public void fillCellsWithAction(Frog f, Organ o); // 根据给定organ的参数,在shape所代表的脑区内添加脑细胞并加入对应细胞的行为 + + public void createCells(Frog f, Organ o); // 在organ所代表的脑区内仅创建空的Cell对象 } diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Dynamic.java b/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Dynamic.java new file mode 100644 index 0000000..49525c9 --- /dev/null +++ b/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Dynamic.java @@ -0,0 +1,44 @@ +/* + * 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.Env; +import com.github.drinkjava2.frog.brain.Cuboid; +import com.github.drinkjava2.frog.brain.Organ; + +/** + * Dynamic organ fill cells with dynamic type action + * + * Dynamic均匀地在所属器官内部播种类型为dynamic的脑细胞,也就是说细胞的所有触突是动态生成的,这是个临时 + * 器官,试图模拟出波的驻点逆向成像,不清楚在没有引入更复杂的器官之前,是否仅凭单一的动态细胞加上其内部神经元参数的调整就可以形成复杂的网络,完成 + * 模式识别工作。基本原理是如果几个不同方向的信号传来,会在这几个方向上动态生成触突,以后只要有一个信号激活,其它方向也会产生反向的激活信号(光子),多余的能量 + * 则贯穿细胞,送到下一个相邻的细胞去处理。 + * + * Dynamic这个器官因为填充所有网格,当脑的维数变大时,将很快耗尽内存,所以只是暂时用来验证思路,以后可能被删除,用随机生成器官(或器官分裂)来代替。随机生成 + * 器官可以将内存溢出(捕获OutofMemoryException)作为一个扣能量条件,再加上越多的脑细胞本身会消耗越多的能量,这样就可以会限制脑的发展大小不会超过虚拟机 + * 允许分配的内存大小。 + * + * @author Yong Zhu + */ +public class Dynamic extends Organ { + private static final long serialVersionUID = 1L; + + public Dynamic() { + super(); + this.shape = new Cuboid(8, 5, 5, Env.FROG_BRAIN_XSIZE / 2 + 2, Env.FROG_BRAIN_YSIZE / 2 + 5, + Env.FROG_BRAIN_ZSIZE / 2); + this.organName = "Ether"; + this.type = Organ.DYNAMIC; // DYNAMIC就是动态触突细胞 + this.allowVary = false;// 不允许变异 + this.allowBorrow = false;// 不允许借出 + } + +} diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Ear.java b/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Ear.java index 6895ca0..ffa5832 100644 --- a/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Ear.java +++ b/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Ear.java @@ -26,34 +26,31 @@ import com.github.drinkjava2.frog.brain.Organ; @SuppressWarnings("all") public class Ear extends Organ {// 耳朵也是长方体,我为什么要用也? private static final long serialVersionUID = 1L; - public int n = 18; // 眼睛有n x n个感光细胞, 用随机试错算法自动变异(加1或减1,最小是3x3) - public Cuboid a = new Cuboid(10, 10, Env.FROG_BRAIN_ZSIZE - 1, 3, 3, 1); - public Cuboid b = new Cuboid(10, 15, Env.FROG_BRAIN_ZSIZE - 1, 3, 3, 1); - public Cuboid c = new Cuboid(15, 10, Env.FROG_BRAIN_ZSIZE - 1, 3, 3, 1); - public Cuboid d = new Cuboid(15, 15, Env.FROG_BRAIN_ZSIZE - 1, 3, 3, 1); + public Cuboid a = new Cuboid(12, 10, Env.FROG_BRAIN_ZSIZE - 1, 3, 3, 1); + public Cuboid b = new Cuboid(12, 15, Env.FROG_BRAIN_ZSIZE - 1, 3, 3, 1); + public Cuboid c = new Cuboid(17, 10, Env.FROG_BRAIN_ZSIZE - 1, 3, 3, 1); + public Cuboid d = new Cuboid(17, 15, Env.FROG_BRAIN_ZSIZE - 1, 3, 3, 1); public Ear() { - this.shape = new Cuboid(10, 10, Env.FROG_BRAIN_ZSIZE - 1, 8, 8, 1); + this.shape = new Cuboid(12, 10, Env.FROG_BRAIN_ZSIZE - 1, 8, 8, 1);// 手工固定耳区的大小 + this.type = Organ.EAR; this.organName = "ear"; - this.allowVary = false; - this.allowBorrow = false; + this.allowVary = false;// 不允许变异 + this.allowBorrow = false;// 不允许借出 + this.color = 5;// blue, see ColorUtils } public void drawOnBrainPicture(Frog f, BrainPicture pic) {// 把自已这个器官在脑图上显示出来,子类可以重写这个方法 - super.drawOnBrainPicture(f, pic); + super.drawOnBrainPicture(f, pic); // 父类方法显示shape形状 pic.drawCuboid(a);// 显示abcd位置在脑图上 pic.drawCuboid(b); pic.drawCuboid(c); pic.drawCuboid(d); } - public void init(Frog f) { // 重写父类方法,播种听力输入细胞,它会将听力区的激活转变成固定向下发散的多个光子,摸拟波源 - shape.fillCells(f, this); - } - /** 给这个耳朵听到一个字母,激活它的听觉输入区, 注意听觉输入区并不等于脑内虚拟听觉成像区,但是第一版...先共用一个区吧 */ public void hearSound(Frog f, String letter) { - f.setCuboidVales(getCuboidByStr(letter), 20); + f.setCuboidVales(getCuboidByStr(letter), 80); } /** 给这个耳朵听到一个字母,激活它的听觉输入区, 注意听觉输入区并不等于听觉成像区 */ diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Empty.java b/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Empty.java new file mode 100644 index 0000000..be26988 --- /dev/null +++ b/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Empty.java @@ -0,0 +1,42 @@ +/* + * 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.Env; +import com.github.drinkjava2.frog.Frog; +import com.github.drinkjava2.frog.brain.Cuboid; +import com.github.drinkjava2.frog.brain.Organ; + +/** + * Empty is a special organ has no cell, only used as media for photon + * + * Empty这个器官唯一目的只是充当光子媒介初始化cell单元格数组,否则光子如果没遇到cell会一直走下出,从脑图上就观察不到光子了 + * + * @author Yong Zhu + */ +public class Empty extends Organ { + private static final long serialVersionUID = 1L; + + public Empty() { + super(); + this.shape = new Cuboid(2, 2, 2, Env.FROG_BRAIN_XSIZE-4, Env.FROG_BRAIN_YSIZE-4, Env.FROG_BRAIN_ZSIZE-4); + this.organName = "Empty"; + this.type = Organ.EMPTY; // Empty这个器官并不播种cell,它存在的唯一目的只是充当光子媒介,否则光子会一直走下去消失 + this.allowVary = false;// 不允许变异 + this.allowBorrow = false;// 不允许借出 + } + + @Override + public void init(Frog f) {// 覆盖父类方法,不添加cell的action,只是创建空的cell + shape.createCells(f, this); + } + +} diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Ether.java b/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Ether.java deleted file mode 100644 index 73ddee6..0000000 --- a/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Ether.java +++ /dev/null @@ -1,53 +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.brain.organ; - -import com.github.drinkjava2.frog.Env; -import com.github.drinkjava2.frog.Frog; -import com.github.drinkjava2.frog.brain.Cell; -import com.github.drinkjava2.frog.brain.Cuboid; -import com.github.drinkjava2.frog.brain.Organ; - -/** - * Ether is a special organ, it fill all rooms with dynamic type cells - * - * Ether(以太)是个假想的特殊的器官,它均匀地在所有room放置类型为dynamic的脑细胞,也就是说细胞的所有触突是动态生成的,这是个临时 - * 类,试图模拟出波的驻点逆向成像,不清楚在没有引入更复杂的器官之前,是否仅凭单一的动态细胞加上其内部神经元参数的调整就可以形成复杂的网络,完成 - * 模式识别工作。基本原理是如果几个不同方向的信号传来,会在这几个方向上动态生成触突,以后只要有一个信号激活,其它方向也会产生反向的激活信号(光子),多余的能量 - * 则贯穿细胞,送到下一个相邻的细胞去处理。 - * - * 以太这个器官因为会填充所有网格,当脑的维数变大时,将很快耗尽内存,所以只是暂时用来验证思路,以后这个器官会被删除,用正常的随机生成器官来代替。随机生成器官 - * 可以将内存溢出(捕获OutofMemoryException)作为一个扣分条件,再加上越多的脑细胞本身会消耗越多的能量,这样就可以会限制脑的发展大小不会超过虚拟机 - * 允许分配的内存大小。 - * - * @author Yong Zhu - */ -public class Ether extends Organ { - private static final long serialVersionUID = 1L; - - public Ether() { - super(); - this.shape = new Cuboid(0, 0, 0, Env.FROG_BRAIN_XSIZE, Env.FROG_BRAIN_YSIZE, Env.FROG_BRAIN_ZSIZE); - this.organName = "Ether"; - this.type = Organ.DYNAMIC; - this.allowVary = false; - this.allowBorrow = false; - } - - public void init(Frog f) { // 重写父类方法,均匀播种脑细胞 - for (int x = 0; x < Env.FROG_BRAIN_XSIZE; x++) - for (int y = 0; y < Env.FROG_BRAIN_YSIZE; y++) - for (int z = 0; z < Env.FROG_BRAIN_ZSIZE; z++) { - f.getRoom(x, y, z).addCell(new Cell(this)); - } - } - -} diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Eye.java b/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Eye.java index bd2a158..52403a7 100644 --- a/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Eye.java +++ b/core3d/src/main/java/com/github/drinkjava2/frog/brain/organ/Eye.java @@ -24,18 +24,11 @@ public class Eye extends Organ {// 眼睛是长方体 public Eye() { this.shape = new Cuboid(0, 5, 5, 1, 10, 10); + this.type = Organ.EYE; this.organName = "eye"; - this.allowVary = false; - this.allowBorrow = false; - } - - public void init(Frog f) { // 重写父类方法,播种视网膜细胞,它会将视网膜的激活转变成固定向右发散的多个光子,摸拟波源 - shape.fillCells(f, this); - } - - /** each step will call Organ's active methodd */ - public void active(Frog f) { // 每一步测试都会调用active方法,通常用于手动生成的器官 - // do nothing + this.allowVary = false;// 不允许变异 + this.allowBorrow = false;// 不允许借出 + this.color = 0;// red, see ColorUtils } /** @@ -50,11 +43,11 @@ public class Eye extends Organ {// 眼睛是长方体 int h = pixels[0].length; Cuboid c = (Cuboid) shape; - // 在视网膜上产生字母像素点阵,即激活这个脑视网膜所在的rooms区,然后由器官播种出的脑细胞负责将激活能量转为光子输送、存贮到其它位置 + // 在视网膜上产生字母像素点阵,即激活这个脑视网膜所在的cells区,然后由器官播种出的脑细胞负责将激活能量转为光子输送、存贮到其它位置 for (int px = 0; px < w; px++) for (int py = 0; py < h; py++) if (pixels[px][py] > 0) - f.getRoom(0, c.y + c.ye - px, c.z + py).setActive(20); + f.getOrCreateCell(0, c.y + c.ye - px, c.z + py).setActive(100); } } diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/egg/Egg.java b/core3d/src/main/java/com/github/drinkjava2/frog/egg/Egg.java index 1826e55..2d92248 100644 --- a/core3d/src/main/java/com/github/drinkjava2/frog/egg/Egg.java +++ b/core3d/src/main/java/com/github/drinkjava2/frog/egg/Egg.java @@ -17,6 +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.organ.Ear; +import com.github.drinkjava2.frog.brain.organ.Empty; +import com.github.drinkjava2.frog.brain.organ.Dynamic; import com.github.drinkjava2.frog.brain.organ.Eye; import com.github.drinkjava2.frog.util.RandomUtils; @@ -38,7 +40,8 @@ public class Egg implements Serializable { public Egg() {// 无中生有,创建一个蛋,先有蛋,后有蛙 organs.add(new Eye()); // 眼是手工创建的,必有 organs.add(new Ear()); // 耳是手工创建的,这个是用来测试ABCD字母识别的 - organs.add(Organ.randomCuboidOrgan()); + organs.add(new Empty()); // Empty什么都不干,只用来作光子媒介 + organs.add(new Dynamic()); // Dynamic具有动态触突 } /** Create egg from frog */ @@ -61,17 +64,17 @@ public class Egg implements Serializable { if (RandomUtils.percent(70)) // 70%的情况下不作为, x就是受精卵 return; // 从y里借一个organ,替换掉原来位置的organ,相当于DNA级别的片段切换,它要求一个随机位置的Organ都允许替换allowBorrow - int yOrganSize = y.organs.size(); - if (yOrganSize > 0) { - int i = RandomUtils.nextInt(yOrganSize); - Organ o = y.organs.get(i); - if (o.allowBorrow) { - if (organs.size() > i && organs.get(i).allowBorrow) - organs.set(i, o);// 用y里的organ替换掉x里的organ,模拟受精 - } - } - if (RandomUtils.percent(50))// 有50%的机率随机会产生新的器官 - organs.add(Organ.randomCuboidOrgan()); + // int yOrganSize = y.organs.size(); + // if (yOrganSize > 0) { + // int i = RandomUtils.nextInt(yOrganSize); + // Organ o = y.organs.get(i); + // if (o.allowBorrow) { + // if (organs.size() > i && organs.get(i).allowBorrow) + // organs.set(i, o);// 用y里的organ替换掉x里的organ,模拟受精 + // } + // } + // if (RandomUtils.percent(50))// 有50%的机率随机会产生新的器官 + // organs.add(Organ.randomCuboidOrgan()); if (RandomUtils.percent(organs.size())) {// 器官会随机丢失,并且机率与器官数量成正比,防止器官无限增长 int i = RandomUtils.nextInt(organs.size()); if (organs.get(i).allowBorrow) diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/objects/LetterTester.java b/core3d/src/main/java/com/github/drinkjava2/frog/objects/LetterTester.java index 033bda7..fa49c64 100644 --- a/core3d/src/main/java/com/github/drinkjava2/frog/objects/LetterTester.java +++ b/core3d/src/main/java/com/github/drinkjava2/frog/objects/LetterTester.java @@ -52,11 +52,11 @@ public class LetterTester implements EnvObject { Ear ear = firstFrog.findOrganByName("ear"); - if (Env.step < Env.STEPS_PER_ROUND / 2) {// 前半段同时还要激活与这个字母对应脑区(听觉输入区) + if (Env.step < Env.STEPS_PER_ROUND / 5*4) {// 前半段同时还要激活与这个字母对应脑区(听觉输入区) ear.hearSound(firstFrog, letter); - } else if (Env.step == Env.STEPS_PER_ROUND / 2) {// 在中段取消字母对应脑区的激活 + } else if (Env.step == Env.STEPS_PER_ROUND / 5*4) {// 在中段取消字母对应脑区的激活 ear.hearNothing(firstFrog); - } else if (Env.step > Env.STEPS_PER_ROUND / 2) {// 后半段要检测这个字母区是否能收到光子信号 + } else if (Env.step > Env.STEPS_PER_ROUND / 5*4) {// 后半段要检测这个字母区是否能收到光子信号 if (firstFrog.getCuboidActiveTotalValue(ear.getCuboidByStr(letter)) > 0) firstFrog.energy += 100; //TODO 然后还要检测其它的区必须没有这个字母的区活跃 diff --git a/core3d/src/main/java/com/github/drinkjava2/frog/util/ColorUtils.java b/core3d/src/main/java/com/github/drinkjava2/frog/util/ColorUtils.java new file mode 100644 index 0000000..bef2f48 --- /dev/null +++ b/core3d/src/main/java/com/github/drinkjava2/frog/util/ColorUtils.java @@ -0,0 +1,68 @@ +/* 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.util; + +import static java.awt.Color.BLACK; +import static java.awt.Color.BLUE; +import static java.awt.Color.CYAN; +import static java.awt.Color.GREEN; +import static java.awt.Color.MAGENTA; +import static java.awt.Color.ORANGE; +import static java.awt.Color.RED; +import static java.awt.Color.YELLOW; + +import java.awt.Color; + +/** + * Color Utilities used in this project + * + * @author Yong Zhu + * @since 1.0 + */ +public class ColorUtils { + private static final Color[] rainbow = new Color[] { RED, ORANGE, YELLOW, GREEN, CYAN, BLUE, MAGENTA }; + private static int nextColor = 0; + + private ColorUtils() {// default private constr + } + + public static int nextColorCode() { + return nextColor++; + } + + public static Color nextRainbowColor() {// 返回下一个彩虹色 + if (nextColor == rainbow.length) + nextColor = 0; + return rainbow[nextColor++]; + } + + public static Color colorByCode(int i) {// 数值取模后返回一个固定彩虹色 + return rainbow[i % 7]; + } + + public static Color rainbowColor(float i) { // 根据数值大小范围,在8种彩虹色中取值 + if (i == 0) + return BLACK; + if (i == 1) + return RED; + if (i <= 3) + return ORANGE; + if (i <= 10) + return YELLOW; + if (i <= 20) + return GREEN; + if (i <= 50) + return CYAN; + if (i <= 100) + return BLUE; + return MAGENTA; + } +} diff --git a/版本提交记录.md b/版本提交记录.md index d9c8c54..75cde42 100644 --- a/版本提交记录.md +++ b/版本提交记录.md @@ -82,4 +82,94 @@ git reset --hard ae34b07e 可以转回到2019-08-04提交的分组测试的找 开始进行3D脑的实际编程。 ### 2019-9-09 到 2019-10-06 之间的6次提交 -主要进行脑框架的显示和字母试别测试环境的搭建,还没开始进行利用器官进行脑细胞播种的工作。这一阶段基本思路是在每一轮的测试过程前半段随机显示ABCD其中的一个字母(即激活视网膜所在的脑区),并同时激活一个任意脑区。在下半段则只激活这个字母的点阵,然后检测对应的这个脑区是否也会激活,如果激活的话,将会增加青蛙的能量值,让它在生存竟争中胜出,这一步是要完成基本的模式识别功能,框架已搭好,但器官的随机生成还没进行,这一步比较复杂,除了器官的大小位置等参数外,神经元的参数也多,比方说输入、输出光子的方向、正负、数量,能量吸收、释放比例,输入输出阀值、疲劳值、疲劳阀值等,这么多参数要利用随机生成器官的方式来筛选,需要的样本数量多,运行时间会比较长。早期是视网膜和识别区在脑长方体的同一侧,后来的提交改为将视网膜移到左侧,也就是说视觉与识别区(对应耳朵的语音区)在物理上呈90度正交,以方便观察和编程。 \ No newline at end of file +主要进行脑框架的显示和字母试别测试环境的搭建,还没开始进行利用器官进行脑细胞播种的工作。这一阶段基本思路是在每一轮的测试过程前半段随机显示ABCD其中的一个字母(即激活视网膜所在的脑区),并同时激活一个任意脑区。在下半段则只激活这个字母的点阵,然后检测对应的这个脑区是否也会激活,如果激活的话,将会增加青蛙的能量值,让它在生存竟争中胜出,这一步是要完成基本的模式识别功能,框架已搭好,但器官的随机生成还没进行,这一步比较复杂,除了器官的大小位置等参数外,神经元的参数也多,比方说输入、输出光子的方向、正负、数量,能量吸收、释放比例,输入输出阀值、疲劳值、疲劳阀值等,这么多参数要利用随机生成器官的方式来筛选,需要的样本数量多,运行时间会比较长。早期是视网膜和识别区在脑长方体的同一侧,后来的提交改为将视网膜移到左侧,也就是说视觉与识别区(对应耳朵的语音区)在物理上呈90度正交,以方便观察和编程。 + +## 版本提交记录(只记录重要更新) + +如果想要运行Frog项目的以前版本,可以结合gitk命令和参考本提交记录对每个更新的简介,用git reset命令回复到以前任一个版本,例如用: +git reset --hard ae34b07e 可以转回到2019-08-04提交的分组测试的找食版本。 + + + +### 2018-1-3 +项目启动,主要是文字方面的一些构想。 + +### 2019-3-11 1.0.0版, Commit:Go frog go! +开发环境完成,演示第一个人工生命诞生。但是所有Frog脑部为空,因为运动神经元被短路,只能固定向一个方向运动。 +这是第一个发布版,演示了生命的随机进化和优胜劣汰。 +![result1](https://gitee.com/drinkjava2/frog/raw/master/result1.gif) + +### 2019-3-18, Commit:Brain picture! +添加了脑结构图形,用于调试用,可以显示第一个胜出的Frog的脑结构,但是运动神经元依然被短路,只能固定向一个方向运动。 +有了脑结构图,就可以防止所有Frog都被淘汰掉,还不知道问题发生在哪里。可以有针对性地改进进化算法、环境的参数改进。 + +### 2019-03-20, 1.0.1版, Commit:Add a button +添加了一个按钮,可以显示、隐藏第一个胜出的Frog的脑结构图,但是运动神经元依然被短路 + +### 2019-03-21, 1.0.2版, Commit:I'm hungry +在脑区添加Hungry,删除随机运动的硬编码,改成由Hungry区来驱动,一旦frog能量小于10000,hungry区的所有脑神经元的input区激活,如果这些神经元的输出区位于move区,则作相应的移动。这是一个更随机一点的运动,不再总是固定向一个方向。 + +### 2019-03-27, 1.0.3版, Commit:Shrink & Sperm +添加了"卵+精子->受精卵"的模拟,这是为了实现生物多样性。添加了每次添加一批随机神经元,但是只保留激活过的,如果某组神经元从没被用到(激活过),则有很大的可能不会将这组神经元添加到蛋中(用进废退规则)。 + +### 2019-03-29, Commit:Rainbow +更正一个小Bug,BrainStructure的zone显示的半径是实际的一半,用彩虹色而不是随机数来表示CellGroup的细胞数量,色彩越靠后表示细胞数越多。 + +### 2019-04-01, Commit:Cleanup +做一些debug清理,每个Frog不再保留egg的副本,“卵+精子->受精卵”算法改进一下,不能简单两两相加,而是随机取一个精子的cellgroup。 + +### 2019-04-06, Commit:Windows align +还是做一些清理, 可以自由调整虚拟环境、脑图的显示大小。下面的打算是将mouth、leg、hungry等区移到蛋里去,允许进化,而不是作为Frog的硬编码存在。 + +### 2019-04-07, Commit:Organ +引入Organ类,将mouth、leg、hungry等作为Organ器官移到蛋里去,而不是作为Frog的硬编码存在,这样架构更清晰,而且便于以后将Organ参与遗传、变异、进化。 + +### 2019-04-08, Commit:Eye shortcut +添加眼睛,能够看到四个正方向的食物,但是自然选择的结果是眼睛和移动区短路了,眼睛起的作用并不大,因为如果有两个方向同时出现食物,目前青蛙是不能判断的。 +下面要考虑逻辑了,也就是思考判断能力(后天条件反射的建立)。 + +### 2019-04-12, Commit:Random frog +没做大改动,只是将青蛙改成按整个地图随机分布,看起来眼睛的作用就比较明显了,比起随机运动,明显食物被吃掉更多。 +![resut2](https://gitee.com/drinkjava2/frog/raw/master/result2.gif) + +### 2019-05-23, Commit:2 eyes no helps +没做大改动,只是演示添加两个眼睛后,对它的进化没有帮助,到此为此,逐渐看出问题了,没有记忆能力和模式识别能力。目前存在两个比较大的硬编码,导致它不能进一步进化:1.用CellGroup这种硬编码方式,导致在Frog的生存期不能产生记忆功能,而需要多次淘汰,这不符合现实中青蛙从小学到大这样的实际过程,它不需要死很多次。另一个问题是眼睛部分存在硬编码,因此只能起到感光作用,但是不具备根据外在图像进行模式识别能力。所以下面要开始进行非常大的结构改进,。将把CellGroup作为器官引入,但是它的内部细胞是动态生成的,而且不是随机生成的,而是任两个细胞在它的区内活跃就生成新的细胞(将来也可以参与新建细胞)。CellGroup的数量、大小、网格密度(直接影响到神经元生成多少和算法快慢)会参与遗传和进化,快乐和痛苦器官会对新细胞生成的类型有影响。fat参数用来指示它的肥胖度。Fat高的遗传时会保留,并可能变大、变小、内部允行连接数更多、分化成更多CellGroup,但是它的内部连接(新建的细胞)不会参与遗传,这样每个个体都出生时都是一张白纸,虽然也许CellGroup已经进化得很多层很复杂。同一个位置可以存在多个CellGroup,这样由多层大小、位置不同的Layer就同时具备了模式识别和记忆功能,而且这个算法比较简单,很好理解。大范围的Cellgroup可以解释条件反射的形成(两件不相干的事之间形成联系),小范围的Cellgroup可以解释模式识别(相邻感光细胞同时激活,经过层层处理后,汇总到最上层的某个Cellgroup的激活)。而所有这些CellGroup的形成(结构和层级)都可以用非常简单的"用进废退"规则(Fat值控制遗传、随机变异和适者生存来探索最优解)来最终进化出来。 + +### 2019-06-13, Commit: Happy & Pain +主要做了一些清理,将所有器官移到单独的类里,删除OrganDesc类。将一些类(如Applicaton移到根包下)移到不同的包下。这个版本是比较大的一个重构,最大的进步是将算法当成一个器官引入,当然,这个版本只存在一个随机连接两端的算法,以后会扩充。 +另外,顺手加上了Happy和Pain两个器官,分别对应进食愉快感和痛苦感,后者在靠近边界时激发。观查它的表现,果然不出所料,痛苦感立即生效,有一些Frog移动到边界后就不再前进,而是顺着边界溜下去了,不傻,但是Happy器官没有生效,这也很显然,因为Happy属于进食反射链的一部分,在没有记忆器官(算法)引入之前,是没有途径使用上进食奖励信号的。 +![resut3](https://gitee.com/drinkjava2/frog/raw/master/result3.gif) + +### 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中提到的仿照全息存储原理,在思维区逆向成像。因为逆向成像的限制,以后的版本,所有的器官会被移到脑图的同一侧,不再是随意分布在脑图上了,这将是一个比较明显的改动。当然随机连接这个算法看起来比较有用,以后还是可能保留的。 +以下为运行图像: +![resut4](https://gitee.com/drinkjava2/frog/raw/master/result4.gif) + +### 2019-08-04, Commit: Screen group test +引入分屏测试功能,如果青蛙数量多,可以分屏来测试,每屏青蛙的数量可以少到只有1只。 + +### 2019-08-05 commit: Seesaw +有了分屏测试功能后,顺便随手加上了一个青蛙走跷跷板自动平衡的演示,它每次只出场一个青蛙, 每轮包括100场测试,大约跑90多轮半个小时(电脑慢)后,出现了下面的画面: +![result5](https://gitee.com/drinkjava2/frog/raw/master/result5_seesaw.gif) +这个版本的目的是为了增加一点趣味性,显得青蛙还是有点"用处"的,省得让人以为这个项目不务正业,只会让青蛙找食。这个版本青蛙的脑结构和找食版的青蛙基本相同,区别只是在于环境不同,也就是说它的表现随着环境而变化,这符合"通用人工智能"的概念,即信号感受器官是统一的(通常是眼睛),但能根据不同的环境完成不同的任务。走跷跷板演示是最后一个2维脑的版本,今后这个项目将沉寂一段较长时间,今后将致力于将青蛙脑重构为3D金字塔形脑结构(见上文),因为这个项目的缺点已经很明显,它不具备对2维图像的模式识别能力,用随机试错的方式只能处理非常简单的、信号在视网膜的固定区域出现的图像信号。 +青蛙的找食效率以及走跷跷板平衡的能力都没有优化到顶点,一些构想中的复杂的器官如“与门”、“或门”(不要怀疑大自然能否进化出这些复杂器官)等都没加上,但我认为这不重要,目前最高优先级是先进行3D脑结构建模,让青蛙能具备2维图形的模式识别(和回忆)功能,这个大的架构重构是它能处理复杂图像信息的立足之本,它的图像识别能力和通常的用上千张图片来训练识别一个图片这种工作模式不同,它是一种通用的,可自动分类识别所有图像的模式,更符合动物脑的工作模式,记住并回忆出某个图像(或任意输入信号场景的组合),可能只需要这种场景重复出现过几次即可,它是一种无外界信号判定,自动分类的识别模式。 + +### 2019-09-09 commit: start work on 3d +开始进行3D脑的实际编程。 + +### 2019-9-09 到 2019-10-06 之间的6次提交 +主要进行脑框架的显示和字母试别测试环境的搭建,还没开始进行利用器官进行脑细胞播种的工作。这一阶段基本思路是在每一轮的测试过程前半段随机显示ABCD其中的一个字母(即激活视网膜所在的脑区),并同时激活一个任意脑区。在下半段则只激活这个字母的点阵,然后检测对应的这个脑区是否也会激活,如果激活的话,将会增加青蛙的能量值,让它在生存竟争中胜出,这一步是要完成基本的模式识别功能,框架已搭好,但器官的随机生成还没进行,这一步比较复杂,除了器官的大小位置等参数外,神经元的参数也多,比方说输入、输出光子的方向、正负、数量,能量吸收、释放比例,输入输出阀值、疲劳值、疲劳阀值等,这么多参数要利用随机生成器官的方式来筛选,需要的样本数量多,运行时间会比较长。早期是视网膜和识别区在脑长方体的同一侧,后来的提交改为将视网膜移到左侧,也就是说视觉与识别区(对应耳朵的语音区)在物理上呈90度正交,以方便观察和编程。 + +### 2019-11-03 commit: Two waves +原来最小三维数组的单元格名为Cube,后改为Room,最后又改为cell。器官不再是直接播种Cell了,而是播种Cell或在已存在的Cell里添加行为Action,这个提交模拟了代表视觉信号和听力信号的两个波的传播,下一步的工作是将这两个波关联起来,实现模式识别,基本原理见评论中的果冻比喻,正在编程中。 +另个这个提交添加了t、f、l、r,x五个键来在脑图上选择顶视、前视、左视、右视、斜视这5个方向的视图。 \ No newline at end of file