diff --git a/README.md b/README.md index 8ba3183..df07403 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什 ## 项目要实现的短期和长远目标 * 脑模型和虚拟环境的初步搭建 [脑模型刚开始搭建。虚拟环境已完成,点击run.bat可以查看演示] -* 使脑模型具有视觉功能,如果有食物在它附近,将激发天生条件反射,向食物移动,并获得进食奖励 [未完成] +* 使脑模型具有视觉功能,如果有食物在它附近,将激发天生条件反射,向食物移动,并获得进食奖励 [未全部完成] * 引入现成的图像识别算法,使脑模型具有图像识别功能,根据形状区分食物、毒物、天敌 [未完成] * 如果误食有毒食物,将激发天生条件反射,获得惩罚并扣除能量,天生痛觉区兴奋。[未完成] * 如果被天敌攻击,将激发天生条件反射,获得惩罚并扣除能量,天生痛觉区强烈兴奋。[未完成] @@ -60,7 +60,7 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什 ## 目前进展和成绩 2019.03.11 虚拟环境已建好,可以模拟低等生命的遗传、繁殖、变异、进化现象,但目前只能往一个方向运动,相当于一个最简单的单细胞生物,还不具备视觉能力,不具备主动找食能力。 -运行run.bat可以查看演示。Env.java中的几个重要参数说明: +运行run.bat可以查看演示(需要安装Java8和Maven)。Env.java中的几个重要参数说明: * SHOW_SPEED: 调整实验的速度(1~1000),值越小则越慢。 * ENV_WIDTH: 虚拟环境的大小(100~1000) * EGG_QTY: 每次允许Frog下多少个蛋,每个蛋可以孵出4个青蛙。通常下蛋取值在10~1000之间。蛋保存着我们测试的结果。实验的最终目标就是获得一个蛋。 @@ -70,8 +70,11 @@ Frog: 这是人工生命的主体,目前起名叫青蛙(Frog),其实叫什 另外每步演示的结果(egg)会存盘在根目根目录下,名为egg.ser,可以删除这个文件以从头开始新的测试。因为还没涉及脑模型的搭建,可以看到有些青蛙跑得飞快,这是自然选择的结果,因为跑在最前面的吃得多。以后会改正这个bug,要让最聪明的、会抢食的Frog胜出,而不是让跑得快的胜出。 2019.03.21 添加了脑图,改进随机运动模式为Hungry区驱动。从脑图上可以直观地观察脑结构,方便调试。 2019.04.01 改进脑图的显示bug, 每一次生成Frog时添加随机神经元,并简单实现"卵+精子->受精卵"算法,以促进种群多样性。 -2019-04-12 添加一个简单的眼睛,自然选择的结果是眼睛被选中,但是和运动区短路了,谈不上智能。但有眼睛后找食效率明显提高了,见下图: -![resut2](https://gitee.com/drinkjava2/frog/raw/master/result2.gif) +2019-04-12 添加一个简单的眼睛(只有四个感光细胞),自然选择的结果是眼睛被选中,但是和运动区短路了,谈不上智能。但有眼睛后找食效率明显提高了,见下图: +![resut2](https://gitee.com/drinkjava2/frog/raw/master/result2.gif) +2019-06-13 做了一些重构清理,加上了Happy和Pain两个器官,分别对应进食奖励和痛苦感,后者在靠近边界时激发。观查它的表现,痛苦感生效了,一些Frog跑到边界后就不再前进,而是顺着边界溜下去了,但是Happy器官没有生效,这也很显然,因为Happy属于复杂的进食条件反射链的一部分,在没有记忆器官(算法)引入之前,再怎么优胜劣汰也是没办法用上进食奖励信号的。见下图: +![resut3](https://gitee.com/drinkjava2/frog/raw/master/result3.gif) + ## 版权 | License [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0) 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 8504bca..57af8e9 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/Env.java +++ b/core/src/main/java/com/github/drinkjava2/frog/Env.java @@ -21,7 +21,7 @@ import com.github.drinkjava2.frog.egg.EggTool; @SuppressWarnings("serial") public class Env extends JPanel { /** Speed of test */ - public static final int SHOW_SPEED = 1; // 测试速度,1~1000,可调, 数值越小,速度越慢 + public static final int SHOW_SPEED = 5; // 测试速度,1~1000,可调, 数值越小,速度越慢 public static final int ENV_WIDTH = 400; // 虚拟环境的宽度, 可调 @@ -32,7 +32,7 @@ public class Env extends JPanel { public static final int FROG_BRAIN_DISP_WIDTH = 300; // Frog的脑图在屏幕上的显示大小,可调 /** Steps of one test round */ - public static final int STEPS_PER_ROUND = 3000;// 每轮测试步数,可调 + public static final int STEPS_PER_ROUND = 2000;// 每轮测试步数,可调 /** Frog's brain width, fixed to 1000 unit */ public static final float FROG_BRAIN_WIDTH = 1000; // frog的脑宽度固定为1000,不要随便调整,因为器官的相对位置和大小是按脑大小设定的 @@ -47,7 +47,7 @@ public class Env extends JPanel { EggTool.deleteEggs(); } - public static final int FOOD_QTY = 2000; // 食物数量, 可调 + public static final int FOOD_QTY = 1000; // 食物数量, 可调 public static final int EGG_QTY = 50; // 每轮下n个蛋,可调,只有最优秀的前n个青蛙们才允许下蛋 @@ -129,6 +129,10 @@ 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; 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 1607324..43a610d 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/Frog.java +++ b/core/src/main/java/com/github/drinkjava2/frog/Frog.java @@ -19,7 +19,6 @@ import java.util.List; import javax.imageio.ImageIO; 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.egg.Egg; @@ -41,7 +40,7 @@ public class Frog { public int x; // frog在Env中的x坐标 public int y; // frog在Env中的y坐标 - public long frogEngery = 100000; // 能量为0则死掉 + public long frogEngery = 10000; // 能量为0则死掉 public boolean alive = true; // 设为false表示青蛙死掉了,将不参与计算和显示,以节省时间 static Image frogImg; @@ -63,22 +62,16 @@ public class Frog { } public boolean active(Env v) { - frogEngery -= 1; + frogEngery-=0.01; if (!alive) { - frogEngery -= 50;// 死了需要消耗更多的能量,退出生存竞争 return false; } if (frogEngery < 0) { // 如果能量小于0则死 + frogEngery-=10; alive = false; return false; } - // for (Cell cell1 : cells) {// 大脑主循环 - // if (cell1.energy > 0) - // cell1.energy--; - // for (Input input : cell1.inputs) { - // // TODO - // } - // } + for (Organ o : organs) { // 调用每个Organ的active方法 o.active(this); } diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/Cell.java b/core/src/main/java/com/github/drinkjava2/frog/brain/Cell.java index 0321019..a45ab9d 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/Cell.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/Cell.java @@ -19,6 +19,8 @@ import com.github.drinkjava2.frog.brain.group.Group; * @since 1.0 */ public class Cell { + public static final float MAX_ENERGY_LIMIT = 1000.0f; + // this cell belong to frog's which organ public Group group; @@ -29,6 +31,6 @@ public class Cell { public Output[] outputs; // 每个细胞有一组输出触突 // energy of cell, energy got from food - public long energy; // 每个细胞当前的能量值 + public float energy; // 每个细胞当前的能量值 } 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 f6d7a91..ada0047 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 @@ -27,22 +27,23 @@ public abstract class Organ extends Zone { private static final long serialVersionUID = 1L; public String name; // 显示在脑图上的器官名称,可选 - public long fat = 0; // 如果活跃多,fat值高,则保留(及变异)的可能性大,反之则很可能丢弃掉 + public long fat = 0; // 如果活跃多,fat值高,则保留(及变异)的可能性大,反之则很可能丢弃掉 public boolean allowBorrow() { // 是否允许在精子中将这个器官借出 return false; } /** If active in this organ's zone? */ - public boolean outputActive(Frog f) { + public boolean outputActive(Frog f) { // 如果一个细胞能量>10,且它的输出触突位于这个器官内,则器官被激活 for (Cell cell : f.cells) { - for (Output output : cell.outputs) { // - if (cell.energy > 10 && this.nearby(output)) { - cell.group.fat++; - cell.energy -= 1; - return true; + if (cell.energy > 10) + for (Output output : cell.outputs) { // + if (this.nearby(output)) { + cell.group.fat++; + cell.energy -= 3; + return true; + } } - } } return false; } @@ -72,7 +73,7 @@ public abstract class Organ extends Zone { newOrgan = this.getClass().newInstance(); copyXYR(this, newOrgan); newOrgan.name = this.name; - newOrgan.fat = this.fat; + newOrgan.fat = this.fat; return newOrgan; } catch (Exception e) { throw new UnknownError("Can not make new Organ copy for " + this); diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/Zone.java b/core/src/main/java/com/github/drinkjava2/frog/brain/Zone.java index bd443cf..d8ae70e 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/Zone.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/Zone.java @@ -31,7 +31,7 @@ public class Zone implements Serializable { // 空构造器不能省 } - public Zone(float x, float y, float r) { + public Zone(float x, float y, float r) {// 用x,y,r来构造 this.x = x; this.y = y; this.r = r; @@ -45,7 +45,7 @@ public class Zone implements Serializable { this.y = Env.FROG_BRAIN_WIDTH; } - public Zone(Zone z) { + public Zone(Zone z) {// 用另一个Zone来构造 this.x = z.x; this.y = z.y; this.r = z.r; diff --git a/core/src/main/java/com/github/drinkjava2/frog/brain/group/Group.java b/core/src/main/java/com/github/drinkjava2/frog/brain/group/Group.java index 6328118..b2abdfa 100644 --- a/core/src/main/java/com/github/drinkjava2/frog/brain/group/Group.java +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/group/Group.java @@ -29,7 +29,7 @@ import com.github.drinkjava2.frog.brain.Organ; * @author Yong Zhu * @since 1.0 */ -public abstract class Group extends Organ { +public abstract class Group extends Organ { private static final long serialVersionUID = 1L; @Override @@ -40,7 +40,7 @@ public abstract class Group extends Organ { /** Each loop step call active method, Child class can override this method */ @Override public void active(Frog f) { // 每一步都会调用器官的active方法 - f.frogEngery -= 3; // 每个器官运动都要消耗能量, 死了也要消耗能量 + f.frogEngery -= 1; // 每个器官运动都要消耗能量, 死了也要消耗能量 if (!f.alive) return; if (f.frogEngery < 0) { // 如果能量小于0则死 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 c47ebe4..5e8902f 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 @@ -38,6 +38,8 @@ public class RandomConnectGroup extends Group { public Zone inputZone; // 输入触突区 public Zone outputZone; // 输出触突区 + float inputWeight = 1; // 输入权重 + float outputWeight = 1; // 输出权重 @Override public void init(Frog f) { @@ -47,6 +49,7 @@ public class RandomConnectGroup extends Group { outputZone = RandomUtils.randomPosInZone(this); Cell c = new Cell(); + Input in = new Input(inputZone); in.cell = c; c.inputs = new Input[] { in }; @@ -61,19 +64,27 @@ public class RandomConnectGroup extends Group { @Override public Organ[] vary() { - if (fat <= 0) - if (RandomUtils.percent(30)) + if (fat <= 0)// 如果胖值为0,表示这个组的细胞没有用到,可以小概率丢掉它了 + if (RandomUtils.percent(50)) return new Organ[] {}; - if (RandomUtils.percent(80)) - return new Organ[] { this }; - return new Organ[] { this, newRandomConnGroup(this) }; + if (RandomUtils.percent(20)) { // 有20机率权重变大 + inputWeight = RandomUtils.vary(inputWeight); + outputWeight = RandomUtils.vary(outputWeight); + } + return new Organ[] { this }; // 大部分时间原样返回它的副本就行了,相当于儿子是父亲的克隆 + } + + public RandomConnectGroup(float x, float y, float r) { + this.x = x; + this.y = y; + this.r = r; + inputZone = RandomUtils.randomPosInZone(this); + outputZone = RandomUtils.randomPosInZone(this); } - public static RandomConnectGroup newRandomConnGroup(Zone z) { - RandomConnectGroup newOne = new RandomConnectGroup(); - newOne.inputZone = RandomUtils.randomPosInZone(z); - newOne.outputZone = RandomUtils.randomPosInZone(z); - return newOne; + public RandomConnectGroup(Zone z) { + inputZone = RandomUtils.randomPosInZone(z); + outputZone = RandomUtils.randomPosInZone(z); } /** Child class can override this method to drawing picture */ 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 4d7d29d..123feae 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 @@ -22,8 +22,14 @@ public class Eat extends Organ {// Eat这个类将食物转化为能量,能量 @Override public void active(Frog f) { - if (Env.foundAndDeleteFood(f.x, f.y)) - f.frogEngery = f.frogEngery + 1000;// 如果青蛙的坐标与食物重合,吃掉food,能量境加 + if (Env.foundAndDeleteFood(f.x, f.y)) { + f.frogEngery = f.frogEngery + 50000;// 如果青蛙的坐标与食物重合,吃掉food,能量境加 + + // 能量境加青蛙感觉不到,但是Happy区激活青蛙能感觉到,因为Happy区是一个脑器官 + + Organ o = f.organs.get(0); + ((Happy) o).happy += 200; // 找到食物有奖! + } } } 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 198924c..f2b2506 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 @@ -78,16 +78,16 @@ public class Eye extends Organ { for (Input input : cell.inputs) { if (input.nearby(this)) { if (foodAtUp && input.nearby(seeUp)) { - input.cell.energy += 30; + input.cell.energy += 500; // 所有的硬编码都是bug,这个500将来要参与进化,下同 } if (foodAtDown && input.nearby(seeDown)) { - input.cell.energy += 30; + input.cell.energy += 500; } if (foodAtLeft && input.nearby(seeLeft)) { - input.cell.energy += 30; + input.cell.energy += 500; } if (foodAtRight && input.nearby(seeRight)) { - input.cell.energy += 30; + input.cell.energy += 500; } } } 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 new file mode 100644 index 0000000..ded35c5 --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Happy.java @@ -0,0 +1,40 @@ +/* + * 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; + +/** + * Happy zone active after ate food + */ +public class Happy extends Organ { // Happy器官是进食后的产生的快感,痛苦和快感是条件反射形成的前题 + private static final long serialVersionUID = 1L; + public float happy = 0; // happy初始值为0, 进食后将由eat器官增加happy值 + + @Override + public void active(Frog f) { + if (happy > 0) { + happy--; + 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 += happy / 10; // 所有的硬编码都是bug,包括这个2和10 + } + } + } + +} 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 dcd05f1..d92d15d 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 @@ -16,19 +16,22 @@ import com.github.drinkjava2.frog.brain.Input; import com.github.drinkjava2.frog.brain.Organ; /** - * Move down frog 1 unit if outputs of nerve cells active in this zone + * Hungry will active cell's inputs, if frog's energy not enough */ public class Hungry extends Organ { private static final long serialVersionUID = 1L; @Override public void active(Frog f) { - for (Cell cell : f.cells) { - if (f.frogEngery < 10000 && cell.energy < 1000) - for (Input input : cell.inputs) - if (input.nearby(this)) // input zone near by hungry zone - cell.energy += 2; - } + if (f.frogEngery < 10000)// 所有的硬编码都是bug,包括这个10000 + 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)) // input zone near by hungry zone + cell.energy += 2; // 所有的硬编码都是bug,包括这个2 + } } } 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 new file mode 100644 index 0000000..ec464d2 --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/brain/organ/Pain.java @@ -0,0 +1,48 @@ +/* + * 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.Input; +import com.github.drinkjava2.frog.brain.Organ; + +/** + * Pain zone active after some bad thingg happen like close to edge, hurt... + * + * 痛是一种惩罚,表示青蛙做错了什么,但是又不至严重到判其死亡的地步 + */ +public class Pain extends Organ { // Pain器官目前激活的条件是离边境20个单元之类,痛苦和快感是条件反射形成的前题 + + private static final long serialVersionUID = 1L; + + public float pain = 0; // happy初始值为0, 如果frog靠近边界,将增加Pain值,将来如果天敌出现也会激活Frog的Pain区 + + @Override + public void active(Frog f) { + if (Env.closeToEdge(f)) + pain = 500;// 所有的硬编码都是bug,包括这个500 + else + pain = 0; + if (pain > 0) { + 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 += pain / 10; // 所有的硬编码都是bug,包括这个10 + } + } + } + +} 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 9419561..7e08a01 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 @@ -20,11 +20,13 @@ import com.github.drinkjava2.frog.brain.group.Group; import com.github.drinkjava2.frog.brain.group.RandomConnectGroup; import com.github.drinkjava2.frog.brain.organ.Eat; import com.github.drinkjava2.frog.brain.organ.Eye; +import com.github.drinkjava2.frog.brain.organ.Happy; import com.github.drinkjava2.frog.brain.organ.Hungry; import com.github.drinkjava2.frog.brain.organ.MoveDown; import com.github.drinkjava2.frog.brain.organ.MoveLeft; import com.github.drinkjava2.frog.brain.organ.MoveRight; import com.github.drinkjava2.frog.brain.organ.MoveUp; +import com.github.drinkjava2.frog.brain.organ.Pain; import com.github.drinkjava2.frog.util.RandomUtils; /** @@ -45,6 +47,8 @@ public class Egg implements Serializable { public List groups = new ArrayList<>(); public Egg() {// 无中生有,创建一个蛋,先有蛋,后有鸡 + organs.add(new Happy().setXYRN(300, 700, 100, "Happy")); + organs.add(new Pain().setXYRN(600, 700, 100, "Pain")); organs.add(new Hungry().setXYRN(300, 100, 100, "Hungry")); organs.add(new MoveUp().setXYRN(800, 100, 60, "Up")); organs.add(new MoveDown().setXYRN(800, 400, 60, "Down")); @@ -52,9 +56,7 @@ public class Egg implements Serializable { organs.add(new MoveRight().setXYRN(900, 250, 60, "Right")); organs.add(new Eat().setXYRN(0, 0, 0, "Eat")); organs.add(new Eye().setXYRN(100, 400, 100, "Eye")); - for (int i = 0; i <10; i++) { - organs.add( new RandomConnectGroup().setXYRN(500, 500, 500, null)); - } + addRandomConnectionGroups(); } @@ -62,10 +64,14 @@ public class Egg implements Serializable { public Egg(Frog frog) { // 青蛙下蛋,每个青蛙的器官会创建自已的副本或变异,可以是0或多个 for (Organ organ : frog.organs) for (Organ newOrgan : organ.vary()) - organs.add(newOrgan); - for (int i = 0; i <10; i++) { - organs.add( new RandomConnectGroup().setXYRN(500, 500, 500, null)); - } + organs.add(newOrgan); + addRandomConnectionGroups(); + } + + private void addRandomConnectionGroups() { + for (int i = 0; i < 20; i++) { + organs.add(new RandomConnectGroup(500, 500, 500)); + } } /** @@ -87,9 +93,7 @@ public class Egg implements Serializable { if (o.allowBorrow()) organs.add(o); } - for (int i = 0; i <10; i++) { - organs.add( new RandomConnectGroup().setXYRN(500, 500, 500, null)); - } + addRandomConnectionGroups(); } } 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 508631b..c6317a3 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 @@ -58,7 +58,7 @@ public class EggTool { 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() + ", "); + System.out.print(", organs =" + newEggs.get(0).organs.size() + ", "); FileOutputStream fo = new FileOutputStream(Application.CLASSPATH + "eggs.ser"); ObjectOutputStream so = new ObjectOutputStream(fo); 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 new file mode 100644 index 0000000..8f253df --- /dev/null +++ b/core/src/main/java/com/github/drinkjava2/frog/env/CellGroup.java @@ -0,0 +1,14 @@ +/* + * 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 6249053..5f514c5 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 @@ -31,9 +31,19 @@ public class RandomUtils { return rand.nextFloat(); } - public static Zone randomPosInZone(Zone z) { + /** Return a random zone inside a zone */ + public static Zone randomPosInZone(Zone z) { // 在一个区内随机取一个小小区 return new Zone(z.x - z.r + z.r * 2 * rand.nextFloat(), z.y - z.r + z.r * 2 * rand.nextFloat(), - z.r * rand.nextFloat() * .02f); + z.r * rand.nextFloat() * .04f); + } + + /** vary a zone position, size a little bit */ + public static Zone varyZone(Zone z) { + Zone zz = new Zone(); + zz.x = vary(z.x); + zz.y = vary(z.y); + zz.r = vary(z.r); + return zz; } public static boolean percent(int percent) { diff --git a/eggs.ser b/eggs.ser index 29b6de0..fa1238a 100644 Binary files a/eggs.ser and b/eggs.ser differ diff --git a/result3.gif b/result3.gif new file mode 100644 index 0000000..ec4ad86 Binary files /dev/null and b/result3.gif differ diff --git a/版本提交记录.md b/版本提交记录.md index 250b5e7..c57555e 100644 --- a/版本提交记录.md +++ b/版本提交记录.md @@ -42,7 +42,7 @@ ### 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-2, 1.0.4版, Commit: Last old version -主要做了一些清理,将所有器官移到单独的类里,删除OrganDesc类。将一些类(如Applicaton移到根包下)移到不同的包下。这个版本是为了下面做重大重构(见上面的构思)做准备,同时也算是给以前的工作做个总结,这个版本是一个分水岭。 - +### 2019-06-13, Commit: Happy & Pain +主要做了一些清理,将所有器官移到单独的类里,删除OrganDesc类。将一些类(如Applicaton移到根包下)移到不同的包下。这个版本是比较大的一个重构,最大的进步是将算法当成一个器官引入,当然,这个版本只存在一个随机连接两端的算法,以后会扩充。 +另外,顺手加上了Happy和Pain两个器官,分别对应进食愉快感和痛苦感,后者在靠近边界时激发。观查它的表现,果然不出所料,痛苦感立即生效,有一些Frog移动到边界后就不再前进,而是顺着边界溜下去了,不傻,但是Happy器官没有生效,这也很显然,因为Happy属于进食反射链的一部分,在没有记忆器官(算法)引入之前,是没有途径使用上进食奖励信号的。