Happy & Pain

pull/1/head
Yong Zhu 6 years ago
parent d47385fd16
commit e3955b58ea

@ -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 添加一个简单的眼睛,自然选择的结果是眼睛被选中,但是和运动区短路了,谈不上智能。但有眼睛后找食效率明显提高了,见下图:
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)

@ -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;

@ -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);
}

@ -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; // 每个细胞当前的能量值
}

@ -34,12 +34,13 @@ public abstract class Organ extends Zone {
}
/** If active in this organ's zone? */
public boolean outputActive(Frog f) {
public boolean outputActive(Frog f) { // 如果一个细胞能量>10,且它的输出触突位于这个器官内,则器官被激活
for (Cell cell : f.cells) {
if (cell.energy > 10)
for (Output output : cell.outputs) { //
if (cell.energy > 10 && this.nearby(output)) {
if (this.nearby(output)) {
cell.group.fat++;
cell.energy -= 1;
cell.energy -= 3;
return true;
}
}

@ -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;

@ -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则死

@ -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 */

@ -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; // 找到食物有奖!
}
}
}

@ -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;
}
}
}

@ -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
}
}
}
}

@ -16,18 +16,21 @@ 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) {
if (f.frogEngery < 10000)// 所有的硬编码都是bug包括这个10000
for (Cell cell : f.cells) {
if (f.frogEngery < 10000 && cell.energy < 1000)
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;
cell.energy += 2; // 所有的硬编码都是bug包括这个2
}
}

@ -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
}
}
}
}

@ -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<Group> 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();
}
@ -63,8 +65,12 @@ public class Egg implements Serializable {
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));
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();
}
}

@ -58,7 +58,7 @@ public class EggTool {
List<Egg> 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);

@ -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 {
}

@ -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) {

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save